单链表及双链表总结

来源:互联网 发布:win10找不到网络打印机 编辑:程序博客网 时间:2024/06/05 10:59

介绍

线性表的链式存储结构,指的是用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的。


链表(Linked List),动态存储分配,运行时分配空间。

存储特点:

  1. 逻辑次序和物理次序不一定相同。
  2. 元素之间的逻辑关系用指针表示

单链表

单向链表是链表的一种,它由节点组成,每个节点都包含下一个节点的指针。


结点结构

数据域data,存储数据元素指针域next,存储指向后继节点的地址

特点节点的连接方向是单向的;相对于数组来说,单链表的随机访问速度较慢,但是单链表删除/添加数据的效率很高


双链表

双向链表是链表的一种。和单链表一样,双向链表也是由节点组成,它的每个数据节点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个节点开始,都可以很方便地访问它的前驱节点和后继节点。一般我们都构造双向循环链表。

结点结构

数据域data,存储数据元素指针域prev,存储指向前驱节点的地址

next,存储指向后继节点的地址




————————————————————————————————————————————————————————————————————————————

单向链表及其操作示例

单向链表的示意图

在单链表的第一个元素结点之前附设一个类型相同的结点,以便空表和非空表处理统一,并且可统一对任意位置的结点的操作实现。


删除结点


添加结点




—————————————————————————————————————————————————————————————————————————————

双向链表及其操作示例

双链表的示意图


删除结点


添加结点




—————————————————————————————————————————————————————————————————————————————

算法实现

C++实现单链表

头文件LInkedList.h

#ifndef LINKED_LIST#define LINKED_LIST#include<iostream>using namespace std;template<class T>struct DNode{public:T value;DNode *next;public:DNode(){}DNode(T t, DNode *next){this->value = t;this->next = next;}};template<class T>class LinkedList{public:LinkedList();~LinkedList();int size();bool is_empty();T get(int index);T get_first();T get_last();bool insert(int index,T t);bool insert_first(T t);bool append_last(T t);bool del(int index);bool delete_first();bool delete_last();private:int count;// 链表计数 DNode<T> *phead;private:DNode<T> *get_node(int index);};template<class T>LinkedList<T>::LinkedList() : count(0){// 创建表头结点phead = new DNode<T>();phead->next = phead;// 设置链表计数为0// count = 0 }template<class T>LinkedList<T>::~LinkedList(){// 删除所有结点DNode<T> *ptmp;DNode<T> *pnode = phead->next;while(pnode!=phead){ptmp = pnode;pnode = pnode->next;delete ptmp;}// 删除表头delete phead;phead = NULL; }// 返回节点数目template<class T>int LinkedList<T>::size(){return count;} // 判断链表是否为空template<class T>bool LinkedList<T>::is_empty(){return count==0;} // 获取第index位置的节点template<class T>DNode<T>* LinkedList<T>::get_node(int index){// 判断参数有效性if(index<0 || index>=count){cout<<"get node failed! the index is out of bound!"<<endl;return NULL;} int i=0;DNode<T>* pindex = phead->next;while(i++<index){pindex = pindex->next;}return pindex; } // 获取第index位置的节点的值 template<class T>T LinkedList<T>::get(int index){return get_node(index)->value;}// 获取第1个节点的值template<class T>T LinkedList<T>::get_first(){return get_node(0)->value;}// 获取最后一个节点的值 template<class T>T LinkedList<T>::get_last(){return get_node(count-1)->value;}// 将节点插入到第index位置之前template<class T>bool LinkedList<T>::insert(int index,T t){if(index==0)return insert_first(t);if(index<0 || index>=count){cout<<"insert node failed! the index is out of bound!"<<endl;return false;}DNode<T> *pindex = get_node(index-1);// 定位到index位置前一个节点 DNode<T> *pnode = new DNode<T>(t,pindex->next);pindex->next = pnode;++count;return true;} // 将节点插入到第一个节点处 template<class T>bool LinkedList<T>::insert_first(T t){DNode<T> *pnode = new DNode<T>(t,phead->next);phead->next = pnode;++count;return true;}// 将节点追加到链表末尾 template<class T>bool LinkedList<T>::append_last(T t){DNode<T> *pnode = new DNode<T>(t,NULL);DNode<T> *ptail = get_node(count-1);// 定位到最后一个节点ptail->next = pnode; ++count;return true;} // 删除index位置的节点template<class T>bool LinkedList<T>::del(int index){if(index<0 || index>=count){cout<<"delete node failed! the index is out of bound!"<<endl;return false;}DNode<T> *pnode;if(index==0)pnode = phead;elsepnode = get_node(index-1);DNode<T> *pindex = get_node(index); pnode->next = pindex->next;delete pindex;--count;return true;}// 删除第一个节点template<class T>bool LinkedList<T>::delete_first(){return del(0);} // 删除最后一个节点 template<class T>bool LinkedList<T>::delete_last(){return del(count-1);}#endif

