单向链表的C++实现
2013-10-17 15:13
495 查看
单向链表的C++实现
链表作为一种基础的数据结构,在计算机科学中广泛应用。特别是在不支持连续存储的空间中,以及实现灵活的内存动态管理中,都能起到重要作用。链表在首尾端及附近的操作普遍优于一般数组array,而且支持在链表内部找到指定位置并插入和删除元素,没必要像数组一样移动一大串元素,而只是在内部对所改变的结点链接进行固定的几个改变即可;但在链表中搜寻元素要遍历链表需O(n)的时间,而不像数组中用O(1)那么快,而且链表在中间的操作会比首尾端慢上不少。
要组成一整条单向链表,就需要定义好链表上的各个结点,并且将单向链表上各结点串在一起:
这个单链表形成后,结构看起来就像这样的:
在组成一个单向链表后,还需要补充一些功能,以便后续实现:
1.定义这个单向链表类的构造函数及析构函数
2.清空链表内所有元素
3.给出元素位置再返回对应结点
4.返回链表内部元素个数
5.判断这个链表是否为空
6.返回链表首尾的元素值
7.查找元素是否在此链表内,如果在则返回所在位置
8.从首端到尾端输出链表上的各元素
9.对链表插入元素以及删除元素
与此同时,顺理成章地给出这些功能的接口们,他们组成了这个单链表类的参考框架:
现在,就具体看看这个单向链表怎么实现的:
1.构造函数和析构函数:
创建了一个新的空链表,首端和尾端均指向NULL,内部元素个数为0;由于在加入元素时用了new,所以要手动地delete,Clear()中进行,析构函数直接调用Clear()即可。
2.清空链表内所有元素:
3.给出元素位置再返回对应结点:
要注意的是,遍历元素位置时避免pNode所获得的值越界,队首元素进不了for循环,改变不了pNode;队尾元素如果设置成i=1;i<=pos;++i,pNode会读取队尾的下一个值,那个值越界。最后就会返回一个未定义的元素。
4.返回首尾端元素、查找元素、输出所有元素、返回元素个数、判断链表是否为空:
5.链表中加入元素:
这里分四种情况讨论:
①插入元素位置越界
②在尾部插入元素
③在头部插入元素
④在其他位置插入元素
若插入元素成功,记得元素个数+1。这里用图示例非空链表首部插入元素,其他情况读者们可以自己试着画图:
代码如下:
6.链表中删除元素:
这里分五种情况讨论:
①链表为空
②删除元素位置越界
③在尾部删除元素
④在头部删除元素
⑤在其他位置删除元素
若删除元素成功,记得元素个数-1。这里用图示例非空链表尾部删除元素,其他情况读者们可以自己试着画图:
代码如下:
最后,将上述实现放入之前提到的框架内,就完成了最后的单向链表C++实现。
简易的单向链表,就这么完成了。还有更加完善的单向链表,那就是STL中的<slist>了,坐等后续更新吧。
参考文献及链接:
1.《算法导论》2nd Thomas H.Cormen , Charles E.Leiserson , Ronald L.Rivest , Cliford Stein 著,潘金贵、顾铁成、李成法、叶懋译
2.《数据结构与算法分析 C++描述》 第3版 Mark Allen Weiss著,张怀勇等译
3.《C++标准模板库 -自修教程及参考手册-》 Nicolai M.Josuttis著,侯捷/孟岩译
4./article/8115603.html
链表作为一种基础的数据结构,在计算机科学中广泛应用。特别是在不支持连续存储的空间中,以及实现灵活的内存动态管理中,都能起到重要作用。链表在首尾端及附近的操作普遍优于一般数组array,而且支持在链表内部找到指定位置并插入和删除元素,没必要像数组一样移动一大串元素,而只是在内部对所改变的结点链接进行固定的几个改变即可;但在链表中搜寻元素要遍历链表需O(n)的时间,而不像数组中用O(1)那么快,而且链表在中间的操作会比首尾端慢上不少。
要组成一整条单向链表,就需要定义好链表上的各个结点,并且将单向链表上各结点串在一起:
#ifndef SIMPLENODE_HPP #define SIMPLENODE_HPP template<typename T> //定义一个模板T 写单链表 class SingleNode { public: T element; SingleNode* next; SingleNode(const T& theElement,SingleNode* nextone=NULL) :element(theElement),next(nextone) {} }; #endif
这个单链表形成后,结构看起来就像这样的:
在组成一个单向链表后,还需要补充一些功能,以便后续实现:
1.定义这个单向链表类的构造函数及析构函数
2.清空链表内所有元素
3.给出元素位置再返回对应结点
4.返回链表内部元素个数
5.判断这个链表是否为空
6.返回链表首尾的元素值
7.查找元素是否在此链表内,如果在则返回所在位置
8.从首端到尾端输出链表上的各元素
9.对链表插入元素以及删除元素
与此同时,顺理成章地给出这些功能的接口们,他们组成了这个单链表类的参考框架:
#ifndef SINGLELINKLIST_HPP #define SINGLELINKLIST_HPP #include<iostream> #include"simplenode.hpp" //这里默认位置pos的开始是从1开始,而不是从0开始 template<class T> class SingleLinkList //单链表类的定义 { private: SingleNode<T>* head; //链表头指针 SingleNode<T>* tail; //链表尾指针 int size; //元素个数 SingleNode<T>* GetPointAt(int pos) {...} //给出元素位置再返回其对应结点 public: SingleLinkList():head(),tail(),size(0) {} ~SingleLinkList() {Clear();} void Clear() {...} int Size() {...} //返回元素个数 bool isempty() {...} //返回链表是否为空 //----------------------------------------------------- //这里添加元素 //------在尾部添加元素 void AddBack(T val) {...} //------在指定位置插入元素 bool AddAt(T val,int pos) { SingleNode<T>* pNode=NULL; if (pos<=0 || pos>size) //插入位置越界 {...} if (pos==size) //在尾部插入元素 AddBack(val); else if (pos==1) //在头部插入元素 {...} else {...} size++; return true; } //----------------------------------------------- //这里删除元素 bool RemoveBack() //删除尾部元素 { return RemoveAt(size); } bool RemoveAt(int pos) //删除指定位置元素 { SingleNode<T>* pNode=NULL; if (isempty()) {...} if (pos<=0 || pos>size) {...} if (size==1) //只有1个元素时相当于清空链表 { Clear(); } if (pos==1) //并且size!=1, 删除头部元素时 {...} else if (pos==size) //size!=1,删除尾部元素时 {...} else {...} size--; return true; } //--------------------------------------- T GetHeadVal() //返回首端元素 {...} T GetTailVal() //返回尾端元素 {...} int Find(T val) //查找元素 {...} void ShowAllVal() //从头到尾输出链表上的元素 {...} }; #endif
现在,就具体看看这个单向链表怎么实现的:
1.构造函数和析构函数:
SingleLinkList():head(),tail(),size(0) {} ~SingleLinkList() {Clear();}
创建了一个新的空链表,首端和尾端均指向NULL,内部元素个数为0;由于在加入元素时用了new,所以要手动地delete,Clear()中进行,析构函数直接调用Clear()即可。
2.清空链表内所有元素:
void Clear() { //从链表头到链表尾的方式逐个删除 const int nums=Size(); if (!isempty()) { for (int k=1;k<=nums;++k) { SingleNode<T>* temp=head->next; delete head; head=temp; size--; } } //如果链表本来就为空,就没必要再进for循环了 }
3.给出元素位置再返回对应结点:
SingleNode<T>* GetPointAt(int pos) { SingleNode<T>* pNode=NULL; if (pos<=0 || pos>size) std::cout<<"out of range."<<std::endl; //链表当前位置越界,异常 else { pNode=head; //当前位置满足条件,则一开始在链表头 for (int i=1;i<=pos-1;++i) pNode=pNode->next; } return pNode; }
要注意的是,遍历元素位置时避免pNode所获得的值越界,队首元素进不了for循环,改变不了pNode;队尾元素如果设置成i=1;i<=pos;++i,pNode会读取队尾的下一个值,那个值越界。最后就会返回一个未定义的元素。
4.返回首尾端元素、查找元素、输出所有元素、返回元素个数、判断链表是否为空:
T GetHeadVal() { if (isempty()) { std::cout<<"the link list is empty"<<std::endl; return NULL; } return head->element; } T GetTailVal() { if (isempty()) { std::cout<<"the link list is empty"<<std::endl; return NULL; } return tail->element; }
int Find(T val) //查找元素 { int pos=1; //从起始位置1号位开始 SingleNode<T>* findNode=head; while (findNode!=NULL) { if (findNode->element==val) return pos; findNode=findNode->next; pos++; } std::cout<<"we can't find it,return -1"<<std::endl; return -1; }
void ShowAllVal() //从头到尾输出链表上的元素 { SingleNode<T>* findNode=head; while (findNode!=NULL) { std::cout<<findNode->element<<" "; findNode=findNode->next; } std::cout<<std::endl; }
int Size() {return size;} //返回元素个数 bool isempty() {return size==0?true:false; } //返回链表是否为空
5.链表中加入元素:
这里分四种情况讨论:
①插入元素位置越界
②在尾部插入元素
③在头部插入元素
④在其他位置插入元素
若插入元素成功,记得元素个数+1。这里用图示例非空链表首部插入元素,其他情况读者们可以自己试着画图:
代码如下:
//------在尾部添加元素 void AddBack(T val) { SingleNode<T>* pNode=new SingleNode<T>(val); if (isempty()) //链表为空时 { head=pNode; tail=pNode; } else { tail->next=pNode; tail=pNode; } size++; } //------在指定位置插入元素 bool AddAt(T val,int pos) { SingleNode<T>* pNode=NULL; if (pos<=0 || pos>size) { std::cout<<"out of range."<<std::endl; return false; } if (pos==size) //在尾部插入元素 AddBack(val); else if (pos==1) //在头部插入元素 { pNode=new SingleNode<T>(val); pNode->next=head; head=pNode; } else { //返回插入位置前面一个的位置指针 SingleNode<T>* pNode=GetPointAt(pos-1); SingleNode<T>* newNode=new SingleNode<T>(val); newNode->next=pNode->next; pNode->next=newNode; } size++; return true; }
6.链表中删除元素:
这里分五种情况讨论:
①链表为空
②删除元素位置越界
③在尾部删除元素
④在头部删除元素
⑤在其他位置删除元素
若删除元素成功,记得元素个数-1。这里用图示例非空链表尾部删除元素,其他情况读者们可以自己试着画图:
代码如下:
bool RemoveBack() //删除尾部元素 { return RemoveAt(size); } bool RemoveAt(int pos) //删除指定位置元素 { SingleNode<T>* pNode=NULL; if (isempty()) { std::cout<<"the link list is empty"<<std::endl; return false; } if (pos<=0 || pos>size) { std::cout<<"out of range."<<std::endl; return false; } if (size==1) //只有1个元素时相当于清空链表 { Clear(); } if (pos==1) //并且size!=1, 删除头部元素时 { pNode=head; head=head->next; delete pNode; } else if (pos==size) { SingleNode<T>* pPreNode=GetPointAt(pos-1); std::cout<<"之前一个元素为"<<pPreNode->element<<std::endl; pNode=pPreNode->next; pPreNode->next=pNode->next; delete pNode; tail=pPreNode; } else { SingleNode<T>* pPreNode=GetPointAt(pos-1); std::cout<<"之前一个元素为"<<pPreNode->element<<std::endl; pNode=pPreNode->next; pPreNode->next=pNode->next; delete pNode; } size--; return true; }
最后,将上述实现放入之前提到的框架内,就完成了最后的单向链表C++实现。
简易的单向链表,就这么完成了。还有更加完善的单向链表,那就是STL中的<slist>了,坐等后续更新吧。
参考文献及链接:
1.《算法导论》2nd Thomas H.Cormen , Charles E.Leiserson , Ronald L.Rivest , Cliford Stein 著,潘金贵、顾铁成、李成法、叶懋译
2.《数据结构与算法分析 C++描述》 第3版 Mark Allen Weiss著,张怀勇等译
3.《C++标准模板库 -自修教程及参考手册-》 Nicolai M.Josuttis著,侯捷/孟岩译
4./article/8115603.html
相关文章推荐
- 数据结构学习系列三-单向循环链表(c++实现且应用模板)
- C++ 实现单向链表
- c++实现单向单链表及常见面试题
- 数据结构C++模板实现之----------------单向链表
- 使用C++实现单向链表
- 单向链表之C++实现
- 单向循环链表的C++实现
- 数据结构-C++实现(二):单向链表
- C++实现单向链表
- 简单单向链表(C++模版技术实现)
- C++ 基于类的单向链表实现
- 利用 C++ 单向链表实现队列
- 【编程题目】求单向链表的倒数第k个节点——关于代码鲁棒性的探讨(C++实现)
- 用C++实现单向循环链表的解决方法
- 用c++实现单向链表的创建,插入和删除
- C++实现单向链表
- 使用C++实现的单向循环链表
- c++ 实现单向链表
- C++中实现一个简单的单向链表
- C++ 使用单向链表实现Stack