循环双向链表-C语言实现

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

/*
2018.8.15
注意三点:
            1.不要将循环写成if    //很尴尬,主要是我犯了这个错误,找了半天还没找出来,第二天看的时候才发现,非常的尴尬
            2.循环链表的判空操作是  p->rear != *L
            3.p = *L,循环体中用p->rear做条件  这种写法便于对当前结点的前一结点操作,插入、删除、修改操作使用这种形式
              p = *L->rear,循环体中用p做条件  这种写法便于对当前结点操作,查找、遍历使用这种形式
       4.双向链表在插入与删除时,要处理好前驱指针和后继指针,切不可遗忘。尤其是插入时,要将新点之后的结点的前驱指向新结点,这里容易被忽略
*/ #include <stdio.h> #include<malloc.h> #include<stdlib.h> #include<time.h> 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("表空 "); while(r != L) //判非空 { printf("第%d个结点的数据是%d ",j,r->date); r = r->rear; j++; } printf(" "); } /* 循环双链表的倒序遍历 */ void PrintList2(LoopList L) { int j = 1; LoopList r = L->pront; //指向L倒数第一个结点 if(r == L) //判空 printf("表空 "); while(r != L) //判非空 { printf("倒数第%d个结点的数据是%d ",j,r->date); r = r->pront; j++; } printf(" "); } /* 循环双链表的创建 */ 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("请选择对线性链表的操作: "); printf("1.创建 "); printf("2.插入 "); printf("3.删除 "); printf("4.查找 "); printf("5.修改 "); printf("6.正序输出 "); printf("7.倒序输出 "); printf("8.退出 "); int a; scanf("%d", &a); switch(a) { case 1: printf("请输入需要创建元素的个数:"); scanf("%d", &i); if(CreatList(&L, i)) printf("创建成功 "); else printf("创建失败 "); break; case 2: printf("请输入需要插入的位置:"); scanf("%d", &i); printf("请输入需要插入的元素:"); scanf("%d", &e); if(LoopInsert(&L, i, e)) printf("插入成功 "); else printf("插入失败 "); break; case 3: printf("请输入需要删除的位置:"); scanf("%d", &i); if(DelList(&L, i, &e)) printf("删除成功 "); else printf("删除失败 "); break; case 4: printf("请输入需要查找的位置:"); scanf("%d", &i); GetElem(L, i, &e); printf("第%d个元素为%d ",i,e); break; case 5: printf("请输入需要修改的位置:"); scanf("%d", &i); printf("请输入新的的元素:"); scanf("%d", &e); if(UpdateList(&L, i, e)) printf("修改成功 "); else printf("修改失败 "); break; case 6: if(L == NULL) { printf("表还未创建 "); break; } PrintList1(L); break; case 7: if(L == NULL) { printf("表还未创建 "); break; } PrintList2(L); break; case 8: return; default: printf("选择错误 "); break; } } }
原文地址:https://www.cnblogs.com/yurui/p/9503164.html