Как создать циклический связанный список

Я знаю, как создавать классы Link и LinearLinkedList, но я просто не могу понять, как преобразовать их в создающий circularlinkedlist.

Я уже прочитал ответ на этот вопрос. Однако я не понимаю, как, если head является None, то как объект типа None может иметь атрибут next? Я просто не могу понять концепцию.

Если бы кто-нибудь мог показать мне функцию __init__ образца CircularLinkedList и простое объяснение того, как она работает, я думаю, что смог бы ее понять.

Спасибо за любую помощь

Изменить: мне нужен только список, который нужно пройти вперед. Если это так, нужно ли радикально менять логику, стоящую за этим?


person Colosus__    schedule 04.04.2015    source источник
comment
Можете ли вы нарисовать диаграмму для такого списка с нулем, одним, двумя элементами и т. д.? Это должно помочь вам понять, как организовать вещи. Кроме того, спросите себя, должен ли список содержать ссылки только в одном направлении или также и в другом.   -  person Ulrich Eckhardt    schedule 04.04.2015
comment
Мне нужно только, чтобы они были подключены по отдельности вперед. Создает ли это огромную разницу, если мне нужно, чтобы он также перемещался назад?   -  person Colosus__    schedule 04.04.2015
comment
Для рисования это просто, но некоторые операции над односвязным списком сложнее, чем над двусвязным списком.   -  person Ulrich Eckhardt    schedule 04.04.2015


Ответы (4)


Часто в круговом связанном списке у вас есть специальная ссылка, которая не содержит значимых данных. Вместо этого это «страж», сообщающий вам, где находится начало (и конец) списка. Эта ссылка будет существовать, даже если список пуст, поэтому ваши алгоритмы будут работать во всех списках, без множества особых случаев, требующих специального кода.

class Link:
    def __init__(self, data, next):
        self.data = data
        self.next = next

class CircularLinkedList:
    def __init__(self):
        self.head = Link(None, None) # this is the sentinel node!
        self.head.next = self.head   # link it to itself

    def add(self, data):             # no special case code needed for an empty list
        self.head.next = Link(data, self.head.next)

    def __contains__(self, data):    # example algorithm, implements the "in" operator
        current = self.head.next
        while current != self.head:
            if current.data == data: # element found
                return True
            current = current.next
        return False
person Blckknght    schedule 04.04.2015
comment
Предположим, я удаляю последнюю ссылку. Будет ли он автоматически настраивать цикл на первую ссылку, или мне придется вручную учитывать это в моей функции удаления? * Разобрался, играя с ним. Спасибо за помощь! - person Colosus__; 04.04.2015

Верно; если нет узлов, то не может быть указателей на следующий/предыдущий:

root
 |
 v
None

Если есть один узел, он связывается назад и вперед сам с собой:

    root
     |
     v
+-> Node <-+
|   next---+
+---prev

Если есть два узла:

      root
       |
       v
  +-> Node   +-> Node <--+
  |   next---+   next--+ |
+-|---prev <-----prev  | |
| +--------------------+ |
+------------------------+
person Aasmund Eldhuset    schedule 04.04.2015
comment
Ваша ситуация для «без узлов» - это не совсем та ситуация, которую описывает ОП (хотя это возможный подход). Вместо этого это больше похоже на ситуацию, которую вы описываете как «один» узел. Однако ваш подход может быть более удобным представлением, поскольку он позволяет упростить None-тесты. - person Joost; 04.04.2015
comment
Спасибо за наглядное представление. Я ценю помощь! - person Colosus__; 04.04.2015

            class Node:
                def __init__(self, d=None, n=None, p=None):
                    self.data = d
                    self.next_node = n
                    self.p_node = p
            
                def __str__(self):
                    return '(' + str(self.data) + ')'
            
            
            class CircularlinkedList:
                def __init__(self, r=None):
                    self.root = r
                    self.size = 0
            
                def add(self, d):
                    if self.size == 0:
                        self.root = Node(d)
                        self.root.next_node = self.root
                    else:
                        new_node = Node(d, self.root.next_node)
                        self.root.next_node = new_node
                    self.size += 1
            
                def find(self, d):
                    this_node = self.root
                    while True:
                        if this_node.data == d:
                            return d
                        elif this_node.next_node == self.root:
                            return False
                        this_node = this_node.next_node
            
                def remove(self, d):
                    this_node = self.root
                    prev_node = None
                    while True:
                        if this_node.data == d:
                            if prev_node is not None:
                                prev_node.next_node = this_node.next_node
                            else:
                                while this_node.next_node != self.root:
                                    this_node = this_node.next_node
                                this_node.next_node = self.root.next_node
                                self.root = self.root.next_node
                            self.size -= 1
                            return True
                        elif this_node.next_node == self.root:
                            return False
                        prev_node = this_node
                        this_node = this_node.next_node
            
                def print_list(self):
                    if self.root is None:
                        return
                    this_node = self.root
                    print(this_node, end='->')
                    while this_node.next_node != self.root:
                        this_node = this_node.next_node
                        print(this_node, end='->')
                    print()
            

           

cll = круговой список()

for i in [5, 7, 3, 8, 9]:

    cll.add(i)

print('Размер='+str(cll.size))

печать (cll. найти (8))

печать (кл. найти (12))

мой_узел = cll.root

 for i in range(8):

    my_node = my_node.next_node

    print(my_node,end='->')

Распечатать()

cll.print_list()

кл.удалить(8)

печать (клл.удалить (15))

print('Размер='+str(cll.size))

кл.удалить(5)

cll.print_list()

person Shah Vipul    schedule 21.11.2020

Важным шагом здесь является то, что голова не None. Только данные узла Link головы являются None, и он указывает на себя через свой атрибут next. Как упоминалось в ответе, на который вы ссылались, это будет выглядеть примерно так:

def __init__(self):
    self.head = Link(None, None)
    self.head.next = self.head
person Joost    schedule 04.04.2015
comment
Кажется, я начинаю понимать. Благодарю вас! - person Colosus__; 04.04.2015