Рубрики
Без рубрики

Вдвойне круговые связанные списки в Python

Двойно круговой связанный список – это структура данных, которая используется для хранения записей в списке. Это принципиально так же, как связанные списки, но с несколькими

Автор оригинала: Pankaj Kumar.

Двойно круговой связанный список – это структура данных, которая используется для хранения записей в списке. Это принципиально так же, как связанные списки, но с несколькими дополнительными основными моментами. В этом руководстве мы посмотрим на то, что такое вдвойне круговой связанный список, как сделать один в Python, и что является его выходом.

Предпосылки

Мы должны сначала обсудить несколько структур данных, прежде чем переходить на вдвойне круговые связанные списки.

1. Связанные списки

Связанный список – это список, в котором элементы связаны с другими элементами определенным образом. Различные типы связанных списков имеют разные способы связывания элементов.

Самый простой связанный список – это «по отдельно связанным списком» или просто «связанный список». В этом каждый элемент ссылается на следующий элемент в списке. (Но не в обратном порядке). Итак, для доступа к NTH Pithone, нам нужно будет получить доступ к пункту (N-1) ITE. И доступ к пункту NTH позволяет нам получить доступ к пункту (N + 1) TH списка.

У нас есть прямой доступ к первому элементу списка, используя, что мы можем получить доступ к 2-м одному, а затем 3-й и т. Д. До последнего элемента, который не имеет доступа к любому другому элементу в списке.

Каждый элемент в связанном списке называется узлом. Каждый узел имеет часть, которая хранит свои данные, а другая часть для хранения ссылки/ссылки на следующий узел.

Одно связанный список в списке

2. Вдвойне связанные списки

Вдвойне связанные списки аналогичны связанным спискам, но в этом случае каждый узел имеет две ссылки, один на следующий узел и один на предыдущий узел.

Таким образом, чтобы получить доступ к NT-узлу, нам нужно будет сначала получить доступ к узлу (N-1) или узлу (N + 1). И после того, как мы получили доступ к NT-узлу, используя его, мы можем получить доступ к узлу (N-1) или узлу (N + 1). То есть обход может случиться в любом направлении.

Каждый узел изготовлен из трех частей, один для данных и двух других для предыдущих и следующих ссылок. Это выглядит что-то подобное:

Список вдвойне связан в списке RIPR 3

3. Круговые связанные списки

Круглые связанные списки также аналогичны связанным спискам, единственное различие, являющееся тем, что последний узел ссылается на первый узел вместо того, чтобы не иметь ссылки. Таким образом, он образует круговую связь между узлами, и если мы продолжим доступ к следующим узлам, он никогда не заканчивается и вернет к началу после первого узла.

Это выглядит что-то подобное:

Круговой связанный список RIP 1

Вдвойне круговые связанные списки

Теперь, когда мы знаем, как выглядят вдвойне связанные списки и круговые связанные списки, как выглядят трудно понять, что будет вдвойне круговой связанный список.

Здесь каждый узел содержит три части, один для данных, а два других для ссылок. Каждый узел ссылается на следующие и предыдущие узлы списка. Для первого узла нет предыдущего узла, поэтому он идет по кругу и ссылкам на последний узел списка. Точно так же для последнего узла нет следующего узла, поэтому он идет по кругу и ссылкам на первый узел списка.

Чтобы получить доступ к любому узлу, нам нужно получить доступ к узлу после него или узла перед ним, и после доступа к любому узлу узлы после и до того, как он может быть напрямую доступен. Но мы также можем получить доступ к последнему узлу прямо с первого узла и наоборот.

Визуализировать, вдвойне круговой связанный список выглядит что-то подобное:

Вдвойне круговой связанный список реп

В приведенном выше примере вы можете видеть, что в списке четыре узла есть четыре узла, и каждый узел подключен к узлу после него и узла перед ним. Последний узел указывает на второй последний узел и первый узел, и первый узел указывает на последний узел и второй узел.

Глава указывает на начало списка, и теперь мы можем либо пересекать вперед и достичь конца, либо мы можем пройти назад и достичь запуска списка.

Реализация вдвойне круговых связанных списков в Python

Мы должны создать два класса, один для узлов, а другой, который будет использовать узлы для создания связанного списка.

Класс: узел

class Node:
    def __init__(self, data = None):
        self.data = data
        self.previous = self
        self.next = self

Первоначально при создании узла он укажет на себя в обоих направлениях сформировать вдвойне круговой связанный список только с одним элементом.

Класс: вдвойне круговой связанный список