测试文件LlistTest.cpp

#include<iostream>#include "LinkedList.h"using namespace std;// 单向链表操作string数据void str_test(){string sarr[4] = {"ten", "twenty", "thirty", "forty"};cout<<"----str_test----"<<endl;// 创建单向链表LinkedList<string> *pdlink = new LinkedList<string>();pdlink->insert(0,sarr[1]);// 将20插入到第一个位置 pdlink->append_last(sarr[0]);// 将10追加到链表末尾pdlink->insert_first(sarr[2]);// 将30插入到第一个位置// 单向链表是否为空cout<<"is_empty()=";if(pdlink->is_empty())cout<<"True"<<endl;elsecout<<"False"<<endl;// 单向链表的大小cout<<"size()="<<pdlink->size()<<endl;// 打印单向链表中的全部数据 int sz = pdlink->size();    for(int i=0; i<sz; i++)        cout << "pdlink("<<i<<")=" << pdlink->get(i) <<endl;} // 单向链表操作int数据void int_test(){cout<<"----int_test----"<<endl;// 创建单向链表LinkedList<int> *pdlink = new LinkedList<int>();pdlink->insert(0,20);// 将20插入到第一个位置 pdlink->append_last(10);// 将10追加到链表末尾pdlink->insert_first(30);// 将30插入到第一个位置// 单向链表是否为空cout<<"is_empty()=";if(pdlink->is_empty())cout<<"True"<<endl;elsecout<<"False"<<endl;// 单向链表的大小cout<<"size()="<<pdlink->size()<<endl;// 打印单向链表中的全部数据 int sz = pdlink->size();    for(int i=0; i<sz; i++)        cout << "pdlink("<<i<<")=" << pdlink->get(i) <<endl;} struct stu{int id;char name[20];};static stu arr_stu[]={{10, "sky"},    {20, "jody"},    {30, "vic"},    {40, "dan"},};// 单向链表操作struct数据void obj_test(){cout<<"----object_test----"<<endl;// 创建单向链表LinkedList<stu> *pdlink = new LinkedList<stu>();pdlink->insert(0,arr_stu[1]);// 将20插入到第一个位置 pdlink->append_last(arr_stu[0]);// 将10追加到链表末尾pdlink->insert_first(arr_stu[2]);// 将30插入到第一个位置// 单向链表是否为空cout<<"is_empty()=";if(pdlink->is_empty())cout<<"True"<<endl;elsecout<<"False"<<endl;// 单向链表的大小cout<<"size()="<<pdlink->size()<<endl;// 打印单向链表中的全部数据 int sz = pdlink->size();    for (int i=0; i<sz; i++)        cout << "pdlink("<<i<<")=" << pdlink->get(i).id<<","<<pdlink->get(i).name <<endl;}int main(){int_test();str_test();obj_test();return 0;}


C++实现双链表

头文件DoubleLink.h

#ifndef DOUBLE_LINK#define DOUBLE_LINK#include<iostream>using namespace std;template<class T>struct DNode{public:T value;DNode *prev;DNode *next;public:DNode(){}DNode(T t, DNode *prev, DNode *next){this->value = t;this->prev = prev;this->next = next;}};template<class T>class DoubleLink{public:DoubleLink();~DoubleLink();int size();bool is_empty();T get(int index);T get_first();T get_last();bool insert(int index,T t);bool insert_first(T t);bool append_last(T t);bool del(int index);bool delete_first();bool delete_last();private:int count;// 链表计数 DNode<T> *phead;private:DNode<T> *get_node(int index);};template<class T>DoubleLink<T>::DoubleLink() : count(0){// 创建表头结点phead = new DNode<T>();phead->prev = phead->next = phead;// 设置链表计数为0// count = 0 }template<class T>DoubleLink<T>::~DoubleLink(){// 删除所有结点DNode<T> *ptmp;DNode<T> *pnode = phead->next;while(pnode!=phead){ptmp = pnode;pnode = pnode->next;delete ptmp;}// 删除表头delete phead;phead = NULL; }// 返回节点数目template<class T>int DoubleLink<T>::size(){return count;} // 判断链表是否为空template<class T>bool DoubleLink<T>::is_empty(){return count==0;} // 获取第index位置的节点template<class T>DNode<T>* DoubleLink<T>::get_node(int index){// 判断参数有效性if(index<0 || index>=count){cout<<"get node failed! the index is out of bound!"<<endl;return NULL;} // 正向查找if(index<=count/2){int i=0;DNode<T>* pindex = phead->next;while(i++<index){pindex = pindex->next;}return pindex;} else// 反向查找 {int i=0;int rindex = count - index -1;DNode<T>* prindex = phead->prev;// 找到尾节点while(i++<rindex){prindex = prindex->prev; } return prindex;}} // 获取第index位置的节点的值 template<class T>T DoubleLink<T>::get(int index){return get_node(index)->value;}// 获取第1个节点的值template<class T>T DoubleLink<T>::get_first(){return get_node(0)->value;}// 获取最后一个节点的值 template<class T>T DoubleLink<T>::get_last(){return get_node(count-1)->value;}// 将节点插入到第index位置之前template<class T>bool DoubleLink<T>::insert(int index,T t){if(index==0)return insert_first(t);// 此处与原文作者有所修正 if(index<0 || index>=count){cout<<"insert node failed! the index is out of bound!"<<endl;return false;}DNode<T> *pindex = get_node(index); // 原文是在此处对index有效性进行检查 DNode<T> *pnode = new DNode<T>(t,pindex->prev,pindex);pindex->prev->next = pnode;pindex->prev = pnode;++count;return true;} // 将节点插入到第一个节点处 template<class T>bool DoubleLink<T>::insert_first(T t){DNode<T> *pnode = new DNode<T>(t,phead,phead->next);phead->next->prev = pnode;phead->next = pnode;++count;return true;}// 将节点追加到链表末尾 template<class T>bool DoubleLink<T>::append_last(T t){DNode<T> *pnode = new DNode<T>(t,phead->prev,phead);phead->prev->next = pnode;phead->prev = pnode;++count;return true;} // 删除index位置的节点template<class T>bool DoubleLink<T>::del(int index){// 此处与原文作者有所修正 if(index<0 || index>=count){cout<<"delete node failed! the index is out of bound!"<<endl;return false;}DNode<T> *pindex = get_node(index);pindex->next->prev = pindex->prev;pindex->prev->next = pindex->next;delete pindex;--count;return true;}// 删除第一个节点template<class T>bool DoubleLink<T>::delete_first(){return del(0);} // 删除最后一个节点 template<class T>bool DoubleLink<T>::delete_last(){return del(count-1);}#endif

