单链表类
链表和数组都属于线性(一对一)数据结构,即每个元素都有自己的前驱或者后继,或者两者都有。不同的是,在数组中,逻辑上相邻的两个元素地址也相邻;而在链表中,逻辑上相邻的两个元素地址未必相邻。
节点
一个单链表由数个节点链接起来,每个节点的定义如下:
class Node {
public:
Node() : next_(nullptr) {
}
Node(const Item &item) : item_(item), next_(nullptr) {
}
Item item_;
Node *next_;
};
Item
是模板参数。每个节点包括一个数据项item_
和一个指向下个节点的指针next_
。
类的声明
slist.h
template <typename Item>
class SList {
class Node {
public:
Node() : next_(nullptr) {
}
Node(const Item &item) : item_(item), next_(nullptr) {
}
Item item_;
Node *next_;
};
public:
SList();
~SList();
void PushFront(const Item &item); // 在链表头插入节点
void PushBack(const Item &item); // 在链表尾插入节点
Item PopFront(); // 从链表头删除节点
bool IsEmpty() const;
size_t Size() const;
private:
Node *first;
Node *last;
size_t N;
};
每个SList
对象都包含一个不保存有效数据的首节点,first
始终指向它。当链表为空时,last
也指向首节点,否则指向链表中的最后一个节点。
N
表示链表中的节点个数(不包括首节点)。
SList
类支持在链表头插入节点、在链表尾插入节点和从链表头删除节点,这3种操作都是O(1)
的复杂度。目前的SList
无法高效地实现从链表尾删除节点,因为要找到last
的前一个节点需要遍历一次链表。
节点是分配在堆上的,析构函数里要及时释放内存,避免内存泄露。
类的实现
slist.h
template <typename Item>
SList<Item>::SList()
{
first = new Node();
last = first;
N = 0;
}
template <typename Item>
SList<Item