Есть ли какое-либо преимущество двусвязной очереди перед односвязной?

Меня попросили реализовать двусвязную очередь, но я знаю, что односвязная очередь проста, и все ее основные функции выполняются в big-Theta 1. В основном я говорю о реализации FIFO (не включая специальные очереди, такие как deque).

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

Есть ли преимущество двусвязной очереди перед односвязной?!


person Ellysherh Kingdom    schedule 29.11.2017    source источник
comment
Вы слышали о двойной очереди? , В этом пользователю разрешено вставлять и удалять из очереди с обоих концов. Это зависит от приложения.   -  person Lalit Verma    schedule 29.11.2017
comment
Вы можете перейти по этой ссылке для того же geeksforgeeks.org/double-linked-list   -  person ankitkhandelwal185    schedule 29.11.2017
comment
Я знаю двустороннюю очередь (deque), но меня беспокоит обычная реализация очереди FIFO @LalitVerma   -  person Ellysherh Kingdom    schedule 29.11.2017
comment
Для обычной структуры списка всегда есть преимущества реализации двусвязного списка, но мой вопрос основан на реализации очереди, поскольку функции отличаются от списка @iwayankit   -  person Ellysherh Kingdom    schedule 29.11.2017


Ответы (2)


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

person Dragonthoughts    schedule 29.11.2017
comment
Для обычных операций с очередью (постановка в очередь, удаление из очереди, а также очистка, получение переднего/заднего значения и получение длины, isEmpty, isFull и т. д.) вам не нужно выполнять итерацию в обоих направлениях. Им даже не нужно, чтобы вы выполняли итерации в любом направлении, кроме вывода очереди и других второстепенных функций. Я до сих пор не вижу преимущества в этом @Dragonthoughts - person Ellysherh Kingdom; 29.11.2017
comment
Как выполнить удаление очереди с любого конца с помощью односвязной очереди без итерации до конца с самого начала? Вам нужно знать, что указывает на ваш конец, чтобы превратить его в ваш новый конец. - person Dragonthoughts; 29.11.2017
comment
Вот почему я включил в свой вопрос слова «основные функции очереди». Вы говорите о специальной очереди (deque), но моя проблема в основном связана с реализацией FIFO, возможно, позвольте мне обновить свой вопрос, чтобы быть более понятным - person Ellysherh Kingdom; 29.11.2017
comment
Если вы создаете реализацию FIFO, вы добавляете на одном конце и удаляете из очереди на другом. Как вы держите свои указатели в порядке, не повторяя до конца одну операцию в односвязной структуре? - person Dragonthoughts; 29.11.2017
comment
@Dragonthoughts Что вы хотите делать с указателями? Мне не нужно ничего трогать посередине. Мне нужны только указатели на первый и последний элемент. Текущий последний элемент указывает на следующий, если я удаляю его из очереди, я получаю оттуда следующий последний указатель. Когда я вставляю спереди, у меня также есть указатель на этот элемент, чтобы изменить его следующее свойство на то, которое я только что вставил. Не нужно повторять или трогать что-то между ними. - person Mörre; 21.01.2019
comment
Когда вы выполняете deque, используя последний указатель, как вы определяете новое значение для вашего последнего указателя? Новый последний указатель должен быть указателем на itme до того, который вы возвращаете, поэтому в односвязном списке вам нужно будет выполнить итерацию к этому элементу, чтобы найти его адрес, и сделать все необходимое для предотвращения этого. указывая на удаленный из очереди элемент. - person Dragonthoughts; 21.01.2019

Вам не нужен двойной LL вместо двухстороннего LL. Двустороннего LL (имеющего указатель на голову и хвост) достаточно.

Для FIFO основными операциями являются постановка в очередь и удаление из очереди. В терминах связанных списков это add_to_end и remove_from_front. Обе они являются операциями O (1) с двусторонним связанным списком.

Если вам нужна структура данных, которая может работать и как очередь, и как стек, вам понадобится двусвязный список для выполнения операций O(1). Основная операция, которая потребовала бы O(n) без двусвязного списка, — это remove_from_end/pop. Причина этого в том, что вам нужно будет найти узел, предшествующий последнему (узел 3 в примере ниже), установить его в конец, а затем удалить его указатель на узел, который вы удаляете. С двойным LL найти этот узел так же просто, как tail.prev; однако с двусторонним LL вам придется выполнить обход O (n), чтобы найти этот узел.

Первые 1 - 2 - 3 - 4 Последние

def remove_from_end():
# get node4 and remove node4 from being the tail. O(1) time as you have a pointer to the tail in a double ended LL.
# set tail node3 and remove the .next from node3 to node4. If you don't have .prev on node4, then it would take O(n) to find node3
person JaTo    schedule 09.02.2020