循环双向链表-C语言实现
发布日期:2021-10-23 14:13:17 浏览次数:4 分类:技术文章

本文共 7212 字,大约阅读时间需要 24 分钟。

直接贴出完整代码,每个函数的功能及部分代码的解释都在注释中,代码亲测可行

 

/*2018.8.15注意三点:            1.不要将循环写成if    //很尴尬,主要是我犯了这个错误,找了半天还没找出来,第二天看的时候才发现,非常的尴尬            2.循环链表的判空操作是  p->rear != *L            3.p = *L,循环体中用p->rear做条件  这种写法便于对当前结点的前一结点操作,插入、删除、修改操作使用这种形式              p = *L->rear,循环体中用p做条件  这种写法便于对当前结点操作,查找、遍历使用这种形式        4.双向链表在插入与删除时,要处理好前驱指针和后继指针,切不可遗忘。尤其是插入时,要将新点之后的结点的前驱指向新结点,这里容易被忽略*/#include 
#include
#include
#include
typedef int ElemType; //元素类型typedef int Status; //返回类型#define OK 1; //函数运行成功返回值#define ERROR 0; //函数运行失败返回值typedef struct Node{ struct Node *pront; //指向前一结点的指针 ElemType date; //结点元素 struct Node *rear; //指向后一结点的指针}Node;typedef struct Node *LoopList; //创建链表/*循环双向链表的插入操作*/Status LoopInsert(LoopList *L, int i, ElemType e){ int j = 1; //计数器,记录当前位置 LoopList r = *L; //指向L //此种写法便于对当前结点的上一结点进行操作 LoopList s; //用于创建新结点// while(r->rear && j < i) //判非空 判位置索引合理 //循环链表的判断非空不是这样的 2018.8.15 while(r->rear != *L && j < i) { r = r->rear; //指针后移 j++; //计数器加1 } if(r->rear == *L || j > i) //判空 判位置索引不合理 return ERROR; s = (LoopList)malloc(sizeof(Node)); //开辟新结点s s->date = e; //为s的数据域赋值 r->rear->pront = s; //使插入结点后的下一结点的前驱指向s s->rear = r->rear; //使s的后继结点等于r的后继结点 s->pront = r; //使s的前驱结点等于r r->rear = s; //使r得后继结点等于s return OK;}/*循环双向链表的删除操作*/Status DelList(LoopList *L, int i, ElemType *e){ int j = 1; //记录当前位置 LoopList r = *L; //指向链表 LoopList s; //用于释放要删除的结点 while(r->rear != *L && j < i) //判非空 判索引位置有效 { r = r->rear; //指针后移 j++; //计数器加1 } if(r->rear == *L || j > i) //判空 判索引位置无效 return ERROR; s = r->rear; //使s指向r *e = s->date; //将要删除的结点数据赋值给e r->rear = s->rear; //使r的后继结点等于r的后继结点 s->rear->pront = r; //使s的后继的前驱结点等于r free(s); //释放s结点 return OK;}/*循环双链表的修改操作*/Status UpdateList(LoopList *L, int i, ElemType e){ int j = 1; //记录当前位置 LoopList r = (*L)->rear; //指向第一个结点 //此种写法便于岁当前结点操作 while(r != *L && j < i) //判非空 判位置索引有效 { r = r->rear; //指针后移 j++; //计数器加1 } if(r == *L || j > i) //判空 判位置索引无效 return ERROR; r->date = e; //使r的数据域等于 e return OK;}/*循环双链表的查找*/Status GetElem(LoopList L, int i, ElemType *e){ int j = 1; //计数器 LoopList r = L->rear; //指向第一个结点 while(r != L && j < i) //判非空 判位置索引有效 { r = r->rear; //指针后移 j++; //计数器加1 } if(r == L || j > i) //判空 判位置索引无效 return ERROR; *e = r->date; //将r的数据域内容赋值给e return OK;}/*循环双链表的正序遍历*/void PrintList1(LoopList L){ int j = 1; LoopList r = L->rear; //指向L第一个结点 if(r == L) //判空 printf("表空\n"); while(r != L) //判非空 { printf("第%d个结点的数据是%d\n",j,r->date); r = r->rear; j++; } printf("\n");}/*循环双链表的倒序遍历*/void PrintList2(LoopList L){ int j = 1; LoopList r = L->pront; //指向L倒数第一个结点 if(r == L) //判空 printf("表空\n"); while(r != L) //判非空 { printf("倒数第%d个结点的数据是%d\n",j,r->date); r = r->pront; j++; } printf("\n");}/*循环双链表的创建*/Status CreatList(LoopList *L, int n){ int i; //计数器 (*L) = (LoopList)malloc(sizeof(Node)); //创建头结点 LoopList s,q; //s用于开辟新结点,q指向表尾 srand(time(0)); //初始化随机数种子 q = *L; //指向表尾结点 for(i = 0; i < n; i++) { s = (LoopList)malloc(sizeof(Node)); //开辟新结点 s->date = rand() % 100 + 1; //为新结点赋值 q->rear = s; //让表尾结点的后继结点指向新结点 s->pront = q; //让新结点的前驱结点指向q q = s; //表尾结点指针后移 } q->rear = *L; //使表尾结点的后继指针指向头结点 (*L)->pront = q; //头指针的前驱结点指向表尾结点 return OK;}void main(){ LoopList L = NULL; //创建链表L int i, e; //i为元素位置,e为元素内容 while(true) { printf("请选择对线性链表的操作:\n"); printf("1.创建\n"); printf("2.插入\n"); printf("3.删除\n"); printf("4.查找\n"); printf("5.修改\n"); printf("6.正序输出\n"); printf("7.倒序输出\n"); printf("8.退出\n"); int a; scanf("%d", &a); switch(a) { case 1: printf("请输入需要创建元素的个数:"); scanf("%d", &i); if(CreatList(&L, i)) printf("创建成功\n"); else printf("创建失败\n"); break; case 2: printf("请输入需要插入的位置:"); scanf("%d", &i); printf("请输入需要插入的元素:"); scanf("%d", &e); if(LoopInsert(&L, i, e)) printf("插入成功\n"); else printf("插入失败\n"); break; case 3: printf("请输入需要删除的位置:"); scanf("%d", &i); if(DelList(&L, i, &e)) printf("删除成功\n"); else printf("删除失败\n"); break; case 4: printf("请输入需要查找的位置:"); scanf("%d", &i); GetElem(L, i, &e); printf("第%d个元素为%d\n",i,e); break; case 5: printf("请输入需要修改的位置:"); scanf("%d", &i); printf("请输入新的的元素:"); scanf("%d", &e); if(UpdateList(&L, i, e)) printf("修改成功\n"); else printf("修改失败\n"); break; case 6: if(L == NULL) { printf("表还未创建\n"); break; } PrintList1(L); break; case 7: if(L == NULL) { printf("表还未创建\n"); break; } PrintList2(L); break; case 8: return; default: printf("选择错误\n"); break; } }}

 

转载于:https://www.cnblogs.com/yurui/p/9503164.html

转载地址:https://blog.csdn.net/weixin_30588827/article/details/98950071 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:《梦断代码》读后感01——Chandle的开始
下一篇:Spring框架参考手册(4.2.6版本)翻译——第三部分 核心技术 6.9.1 @Required

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年04月21日 10时42分12秒