测试文件DLinkTest.cpp

#include<iostream>#include "DoubleLink.h"using namespace std;// 双向链表操作string数据void str_test(){string sarr[4] = {"ten", "twenty", "thirty", "forty"};cout<<"----str_test----"<<endl;// 创建双向链表DoubleLink<string> *pdlink = new DoubleLink<string>();pdlink->insert(0,sarr[1]);// 将20插入到第一个位置 pdlink->append_last(sarr[0]);// 将10追加到链表末尾pdlink->insert_first(sarr[2]);// 将30插入到第一个位置// 双向链表是否为空cout<<"is_empty()=";if(pdlink->is_empty())cout<<"True"<<endl;elsecout<<"False"<<endl;// 双向链表的大小cout<<"size()="<<pdlink->size()<<endl;// 打印双向链表中的全部数据 int sz = pdlink->size();    for(int i=0; i<sz; i++)        cout << "pdlink("<<i<<")=" << pdlink->get(i) <<endl;} // 双向链表操作int数据void int_test(){cout<<"----int_test----"<<endl;// 创建双向链表DoubleLink<int> *pdlink = new DoubleLink<int>();pdlink->insert(0,20);// 将20插入到第一个位置 pdlink->append_last(10);// 将10追加到链表末尾pdlink->insert_first(30);// 将30插入到第一个位置// 双向链表是否为空cout<<"is_empty()=";if(pdlink->is_empty())cout<<"True"<<endl;elsecout<<"False"<<endl;// 双向链表的大小cout<<"size()="<<pdlink->size()<<endl;// 打印双向链表中的全部数据 int sz = pdlink->size();    for(int i=0; i<sz; i++)        cout << "pdlink("<<i<<")=" << pdlink->get(i) <<endl;} struct stu{int id;char name[20];};static stu arr_stu[]={{10, "sky"},    {20, "jody"},    {30, "vic"},    {40, "dan"},};// 双向链表操作struct数据void obj_test(){cout<<"----object_test----"<<endl;// 创建双向链表DoubleLink<stu> *pdlink = new DoubleLink<stu>();pdlink->insert(0,arr_stu[1]);// 将20插入到第一个位置 pdlink->append_last(arr_stu[0]);// 将10追加到链表末尾pdlink->insert_first(arr_stu[2]);// 将30插入到第一个位置// 双向链表是否为空cout<<"is_empty()=";if(pdlink->is_empty())cout<<"True"<<endl;elsecout<<"False"<<endl;// 双向链表的大小cout<<"size()="<<pdlink->size()<<endl;// 打印双向链表中的全部数据 int sz = pdlink->size();    for (int i=0; i<sz; i++)        cout << "pdlink("<<i<<")=" << pdlink->get(i).id<<","<<pdlink->get(i).name <<endl;}int main(){int_test();str_test();obj_test();return 0;}


参考资料:

感谢作者 (如果天空不死)数组、单链表和双链表介绍 以及 双向链表的C/C++/Java实现

0 0