class DCLL:
    def __init__(self):
        self.head = None
        self.count = 0
    
    def __repr__(self):
        string = ""
         
        if(self.head == None):
            string += "Doubly Circular Linked List Empty"
            return string
         
        string += f"Doubly Circular Linked List:\n{self.head.data}"       
        temp = self.head.next
        while(temp != self.head):
            string += f" -> {temp.data}"
            temp = temp.next
        return string
    
    def append(self, data):
        self.insert(data, self.count)
        return
    
    def insert(self, data, index):
        if (index > self.count) | (index < 0):
            raise ValueError(f"Index out of range: {index}, size: {self.count}")
        
        if self.head == None:
            self.head = Node(data)
            self.count = 1
            return
        
        temp = self.head
        if(index == 0):
            temp = temp.previous
        else:
            for _ in range(index - 1):
                temp = temp.next
        
        temp.next.previous = Node(data)
        temp.next.previous.next, temp.next.previous.previous = temp.next, temp
        temp.next = temp.next.previous
        if(index == 0):
            self.head = self.head.previous
        self.count += 1
        return
    
    def remove(self, index):
        if (index >= self.count) | (index < 0):
            raise ValueError(f"Index out of range: {index}, size: {self.count}")
            
        if self.count == 1:
            self.head = None
            self.count = 0
            return
        
        target = self.head
        for _ in range(index):
            target = target.next
            
        if target is self.head:
            self.head = self.head.next
            
        target.previous.next, target.next.previous = target.next, target.previous
        self.count -= 1
        
    def index(self, data):
        temp = self.head
        for i in range(self.count):
            if(temp.data == data):
                return i
            temp = temp.next
        return None
    
    def get(self, index):
        if (index >= self.count) | (index < 0):
            raise ValueError(f"Index out of range: {index}, size: {self.count}")
            
        temp = self.head
        for _ in range(index):
            temp = temp.next
        return temp.data
    
    def size(self):
        return self.count
    
    def display(self):
        print(self)

Вышеуказанный класс содержит много методов, давайте обсудим их один за другим.

То __в этом__ метод

Мы объявляем двух членов, голова и Считать Инициализирован Нет и 0 Соответственно, потому что в списке нет узлов в списке.

То __repr__ метод

__repr__ Способ вернет строку, которая напечатает содержимое списка на экране.

То присоединиться к а также вставлять метод

Мы можем либо добавить или вставлять узлы в списке. Добавить Метод создан только для удобства, поскольку он называет Вставить Способ и отправляет соответствующие значения.

В Вставить Способ, мы сначала проверим, если индекс находится в диапазоне или нет, а если нет, мы поднимаем ValueError Отказ Затем, если список пуст, то мы просто назначаем новый узел для голова и сделать Считать равный 1. Теперь мы достигаем узла непосредственно перед индекс где новый узел должен быть вставлен.

На данный момент мы делаем предыдущий узла по указанному индексу, равным новым узлам. Затем мы делаем новый узел Следующий и предыдущий равный узлу по указанному индексу и узеру до указанного индекса соответственно. И теперь мы делаем Следующий из узла до указанного индекса, равный новому узлу. Наконец, если указанный индекс был 0 тогда мы делаем голова указать на узел незадолго до того, как он указывал.

Просто увеличивайте Считать и Вставить метод сделан.

То Удалить метод

В этом методе мы впервые проверим, если индекс не имеет диапазона и бросать ValueError если это. Тогда, если только один узел, мы просто сделаем голова как Нет и сделать Считать как 0 и вернуться.

Если нет, мы достигаем необходимого узла, который будет удален, и если целевой узел является голова мы делаем голова Укажите на узел после этого, чтобы мы не теряем список.

Наконец, мы делаем Следующий из узла до указанного указателя точки на узел после указанного индекса, и мы делаем предыдущий из узла после указанного указателя указывают на узел до указанного индекса. Это сделает узел по указанному индексу, недостойным из списка (в основном пропущенном), и мы уменьшаем количество, чтобы закончить метод.

То индекс , получать , размер , а также отображать метод

индекс Метод ищет линейно через список и возвращает индекс, если элемент найден, Нет иначе.

получить Метод возвращает элемент по указанному индексу и повышает ValueError Если индекс вне диапазона.

Размер Метод возвращает количество элементов в списке.

Дисплей Метод печатает список.

Выход

Python DCLL вывод 1
Python DCLL вывод 2

Заключение

В этом руководстве мы подробно изучили вдвое круговое соединенное списком и реализовали его в Python. Надеюсь, вам понравилось узнать об этом и увидимся в следующем руководстве.