一、双向循环链表
最后一个结点的后继指向头结点,头结点的前驱指向最后一个结点的双向链表
二、双向循环链表的基本操作
1.整表创建
void CreateDCLinkList(DCLinkList* L,int n)
{
DCLinkList r,s;
int data;
(*L) = (DCLinkList)malloc(sizeof(DNode));
(*L)->next = (*L); //初始化头结点的后继指针指向自己
(*L)->prior = (*L); //初始化头结点的前驱指针指向自己
r = (*L); //工作指针
for (int i = 0; i < n; i++)
{
scanf("%d", &data);
s = (DCLinkList)malloc(sizeof(DNode));
s->data = data;
s->prior = r; //连接上一结点
s->next = (*L); //新结点的后继指向头结点
r->next = s; //上一结点连接新结点
(*L)->prior = s; //头结点的前继指向新节点
r = s; //更新指针
}
}
2.求表长
int GetLength(DCLinkList L)
{
int count = 0;
DCLinkList head = L; //记下头指针位置
//画图细细品味
while (L->next!=head)
{
L = L->next;
count++;
}
return count;
}
3.获取结点
/*初始条件:表已经存在*/
/*操作结果:返回第i个位置的结点*/
DCLinkList GetNode(DCLinkList L, int i)
{
int length = GetLength(L);
DCLinkList p;
if (i == 0)
return L;
if (i<0 || i>length) //位置不合法
return NULL;
if (i >= (length/ 2)) //从表尾开始遍历
{
p = L->prior; //p被赋值为最后一个结点
//当在表尾开始遍历时,只需要遍历(表长-i)次
for (int j = 0; j < length - i; j++)
p = p->prior;
}
else //从表头开始遍历
{
p = L;
//当在表头开始遍历时,只需要遍历i次
for (int j = 0; j < i; j++)
p = p->next;
}
return p;
}
4.插入结点
/*初始条件:表已经存在*/
/*操作结果:在第i个结点插入结点*/
int ListInsert(DCLinkList* L, int i, ElemType e)
{
DCLinkList p, s;
p = GetNode((*L), i - 1); //找到第i个结点的前驱结点
if (p == NULL)
return 0;
s = (DCLinkList)malloc(sizeof(DNode));
s->data = e;
s->next = p->next;
s->prior = p;
p->next->prior = s;
p->next = s;
return 1;
}
5.删除结点
/*初始条件:表已经存在*/
/*操作结果:删除第i个位置上的结点,并用e回收删除结点的数据域*/
int ListDelete(DCLinkList* L, int i, ElemType* e)
{
DCLinkList p,s;
p = GetNode((*L), i);
if (p == NULL)
return 0;
p->prior->next = p->next;
p->next->prior = p->prior;
*e = p->data;
free(p);
return 1;
}
6.重置为空表
void ClearList(DCLinkList* L)
{
DCLinkList p,s;
p = (*L)->next; //从第一个结点开始删除
while (p!= (*L)) //当p等于头结点时说明已经遍历完整表
{
s = p; //备份要删除的结点
p = p->next; //移动到下一个结点
free(s); //删除备份结点
}
//重置头结点的后继和前驱
(*L)->next = (*L);
(*L)->prior = (*L);
}