上文“数据结构C++描述—线性表的基本操作”中所述的线性表是基于公式化描述来存储数据的,即它的存储位置之间满足一定的数学关系。而利用链表描述线性表时,某个元素的描述包含两部分:链接域(指向下一个或上一个节点)和数据域(存储当前元素的值)。因此,链表利用链接指针将各个数据连接起来。
链表包括:
1. 单链表:只有指向下一个元素的指针,最后一个节点链接域为NULL(或0)如下图所示(图片来源于文末参考文献)
2. 循环链表:在单链表头指针前面新增一个节点作为头结点(*first),将最后一个节点的链接指针改为指向头结点 *first,就构成了循环链表。(如下图所示,图片来源于参考文献)
3. 双向链表:对于双向链表,链接域中有两个链接指针*left(指向前一个节点,如果有)和 *right(指向下一个节点,如果有)。(如下图所示,图片来源于参考文献)
下文重点讲述单链表的操作。
1、单链表的操作主要包括:
2、链表各种操作的C++实现
链表抽象为Chain链表操作类和ChainNode节点类。链表的创建和删除利用Chain()类的构造函数Chain()和析构函数~Chain()实现。Chain()类有一个私有成员变量,头节点指针*first,在创建链表时,初始化为0;ChainNode类具有两个私有成员变量,分别存储节点的数据(data)和指向下一个节点的指针 (link)。由于Chain()类需要访问ChainNode类的私有成员,因此,将Chain类声明为ChainNode类的友类。两个类的具体声明如下:
template <class T> class Chain;
//节点类---ChainNode
template <class T>
class ChainNode
{
friend Chain<T>; //由于Chain()类需要访问ChainNode类的私有成员,因此,声明为Chain类的友类
private:
T data;
ChainNode<T> *link;
};
//链表操作类---Chain
template <class T>
class Chain{
public:
Chain(){first=0;}; //创建链表
~Chain(); //删除链表
bool IsEmpty() const{return first==0;} //判断链表是否为空,即首节点是否等于末节点
int Length() const; //链表长度,即链表中节点个数
bool Find(int k,T &x) const; //寻找第k个位置的元素,若存在,返回true,并赋给x;若不存在,返回false
int Search(const T &x) const; //返回链表中元素x的位置,若不存在,返回0
Chain<T>& Delete(int k,T &x); //删除第k个位置的元素,并将它赋给x
Chain<T>& Insert(int k,const T &x); //在第k个位置后插入x
void Output(ostream &out) const; //输出链表---运算符重载
Chain<T>& Erase(); //删除表中所有节点
void Zero(); //将first指针清零
Chain<T>& Append(T x); //在链表末尾追加一个数据
private:
ChainNode<T> *first; //指向第一个节点的指针
};
2.1 删除链表—Chain类的析构函数~Chain()
//析构函数
template <class T>
Chain<T>::~Chain()
{
ChainNode<T> *next; //下一个节点
while(first)
{
next=first->link; //指向下一个节点
delete first; //删除当前节点
first=next; //循环
}
}
2.3 返回链表长度
//返回链表长度
template <class T>
int Chain<T>::Length() const
{
ChainNode<T> *current=first;
int len=0;
while(current)
{
len++;
current=current->link;
}
return len;
}
2.3 寻找第k个位置的元素
//寻找第k个位置的元素,若存在,返回true,并赋给x;若不存在,返回false
template <class T>
bool Chain<T>::Find(int k,T &x) const
{
if(k<0)
throw OutOfRange();
ChainNode<T> *current=first; //初始化current
for(int i=1;i<k && current;i++) //移动到第k个位置
current=current->link;
if(current)
{
x=current->data; //获取当前数据
return true;
}
else
return false;
}
2.4 返回链表中元素x的位置
//返回链表中元素x的位置,若不存在,返回0
template <class T>
int Chain<T>::Search(const T &x) const
{
ChainNode<T> *current;
int i=1; //链表元素位置坐标
//遍历链表
for(current=first;current;current=current->link)
{
if(current->data==x)
return i;
i++;
}
return 0;
}
2.5 删除第k个位置的元素
//删除第k个位置的元素,并将它赋给x
template <class T>
Chain<T>& Chain<T>::Delete(int k,T &x)
{
if(k<=0) throw OutOfRange();
ChainNode<T> *current=first;
if(k==1) //删除第一个元素
first=first->link; //将第2个元素作为链表首端
else //删除非首端元素,包括中间元素和末尾元素
{
for(int i=1;i<k-1 && current;i++)
current=current->link; //移动到第k-1个位置,出去末尾
ChainNode<T> *previous=current; //保存current前一个节点
current=current->link; //第k个节点
x=current->data; //将第k个位置上的元素赋给x
if(current) //若current不是末节点
{
ChainNode<T> *After=current->link; //保存current后一个节点
delete current; //删除current节点
previous->link=After; //连接current前后的两个节点
}
else //若是末节点
delete current;
}
return *this;
}
2.6 在第k个位置后插入元素
//在第k个位置后插入元素
template<class T>
Chain<T>& Chain<T>::Insert(int k,const T &x)
{
if(k<0) //k设置错误
throw OutOfRange();
ChainNode<T> *current=first;
for(int i=1;i<k && current;i++) //移动到第k个位置
current=current->link;
if(k>0 && !current) throw OutOfRange(); //不存在第k个元素
ChainNode<T> *y=new ChainNode<T>; //新建节点
y->data=x; //将x赋给新建节点的data
//在正确位置插入新节点
if(k) //k不为0
{
y->link=current->link; //指向原来的第k+1个节点
current->link=y; //原来第k个节点指向新建节点
}
else //k=0,在链表首端插入
{
y->link=first; //指向首端
first=y;
}
return *this;
}
2.7 删除链表中所有节点
template<class T>
Chain<T>& Chain<T>::Erase()
{
ChainNode<T> *next;
while(first)
{
next=first->link;
delete first;
first=next;
}
return *this;
}
2.8 将first指针清零
template <class T>
void Chain<T>::Zero()
{
first=0;
}
2.9 在链表末尾追加一个数据
//在链表末尾追加一个数据
template <class T>
Chain<T>& Chain<T>::Append(T x)
{
int n=Length();
Insert(n,x);
return *this;
}
2.10 输出链表—运算符重载
template <class T>
void Chain<T>::Output(ostream &out) const
{
ChainNode<T> *current;
for(current=first;current;current=current->link)
out<<current->data<<" ";
}
//重载“<<”
template <class T>
ostream & operator<<(ostream &out,const Chain<T> &x)
{
x.Output(out);
return out;
}
3 测试数据
Chain<int> c;
cout<<"新建链表: "<<endl;
c.Length();
cout<<"链表是否为空: "<<c.IsEmpty()<<endl;
cout<<"链表的长度: "<<c.Length()<<endl;
cout<<"链表为: "<<c<<endl<<endl;
//测试Insert()函数
c.Insert(0,1).Insert(1,2).Insert(2,3).Insert(3,4);
cout<<"测试Insert()函数---Insert(0,1).Insert(1,2):"<<endl;
cout<<"链表是否为空: "<<c.IsEmpty()<<endl;
cout<<"链表的长度: "<<c.Length()<<endl;
cout<<"链表为: "<<c<<endl<<endl;
//测试Find()函数
int x;
c.Find(2,x);
cout<<"测试Find()函数---c.Find(2,x):"<<endl;
cout<<"x为: "<<x<<endl<<endl;
//测试Search()
cout<<"测试Search():"<<endl;
cout<<"元素0的位置为: "<<c.Search(0)<<endl;
cout<<"元素2的位置为: "<<c.Search(2)<<endl<<endl;
//测试Delete()
cout<<"测试Delete():"<<endl;
cout<<"原链表: "<<c<<endl;
//c.Delete(1,x);
//cout<<"c.Delete(1,x): "<<x<<endl<<endl;
c.Delete(1,x);
cout<<"c.Delete(1,x): "<<c<<endl<<endl;
//测试Erase()函数
//c.Erase();
//cout<<"Erase()后: "<<c<<endl<<endl;
//测试append()函数
c.Append(5);
cout<<"Append()后: "<<c<<endl<<endl;
参考文献:
[1] 数据结构算法与应用:C++描述(Data Structures, Algorithms and Applications in C++ 的中文版)