您的位置:首页 > 其它

链表原理详解及其实现

2016-03-21 21:53 1046 查看

什么是链表?

链表,顾名思义,是一条相互链接的数据节点表。每个节点由两部分组成:数据和指向下一个节点的指针。链表的基本结构如下图所示:



一般来说,链表的头结点不存放具体的数据,所以也被称为哑节点(dummy node)。原因在于这样可以比较好地区分链表的头结点,而且可以大大简化链表的各种操作,避免很多不必要的边界讨论。

链表的种类

单向链表 双向链表 循环链表 多向表(网状表)

链表的优缺点

这里的优缺点主要是和链表对应的另一个数据结构:数组相比得出的。

链表的优点在于:

1.物理存储单元上非连续,而且采用动态内存分配,能够有效的分配和利用内存资源;

2.节点删除和插入简单,不需要内存空间的重组。

作为一种数据结构,链表必然也有让人诟病的地方。链表的缺点在于:

1.不能进行索引访问,只能从头结点开始顺序查找;

2.数据结构较为复杂,需要大量的指针操作,容易出错。

单向链表的模板类实现

笔者实现了一个单向链表模板类,支持了绝大部分链表操作。

(笔者坚信好的代码不必写过多的注释,代码本身即具有良好的可阅读性)

首先需要定义链表节点类:

template <class T>
class Node
{
public:
Node();
~Node();

T val;
Node *next;
};


链表类的定义如下:

template <class T>
class List
{
public:
List();
~List();

void isEmpty();
void isHead(Node<T> *node);
void isTail(Node<T> *node);

Node<T> *getHead();
Node<T> *getTail();

Node<T> *find(T val);
Node<T> *findPrevious(T val);

void insert(Node<T> *node, T val);
void append(T val);
void remove(T val);
void reverse();

int size();
void clear();
void print();

private:
Node<T> *_head;
};


下面是具体的链表操作实现:

1.链表是否为空

template <class T>
void List<T>::isEmpty()
{
return _head->next == NULL;
}


2.判断节点是否为头结点

template <class T>
void List<T>::isHead(Node<T> *node)
{
return node == _head;
}


3.判断节点是否为尾节点

template <class T>
void List<T>::isTail(Node<T> *node)
{
return node->next == NULL;
}


4.获取链表的头结点

template <class T>
Node<T> *List<T>::getHead()
{
return _head;
}


5.获取节点的尾节点

template <class T>
Node<T> *List<T>::getTail()
{
Node<T> *tmpNode = _head;
while(tmpNode->next)
{
tmpNode = tmpNode->next;
}
return tmpNode;
}


6.查找节点

template <class T>
Node<T> *List<T>::find(T val)
{
Node<T> *tmpNode = _head->next;
while(tmpNode)
{
if (tmpNode->val == val)
{
return tmpNode;
}
tmpNode = tmpNode->next;
}
return NULL;
}


7.查找上一个节点

template <class T>
Node<T> *List<T>::findPrevious(T val)
{
Node<T> *tmpNode = _head;
while(tmpNode->next)
{
if (tmpNode->next->val == val)
{
return tmpNode;
}
tmpNode = tmpNode->next;
}
return NULL;
}


8.在指定节点之后插入新节点

template <class T>
void List<T>::insert(Node<T> *node, T val)
{
Node<T> *tmpNode = _head->next;
while(tmpNode)
{
if (tmpNode == node)
{
Node<T> *newNode = new Node<T>();
newNode->val = val;
newNode->next = tmpNode->next;
tmpNode->next = newNode;
return;
}
tmpNode = tmpNode->next;
}
}


9.在链表尾部插入节点

template <class T>
void List<T>::append(T val)
{
Node<T> *newNode = new Node<T>();
newNode->val = val;
Node<T> *tail = getTail();
tail->next = newNode;
}


10.删除节点

template <class T>
void List<T>::remove(T val)
{
Node<T> *prevNode = findPrevious(val);

if (prevNode)
{
Node<T> *tmpNode = prevNode->next;
prevNode->next = prevNode->next->next;
delete tmpNode;
}
}


11.反转链表

template <class T>
void List<T>::reverse()
{
Node<T> *tmpNode = _head->next;
Node<T> *prevNode = NULL;
while(tmpNode)
{
Node<T> *nextNode = tmpNode->next;
tmpNode->next = prevNode;
prevNode = tmpNode;
tmpNode = nextNode;
}
_head->next = prevNode;
}


12.获取链表的节点数

template <class T>
int List<T>::size()
{
Node<T> *tmpNode = _head->next;
int n = 0;
while(tmpNode)
{
tmpNode = tmpNode->next;
n++;
}
return n;
}


13.删除整个链表

template <class T>
void List<T>::clear()
{
Node<T> *tmpNode = _head->next;
while(tmpNode)
{
Node<T> *node = tmpNode;
tmpNode = tmpNode->next;
delete node;
}
_head->next = NULL;
}


14.打印链表的所有节点

template <class T>
void List<T>::print()
{
Node<T> *tmpNode = _head->next;
while(tmpNode)
{
std::cout << tmpNode->val;//类型T需要重载输出流操作符
<<
tmpNode = tmpNode->next;
if (tmpNode)
{
std::cout << " ";
}
}
std::cout << std::endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: