双向链表(Doubly Linked List)
1. 双向链表的概念
1.1 双向链表的定义
- 双向链表又称为双链表,是链表的一种。
1.2 双向链表的结点结构
- 双向链表的结点包括三个部分:前驱指针域、数据域和后继指针域。
(1)前驱指针域(lLink),又称为左链指针,用于存放一个指针,该指针指向上一个结点的开始存储地址。
(2)数据域(data),用于存储该结点的数据元素,数据元素类型由应用问题决定。
(3)后继指针域(rLink),又称为右链指针,用于存放一个指针,该指针指向下一个结点的开始存储地址。 - 双向链表的结点结构示意图:
1.3 双向链表中各结点的链接方式
- 双向链表常采用带附加头结点的循环链表的链接方式。
- 一个双向链表有一个附加头结点,由链表的头指针first指示,它的data域或者不放数据,或者存放一个特殊要求的数据,它的lLink指向链表的尾结点(即最后一个结点),它的rLink指向链表的首元结点(即第一个结点)。
- 双向链表的首元结点的左链指针lLink和尾结点的右链指针rLink都指向附加头结点first。
- 从双向链表中的任意一个结点开始,就可以直接访问它的前驱结点和后继结点。
- 双向链表(带附加头结点的)中各结点的链接方式示意图示意图:
2. 双向链表的实现
2.1 链表的结点结构定义
文件:LinkNode.h
#ifndef LINK_NODE_H_ #define LINK_NODE_H_ #include <iostream> #include <string> #include <strstream> using namespace std; template <class T> struct LinkNode //链表结点类的定义 { T data; //数据域 LinkNode<T> *lLink; //指针域——前驱指针 LinkNode<T> *rLink; //指针域——后继指针 //仅初始化指针成员的构造函数 LinkNode(LinkNode<T>* lptr = NULL, LinkNode<T>* rptr = NULL){ lLink = lptr; rLink = rptr; } //初始化数据与指针成员的构造函数 LinkNode(const T& value, LinkNode<T>* lptr = NULL, LinkNode<T>* rptr = NULL){ data = value; lLink = lptr; rLink = rptr;} }; #endif /* LINK_NODE_H_ */
2.2 双向链表的类定义及其操作的实现(带附加头结点)
文件:DoublyLinkedList.h
#ifndef DBL_LINKED_LIST_H_ #define DBL_LINKED_LIST_H_ #include "LinkNode.h" template <class T> class DblLinkedList//带附加头结点 { public: DblLinkedList(); //构造函数 DblLinkedList(const DblLinkedList<T>& L); //拷贝构造函数 ~DblLinkedList(); //析构函数 public: int Length()const; //计算链表的结点总数(除附加头结点) LinkNode<T>* Search(const T& x)const; //搜索数据值为x的结点并返回 LinkNode<T>* Locate(int i, bool isLtoR = true)const; //获取第i个结点并返回,遍历方向默认是从左往右 bool GetData(int i, T& x, bool isLtoR = true)const; //获取第i个结点的数据值保存至x,并返回获取成功与否,遍历方向默认是从左往右 bool SetData(int i, const T& x, bool isLtoR = true); //修改第i个结点的数据值为x,遍历方向默认是从左往右 bool Insert(int i, const T& x, bool isLtoR = true); //在第i个结点后插入数据值为x的新结点,遍历方向默认是从左往右 bool Remove(int i, T& x, bool isLtoR = true); //删除第i个结点,并将被删结点的数据值保存至x,遍历方向默认是从左往右 bool IsEmpty()const; //判断表是否为空 bool IsFull()const; //判断表是否为满 void Sort(); //表排序——冒泡排序 void InputFront(const T& endTag); //前插法建立链表 void InputRear(const T& endTag); //后插法建立链表 void Output()const; //输出所有结点的数据值 void Reverse(); //链表逆置 void MakeEmpty(); //清空链表(保留附加头结点) DblLinkedList<T>& operator=(const DblLinkedList<T>& L); //链表间赋值操作——重载等号运算符 public: LinkNode<T>* GetHead()const; //返回附加头结点的地址 T get_value(string& s_value); //返回输入的结点数据值 public: static bool IsNumber(const string& s_num); //判断输入的字符串每个字符是否都是数值0~9 static T StrToTtype(const string& s_num); //类型转换——将string型转为模板类型T private: LinkNode<T> *first; //链表的头结点 }; //构造函数 template<class T> DblLinkedList<T>::DblLinkedList() : first(new LinkNode<T>) { first->lLink = first; first->rLink = first; cout << "$ 执行构造函数" << endl; } //拷贝构造函数 template<class T> DblLinkedList<T>::DblLinkedList(const DblLinkedList<T>& L) { cout << "$ 执行拷贝构造函数" << endl; LinkNode<T> *srcptr = L.GetHead(); LinkNode<T> *destptr = first = new LinkNode<T>; while (L.GetHead() != srcptr->rLink) { srcptr = srcptr->rLink; destptr->rLink = new LinkNode<T>(srcptr->data); destptr->rLink->lLink = destptr; destptr = destptr->rLink; } first->lLink = destptr; destptr->rLink = first; } //析构函数 template<class T> DblLinkedList<T>::~DblLinkedList() { cout << "$ 执行析构函数" << endl; MakeEmpty(); } //计算链表的结点总数(除附加头结点) template<class T> int DblLinkedList<T>::Length()const { int count = 0; LinkNode<T> *curNode = first->rLink; while (first != curNode) { curNode = curNode->rLink; count++; } return count; } //搜索数据值为x的结点并返回 template<class T> LinkNode<T>* DblLinkedList<T>::Search(const T& x)const { LinkNode<T> *curNode = first->rLink; while ((first != curNode) && (x != curNode->data)) { curNode = curNode->rLink; } if (first == curNode) { curNode = NULL; } return curNode; } //获取第i个结点并返回,遍历方向默认是从左往右 template<class T> LinkNode<T>* DblLinkedList<T>::Locate(int i, bool isLtoR)const { if (i < 0) { return NULL; } if ((first == first->rLink) || (0 == i)) { return first; } int location = 1; LinkNode<T> *curNode = NULL; if (true == isLtoR) { curNode = first->rLink; } else { curNode = first->lLink; } while ((location < i) && (first != curNode)) { if (true == isLtoR) { curNode = curNode->rLink; } else { curNode = curNode->lLink; } location++; } if (first == curNode) { curNode = NULL; } return curNode; } //获取第i个结点的数据值保存至x,并返回获取成功与否,遍历方向默认是从左往右 template<class T> bool DblLinkedList<T>::GetData(int i, T& x, bool isLtoR)const { LinkNode<T> *curNode = Locate(i, isLtoR); if ((NULL == curNode) || (first == curNode)) { return false; } x = curNode->data; return true; } //修改第i个结点的数据值为x,遍历方向默认是从左往右 template<class T> bool DblLinkedList<T>::SetData(int i, const T& x, bool isLtoR) { LinkNode<T> *curNode = Locate(i, isLtoR); if ((NULL == curNode) || (first == curNode)) { return false; } curNode->data = x; return true; } //在第i个结点后插入数据值为x的新结点,遍历方向默认是从左往右 template<class T> bool DblLinkedList<T>::Insert(int i, const T& x, bool isLtoR) { LinkNode<T> *curNode = Locate(i, isLtoR); if (NULL == curNode) { return false; } LinkNode<T> *newNode = new LinkNode<T>(x); if (NULL == newNode) { cerr << "* 存储分配错误" << endl; exit(1); } if (true == isLtoR) { newNode->lLink = curNode; newNode->rLink = curNode->rLink; curNode->rLink->lLink = newNode; curNode->rLink = newNode; } else { newNode->lLink = curNode->lLink; newNode->rLink = curNode; curNode->lLink->rLink = newNode; curNode->lLink = newNode; } return true; } //删除第i个结点,并将被删结点的数据值保存至x,遍历方向默认是从左往右 template<class T> bool DblLinkedList<T>::Remove(int i, T& x, bool isLtoR) { LinkNode<T> *delNode = Locate(i, isLtoR); if ((NULL == delNode) || (first == delNode)) { return false; } delNode->rLink->lLink = delNode->lLink; delNode->lLink->rLink = delNode->rLink; x = delNode->data; delete delNode; return true; } //判断表是否为空 template<class T> bool DblLinkedList<T>::IsEmpty()const { return (first == first->rLink) ? true : false; } //判断表是否为满 template<class T> bool DblLinkedList<T>::IsFull()const { return false; } //表排序——冒泡排序 template<class T> void DblLinkedList<T>::Sort() { LinkNode<T> *curNode = first->rLink; while (first != curNode) { LinkNode<T> *nextNode = curNode->rLink; while (first != nextNode) { if (curNode->data < nextNode->data) { T temp = curNode->data; curNode->data = nextNode->data; nextNode->data = temp; } nextNode = nextNode->rLink; } curNode = curNode->rLink; } } //前插法建立链表 //endTag是约定的输入序列结束的标志。如果输入序列是正整数,endTag可以是0或负数; //如果输入序列是字符,endTag可以是字符集中不会出现的字符,如“\0”。 template<class T> void DblLinkedList<T>::InputFront(const T& endTag) { MakeEmpty(); LinkNode<T> *lastNode = NULL; string s_value; T value = get_value(s_value); while (endTag != value) { LinkNode<T> *newNode = new LinkNode<T>(value); if (NULL == newNode) { cerr << "* 存储分配错误" << endl; exit(1); } if (first->rLink == first) { lastNode = newNode; } newNode->lLink = first; newNode->rLink = first->rLink; first->rLink->lLink = newNode; first->rLink = newNode; value = get_value(s_value); } first->lLink = lastNode; lastNode->rLink = first; } //后插法建立链表 //endTag是约定的输入序列结束的标志。如果输入序列是正整数,endTag可以是0或负数; //如果输入序列是字符,endTag可以是字符集中不会出现的字符,如“\0”。 template<class T> void DblLinkedList<T>::InputRear(const T& endTag) { MakeEmpty(); LinkNode<T> *lastNode = first; string s_value; T value = get_value(s_value); while (endTag != value) { LinkNode<T> *newNode = new LinkNode<T>(value); if (NULL == newNode) { cerr << "* 存储分配错误" << endl; exit(1); } newNode->lLink = lastNode; newNode->rLink = lastNode->rLink; lastNode->rLink = newNode; lastNode = newNode; value = get_value(s_value); } first->lLink = lastNode; lastNode->rLink = first; } //输出所有结点的数据值 template<class T> void DblLinkedList<T>::Output()const { LinkNode<T> *curNode = first->rLink; while (first != curNode) { cout << "curNode->data = " << curNode->data << endl; curNode = curNode->rLink; } } //链表逆置 template<class T> void DblLinkedList<T>::Reverse() { LinkNode<T> *prevNode = first; LinkNode<T> *curNode = first->rLink; LinkNode<T> *nextNode = curNode->rLink; while (first != curNode) { curNode->rLink = prevNode; curNode->lLink = nextNode; prevNode = curNode; curNode = nextNode; nextNode = curNode->rLink; } first->lLink = nextNode; first->rLink = prevNode; } //清空链表(保留附加头结点) template<class T> void DblLinkedList<T>::MakeEmpty() { LinkNode<T> *curNode = NULL; while (first != first->rLink) //当链表不为空时,删去链表中所有结点 { curNode = first->rLink; //保存被删结点 first->rLink = curNode->rLink; //将链表附加头结点中指针域的指针指向被删结点的下一个结点 delete curNode; //从链表上摘下被删结点 } } //链表间赋值操作——重载等号运算符 template<class T> DblLinkedList<T>& DblLinkedList<T>::operator=(const DblLinkedList<T>& L) { cout << "$ 执行赋值操作函数" << endl; LinkNode<T> *srcptr = L.GetHead(); LinkNode<T> *destptr = first = new LinkNode<T>; while (L.GetHead() != srcptr->rLink) { srcptr = srcptr->rLink; destptr->rLink = new LinkNode<T>(srcptr->data); destptr->rLink->lLink = destptr; destptr = destptr->rLink; } first->lLink = destptr; destptr->rLink = first; return *this; } //返回附加头结点的地址 template<class T> LinkNode<T>* DblLinkedList<T>::GetHead()const { return first; } //返回输入的结点数据值 template <class T> T DblLinkedList<T>::get_value(string& s_value) { cout << "newNode->data = "; cin >> s_value; return StrToTtype(s_value); } //判断输入的字符串每个字符是否都是数值0~9 template <class T> bool DblLinkedList<T>::IsNumber(const string& s_num) { for (size_t i = 0; i < s_num.size(); i++) { if ((s_num[i] < '0') || (s_num[i] > '9')) { return false; } } return true; } //类型转换——将string型转为模板类型T template <class T> T DblLinkedList<T>::StrToTtype(const string& s_num) { T n_num; strstream ss_num; ss_num << s_num; ss_num >> n_num; return n_num; } #endif /* DBL_LINKED_LIST_H_ */
2.3 主函数(main函数)的实现
文件:main.cpp
#include "DblLinkedList.h" //带附加头结点 #define EXIT 0 //退出 #define CONSTRUCT_COPY 1 //拷贝构造链表 #define LENGTH 2 //计算链表的结点总数 #define SEARCH 3 //搜索数据值为x的结点并返回 #define LOCATE 4 //获取第i个结点并返回,遍历方向默认是从左往右 #define GETDATA 5 //获取第i个结点的数据值保存至x,并返回获取成功与否,遍历方向默认是从左往右 #define SETDATA 6 //修改第i个结点的数据值为x,遍历方向默认是从左往右 #define INSERT 7 //在第i个结点后插入数据值为x的新结点,遍历方向默认是从左往右 #define REMOVE 8 //删除第i个结点,并将被删结点的数据值保存至x,遍历方向默认是从左往右 #define ISEMPTY 9 //判断表是否为空 #define ISFULL 10 //判断表是否为满 #define SORT 11 //表排序——冒泡排序 #define INPUTFRONT 12 //前插法建立链表 #define INPUTREAR 13 //后插法建立链表 #define OUTPUT 14 //输出所有结点的数据值 #define REVERSE 15 //链表逆置 #define MAKEEMPTY 16 //清空链表 #define OPERATOR_COPY 17 //链表间赋值操作——重载等号运算符 #define GETHEAD 18 //返回头结点的地址 void print_description() { cout << "------------------------------>双向链表<------------------------------" << endl; cout << "功能选项说明:" << endl; cout << "#0: 退出" << endl; cout << "#1: 拷贝构造链表" << endl; cout << "#2: 计算链表的结点总数" << endl; cout << "#3: 搜索数据值为x的结点并返回" << endl; cout << "#4: 获取第i个结点并返回,遍历方向默认是从左往右" << endl; cout << "#5: 获取第i个结点的数据值保存至x,并返回获取成功与否,遍历方向默认是从左往右" << endl; cout << "#6: 修改第i个结点的数据值为x,遍历方向默认是从左往右" << endl; cout << "#7: 在第i个结点后插入数据值为x的新结点,遍历方向默认是从左往右" << endl; cout << "#8: 删除第i个结点,并将被删结点的数据值保存至x,遍历方向默认是从左往右" << endl; cout << "#9: 判断表是否为空" << endl; cout << "#10:判断表是否为满" << endl; cout << "#11:表排序——冒泡排序" << endl; cout << "#12:前插法建立链表" << endl; cout << "#13:后插法建立链表" << endl; cout << "#14:输出所有结点的数据值" << endl; cout << "#15:链表逆置" << endl; cout << "#16:清空链表" << endl; cout << "#17:链表间赋值操作——重载等号运算符" << endl; cout << "#18:返回头结点的地址" << endl; cout << "--------------------------------------------------------------------" << endl; } //输入结点编号 template <class T> int get_item() { cout << "> 请输入结点编号,item = "; string s_item; cin >> s_item; while (false == DblLinkedList<T>::IsNumber(s_item)) { cout << "* 输入有误,请重新输入:"; cin >> s_item; } return atoi(s_item.c_str()); } //输入数据值 template <class T> T get_data() { cout << "> 请输入数据值,data = "; string s_data; cin >> s_data; return DblLinkedList<T>::StrToTtype(s_data); } //输入结束标志位 template <class T> T get_endtag() { cout << "请输入结束标志值,endTag = "; string s_endTag; cin >> s_endTag; return DblLinkedList<T>::StrToTtype(s_endTag); } //输入遍历方向,是否从左往右,是输入1,否输入0 template <class T> bool get_dir() { cout << "> 请输入遍历方向,是否从左往右,是输入1,否输入0,isLtoR = "; string s_dir; cin >> s_dir; while (false == DblLinkedList<T>::IsNumber(s_dir)) { cout << "* 输入有误,请重新输入:"; cin >> s_dir; } return atoi(s_dir.c_str()) ? true : false; } //构造双向链表 template <class T> DblLinkedList<T>* construct_dbllinkedList() { cout << "\n==> 创建双向链表" << endl; DblLinkedList<T> *dbllinkedList = new DblLinkedList<T>; return dbllinkedList; } //析构双向链表 template <class T> void destory_dbllinkedList(DblLinkedList<T>* dbllinkedList) { cout << "\n==> 释放双向链表在堆中申请的空间,并将指向该空间的指针变量置为空" << endl; delete dbllinkedList; dbllinkedList = NULL; } //拷贝构造链表 template <class T> void construct_copy(DblLinkedList<T>* dbllinkedList) { cout << "$ 执行拷贝构造链表函数" << endl; DblLinkedList<T> cpy_linkedlist = *dbllinkedList; cpy_linkedlist.Output(); } //计算链表的结点总数 template <class T> void length(DblLinkedList<T>* dbllinkedList) { cout << "$ 执行计算链表的结点总数函数,Length = " << dbllinkedList->Length() << endl; } //搜索数据值为x的结点并返回 template <class T> void search(DblLinkedList<T>* dbllinkedList) { cout << "$ 执行搜索数据值为x的结点并返回函数" << endl; T data = get_data<T>(); LinkNode<T> *node = dbllinkedList->Search(data); if (NULL == node) { cout << "* 搜索失败" << endl; return; } cout << "* 搜索成功,data = " << node->data << endl; } //获取第i个结点并返回,遍历方向默认是从左往右 template <class T> void locate(DblLinkedList<T>* dbllinkedList) { cout << "$ 执行获取第i个结点并返回遍历方向默认是从左往右函数" << endl; int n_item = get_item<T>(); bool isLtoR = get_dir<T>(); LinkNode<T> *node = dbllinkedList->Locate(n_item, isLtoR); if ((NULL == node) || (dbllinkedList->GetHead() == node)) { cout << "* 获取失败" << endl; return; } cout << "* 获取成功,item = " << n_item << ",data = " << node->data << endl; } //获取第i个结点的数据值保存至x,并返回获取成功与否,遍历方向默认是从左往右 template <class T> void getdata(DblLinkedList<T>* dbllinkedList) { cout << "$ 执行获取第i个结点的数据值保存至x并返回获取成功与否遍历方向默认是从左往右函数" << endl; T data; int n_item = get_item<T>(); bool isLtoR = get_dir<T>(); if (false == dbllinkedList->GetData(n_item, data, isLtoR)) { cout << "* 获取失败" << endl; return; } cout << "* 获取成功,item = " << n_item << ",data = " << data << endl; } //修改第i个结点的数据值为x,遍历方向默认是从左往右 template <class T> void setdata(DblLinkedList<T>* dbllinkedList) { cout << "$ 执行修改第i个结点的数据值为x遍历方向默认是从左往右函数" << endl; int n_item = get_item<T>(); T data = get_data<T>(); bool isLtoR = get_dir<T>(); if (false == dbllinkedList->SetData(n_item, data, isLtoR)) { cout << "* 修改失败" << endl; return; } cout << "* 修改成功,item = " << n_item << ",data = " << data << endl; } //在第i个结点后插入数据值为x的新结点,遍历方向默认是从左往右 template <class T> void insert(DblLinkedList<T>* dbllinkedList) { cout << "$ 执行在第i个结点后插入数据值为x的新结点遍历方向默认是从左往右函数" << endl; int n_item = get_item<T>(); T data = get_data<T>(); bool isLtoR = get_dir<T>(); if (false == dbllinkedList->Insert(n_item, data, isLtoR)) { cout << "* 插入失败" << endl; return; } cout << "* 插入成功,item+1 = " << n_item+1 << ",data = " << data << endl; } //删除第i个结点,并将被删结点的数据值保存至x,遍历方向默认是从左往右 template <class T> void remove(DblLinkedList<T>* dbllinkedList) { cout << "$ 执行删除第i个结点并将被删结点的数据值保存至x遍历方向默认是从左往右函数" << endl; T data; int n_item = get_item<T>(); bool isLtoR = get_dir<T>(); if (false == dbllinkedList->Remove(n_item, data, isLtoR)) { cout << "* 删除失败" << endl; return; } cout << "* 删除成功,item = " << n_item << ",data = " << data << endl; } //判断表是否为空 template <class T> void isempty(DblLinkedList<T>* dbllinkedList) { cout << "$ 执行判断表是否为空函数,IsEmpty = " << dbllinkedList->IsEmpty() << endl; } //判断表是否为满 template <class T> void isfull(DblLinkedList<T>* dbllinkedList) { cout << "$ 执行判断表是否为满函数,IsFull = " << dbllinkedList->IsFull() << endl; } //表排序——冒泡排序 template <class T> void sort(DblLinkedList<T>* dbllinkedList) { cout << "$ 执行表排序——冒泡排序函数" << endl; dbllinkedList->Sort(); } //前插法建立链表 template <class T> void inputfront(DblLinkedList<T>* dbllinkedList) { cout << "$ 执行前插法建立链表函数" << endl; T endTag = get_endtag<T>(); dbllinkedList->InputFront(endTag); } //后插法建立链表 template <class T> void inputrear(DblLinkedList<T>* dbllinkedList) { cout << "$ 执行后插法建立链表函数" << endl; T endTag = get_endtag<T>(); dbllinkedList->InputRear(endTag); } //输出所有结点的数据值 template <class T> void output(DblLinkedList<T>* dbllinkedList) { cout << "$ 执行输出所有结点的数据值函数" << endl; dbllinkedList->Output(); } //链表逆置 template <class T> void reverse(DblLinkedList<T>* dbllinkedList) { cout << "$ 执行链表逆置函数" << endl; dbllinkedList->Reverse(); } //清空链表 template <class T> void make_empty(DblLinkedList<T>* dbllinkedList) { cout << "$ 执行清空链表函数" << endl; dbllinkedList->MakeEmpty(); } //链表间赋值操作——重载等号运算符 template <class T> void operator_copy(DblLinkedList<T>* dbllinkedList) { cout << "$ 执行链表间赋值操作——重载等号运算符函数" << endl; DblLinkedList<T> cpy_linkedlist; cpy_linkedlist = *dbllinkedList;//或cpy_linkedlist.operator=(*dbllinkedList); cpy_linkedlist.Output(); } //返回头结点的地址 template <class T> void gethead(DblLinkedList<T>* dbllinkedList) { LinkNode<T> *head = dbllinkedList->GetHead(); cout << "$ 执行返回头结点的地址函数,&first = " << &head << endl; } //双向链表操作选择 template <class T> void select_operation(DblLinkedList<T>* dbllinkedList) { if (NULL == dbllinkedList) { cout << "* 没有构造双向链表,请先构造双向链表。" << endl; return; } string s_operation; while (s_operation != "0") { cout << "\n==> 请输入功能选项编号(按\"0\"退出程序):"; cin >> s_operation; while (false == DblLinkedList<T>::IsNumber(s_operation)) { cout << "* 输入有误,请重新输入:"; cin >> s_operation; } int n_operation = atoi(s_operation.c_str()); switch (n_operation) { case EXIT://退出 { cout << "$ 退出程序" << endl; break; } case CONSTRUCT_COPY://拷贝构造链表 { construct_copy(dbllinkedList); break; } case LENGTH://计算链表的结点总数 { length(dbllinkedList); break; } case SEARCH://搜索数据值为x的结点并返回 { search(dbllinkedList); break; } case LOCATE://获取第i个结点并返回,遍历方向默认是从左往右 { locate(dbllinkedList); break; } case GETDATA://获取第i个结点的数据值保存至x,并返回获取成功与否,遍历方向默认是从左往右 { getdata(dbllinkedList); break; } case SETDATA://修改第i个结点的数据值为x,遍历方向默认是从左往右 { setdata(dbllinkedList); break; } case INSERT://在第i个结点后插入数据值为x的新结点,遍历方向默认是从左往右 { insert(dbllinkedList); break; } case REMOVE://删除第i个结点,并将被删结点的数据值保存至x,遍历方向默认是从左往右 { remove(dbllinkedList); break; } case ISEMPTY://判断表是否为空 { isempty(dbllinkedList); break; } case ISFULL://判断表是否为满 { isfull(dbllinkedList); break; } case SORT://表排序——冒泡排序 { sort(dbllinkedList); break; } case INPUTFRONT://前插法建立链表 { inputfront(dbllinkedList); break; } case INPUTREAR://后插法建立链表 { inputrear(dbllinkedList); break; } case OUTPUT://输出所有结点的数据值 { output(dbllinkedList); break; } case REVERSE://链表逆置 { reverse(dbllinkedList); break; } case MAKEEMPTY://清空链表 { make_empty(dbllinkedList); break; } case OPERATOR_COPY://链表间赋值操作——重载等号运算符 { operator_copy(dbllinkedList); break; } case GETHEAD://返回头结点的地址 { gethead(dbllinkedList); break; } default: { cout << "* 请输入正确的功能选项编号" << endl; break; } } } } int main(int argc, char* argv[]) { print_description(); DblLinkedList<int> *dbllinkedList = construct_dbllinkedList<int>(); select_operation(dbllinkedList); destory_dbllinkedList(dbllinkedList); system("pause"); return 0; }
3. 双向链表的优缺点
3.1 优点
- 没有空间限制,存储元素的个数无上限,基本只与内存空间大小有关。
- 插入和删除元素速率高。
- 只要知道表中任何一个结点的地址,就可以直接访问它的前驱结点和后继结点。
3.2 缺点
- 占用额外的空间以存储指针(浪费空间)。
- 随机存取元素速率低。
3.3 双向链表的适用情况
- 适用于需要进行大量增添和删除元素操作而对访问元素无要求的,及预先无法确定表的大小的程序。
参考文献:
[1]《数据结构(用面向对象方法与C++语言描述)(第2版)》殷人昆——第二章
[2]《C/C++常用算法手册》秦姣华、向旭宇——第二章
[3] 百度搜索关键字:双向链表的优缺点