C_线性表(ADT)-双向循环链表的表示和实现

来源:互联网 发布:图像算法工程师 编辑:程序博客网 时间:2024/06/05 08:16

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。(解释来自百度百科)


下面是网上的一张双向循环链表的结构图片:



双向链表定义:

typedef struct DuLNode{ElemType data;DuLNode *prior;//指向直接前驱DuLNode *next;//指向直接后继 }DuLNode,*DuLinkList;

双向链表基本操作:

/*操作结果:产生空的双向循环链表L*/Status InitList(DuLinkList &L)/*初始条件:双链循环线性表L已存在*//*操作结果:摧毁双向循环链表L*/void DestroyList(DuLinkList &L)/*初始条件:双链循环线性表L已存在*//*操作结果:将L重置为空表*/Status ClearList(DuLinkList L)/*初始条件:双链循环线性表L已存在*//*操作结果:若L为空表,则返回TRUE;否则返回FALSE*/Status ListEmpty(DuLinkList L)/*初始条件:双链循环线性表L已存在*//*操作结果:返回L中数据元素个数*/Status ListLength(DuLinkList L)/*初始条件:双链循环线性表L已存在*//*操作结果:当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR*/Status GetElem(DuLinkList L,int i,ElemType &e)/*初始条件:L已存在,compare()是数据元素判定的函数*//*操作结果:返回L中第1个与e满足关系的compare()的数据元素的位序。若这样的元素不存在,则返回ERROR。*/Status LocateElem(DuLinkList L,ElemType e,Status (*compare)(ElemType,ElemType))/*初始条件:双链循环线性表L已存在*//*操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱;否则操作失败,pre_e无定义*/Status PriorElem(DuLinkList L,ElemType cur_e,ElemType &pre_e)/*初始条件:双链循环线性表L已存在*//*操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后续;否则返回FALSE,next_e无定义*/Status NextElem(DuLinkList L,ElemType cur_e,ElemType &next_e)/*初始条件:双链循环线性表L已存在*//*操作结果:在双向链表L中返回第i个元素的地址。i为0,返回头结点的地址,若第i个元素不存在,返回NULL。*/DuLinkList GetElemP(DuLinkList L,int i)/*初始条件:双链循环线性表L已存在*//*操作结果:在带头结点的双链循环线性表L中第i个位置之前插入元素e,i的取值为1≤i≤表长+1。*/Status ListInsert(DuLinkList L,int i,ElemType e)/*初始条件:双链循环线性表L已存在*//*操作结果:删除带头结点的双链循环线性表L的第i个元素,i的合法值为1≤i ≤表长*/Status ListDelete(DuLinkList L,int i,ElemType &e)/*初始条件:双链循环线性表L已存在*//*操作结果:由双链循环线性表L的头结点出发,正序对每个数据元素调用函数visit()*/void ListTraverse(DuLinkList L,void(*visit)(ElemType))/*初始条件:双链循环线性表L已存在*//*操作结果:由双链循环线性表的L的头结点出发,逆序对每个数据元素调用visit()*/void ListTraverseBack(DuLinkList L,void(*visit)(ElemType))

双向链表操作的基本实现:

产生空的双向循环链表L

/*操作结果:产生空的双向循环链表L*/Status InitList(DuLinkList &L){L=(DuLinkList)malloc(sizeof(DuLNode));if(L){L->next=L->prior=L;return OK;}else{printf("产生空的双向循环链表失败!\n");return ERROR;}}



摧毁双向循环链表

/*初始条件:双链循环线性表L已存在*//*操作结果:摧毁双向循环链表L*/void DestroyList(DuLinkList &L){ DuLinkList q;DuLinkList p=L->next;//指向第一个结点(头结点)while(p!=L) //p没有到表头{q=p->next;free(p);p=q;}free(L);L=NULL;printf("线性表被摧毁!\n");printf("退出程序!\n");exit(0);}

注:摧毁链表后链表不存在,进行不了其它基本操作,就直接退出程序了

将L重置为空表

Status ClearList(DuLinkList L){ DuLinkList q;DuLinkList p=L->next;//p指向第一个结点while(p!=L)//p没有到达表头{q=p->next;free(p);p=q;}L->next=L->prior=L;//头节点的两个指针域均指向自身return OK;} 


判断双向循环链表是否为空表:

/*初始条件:双链循环线性表L已存在*//*操作结果:若L为空表,则返回TRUE;否则返回FALSE*/Status ListEmpty(DuLinkList L){if(L->next==L&&L->prior==L)return TRUE;elsereturn FALSE;}


返回链表长度

/*初始条件:双链循环线性表L已存在*//*操作结果:返回L中数据元素个数*/Status ListLength(DuLinkList L){int i=0;DuLinkList p=L->next;//p指向第一个节点while(p!=L)//p没到表头{i++;p=p->next;}return i;} 


返回位序结点

/*初始条件:双链循环线性表L已存在*//*操作结果:当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR*/Status GetElem(DuLinkList L,int i,ElemType &e){int j=1;DuLinkList p=L->next;//p指向第1个结点while(p!=L&&j<i)//顺指针向后查找,直到p指向第i个元素或p指向头结点{p=p->next;j++;} if(p==L||j>i)//第i个元素不存在return ERROR;e=p->data;//取第i个元素return OK;} 


返回结点位序

*初始条件:L已存在,compare()是数据元素判定的函数*//*操作结果:返回L中第1个与e满足关系的compare()的数据元素的位序。若这样的元素不存在,则返回ERROR。*/Status LocateElem(DuLinkList L,ElemType e,Status (*compare)(ElemType,ElemType)){int i=0;DuLinkList p=L->next;//p指向第1个元素while(p!=L){i++;if(compare(p->data,e))//找到这样的元素return i;p=p->next;  }return ERROR;}


返回结点前驱

/*初始条件:双链循环线性表L已存在*//*操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱;否则操作失败,pre_e无定义*/Status PriorElem(DuLinkList L,ElemType cur_e,ElemType &pre_e){DuLinkList p=L->next->next;//p指向第二个数据元素while(p!=L)//没有到达表头 {if(p->data==cur_e){pre_e=p->prior->data;return TRUE;}p=p->next;}return FALSE;}


返回结点后继

/*初始条件:双链循环线性表L已存在*//*操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继;否则返回FALSE,next_e无定义*/Status NextElem(DuLinkList L,ElemType cur_e,ElemType &next_e){DuLinkList p=L->next->next;//p指向第2个元素while(p!=L)//p没到表头{if(p->prior->data==cur_e){next_e=p->data;return TRUE;}p=p->next;}return FALSE;}


在i位置前置入元素

/*初始条件:双链循环线性表L已存在*//*操作结果:在带头结点的双链循环线性表L中第i个位置之前插入元素e,i的取值为1≤i≤表长+1。*/Status ListInsert(DuLinkList L,int i,ElemType e){DuLinkList p,s;if(i<1||i>ListLength(L)+1)//i值不合法return ERROR;p=GetElemP(L,i-1);//在L中确定第i个元素前驱的位置指针pif(!p)return ERROR;//p=NULL即第i个元素的前驱不存在s=(DuLinkList)malloc(sizeof(DuLNode));if(!s)return ERROR;s->data=e;s->prior=p;//在第i-1个元素之后插入 s->next=p->next;p->next->prior=s;p->next=s;return OK; }


删除链表中第i个元素

/*初始条件:双链循环线性表L已存在*//*操作结果:删除带头结点的双链循环线性表L的第i个元素,i的合法值为1≤i ≤表长*/Status ListDelete(DuLinkList L,int i,ElemType &e){DuLinkList p;if(i<1)//i值不合法return ERROR;p=GetElemP(L,i);//在L中确定第i个元素的位置指针pif(!p)//p=NULL,即第i个元素不存在return ERROR;e=p->data;p->prior->next=p->next;p->next->prior=p->prior;free(p);return OK;  }


正序遍历

/*初始条件:双链循环线性表L已存在*//*操作结果:由双链循环线性表L的头结点出发,正序对每个数据元素调用函数visit()*/void ListTraverse(DuLinkList L,void(*visit)(ElemType)){DuLinkList p=L->next;//p指向头结点while(p!=L){visit(p->data);p=p->next;}printf("\n"); }


逆序遍历

/*初始条件:双链循环线性表L已存在*//*操作结果:由双链循环线性表的L的头结点出发.逆序对每个数据元素调用visit()*/void ListTraverseBack(DuLinkList L,void(*visit)(ElemType)){DuLinkList p=L->prior;//p指向尾结点while(p!=L){visit(p->data);p=p->prior;} printf("\n");}


嗯下面就是在VC中的测试:

//双向循环链表//头结点为第一个结点的前驱 #include<stdio.h>#include<stdlib.h>#include<string.h>#define OK 1#define ERROR 0#define TRUE 1#define FALSE 0typedef int ElemType;typedef int Status;typedef struct DuLNode{ElemType data;DuLNode *prior;//指向直接指针 DuLNode *next;//指向直接后续 }DuLNode,*DuLinkList;Status compare(ElemType e1,ElemType e2){if(e1==e2)return 0;else if(e1>e2)return 1;else if(e1<e2)return -1;}Status equal(ElemType c1,ElemType c2){if(c1==c2)return TRUE;elsereturn ERROR;}void visit(ElemType e){printf("%d \n",e);}void print(ElemType c){printf("%d ",c);}/*操作结果:产生空的双向循环链表L*/Status InitList(DuLinkList &L){L=(DuLinkList)malloc(sizeof(DuLNode));if(L){L->next=L->prior=L;return OK;}else{printf("产生空的双向循环链表失败!\n");return ERROR;}}/*初始条件:双链循环线性表L已存在*//*操作结果:摧毁双向循环链表L*/void DestroyList(DuLinkList &L){ DuLinkList q;DuLinkList p=L->next;//指向第一个结点(头结点)while(p!=L) //p没有到表头{q=p->next;free(p);p=q;}free(L);L=NULL;printf("线性表被摧毁!\n");printf("退出程序!\n");exit(0);}/*初始条件:双链循环线性表L已存在*//*操作结果:将L重置为空表*/Status ClearList(DuLinkList L){ DuLinkList q;DuLinkList p=L->next;//p指向第一个结点while(p!=L)//p没有到达表头{q=p->next;free(p);p=q;}L->next=L->prior=L;//头节点的两个指针域均指向自身return OK;} /*初始条件:双链循环线性表L已存在*//*操作结果:若L为空表,则返回TRUE;否则返回FALSE*/Status ListEmpty(DuLinkList L){if(L->next==L&&L->prior==L)return TRUE;elsereturn FALSE;}/*初始条件:双链循环线性表L已存在*//*操作结果:返回L中数据元素个数*/Status ListLength(DuLinkList L){int i=0;DuLinkList p=L->next;//p指向第一个节点while(p!=L)//p没到表头{i++;p=p->next;}return i;} /*初始条件:双链循环线性表L已存在*//*操作结果:当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR*/Status GetElem(DuLinkList L,int i,ElemType &e){int j=1;DuLinkList p=L->next;//p指向第1个结点while(p!=L&&j<i)//顺指针向后查找,直到p指向第i个元素或p指向头结点{p=p->next;j++;} if(p==L||j>i)//第i个元素不存在return ERROR;e=p->data;//取第i个元素return OK;} /*初始条件:L已存在,compare()是数据元素判定的函数*//*操作结果:返回L中第1个与e满足关系的compare()的数据元素的位序。若这样的元素不存在,则返回ERROR。*/Status LocateElem(DuLinkList L,ElemType e,Status (*compare)(ElemType,ElemType)){int i=0;DuLinkList p=L->next;//p指向第1个元素while(p!=L){i++;if(compare(p->data,e))//找到这样的元素return i;p=p->next;  }return ERROR;}/*初始条件:双链循环线性表L已存在*//*操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱;否则操作失败,pre_e无定义*/Status PriorElem(DuLinkList L,ElemType cur_e,ElemType &pre_e){DuLinkList p=L->next->next;//p指向第二个数据元素while(p!=L)//没有到达表头 {if(p->data==cur_e){pre_e=p->prior->data;return TRUE;}p=p->next;}return FALSE;}/*初始条件:双链循环线性表L已存在*//*操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继;否则返回FALSE,next_e无定义*/Status NextElem(DuLinkList L,ElemType cur_e,ElemType &next_e){DuLinkList p=L->next->next;//p指向第2个元素while(p!=L)//p没到表头{if(p->prior->data==cur_e){next_e=p->data;return TRUE;}p=p->next;}return FALSE;}/*初始条件:双链循环线性表L已存在*//*操作结果:在双向链表L中返回第i个元素的地址。i为0,返回头结点的地址,若第i个元素不存在,返回NULL。*/DuLinkList GetElemP(DuLinkList L,int i){int j;DuLinkList p=L;//p指向头结点if(i<0||i>ListLength(L))//i值不合法return ERROR;for(j=1;j<=i;j++)p=p->next;return p; }/*初始条件:双链循环线性表L已存在*//*操作结果:在带头结点的双链循环线性表L中第i个位置之前插入元素e,i的取值为1≤i≤表长+1。*/Status ListInsert(DuLinkList L,int i,ElemType e){DuLinkList p,s;if(i<1||i>ListLength(L)+1)//i值不合法return ERROR;p=GetElemP(L,i-1);//在L中确定第i个元素前驱的位置指针pif(!p)return ERROR;//p=NULL即第i个元素的前驱不存在s=(DuLinkList)malloc(sizeof(DuLNode));if(!s)return ERROR;s->data=e;s->prior=p;//在第i-1个元素之后插入 s->next=p->next;p->next->prior=s;p->next=s;return OK; }/*初始条件:双链循环线性表L已存在*//*操作结果:删除带头结点的双链循环线性表L的第i个元素,i的合法值为1≤i ≤表长*/Status ListDelete(DuLinkList L,int i,ElemType &e){DuLinkList p;if(i<1)//i值不合法return ERROR;p=GetElemP(L,i);//在L中确定第i个元素的位置指针pif(!p)//p=NULL,即第i个元素不存在return ERROR;e=p->data;p->prior->next=p->next;p->next->prior=p->prior;free(p);return OK;  }/*初始条件:双链循环线性表L已存在*//*操作结果:由双链循环线性表L的头结点出发,正序对每个数据元素调用函数visit()*/void ListTraverse(DuLinkList L,void(*visit)(ElemType)){DuLinkList p=L->next;//p指向头结点while(p!=L){visit(p->data);p=p->next;}printf("\n"); }/*初始条件:双链循环线性表L已存在*//*操作结果:由双链循环线性表的L的头结点出发.逆序对每个数据元素调用visit()*/void ListTraverseBack(DuLinkList L,void(*visit)(ElemType)){DuLinkList p=L->prior;//p指向尾结点while(p!=L){visit(p->data);p=p->prior;} printf("\n");}int main(){DuLinkList L;int ch;int i,n,j;ElemType e;if(InitList(L))printf("创建双向循环链表成功!\n");printf("请输入循环链表的长度:");scanf("%d",&n);printf("请输入循环链表各个数据:");for(i=1;i<=n;i++){scanf("%d",&e);ListInsert(L,i,e);//在第i个结点之前插入e}printf("*********************************\n");printf("1、插入结点\n2、删除结点\n3、清空链表\n");printf("4、摧毁链表\n5、判空链表\n6、链表表长\n");printf("7、结点前驱\n8、结点后续\n");printf("9、查询位序结点\n10、查询结点位序\n");printf("11、正序遍历链表\n12、逆序遍历链表\n");printf("0、退出操作\n"); printf("*********************************\n");printf("请选择接下来要进行的操作:");while(scanf("%d",&ch)&&ch!=0){if(ch==1){int set;printf("请输入在第几个结点之前插入新结点:");scanf("%d",&set);printf("请输入要插入结点的数据:");scanf("%d",&e);if(ListInsert(L,set,e))printf("操作成功!\n");}if(ch==2){int set;printf("请输入要删除第几个结点:");scanf("%d",&set);if(ListDelete(L,set,e))printf("成功删除第%d个结点,其值为%d\n",set,e);}if(ch==3){if(ClearList(L))printf("已成功清空链表!\n");}if(ch==4){DestroyList(L);}if(ch==5){if(ListEmpty(L))printf("这是一个空的链表!\n");elseprintf("这不是一个空的链表!\n");}if(ch==6){printf("链表的长度为:%d\n",ListLength(L));}if(ch==7){printf("请输入要查找元素的前驱:");scanf("%d",&n);if(PriorElem(L,n,e))printf("%d元素的前驱是%d\n",n,e);elseprintf("输入错误!\n");//输入的是首结点也会判断为输入错误 }if(ch==8){printf("请输入要查找元素的后续:");scanf("%d",&n);if(NextElem(L,n,e))printf("%d元素的后续是%d\n",n,e);elseprintf("输入错误!\n");//输入的是尾结点也会判断尾输入错误 }if(ch==9){printf("请输入要匹配的数据元素:");scanf("%d",&n); if(LocateElem(L,n,equal)) printf("等于%d的元素是第%d个\n",n,LocateElem(L,n,equal)); else printf("链表中不存在元素%d\n",n);}if(ch==10){int set;printf("请输入要查询链表位序的值:");scanf("%d",&set);if(GetElem(L,set,e))printf("链表的第%d个元素的值为%d\n",set,e);elseprintf("输入错误!\n");}if(ch==11){printf("正序输出链表:");ListTraverse(L,print);}if(ch==12){printf("逆序输出链表:");ListTraverseBack(L,print);}printf("请选择接下来要进行的操作:");}printf("成功退出操作!\n"); return 0;}


阅读全文
1 0