把双链表改为循环双链表只需要将双链表的尾结点指针由原来的空改为指向头结点,把头结点的prior指针域改为指向尾结点足以,这样就把整个双链表形成了两个环。
如图所示:
循环双链表的操作与双链表基本一致,差别在于遍历链表时,判别当前指针p是否指向表尾结点的终止条件不同:
双链表:p->next != NULL
循环双链表:p->next != h
为空条件不同:
双链表:h->next==NULL && h->prior==NULL
循环双链表:h->next==h && h->prior==h
对于双链表,采用类似于单链表的类型声明,其结点类型DLinkList的声明如下:
typedef int ElemType;
typedef struct Node
{
ElemType data;//存储线性表的元素值(1个)
struct Node *next;//存储后继元素节点的地址
struct Node *prior;//存储前驱元素节点的地址
}DCLinkList;
因为双链表的每个结点都有一个指向前驱结点的指针和一个指向后继结点的指针,因此双链表访问一个结点的前、后结点比单链表更方便。
1)初始化双链表
构造一个空的双链表,空双链表中只存在一个头结点,头结点类型与普通结点一样,data值不用。
DCLinkList *InitList()
{
DCLinkList *h;
h=(DCLinkList *)malloc(sizeof(DCLinkList));
h->next=h;
h->prior=h;
return h;
}
2)销毁双链表
这里调用ListDelete(DLinkList *h,int i,ElemType *e),删除每个结点并释放,代码如下:
void DestroyList(DCLinkList *h)
{
int ListDelete(DCLinkList *h,int i,ElemType *e);
ElemType v;
while(h->next!=h||h->prior!=h)//不空
{
//删除第1个元素节点
ListDelete(h,1,&v);
}
free(h);
}
3)判断双链表是否为空
为空条件:h->next == NULL and h->prior == NULL
代码如下:
ListEmpty(DCLinkList *h)
{
if(h->next==NULL&&h->prior==NULL)
{
return 1;
}
else
{
return 0;
}
}
4)求双链表长度
代码如下:
int ListLength(DCLinkList *h)
{
DCLinkList *p;
int len;
p=h;
len=0;
while(p->next!=NULL)
{
p=p->next;
len=len+1;
}
return len;
}
5_1)输出双链表元素
代码如下:
void DispList(DCLinkList *h)
{
DCLinkList *p;
p=h;
printf("线性表的元素为:");
while(p->next!=NULL)
{
p=p->next;
printf("%d ",p->data);
}
printf("\n");
}
5_2)逆向输出双链表元素
代码如下:
void DispList1(DCLinkList *h)
{
DLinkList *p;
//让p指向最后一个元素节点
p=h;
while(p->next!=h)
{
p=p->next;
}
//从最后一个元素逆序输出至第一个元素
printf("线性表的元素为:");
while(p!=h)
{
printf("%d ",p->data);
p=p->prior;
}
printf("\n");
}
6)取值
取双链表中第i位置的元素,需要判断参数合法性,这里可以调用求长度ListLength(DLinkList *h)的函数来确定双链表范围,代码如下:
/*
6.取值
参数合法:i>=1 && i<=ListLength(h)
若参数合法,进行相关操作,返回1;
否则,提示,返回0
*/
int GetElem(DCLinkList *h,int i,ElemType *e)
{
DCLinkList *p;
int j;
if(i>=1 && i<=ListLength(h))
{
p=h;
for(j=1;j<=i;j++)
{
p=p->next;
}
*e=p->data;
return 1;
}
else
{
printf("参数错误!\n");
return 0;
}
}
7)查找
查找双链表中是否存在某个值e,代码如下:
/*
在线性表中查找是否存在值为e的元素,
若存在,返回该元素的位序
否则,返回0
*/
int LocateElem(DCLinkList *h,ElemType e)
{
DCLinkList *p;
int len;
p=h;
len=0;
while(p->next!=h)
{
p=p->next;
len=len+1;
if(p->data==e)
{
return len;
}
}
return 0;
}
8)插入元素
插入元素需要判断插入位置的合法性,双链表中在第i个位置插入元素e与单链表类似,要先找到第i-1个位置(让p指向它),然后在p所指向的结点后面插入新结点,
插入元素需要改变四个指针域
代码如下:
/*
参数合法:i>=1 && i<=ListLength(h)+1
若参数合法,进行相关操作,返回1;
否则,提示,返回0
*/
int ListInsert(DCLinkList *h,int i,ElemType e)
{
DCLinkList *p,*q;
int j;
if(i>=1 && i<=ListLength(h)+1)
{
//1.构造一个节点q,存储元素e
q=(DCLinkList *)malloc(sizeof(DCLinkList));
q->data=e;
//2.让p指向第i-1个元素节点
p=h;
for(j=1;j<=i-1;j++)
{
p=p->next;
}
//3.添加
q->next=p->next;
p->next->prior=q;
p->next=q;
q->prior=p;
return 1;
}
else
{
printf("参数错误!\n");
return 0;
}
}
9)删除元素
双链表中在删除第i个位置元素e与单链表类似,要先找到第i-1个位置(让p指向它),然后删除p所指向的结点,
删除元素需要改变两个指针域
代码如下:
/*
参数合法:i>=1 && i<=ListLength(h)
若参数合法,进行相关操作,返回1;
否则,提示,返回0
*/
int ListDelete(DCLinkList *h,int i,ElemType *e)
{
DCLinkList *p,*q;
int j;
if(i>=1 && i<=ListLength(h))
{
//1.让p指向第i-1个
p=h;
for(j=1;j<=i-1;j++)
{
p=p->next;
}
//2.让q指向第i个
q=p->next;
//3.把要删除的元素值存储到*e中
*e=q->data;
//4.删除
p->next=q->next;
q->next->prior=p;
//5.释放存储空间
free(q);
return 1;
}
else
{
printf("参数错误!\n");
return 0;
}
}
最后再附上完整代码:
#include <stdio.h>
typedef int ElemType;
typedef struct Node
{
ElemType data;//存储线性表的元素值(1个)
struct Node *next;//存储后继元素节点的地址
struct Node *prior;//存储前驱元素节点的地址
}DCLinkList;
/*
最后一个节点的后继是头节点;
头节点的前驱是最后一个节点。
为了方便操作,特别地加了一个头节点进来,类型和普通节点一样
data:不用
next:存储第1个元素节点的地址
prior:最后一个节点的地址
执行语句p=p->next;一次,p的指向往后移动一个位置
执行语句p=p->prior;一次,p的指向往前移动一个位置
空:h->next==h && h->prior==h
最后一个节点:若p->next==h,说明p指向最后一个节点
*/
/*
1.初始化
构造一个空的线性表
*/
DCLinkList *InitList()
{
DCLinkList *h;
h=(DCLinkList *)malloc(sizeof(DCLinkList));
h->next=h;
h->prior=h;
return h;
}
/*
2.销毁
*/
void DestroyList(DCLinkList *h)
{
int ListDelete(DCLinkList *h,int i,ElemType *e);
ElemType v;
while(h->next!=h||h->prior!=h)//不空
{
//删除第1个元素节点
ListDelete(h,1,&v);
}
free(h);
}
/*
3.判断线性表是否为空
若为空,返回1;
否则,返回0
*/
ListEmpty(DCLinkList *h)
{
if(h->next==h&&h->prior==h)
{
return 1;
}
else
{
return 0;
}
}
/*
4.求长度
*/
int ListLength(DCLinkList *h)
{
DCLinkList *p;
int len;
p=h;
len=0;
while(p->next!=h)
{
p=p->next;
len=len+1;
}
return len;
}
/*
5.输出
*/
void DispList(DCLinkList *h)
{
DCLinkList *p;
p=h;
printf("线性表的元素为:");
while(p->next!=h)
{
p=p->next;
printf("%d ",p->data);
}
printf("\n");
}
/*
5.输出
*/
void DispList1(DCLinkList *h)
{
DCLinkList *p;
//让p指向最后一个元素节点
p=h;
while(p->next!=h)
{
p=p->next;
}
//从最后一个元素逆序输出至第一个元素
printf("线性表的元素为:");
while(p!=h)
{
printf("%d ",p->data);
p=p->prior;
}
printf("\n");
}
/*
6.取值
参数合法:i>=1 && i<=ListLength(h)
若参数合法,进行相关操作,返回1;
否则,提示,返回0
*/
int GetElem(DCLinkList *h,int i,ElemType *e)
{
DCLinkList *p;
int j;
if(i>=1 && i<=ListLength(h))
{
p=h;
for(j=1;j<=i;j++)
{
p=p->next;
}
*e=p->data;
return 1;
}
else
{
printf("参数错误!\n");
return 0;
}
}
/*
7.查找
在线性表中查找是否存在值为e的元素,
若存在,返回该元素的位序
否则,返回0
*/
int LocateElem(DCLinkList *h,ElemType e)
{
DCLinkList *p;
int len;
p=h;
len=0;
while(p->next!=h)
{
p=p->next;
len=len+1;
if(p->data==e)
{
return len;
}
}
return 0;
}
/*
8.添加
参数合法:i>=1 && i<=ListLength(h)+1
若参数合法,进行相关操作,返回1;
否则,提示,返回0
*/
int ListInsert(DCLinkList *h,int i,ElemType e)
{
DCLinkList *p,*q;
int j;
if(i>=1 && i<=ListLength(h)+1)
{
//1.构造一个节点q,存储元素e
q=(DCLinkList *)malloc(sizeof(DCLinkList));
q->data=e;
//2.让p指向第i-1个元素节点
p=h;
for(j=1;j<=i-1;j++)
{
p=p->next;
}
//3.添加
q->next=p->next;
p->next->prior=q;
p->next=q;
q->prior=p;
return 1;
}
else
{
printf("参数错误!\n");
return 0;
}
}
/*
9.删除
参数合法:i>=1 && i<=ListLength(h)
若参数合法,进行相关操作,返回1;
否则,提示,返回0
*/
int ListDelete(DCLinkList *h,int i,ElemType *e)
{
DCLinkList *p,*q;
int j;
if(i>=1 && i<=ListLength(h))
{
//1.让p指向第i-1个
p=h;
for(j=1;j<=i-1;j++)
{
p=p->next;
}
//2.让q指向第i个
q=p->next;
//3.把要删除的元素值存储到*e中
*e=q->data;
//4.删除
p->next=q->next;
q->next->prior=p;
//5.释放存储空间
free(q);
return 1;
}
else
{
printf("参数错误!\n");
return 0;
}
}
/*
变量先定义,再赋初值,才能使用
*/
int main()
{
/*
int a;
int b;
b=a*10;
printf("%d\n",b);*/
/*
int *p;
p=(int *)malloc(sizeof(int));
*p = 123;
printf("%d\n",*p);
free(p);
*/
return 1;
}
代码是再单链表的基础上修改的,如有错误,请多多指教