一、解析
将单链表中终端结点的指针端由空指针改为指向头结点,就使整个链表形成一个环,这种头尾相接的单链表成为单循环链表,简称循环链表(circular linked list)。
循环链表解决了一个很麻烦的问题,就是如何从当中任意一个结点除非,访问到链表的全部结点。
为了使空链表与非空链表处理一致,我们通常设一个头结点,当然,这并不是说,循环链表一定要头结点。
其实循环链表和单链表的主要差异就在于循环的判断条件上,原来是判断p->next是否为空,现在则是p->next不等于头结点。
对于非空的循环链表就如下图所示:
其实循环链表和单链表的主要差异就在于循环的判断上,原来是判断p->next是否为空,现在则是p->next不等于头节点,则循环没有结束。
在单链表中有了头节点时,可以用O(1)的时间访问第一个节点,对于要访问到最后一个节点需要O(n),因为需要从头节点到尾节点都扫描一遍,如何利用O(1)的时间有链表指针访问到最后一个节点?这里只需要修改一下链表结构即可,也就是不使用头指针,而是用指向终端结点的尾指针来表示,如下图所示:
从上图可以看到,终端结点用尾指针rear指示,则查找终端结点的复杂度是O(1),而开始节点其实就是rear->next->next,时间复杂度也是O(1)。
尾指针的存在对于两个链表合并的时候非常实用,如下例子所示:
有两个循环链表,它们的尾指针分表是rearA和rearB,如图所示:
想要合并这两个链表只需如下操作即可:
P=rearA->next;//保存A表的头节点,即①
rearA->next=rearB->next->next;//将本是指向B表的第一个节点(不是头节点)赋值给rearA->next,即②
rearB->next=p;//将原A表的头节点赋值给rearB->next,即③
free(p);//释放p
二、循环链表初始化
初始化算法:
1. 分配一个节点的内存
2. 指针域指向头结点
三、元素插入
在L的第i个位置之前插入元素e算法:
1. p指向头结点
2.检测位置i是否在链表长度之外
3. 寻找第i-1个结点
4. 生成新结点
5.将元素e插入L中
6. 改变尾结点指针
四、元素读取
获取链表中第i个元素算法:
1. p指向第一个结点
2. 顺指针向后查找,直到p指向第i个元素
3. 取第i个元素
五、获取元素e的前驱
获取元素e的前驱算法:
1. p指向第一个结点,q=p->next
2. 循环:p没到表尾
如果当前元素值是元素e则返回该元素前驱p->data;否则p=q;q=q->next;
六、获取元素e的后继
算法:
1. p指向第一个结点
2. 循环:p没到表尾
如果p->data是元素e则返回p->next->data;否则p=p->next继续循环
七、删除L的第i个元素
算法:
1. p指向头结点
2. 寻找第i-1个结点
3. q指向待删除结点,修改表尾指针
4. 释放待删除结点
C语言实现双向链表:
//list.h
struct SigClNode
{
ElemType data;
struct SigClNode *next;
}SigClNode;
typedef struct SigClNode *SigClList;//定义SigList
/* 操作结果:构造一个空的线性表L */
int SigClListInit(SigClList *L);
/* 操作结果:销毁线性表L */
int SigClListDestroy(SigClList *L);
/* 初始条件:线性表L已存在。操作结果:将L重置为空表 */
int SigClListClear(SigClList *L);
/* 初始条件:线性表L已存在。
操作结果:若L为空表,则返回OK,否则返回ERROR */
int SigClListEmpty(SigClList L);
/* 初始条件:L已存在。操作结果:返回L中数据元素个数 */
int SigClListLength(SigClList L);
/* 当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR */
int SigClListGetElem(SigClList L,int i,ElemType *e);
/* 初始条件:线性表L已存在,SigClListCompare()是数据元素判定函数 */
/* 操作结果:返回L中第1个与e满足关系SigClListCompare()的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
int SigClListLocateElem(SigClList L,ElemType e,int(*SigClListCompare)(ElemType,ElemType));
/* 初始条件:线性表L已存在 */
/* 操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱, */
/* 否则操作失败,pre_e无定义 */
int SigClListPriorElem(SigClList L,ElemType cur_e,ElemType *pre_e);
/* 初始条件:线性表L已存在 */
/* 操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继, */
/* 否则操作失败,next_e无定义 */
int SigClListNextElem(SigClList L,ElemType cur_e,ElemType *next_e);
/* 在L的第i个位置之前插入元素e */
int SigClListInsert(SigClList *L,int i,ElemType e);
/* 删除L的第i个元素,并由e返回其值 */
int SigClListDelete(SigClList *L,int i,ElemType *e);
int SigClListTraverse(SigClList L,void(*vi)(ElemType));
int SigClListCompare(ElemType c1,ElemType c2);
void SigClListVisit(ElemType c);
//list.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"
/* 操作结果:构造一个空的线性表L */
int SigClListInit(SigClList *L)
{
/* 产生头结点,并使L指向此头结点 */
*L=(SigClList)malloc(sizeof(struct SigClNode));
/* 存储分配失败 */
if(!*L)
{
return ERROR;
}
/* 指针域指向头结点 */
(*L)->next=*L;
return OK;
}
/* 操作结果:销毁线性表L */
int SigClListDestroy(SigClList *L)
{
/* p指向头结点 */
SigClList q,p=(*L)->next;
/* 没到表尾 */
while(p!=*L)
{
q=p->next;
free(p);
p=q;
}
free(*L);
*L=NULL;
return OK;
}
/* 初始条件:线性表L已存在。操作结果:将L重置为空表 */
int SigClListClear(SigClList *L) /* 改变L */
{
SigClList p,q;
*L=(*L)->next; // L指向头结点
p=(*L)->next; // p指向第一个结点
while(p!=*L) // 没到表尾
{
q=p->next;
free(p);
p=q;
}
(*L)->next=*L; // 头结点指针域指向自身
return OK;
}
/* 初始条件:线性表L已存在。
操作结果:若L为空表,则返回OK,否则返回ERROR */
int SigClListEmpty(SigClList L)
{
if(L->next==L) // 空
{
return OK;
}
else
{
return ERROR;
}
}
/* 初始条件:L已存在。操作结果:返回L中数据元素个数 */
int SigClListLength(SigClList L)
{
int i=0;
SigClList p=L->next; // p指向头结点
while(p!=L) // 没到表尾
{
i++;
p=p->next;
}
return i;
}
/* 当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR */
int SigClListGetElem(SigClList L,int i,ElemType *e)
{
int j=1; /* 初始化,j为计数器 */
SigClList p=L->next->next; /* p指向第一个结点 */
if(i<=0||i>SigClListLength(L)) /* 第i个元素不存在 */
{
return ERROR;
}
while(j<i)
{ /* 顺指针向后查找,直到p指向第i个元素 */
p=p->next;
j++;
}
*e=p->data; /* 取第i个元素 */
return OK;
}
/* 初始条件:线性表L已存在,SigClListCompare()是数据元素判定函数 */
/* 操作结果:返回L中第1个与e满足关系SigClListCompare()的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
int SigClListLocateElem(SigClList L,ElemType e,int(*SigClListCompare)(ElemType,ElemType))
{
int i=0;
SigClList p=L->next->next; //p指向第一个结点
while(p!=L->next)
{
i++;
if(SigClListCompare(p->data,e)) // 满足关系
return i;
p=p->next;
}
return 0;
}
/* 初始条件:线性表L已存在 */
/* 操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱, */
/* 否则操作失败,pre_e无定义 */
int SigClListPriorElem(SigClList L,ElemType cur_e,ElemType *pre_e)
{
SigClList q,p=L->next->next; // p指向第一个结点
q=p->next;
while(q!=L->next) // p没到表尾
{
if(q->data==cur_e)
{
*pre_e=p->data;
return OK;
}
p=q;
q=q->next;
}
return ERROR;
}
/* 初始条件:线性表L已存在 */
/* 操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继, */
/* 否则操作失败,next_e无定义 */
int SigClListNextElem(SigClList L,ElemType cur_e,ElemType *next_e)
{
SigClList p=L->next->next; // p指向第一个结点
/* p没到表尾 */
while(p!=L)
{
if(p->data==cur_e)
{
*next_e=p->next->data;
return OK;
}
p=p->next;
}
return ERROR;
}
/* 在L的第i个位置之前插入元素e */
int SigClListInsert(SigClList *L,int i,ElemType e) /* 改变L */
{
SigClList p=(*L)->next,s; // p指向头结点
int j=0;
/* 无法在第i个元素之前插入 */
if(i<=0||i>SigClListLength(*L)+1)
{
return ERROR;
}
/* 寻找第i-1个结点 */
while(j<i-1)
{
p=p->next;
j++;
}
s=(SigClList)malloc(sizeof(struct SigClNode)); //生成新结点
s->data=e; // 插入L中
s->next=p->next;
p->next=s;
if(p==*L) // 改变尾结点
{
*L=s;
}
return OK;
}
/* 删除L的第i个元素,并由e返回其值 */
int SigClListDelete(SigClList *L,int i,ElemType *e) /* 改变L */
{
SigClList p=(*L)->next,q; // p指向头结点
int j=0;
/* 第i个元素不存在 */
if(i<=0||i>SigClListLength(*L))
{
return ERROR;
}
/* 寻找第i-1个结点 */
while(j<i-1)
{
p=p->next;
j++;
}
q=p->next; // q指向待删除结点
p->next=q->next;
*e=q->data;
/* 删除的是表尾元素 */
if(*L==q)
{
*L=p;
}
free(q); // 释放待删除结点
return OK;
}
int SigClListTraverse(SigClList L,void(*vi)(ElemType))
{
SigClList p=L->next->next;
while(p!=L->next)
{
vi(p->data);
p=p->next;
}
printf("\n");
return OK;
}
int SigClListCompare(ElemType c1,ElemType c2)
{
if(c1==c2)
{
return OK;
}
else
{
return ERROR;
}
}
void SigClListVisit(ElemType c)
{
printf("[%s %d]%d ",__FUNCTION__,__LINE__,c);
}
int main()
{
SigClList L;
ElemType e;
int j = 0;
int i = 0;
i=SigClListInit(&L); /* 初始化单循环链表L */
printf("[%s %d]初始化单循环链表L i=%d (1:初始化成功)\n",__FUNCTION__,__LINE__,i);
i=SigClListEmpty(L);
printf("[%s %d]L是否空 i=%d(1:空 -1:否)\n",__FUNCTION__,__LINE__,i);
SigClListInsert(&L,1,3); /* 在L中依次插入3,5 */
SigClListInsert(&L,2,5);
i=SigClListGetElem(L,1,&e);
j=SigClListLength(L);
printf("[%s %d]L中数据元素个数=%d,第1个元素的值为%d。\n",__FUNCTION__,__LINE__,j,e);
printf("[%s %d]L中的数据元素依次为:",__FUNCTION__,__LINE__);
SigClListTraverse(L,SigClListVisit);
SigClListPriorElem(L,5,&e); // 求元素5的前驱
printf("[%s %d]5前面的元素的值为%d。\n",__FUNCTION__,__LINE__,e);
SigClListNextElem(L,3,&e); // 求元素3的后继
printf("[%s %d]3后面的元素的值为%d。\n",__FUNCTION__,__LINE__,e);
printf("[%s %d]L是否空 %d(1:空 -1:否)\n",__FUNCTION__,__LINE__,SigClListEmpty(L));
j=SigClListLocateElem(L,5,SigClListCompare);
if(j)
{
printf("[%s %d]L的第%d个元素为5。\n",__FUNCTION__,__LINE__,j);
}
else
{
printf("[%s %d]不存在值为5的元素\n",__FUNCTION__,__LINE__);
}
i=SigClListDelete(&L,2,&e);
printf("[%s %d]删除L的第2个元素:\n",__FUNCTION__,__LINE__);
if(i)
{
printf("[%s %d]删除的元素值为%d,现在L中的数据元素依次为:",__FUNCTION__,__LINE__,e);
SigClListTraverse(L,SigClListVisit);
}
else
{
printf("[%s %d]删除不成功!\n",__FUNCTION__,__LINE__);
}
printf("[%s %d]清空L:%d(1: 成功)\n",__FUNCTION__,__LINE__,SigClListClear(&L));
printf("[%s %d]清空L后,L是否空:%d(1:空 -1:否)\n",__FUNCTION__,__LINE__,SigClListEmpty(L));
printf("[%s %d]销毁L:%d(1: 成功)\n",__FUNCTION__,__LINE__,SigClListDestroy(&L));
return 0;
}