一、定义
链表是数据结构中,最简单的一种数据结构。简单到你可以将它看成一个数组
,只不过这个数组元素不像常规数组那样内存连续,而是类似于一根链条,被某些东西
给连接起来。
单链表
单链表由一系列不必在内存中相连的结构组成,每一个结构均含有表元素和指向包含该元素的后继元的结构的指针。
上图为链表的基本结构图,最后一个元素...
的后继元为NULL
。
删除节点
单链表删除节点相当简单,只需要更改被删节点的前驱元的next指针,指向被删节点的后继元,即可完成节点的删除工作。如下图所示:
上图中,节点NodeB是被删节点,因此只需要将节点NodeA的next
指针指向节点NodeC即可。
增加节点
上图中,要在节点NodeA和节点NodeB中间插入节点NodeD,只需要将NodeA的next指针指向节点NodeD,同时将节点NodeD的next指针指向节点NodeB即可。
双链表
双链表是在单链表的基础上,增加一个指向上一个节点的指针。这样做的好处是,对于倒序遍历链表,实现方式相当简单。
双链表的图示如下:
循环链表
循环链表则是在单/双链表的基础上进一步扩展,将原本表尾指向NULL的指针,换成指向表头节点。
循环链表(双链表)图示如下:
二、实现
节点(Node)
节点是表形数据结构中的基本单元,甚至也是树形数据结构的基本单元。以下代码定义一个简单的节点类型:
template <typename T>
class Node
{
public:
Node(T *entity = nullptr) : m_pEntity(entity) {}
virtual ~Node() = 0 {}
/**
* @brief 设置节点的数据
*
* @param ent 新的节点数据
*/
void setEntity(T *ent) { m_pEntity = ent; }
/**
* @brief 获取节点的数据
*
* @return T* 节点的数据
*/
T *entity() { return m_pEntity; }
protected:
// 节点的数据域
T *m_pEntity;
};
单链表
/**
* @brief 单链表类。
*
* @tparam T
*/
template<typename T>
class SingleLinkedList
{
public:
SingleLinkedList() : m_pHead(nullptr), m_pTail(nullptr) {}
SingleLinkedList(const SingleLinkedList &rhs) : m_pHead(rhs.m_pHead), m_pTail(rhs.m_pTail) {}
~SingleLinkedList() {}
/**
* @brief 构造一个空的单链表。
*
* @return SingleLinkedList<T>* 构造出来的空单链表
*/
static SingleLinkedList<T>* constructEmpty()
{
SingleLinkedList<T> *ret = new SingleLinkedList<T>;
return ret;
}
SingleListNode<T> *head() { return m_pHead; }
bool empty() { return m_pHead == m_pTail; }
// 单链表的插入操作
void insert(T *ent, SingleListNode<T>* pos)
{
if(! pos)
return;
SingleListNode<T> newNode = new SingleListNode<T>(ent);
auto next = pos->next();
// 将当前节点的next指针指向新节点
pos->setNext(newNode);
// 再将新节点的next指针指向原本的next节点。
newNode->setNext(next);
// 如此就完成了节点的插入操作
}
// 单链表的删除操作
void deleteNode(T* ent)
{
if(m_pHead && m_pHead->entity() == ent)
{
m_pHead = m_pHead->next();
return;
}
// 由于单链表没有记录上一个节点的指针,因此这里使用双指针的方式,来进行单链表
// 节点的删除操作。
SingleListNode<T> *previous = m_pHead;
SingleListNode<T> *current = m_pHead->next();
while (current)
{
if(current->entity() == ent)
{
// 如果当前节点的数据对象就是要删除的数据对象,
// 则直接将当前节点的上一级节点的next指针,指向当前节点的下一级节点。
previous->setNext(current->next());
break;
}
previous = current;
current = current->next();
}
}
// 单链表的查找操作
SingleListNode<T>* findPrevious(T* ent)
{
SingleListNode<T> *cur = m_pHead;
while (cur)
{
if(cur->entity() == ent)
return cur;
cur = cur->next();
}
}
protected:
SingleListNode<T> *m_pHead;
SingleListNode<T> *m_pTail;
};