为了方便,将元素类型和操作结构状态码的定义放到头文件自定义"ElemType.h"中
/** * #ifndef: 一种宏定义,是"if not defined"的简写,当包含该头文件的C源文件第一次包含该头文件时,未定义过该头文件,条件为真 * 回执行语句#ifndef和语句#endif间的代码,当多次包含时, * 不再执行#ifndef和#endif间的代码,应为已经定义过了,条件为假 */ #ifndef DATASTRUCTURE_ELEMTYPE_H #define DATASTRUCTURE_ELEMTYPE_H #include "stdio.h" typedef double ElemType; //操作成功 #define OK 1 //操作错误 #define ERROR 0 //操作异常 #define OVERFLOW -2 //定义元素类型,int可使用基本数据类型和用户自定义数据类型替换,根据使用场景选择 typedef int Status ; double absForDouble(double a); /** * 求绝对值 * @param a * @return 返回a的绝对值 */ double absForDouble(double a) { if (a < 0)return -a; return a; } /** * 实现两个ElemType类型变量的匹配 * @param e1 ElemType类型变量e1 * @param e2 ElemType类型变量e2 * @return 匹配结果,1表示匹配,0表示不匹配 */ int match(ElemType e1, ElemType e2){ if(absForDouble(e1-e2)<1e-6) return 1; return 0; } /** * 打印数据元素 */ printElem(ElemType e){ printf("Current element‘s data is %lf!\n",e); } #endif //DATASTRUCTURE_ELEMTYPE_H
循环链表的定义
#include<stdio.h> #include<stdlib.h> #include "ElemType.h" /** * 循环链表 * 什么是循环链表? * 循环链表是另一种形式的链式存储结构。其特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环,由此,从表中任一个结点出发均可找到表中其他结点。 */ /** * 循环链表的定义 */ typedef struct { ElemType data; struct LNode *next; } LNode, *CircularLinkedList;
循环链表上基本操作的实现
/** * 初始化 * 初始化循环链表,申请一个头结点,使头指针指向头结点,置头结点的指针域为头指针 * 算法描述: * 1、申请一个头结点,使指向头指针的指针L指向的头指针指向头结点,若申请失败,返回OVERFLOW * 2、置头结点的指针域为头指针 * 3、返回OK * @param L 指向单链表头指针的指针 * @return 操作结果状态码 */ Status initCircularLinkedList(CircularLinkedList *L) { //申请一个头结点,使指向头指针的指针L指向的头指针指向头结点 *L = (LNode *) malloc(sizeof(LNode)); //若申请失败,返回OVERFLOW if (!(*L)) return OVERFLOW; //置头结点的指针域为头指针 (*L)->next = *L; (*L)->data = 0; //返回OK return OK; } /* * 销毁循环链表 * 算法描述: * 1、判断指向头指针的指针L是否合法(即*L(头指针)是否指向NULL),若不合法(*L指向NULL),返回ERROR * 2、定义指向当前结点的指针p,使p指向首元结点 * 3、定义临时指针t指向指针p指向的结点的直接后继 * 4、循环释放指针p指向的结点所占用的内存空间,并使p指向指针t指向的结点,使指针t指向指针p指向的结点的直接后继结点,当p=*L时,即销毁完全部结点时,循环终止 * 5、释放头指针*L指向的头结点占用的内存空间 * 6、置指针L(头指针),p,t为NULL,返回OK * @param L 指向循环链表头结点的指针L * @return 操作结果状态码 */ Status destroyCircularLinkedList(CircularLinkedList *L) { //判断指向头指针的指针L是否合法(即*L(头指针)或L是否指向NULL),若不合法(*L或L指向NULL),返回ERROR if (!(*L) || !L) { return ERROR; } //定义指向当前结点的指针p,使p指向首元结点 LNode *p = (*L)->next; //定义临时指针t指向指针p指向的结点的直接后继 LNode *t = p->next; //当p=*L时,即销毁完除头结点外的全部结点时,循环终止 while (p != *L) { //释放指针p指向的结点所占用的内存空间 free(p); //使p指向指针t指向的结点 p = t; //使指针t指向指针p指向的结点的直接后继结点 t = p->next; } //释放头指针*L指向的头结点占用的内存空间 free(*L); free(L); //置指针L,p,t为NULL,返回OK L = NULL; p = NULL; t = NULL; return OK; } /** * 清空循环链表 * 算法描述: * 1、判断指针L是否合法,若不合法,返回ERROR * 2、定义指向当前结点的指针p指向首元结点 * 3、定义临时指针t指向指针p指向的结点的直接后继结点 * 4、循环释放指针p指向的结点占用的内存,并使指针p指向下一个结点(指针t指向的结点),使指针t指向指针p指向的结点的直接后继结点,当p=*L(p指向头结点,除头节点外的其他结点均被释放),终止循环 * 5、置*L的指针域为*L * 6、置指针p,t指向NULL,返回OK * @param L 指向循环链表的头指针的指针L * @return 操作结果状态码 */ Status clearCircularLinkedList(CircularLinkedList *L) { //判断指针L是否合法,若不合法,返回ERROR if (!L || !(*L)) return ERROR; //定义指向当前结点的指针p指向首元结点 LNode *p = (*L)->next; //定义临时指针t指向指针p指向的结点的直接后继结点 LNode *t = p->next; //当p=*L(p指向头结点,除头节点外的其他结点均被释放),终止循环 while (p != (*L)) { //释放指针p指向的结点占用的内存 free(p); //使指针p指向下一个结点(指针t指向的结点) p = t; //使指针t指向指针p指向的结点的直接后继结点 t = p->next; } //置*L的指针域为*L (*L)->next = *L; //置指针p,t指向NULL,返回OK p = NULL; t = NULL; return OK; } /** * 空表判断 * 算法描述: * 1、判断头指针p是否合法,若不合法,置*ret为零(假值),返回ERROR * 2、若循环链表为空表,则只包含头结点,且头结点的直接后继结点是头结点本身,因此若L->next=L,置*ret为1(真值),表示当前循环链表为空表 * 3、否则,当前循环链表不是空表,置*ret为零(假值) * 4、返回OK * @param L 指针循环链表头结点的头指针L * @param ret 指向用以保持单链表是否为空表信息的变量的指针ret * @return 操作结果状态码 */ Status circularLinkedListIsEmpty(CircularLinkedList L, int *ret) { //判断头指针p是否合法,若不合法,置ret为零(假值),返回ERROR if (!L) { *ret = 0; return ERROR; } if (L == L->next) { ////若循环链表为空表,则只包含头结点,且头结点的直接后继结点是头结点本身,因此若L->next=L,置ret为1(真值),表示当前循环链表为空表 *ret = 1; } else { //否则,当前循环链表不是空表,置ret为零(假值) *ret = 0; } //返回OK return OK; } /** * 获取循环链表长度 * 算法描述: * 1、判断指针L是否合法,不合法,置*len为负一(表示循环链表为初始化),返回ERROR * 2、定义指向当前结点的指针p使其指向首元结点 * 3、定义计数器j记录指针p由首元结点移动至头结点需要依次的次数,j初始值为零 * 4、循环移动指针p并使计数器j自增直至p=L(已经移动到了首元结点) * 5、把计数器j的值赋值给*len * 6、置指针p指向NULL,返回OK * @param L 指向循环链表的头结点的头指针L * @param len 指向用以保存循环链表的结点个数的变量的指针len * @return 操作结果状态码 */ Status getCircularLinkedListLength(CircularLinkedList L, int *len) { //判断指针L是否合法,不合法,置*len为负一(表示循环链表为初始化),返回ERROR if (!L) { *len = -1; return ERROR; } //定义指向当前结点的指针p使其指向首元结点 LNode *p = L->next; //定义计数器j记录指针p由首元结点移动至头结点需要依次的次数,j初始值为零 int j = 0; //循环移动指针p并使计数器j自增直至p=L(已经移动到了首元结点) while (p != L) { p = p->next; ++j; } //把计数器j的值赋值给*len *len = j; //置指针p指向NULL,返回OK p = NULL; return OK; } /** * 取值 * 取循环链表上第i个结点的数据域的值,i值必须合法,其范围为从1到n的整数,n为当前单链表的结点个数 * 算法描述: * 1、判断指针L是否合法,若不合法,置*e的值为0(无任何意义),返回ERROR * 2、定义指向当前结点的指针p并使其指向首元结点 * 3、定义计数器j记录指针p由首元结点移动到结点i的次数,即当j=i-1时即说明移动到结点i * 4、循环移动指针p并使计数器j自增直至p=L或者j=i-1 * 5、判断循环终止条件,若p=L则说明遍历了所有循环链表的结点仍未到达结点i,即i > n,i非法,置*e的值为0(无任何意义),返回ERROR * 6、若j>i-1则说明未移动i-1次循环即结束,即i<1,i非法,置*e的值为0(无任何意义),返回ERROR * 7、i合法,将指向当前结点的指针p(此时恰好指向结点i)的数据域赋值给*e * 8、置指针p=NULL,返回OK * @param L 指向循环链表的头结点的头指针L * @param i 结点位置i * @param e 指向用以保存结点i的数据域的变量的指针e * @return 操作结果状态码 */ Status getCircularLinkedListElem(CircularLinkedList L, int i, ElemType *e) { //判断指针L是否合法,若不合法,置*e的值为0(无任何意义),返回ERROR if (!L) { *e = 0; return ERROR; } //定义指向当前结点的指针p并使其指向首元结点 LNode *p = L->next; //定义计数器j记录指针p由首元结点移动到结点i的次数,即当j=i-1时即说明移动到结点i,初始值未零(首元结点移动到第一个结点需要移动零次) int j = 0; //循环移动指针p并使计数器j自增直至p=L或者j=i-1 while (p != L && j < i - 1) { p = p->next; ++j; } //判断循环终止条件,若p=L则说明遍历了所有循环链表的结点仍未到达结点i,即i > n,i非法,置*e的值为0(无任何意义),返回ERROR //若j>i-1则说明未移动i-1次循环即结束,即i<1,i非法,置*e的值为0(无任何意义),返回ERROR if (p == L || j > i - 1) { *e = 0; return ERROR; } //i合法,将指向当前结点的指针p(此时恰好指向结点i)的数据域赋值给*e *e = p->data; //置指针p=NULL,返回OK p = NULL; return OK; } /** * 定位元素 * 定位循环链表中第一个数据域与给定ElemType匹配的结点的位置i和指向该结点的指针 * 算法描述: * 1、判断指针L是否合法,不合法,置*i为零,置*curP为NULL(表示循环链表为初始化),返回ERROR * 2、定义指向当前结点的指针p使其指向首元结点 * 3、定义计数器j记录当前结点序号,初始值为1(首元结点为第一个结点) * 4、循环移动指针p使计数器j自增直至p=L或者指针p的数据域与e匹配 * 5、判断循环终止原因,若p=L,则说明遍历了循环链表所有结点仍未能找到数据域与e匹配的结点,置*i未负一,置*curP为NULL,表示未找到 * 6、否则,把计数器j的值赋值给*i,把指针p的值赋值给*curP,表示结点i是循环链表的第一个数据域与e匹配的结点,*curP指向该结点 * 7、置指针p为NULL,返回OK * @param L 指向循环链表的头结点的头指针L * @param i 指向用以保存结点位置信息的变量的指针 * @param e 给定的ElemType的置 * @param curP 指向匹配结点的指针的指针 * @return 操作结果状态码 */ Status locateAndIndexOfCircularLinkedListElem(CircularLinkedList L, int *i, LNode **curP, ElemType e) { //判断指针L是否合法,不合法,置*i为零,置*curP为NULL(表示循环链表为初始化),返回ERROR if (!L) { *i = 0; *curP = NULL; return ERROR; } //定义指向当前结点的指针p使其指向首元结点 LNode *p = L->next; //定义计数器j记录当前结点序号,初始值为1(首元结点为第一个结点) int j = 1; //循环移动指针p使计数器j自增直至p=L或者指针p的数据域与e匹配 while (p != L && !match(p->data, e)) { p = p->next; ++j; } //判断循环终止原因,若p=L,则说明遍历了循环链表所有结点仍未能找到数据域与e匹配的结点,置*i未负一,,置*curP为NULL表示未找到 if (p == L) { *curP = NULL; *i = -1; } //否则,把计数器j的值赋值给*i,把指针p的值赋值给*curP,表示结点i是循环链表的第一个数据域与e匹配的结点,*curP指向该结点 *curP = p; *i = j; //置指针p为NULL,返回OK p = NULL; return OK; } /** * 获取前趋 * 获取循环链表上某结点的前趋结点 * 算法描述: * 1、判断指针L是否合法,若非法,置*priorP为NULL,返回ERROR * 2、定义指向当前结点的指针p使其指向循环链表的头结点 * 3、定义标识变量isVisitHead,置其值为零(假值),假值表示指针p第一次访问头结点 * 4、循环移动指针p直至p->next=curE或者(p=L且isVisitHead为真)(直至p第二次指向头结点,说明变量完所有结点仍未找到curP指向的结点的前趋,即curP没有指向循环链表上的任何结点) * 5、判断循环终止原因,若p=L且isVisitHead为真则说明curP不指向循环链表上的任何结点,置*priorP为NULL,返回ERROR * 6、否则,将指针p的值赋值给*priorP * 7、置指针p为NULL,返回OK * @param L 指向循环链表头结点的头指针 * @param curP 指向当前结点的指针 * @param priorP 指向保存指针当前结点的前趋结点的增长的增长 * @return 操作结果状态码 */ Status getProirCircularLinkedList(CircularLinkedList L, LNode *curP, LNode **priorP) { //判断指针L是否合法,若非法,置*priorP为NULL,返回ERROR if (!L) { *priorP = NULL; return ERROR; } //定义指向当前结点的指针p使其指向循环链表的头结点 LNode *p = L; //定义标识变量isVisitHead,置其值为零(假值),假值表示指针p第一次访问头结点 int isVisitHead = 0; //循环移动指针p直至p->next=curP或者(p=L且isVisitHead为真)(直至p第二次指向头结点,说明变量完所有结点仍未找到curP指向的结点的前趋,即curP没有指向循环链表上的任何结点) while (p->next != curP && !(p == L && isVisitHead)) { //修改标识变量 isVisitHead = 1; p = p->next; } //判断循环终止原因,若p=L且isVisitHead为真则说明curP不指向循环链表上的任何结点,置*priorP为NULL,返回ERROR if (p == L && isVisitHead) { *priorP = NULL; return ERROR; } //否则,将指针p的值赋值给*priorP *priorP = p; //置指针p为NULL,返回OK p = NULL; return OK; } /** * 获取后继 * 获取循环链表当前结点的直接后继结点 * 算法描述: * 1、判断指针L是否合法,若非法,置*nextP为NULL,返回NULL * 2、定义指向当前结点的指针p使其指向循环链表的首元结点 * 3、若curP=L,说明当前结点是头结点,将其指针域赋值给*nextP,返回OK * 4、否则循环移动指针p直至p=curP或者p=L * 5、判断循环终止原因,若p=L则,说明遍历了循环链表上的所有结点,仍未找到与curP指向的结点,说明curP非法,置*nextP为NULL,返回ERROR * 6、否则说明curP指向的结点的确是循环链表上的结点,直接将curP指向的结点的指针域的值赋值给*nextP即可 * 7、置指针p=NULL,返回OK * @param L 指向循环列表的头结点的头指针 * @param curP 指向当前结点的指针 * @param nextP 指向指向当前结点后继结点的指针的指针 * @return 操作结果状态码 */ Status getNextCircularLinkedList(CircularLinkedList L, LNode *curP, LNode **nextP) { //判断指针L是否合法,若非法,置*nextP为NULL,返回NULL if (!L) { *nextP = NULL; return ERROR; } //定义指向当前结点的指针p使其指向循环链表的首元结点 LNode *p = L->next; //若curP=L,说明当前结点是头结点,将其指针域赋值给*nextP,返回OK if (curP == L) { *nextP = curP->next; return OK; } //否则循环移动指针p直至p=curP或者p=L while (p != curP && p != L) { p = p->next; } //判断循环终止原因,若p=L则,说明遍历了循环链表上的所有结点,仍未找到与curP指向的结点,说明curP非法,置*nextP为NULL,返回ERROR if (p == L) { *nextP = NULL; return ERROR; } //否则说明curP指向的结点的确是循环链表上的结点,直接将curP指向的结点的指针域的值赋值给*nextP即可 *nextP = curP->next; //置指针p=NULL,返回OK p = NULL; return OK; } /** * 插入 * 在循环链表位置i上插入数据域为e的新结点,即在结点i-1和结点i间插入一个新结点(结点i-1和结点i可能不存在),i的取值范围[1,n+1],i是整数 * 算法描述: * 1、判断指针L及指向的指针是否合法,不合法,返回ERROR * 2、定义指向当前结点的指针p使其指向头结点 * 3、定义计数器j记录指针p由首元结点移动到结点i-1所需的移动次数,置j初始值为0,当移动至结点i-1时,计数器j应该等于i-1 * 4、定义计数器count记录指针p指向头结点的次数 * 5、循环移动指针p直至指针p第二次指向头结点(说明移动了n次仍未到达结点i-1,故重新指向头结点)或者j=i-1(移动到了结点i-1) * 6、判断循环终止条件,若count=2,则说明i-1>n,移项得i>n+1,i值非法,返回ERROR * 7、若j>i-1说明还未移动i-1次,循环就结束了,即i<0,i不合法,返回ERROR * 8、否则循环终止原因是指针p指向了结点i-1可以进行插入操作了 * 9、申请新结点,定义指向结点的指针s指向新结点,置新结点的数据域为e,置新结点的指针域指向原来循环链表上的结点i(指针p指向结点的直接后继) * 10、使指针p的指向的结点(结点i-1)的指针域指向新结点 * 11、置指针p、s为NULL,返回OK * @param L 指向指向循环列表的头结点的头指针的指针 * @param i 欲插入的位置i * @param e 插入结点的数据域e * @return 操作结果状态码 */ Status insertNodeCircularLinkedList(CircularLinkedList *L, int i, int e) { //判断指针L及指向的指针是否合法,不合法,返回ERROR if (!L || !(*L))return ERROR; //定义指向当前结点的指针p使其指向头结点 LNode *p = (*L); //定义计数器j记录指针p由首元结点移动到结点i-1所需的移动次数,置j初始值为0,当移动至结点i-1时,计数器j应该等于i-1 int j = 0; //定义计数器count记录指针p指向头结点的次数 int count = 1; //循环移动指针p直至指针p第二次指向头结点(说明移动了n+1次仍未到达或恰好到达结点i-1,故重新指向头结点)或者j=i-1(移动到了结点i-1) while (count < 2 && j < i - 1) { p = p->next; ++j; //指针p第二次指向头结点,修改计数器count的值 if (p == *L)count++; } //判断循环终止条件,若count=2,则说明i-1>=n+1,移项得i>=n+2,i值非法,返回ERROR //若j>i-1说明还未移动i-1次,循环就结束了,即i<0,i不合法,返回ERROR if (count == 2 || j > i - 1) { return ERROR; } //否则循环终止原因是指针p指向了结点i-1可以进行插入操作了 //申请新结点,定义指向结点的指针s指向新结点,置新结点的数据域为e,置新结点的指针域指向原来循环链表上的结点i(指针p指向结点的直接后继) LNode *s = (LNode *) malloc(sizeof(LNode)); s->data = e; s->next = p->next; //使指针p的指向的结点(结点i-1)的指针域指向新结点 p->next = s; //置指针p、s为NULL,返回OK p = NULL; s = NULL; return OK; } /** * 删除 * 删除循环链表位置i上的结点,即删除结点i-1和结点i+1之间的结点(结点i-1和结点i+1有可能不存在,必须检验i值的合法性,i(-[1,n],i是整数) * 算法描述: * 1、检验指针L和*L是否合法,若非法,返回ERROR * 2、定义指向当前结点的增长p使其指向头结点 * 3、定义计数器j记录指针p由头结点移动至结点i-1需移动的次数,置计数器初始值为零,当j=i -1即移动到了结点i-1 * 4、循环移动指针p直至p->next=*L或者j=i-1 * 5、判断循环终止条件,若p->next=*L说明指针p指向尾结点,而指针由头结点移动至尾结点(移动n次)仍未到达结点或者恰好到达结点i-1,即i-1>=n,移项可得i>=n+1,i非法,返回ERROR * 6、若j>i-1则说明还未移动满i-1次,循环就结束了,说明计数器j值仍然是零没有变化,即i-1<0,i<1,i非法,返回ERROR * 7、否则,说明循环结束原因是指针p指向了结点i-1,可以进行删除操作了 * 8、定义临时指针变量t使其指向指针p指向结点的直接后继结点(结点i) * 9、使指针p指向的结点(结点i-1)的指针域指向指针t指向结点(结点i)的直接后继结点(结点i+1) * 10、释放指针t指向结点(结点i)所占用的内存空间 * 11、置指针p,t未NULL,返回OK * @param L 指向指向循环链表头结点的头指针的指针 * @param i 欲删除的结点的位置 * @return 操作结果状态码 */ Status deleteNodeCircularLinkedList(CircularLinkedList *L, int i) { //检验指针L和*L是否合法,若非法,返回ERROR if (!L || !(*L)) { return ERROR; } //定义指向当前结点的增长p使其指向头结点 LNode *p = (*L); //定义计数器j记录指针p由头结点移动至结点i-1需移动的次数,置计数器初始值为零,当j=i -1即移动到了结点i-1 int j = 0; //循环移动指针p直至p->next=*L或者j=i-1 while (p->next != (*L) && j < i - 1) { p = p->next; ++j; } //判断循环终止条件,若p->next=*L说明指针p指向尾结点,而指针由头结点移动至尾结点(移动n次)仍未到达结点或者恰好到达结点i-1,即i-1>=n,移项可得i>=n+1,i非法,返回ERROR //若j>i-1则说明还未移动满i-1次,循环就结束了,说明计数器j值仍然是零没有变化,即i-1<0,i<1,i非法,返回ERROR if (p->next == (*L) || j > i - 1) { return ERROR; } //否则,说明循环结束原因是指针p指向了结点i-1,可以进行删除操作了 //定义临时指针变量t使其指向指针p指向结点的直接后继结点(结点i) LNode *t = p->next; //使指针p指向的结点(结点i-1)的指针域指向指针t指向结点(结点i)的直接后继结点(结点i+1) p->next = t->next; //释放指针t指向结点(结点i)所占用的内存空间 free(t); //置指针p,t未NULL,返回OK p = NULL; t = NULL; return OK; } /** * 构造循环链表 * 使用前插法构造具有n个结点(不计算头结点)的循环链表 * 算法描述: * 1、判断指针L是否合法,若不合法,返回ERROR * 2、申请一个头结点,使指针*L指向头结点,若申请失败,返回OVERFLOW * 3、使头结点的指针域指向头结点,数据域为零(无意义) * 4、定义指向新结点的指针s * 5、循环申请新结点,使指针s指向新结点,使若申请失败,返回OVERFLOW,读入相应的数据,将其指针域指向当前头结点指针域指向的结点,使头结点指向新结点 * 6、置指针s为NULL,返回OK * @param L 指向指向循环链表头结点的头指针的指针 * @param n 循环链表的结点个数(不计算头结点) * @return 操作结果状态码 */ Status createCircularLinkedListByInsertNewNodeAfterHeadNode(CircularLinkedList *L, int n) { //判断指针L是否合法,若不合法,返回ERROR if (!L)return ERROR; //申请一个头结点,使指针*L指向头结点 *L = (LNode *) malloc(sizeof(LNode)); //若申请失败,返回OVERFLOW if (!(*L))return OVERFLOW; //使头结点的指针域指向头结点,数据域为零(无意义) (*L)->next = *L; (*L)->data = 0; //定义指向新结点的指针s LNode *s = NULL; //循环 ElemType e; int i; for (i = 0; i < n; ++i) { //申请新结点,使指针s指向新结点 s = (LNode *) malloc(sizeof(LNode)); //使若申请失败,返回OVERFLOW if (!s)return OVERFLOW; //读入相应的数据 printf("请输入结点%d的数据:\n", i + 1); scanf("%lf", &e); s->data = e; //将其指针域指向当前头结点指针域指向的结点,使头结点指向新结点 s->next = (*L)->next; (*L)->next = s; } //置指针s为NULL,返回OK s = NULL; return OK; } /** * 构造循环链表 * 使用后插法构造具有n个结点(不计算头结点)的循环链表 * 算法描述: * 1、判断指针L是否合法,若不合法,返回ERROR * 2、申请一个头结点,使指针*L指向头结点,若申请失败,返回OVERFLOW * 3、使头结点的指针域指向头结点,数据域为零(无意义) * 4、定义尾指针r使其指向头结点 * 5、定义指向新结点的指针s * 6、循环申请新结点,使指针s指向新结点,使若申请失败,返回OVERFLOW,读入相应的数据,使新结点指针域指向头结点,使尾指针指向结点的指针域指向新结点 * 7、置指针s,r为NULL,返回OK * @param L 指向指向循环链表头结点的头指针的指针 * @param n 循环链表的结点个数(不计算头结点) * @return 操作结果状态码 */ Status createCircularLinkedListByInsertNewNodeAfterRearNode(CircularLinkedList *L, int n) { //判断指针L是否合法,若不合法,返回ERROR if (!L) { return ERROR; } //申请一个头结点,使指针*L指向头结点 *L = (LNode *) malloc(sizeof(LNode)); //若申请失败,返回OVERFLOW if (!(*L))return OVERFLOW; //使头结点的指针域指向头结点,数据域为零(无意义) (*L)->next = *L; (*L)->data = 0; //定义尾指针r使其指向头结点 LNode *r = *L; //定义指向新结点的指针s LNode *s = NULL; ElemType e; int i; for (i = 0; i < n; ++i) { //循环申请新结点,使指针s指向新结点 s = (LNode *) malloc(sizeof(LNode)); //使若申请失败,返回OVERFLOW if (!s)return OVERFLOW; //读入相应的数据 printf("请输入结点%d的数据:\n", i + 1); scanf("%lf", &e); s->data = e; //使新结点指针域指向头结点 s->next = *L; // 尾指针指向结点的指针域指向新结点 r->next = s; } //置指针s,r为NULL,返回OK s = NULL; r = NULL; return OK; } /** * 遍历 * 遍历循环链表 * 算法描述: * 1、判断指针L是否合法,若非法,返回ERROR * 2、定义指向当前结点的指针p指向首元结点 * 3、循环访问指针p指向结点的数据域并移动指针p直至p=L(遍历完成) * 4、置指针p尾NULL,返回OK * @param L 指向循环链表头结点的头指针 * @return 操作结果状态码 */ Status traverseCircularLinkedList(CircularLinkedList L) { //判断指针L是否合法,若非法,返回ERROR if (!L)return ERROR; //定义指向当前结点的指针p指向首元结点 LNode *p = L->next; //循环访问指针p指向结点的数据域并移动指针p直至p=L(遍历完成) while (p != L) { printElem(p->data); p = p->next; } //置指针p尾NULL,返回OK p = NULL; return OK; }
测试定义好的循环链表和其基本操作
int main() { CircularLinkedList L = NULL; //测试初始化循环链表 initCircularLinkedList(&L); if (!L) { printf("初始化失败!\n"); } else { printf("初始化成功!\n"); //测试空表判断 int ret = 0; if (circularLinkedListIsEmpty(L, &ret)) { if (ret) { printf("循环链表是空表\n"); } else { printf("循环链表不是空表\n"); } } //测试获取长度 int len; if (getCircularLinkedListLength(L, &len)) { printf("现在循环链表长度为 %d\n", len); } else { printf("现在循环链表长度为 %d\n", len); } //测试插入 if (insertNodeCircularLinkedList(&L, 1, 2) && insertNodeCircularLinkedList(&L, 1, 3)) { printf("插入成功\n"); printf("现在在循环链表的位置1上插入一个数据域为2的新结点"); printf("现在在循环链表的位置1上插入一个数据域为3的新结点"); //测试取值 ElemType e; if (getCircularLinkedListElem(L, 1, &e)) { printf("循环链表上结点序号为1的结点的数据域为 %lf\n", e); } else { printf("取值失败\n"); } //测试获取长度 if (getCircularLinkedListLength(L, &len)) { printf("现在循环链表长度为 %d\n", len); } else { printf("现在循环链表长度为 %d\n", len); } //测试空表判断 if (circularLinkedListIsEmpty(L, &ret)) { if (ret) { printf("循环链表是空表\n"); } else { printf("循环链表不是空表\n"); } } //测试定位 e = 2; int curI = 0; LNode *curP = NULL; if (locateAndIndexOfCircularLinkedListElem(L, &curI, &curP, e)) { printf("定位成功\n"); printf("循环链表上第一个数据域为%lf的结点的序号为%d,其地址是%d\n", e, curI, curP); } else { printf("定位失败\n"); printf("循环链表上第一个数据域为e的结点的序号为%d,其地址是%d\n", curI, curP); } curP = NULL; } else { printf("插入失败\n"); } } //测试清空循环链表 if (clearCircularLinkedList(&L)) { printf("清空成功\n"); } else { printf("清空失败\n"); } //测试空表判断 int ret = 0; if (circularLinkedListIsEmpty(L, &ret)) { if (ret) { printf("循环链表是空表\n"); } else { printf("循环链表不是空表\n"); } } //测试获取长度 int len; if (getCircularLinkedListLength(L, &len)) { printf("现在循环链表长度为 %d\n", len); } else { printf("现在循环链表长度为 %d\n", len); } //测试销毁循环链表 if (destroyCircularLinkedList(&L)) { printf("销毁成功\n"); L = NULL; } else { printf("销毁失败\n"); } //测试空表判断 if (circularLinkedListIsEmpty(L, &ret)) { if (ret) { printf("循环链表是空表\n"); } else { printf("循环链表不是空表\n"); } } //测试获取长度 if (getCircularLinkedListLength(L, &len)) { printf("现在循环链表长度为 %d\n", len); } else { printf("现在循环链表长度为 %d\n", len); } L = NULL; //测试前插法 int size; printf("请输入要构造的循环链表的长度:\n"); scanf("%d", &size); if (createCircularLinkedListByInsertNewNodeAfterHeadNode(&L, size)) { printf("前插法功能正常!\n"); //测试遍历 traverseCircularLinkedList(L); } else { printf("前插法功能不正常!\n"); } //测试删除 int curI = 3; printf("请输入删除的结点序号:\n"); scanf("%d", &curI); if (deleteNodeCircularLinkedList(&L, curI)) { printf("现在删除循环链表上序号为%d的结点\n", curI); printf("删除成功!\n"); //测试遍历 traverseCircularLinkedList(L); LNode *curP = NULL; ElemType e; printf("请输入要定位的结点的数据域:\n"); scanf("%lf", &e); if (locateAndIndexOfCircularLinkedListElem(L, &curI, &curP, e)) { //测试获取前趋 /*LNode *antherP = (LNode *) malloc(sizeof(LNode)); antherP->next = NULL; antherP->data = 0;*/ LNode *priorP = NULL; if (getProirCircularLinkedList(L, curP, &priorP)) { printf("获取前趋成功!\n"); printf("数据域为%lf的结点的前趋结点的地址是%d,数据域为%lf\n", e, priorP, priorP->data); } else { printf("获取前趋失败!\n"); } //测试获取后继 LNode *nextP = NULL; if (getNextCircularLinkedList(L, curP, &nextP)) { printf("获取后继成功!\n"); printf("数据域为%lf的结点的后继结点的地址是%d,数据域为%lf\n", e, nextP, nextP->data); } else { printf("获取后继失败!\n"); } priorP = NULL; nextP = NULL; } else { printf("定位失败!\n"); } curP = NULL; /*antherP = NULL;*/ } else { printf("删除失败!\n"); //测试遍历 traverseCircularLinkedList(L); } return 0; }
原文:https://www.cnblogs.com/RGBTH/p/13376996.html