本文接上一篇,主要介绍“Deque”的另一种更高效的实现——DequeAsDoublyLinkedList。
一、操作效率之比
前一篇中学到的DequeAsLinkedList,它的底层是采用的是单链表(点击打开链接)。单链表的特点是:“它只有一个指针域,指向后继者”,只能从前向后遍历,不能从后向前遍历。故删除head元素比较简单,直接删除指向的元素,并移动head指针即可,消耗为O(1);而删除tail元素,则需要先遍历整个链表,获取tail的前节点,删除尾元素后,还要修改它的前节点的next指针,并移动tail指针,遍历链表的时间消耗是O(n)。这样,DequeHead的时间是O(1);而DequeTail的时间是O(n)。
要想提高DequeTail的效率,需要从底层进行修改,最好的办法是采用“双向链表”(点击打开链接),这样,在头尾的操作都是一样的,不足的是占用的内存更大,且需要对每个节点的prev和next指针进行管理。
二、DequeAsDoublyLinkedList
接口声明
<span style="font-size:14px;">#pragma once
#include "Deque.h"
#include "DoublyLinkedList.h"
using namespace FoundationalDataStructure;
class DequeAsDoublyLinkedList : public Deque
{
public:
DequeAsDoublyLinkedList();
~DequeAsDoublyLinkedList();
void Purge();
void Accept(Visitor &) const;
Object & Head() const;
Object & Tail() const;
void Enqueue(Object &);
void EnqueueHead(Object&);
void EnqueueTail(Object &);
Object & Dequeue();
Object & DequeueHead();
Object & DequeueTail();
protected:
int CompareTo(Object const &) const;
private:
DoublyLinkedList<Object*> list;
};
</span>
接口实现
#include "DequeAsDoublyLinkedList.h"
DequeAsDoublyLinkedList::DequeAsDoublyLinkedList()
: list()
{
}
DequeAsDoublyLinkedList::~DequeAsDoublyLinkedList()
{
Purge();
}
void DequeAsDoublyLinkedList::Purge()
{
if (IsOwner())
{
for (auto ptr = list.Head(); ptr != NULL; ptr = ptr->Next())
delete ptr->Datum();
}
list.Purge();
count = 0;
}
void DequeAsDoublyLinkedList::Accept(Visitor & visitor) const
{
for (auto ptr = list.Head(); ptr != NULL && !visitor.IsDone(); ptr = ptr->Next())
visitor.Visit(*ptr->Datum());
}
Object & DequeAsDoublyLinkedList::Head() const
{
if (count == 0)
throw std::domain_error("queue is empty");
return *list.First();
}
Object & DequeAsDoublyLinkedList::Tail() const
{
if (count == 0)
throw std::domain_error("deque is empty");
return *list.Last();
}
void DequeAsDoublyLinkedList::Enqueue(Object& object)
{
Deque::Enqueue(object);
}
void DequeAsDoublyLinkedList::EnqueueHead(Object & object)
{
list.Prepend(&object);
++count;
}
void DequeAsDoublyLinkedList::EnqueueTail(Object & object)
{
list.Append(&object);
++count;
}
Object & DequeAsDoublyLinkedList::Dequeue()
{
return Deque::Dequeue();
}
Object & DequeAsDoublyLinkedList::DequeueHead()
{
if (count == 0)
throw std::domain_error("queue is empty");
Object &result = *list.First();
list.Extract(&result);
--count;
return result;
}
Object & DequeAsDoublyLinkedList::DequeueTail()
{
if (count == 0)
throw std::domain_error("deque is empty");
Object & result = *list.Last();
list.Extract(&result);
--count;
return result;
}
int DequeAsDoublyLinkedList::CompareTo(Object const & object) const
{
return -1;
}