单链表是一种最简单的数据结构,也叫线性链表。用它来表示线性关系时,用指针表示结点之间的逻辑关系。因此单链表的一个存储结点包含两个部分:
|
Data |
link |
其中data部分称为数据域,用于存储线性表的一个数据元素,其数据类型由用户的参数决定。link部分称为指针域或者链域,用于存放一个指针,该指针表示该链表中下一个结点的开始地址。
该结构采用一个LinkNode类来实现:
该结构采用一个LinkNode类来实现:
template<class T>
class LinkNode{ //链表结点类
public:
int data;
LinkNode<T> *link;
//---------只初始化指针域的构造函数------
LinkNode(LinkNode<T> *ptr=NULL)
{
link=ptr;
}
//--------初始化数据域和指针域-----------
LinkNode(const T& item,LinkNode<T> *ptr=NULL)
{
data=item;
link=ptr;
}
};
该类使用了C++的模板类,这样就可以在调用时传入具体的类型,具有灵活性。
在类定义的开始处使用了C++的宏定义:
#ifndef LIST_H
#define LITS_H
#endif // !LIST_H
防止重复定义头文件。
单链表的的结构图如下:

链表的第一个结点可以通过链表的头指针first找到,其他结点的地址则在前驱结点的link域中,链表的最后一个结点没有后继,在链表的link域中放一个NULL值。
链表类使用基类和派生类的方法实现,基类是上述的LinkNode类,派生类继承LinkNode类,其定义如下:
在类定义的开始处使用了C++的宏定义:
#ifndef LIST_H
#define LITS_H
#endif // !LIST_H
防止重复定义头文件。
单链表的的结构图如下:

链表的第一个结点可以通过链表的头指针first找到,其他结点的地址则在前驱结点的link域中,链表的最后一个结点没有后继,在链表的link域中放一个NULL值。
链表类使用基类和派生类的方法实现,基类是上述的LinkNode类,派生类继承LinkNode类,其定义如下:
template<class T>
class List:public LinkNode<T>{
public:
LinkNode<T> *first; //链表头指针
public:
//----------只初始化头指针的构造函数----------
List()
{
//初始化链表头指针
first=new LinkNode<T>;
}
//---------初始化数据成员和指针的构造函数-----
List(const T& x)
{
first=new LinkNode<T>(x);
}
//---------复制构造函数--------------
List(List<T>& L );
//---------析构函数------------------
~List()
{
makeEmpty();
}
//---------------单链表相关操作-----------
int Length()const; //计算链表长度
LinkNode<T> *getHead()const{return first;}//返回附加头结点的地址
LinkNode<T> *getHead(LinkNode<T> *p){first=p;}//设置附加头结点的地址
LinkNode<T> *Search(T x); //搜索包含数据x的元素
LinkNode<T> *Locate(int i); //搜索第i个元素的地址
T *getData(int i); //取出第i个元素的值
void setData(int i,T& x); //将第i个元素设置为x
bool IsEmpty()const //判断表是否为空
{
return first->link==NULL?true:false;
}
bool IsFull()const{return false;}//判断表满
void Sort(); //排序
void makeEmpty(); //清空链表
bool Insert(int i,const T &x); //在第i个元素后面插入元素
bool Remove(int i,T &x); //删除第i个元素,x返回该删除的值
void output(); //输出
//------------建立单链表的两种方法---
void InputFront(T endTag); //前插法建立单链表
void InputRear(T endTag); //后插法建立单链表
//操作符重载函数
List<T>& operator=(List<T>& L); //重载函数,赋值
};
利用单链表表示线性表,将使得插入和删除变得很方便,只要修改链中结点的位置,无需移动表中的元素,就能实现高效的插入和删除。插入算法:
1、若Ai是链表中的第一个结点中的数据,则新结点newNode应该插入到第一个结点之前,这时必须修改链表的头指针first,插入时要修改指针为:
newNode->link=first;first=newNode
2、若Ai不是链表中的第一个元素,也不是最后一个结点,首先让一个检测结点current指向Ai所在结点,再将新结点插入到Ai所在结点之后。此时需要修改指针为:
newNode->link=current->link;current->link=newNode
3、当Ai是链表中的最后一个结点,新结点追加在表尾,这时先让current指向含An的结点,即表中最后一个结点,再指向
newNode->link=current->link;current->link=newNode;
插入结点的代码如下:
//---------单链表的插入--------
template<class T>
bool List<T>::Insert(int i,const T& x)
{
//链表为空或者插入到第一个元素之前,此时i=0
if(i==0 || first==NULL)
{
//建立一个新结点
LinkNode<T> *newNode=new LinkNode<T>(x);
//如果建立该结点失败,输出提示信息
if(newNode==NULL)
{
cerr<<"存储分配错误\n";
exit(1);
}
//将新建立的结点的link指针赋值为first,将first赋值为newNode
newNode->link=first;
first=newNode;
}
else
{
//在链表的中间或者尾部插入新结点,在第i个结点处插入元素,则需先找到该位置
LinkNode<T> *current=first;
//循环查找第i个结点
for(int k=1;k<i;k++)
{
if(current==NULL)
break;
else
{
current=current->link;
}
}
//如果i>该链表的长度
if(current==NULL && first!=NULL)
{
cerr<<"链表太短,已经到达链表尾部\n";
return false;
}
else
{
//将该结点插到链表中间
LinkNode<T> *newNode=new LinkNode<T>(x);
//如果建立该结点失败,输出提示信息
if(newNode==NULL)
{
cerr<<"存储分配错误\n";
exit(1);
}
newNode->link=current->link;
current->link=newNode;
}
}
return true;
}
单链表的删除算法也分为两种情况:
1、在链表的第一个位置处删除,这时需要先用指针del保存第一个结点的地址,再将链表的头指针指向其下一个结点,使其成为新的链表的首元素结点,最后删除由del保存的原首元素地址。
del=first;first=first->link;delete del;
2、在链表的中间或者尾部删除,首先用del保存第i个结点的地址,再让第i-1个结点的link指针保存第i+1个结点的地址,通过重新拉链,把第i个结点从链中分离出来,最后再删除del保存的结点。
del=current->link;current->link=del->link;delete del;
//---------单链表的删除---------
template<class T>
bool List<T>::Remove(int i, T& x)
{
//把链表中第i个元素删去,i从1开始
LinkNode<T> *del,*current;
//如果i==1,则用del记录这个指针,然后重新拉链
if(i<=1)
{
del=first;
first=first->link;
}
else
{
//如果不是第一个结点,首先要遍历找到第i-1个结点
current=first->link; //记录当前的头指针
for(int k=1;k<i-1;k++)
{
if(current=NULL)
break;
else
{
current=current->link;
}
}
//空链表或者链表太短
if(current==NULL||current->link==NULL)
{
cerr<<"链表的长度太短,已经到达尾部\n";
return false;
}
//删除中间结点和尾结点
del=current->link;
current->link=del->link;
}
//取出被删结点中的数据值
x=del->data;
//删除这个指针
delete del;
return true;
}当寻找第i-1个基点时有三种情况,第一种是current=NULL,链表太短。第二种情况是current!=NULL,但是current->link==NULL,此时也无法
删除,第三种情况就是正常的可以删除的情况。
单链表的重点是插入和删除元素。
本文介绍了单链表的基本概念,包括数据结构组成与实现方式,并详细解析了单链表的插入与删除算法。

772

被折叠的 条评论
为什么被折叠?



