链表原理详解及其实现
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; }
相关文章推荐
- Delphi IOS环境安装
- HDU 5646
- win10安装markdown出现未知错误
- TweenMax page-hopper
- [bzoj3638]k-Maximum Subsequence Sum
- 深入理解C指针学习笔记(一)
- java中throw和throws的区别
- SDAU 课程练习2 1002
- Qt版本差异造成的问题与解决方法
- instancetype和id
- Stack Overflow网站加载慢,无法显示更多评论等问题
- 第十四讲--PGA管理和调整
- mysql按汉语拼音首字母排序
- 数字颠倒
- 【CV】ICCV2015_Unsupervised Visual Representation Learning by Context Prediction
- hdu 1828 Picture【扫描线求周长模板题】
- linux基本正则和扩展正则建dan
- 北化oj 2110- 程序改错 - 多语句宏
- codevs2800送外卖
- 强连通分量 CCF201509-4 高速公路