/* Copyright (C++) 2019 * Ltd. All rights reserved. * Create date : 2019-08-27 11:41:04 *================================================*/ /* 2018.8.15 注意三点: 1.不要将循环写成if //很尴尬,主要是我犯了这个错误,找了半天还没找出来,次日看的时候才发现,很是的尴尬 2.循环链表的判空操做是 p->next != *L 3.p = *L,循环体中用p->next作条件 这种写法便于对当前结点的前一结点操做,插入、删除、修改操做使用这种形式 p = *L->next,循环体中用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 *prior; //指向前一结点的指针 ElemType date; //结点元素 struct Node *next; //指向后一结点的指针 }Node, *LoopDList; /* 循环双链表的建立 */ Status CreatList(LoopDList &L, int *arr, int n) { int i; //计数器 L = (LoopDList)malloc(sizeof(Node)); //建立头结点 L->next = L; L->prior = L; LoopDList s,p; //s用于开辟新结点,p指向表尾 p = L; //指向表尾结点 for(i = 0; i < n; i++) { s = (LoopDList)malloc(sizeof(Node)); //开辟新结点 s->date = arr[i]; //为新结点赋值 p->next = s; //让表尾结点的后继结点指向新结点 s->prior = p; //让新结点的前驱结点指向p p = s; //表尾结点指针后移 } p->next = L; //使表尾结点的后继指针指向头结点 L->prior = p; //头指针的前驱结点指向表尾结点 return OK; } /* 循环双向链表的插入操做 */ Status LoopInsert(LoopDList &L, int i, ElemType e) { int j = 1; //计数器,记录当前位置 LoopDList p = L; //指向L //此种写法便于对当前结点的上一结点进行操做 LoopDList s; //用于建立新结点 // while(p->next && j < i) //判非空 判位置索引合理 //循环链表的判断非空不是这样的 2018.8.15 while(p->next != L && j < i) { p = p->next; //指针后移 j++; //计数器加1 } if(p->next == L || j > i) //判空 判位置索引不合理 return ERROR; s = (LoopDList)malloc(sizeof(Node)); //开辟新结点s s->date = e; //为s的数据域赋值 s->prior = p->prior; s->next = p; p->prior->next = s; p->prior = s; #if 0 p->next->prior= s; //使插入结点后的下一结点的前驱指向s s->next = p->next; //使s的后继结点等于p的后继结点 s->prior= p; //使s的前驱结点等于p p->next = s; //使p得后继结点等于s #endif return OK; } /* 循环双向链表的删除操做 */ Status DelList(LoopDList &L, int i, ElemType *e) { int j = 1; //记录当前位置 LoopDList p = L; //指向链表 LoopDList s; //用于释放要删除的结点 while(p->next != L && j < i) //判非空 判索引位置有效 { p = p->next; //指针后移 j++; //计数器加1 } if(p->next == L || j > i) //判空 判索引位置无效 return ERROR; s = p->next; //使s指向p *e = s->date; //将要删除的结点数据赋值给e p->next = s->next; //使p的后继结点等于r的后继结点 s->next->prior = p; //使s的后继的前驱结点等于p free(s); //释放s结点 return OK; } /* 循环双链表的修改操做 */ Status UpdateList(LoopDList *L, int i, ElemType e) { int j = 1; //记录当前位置 LoopDList r = (*L)->next; //指向第一个结点 //此种写法便于岁当前结点操做 while(r != *L && j < i) //判非空 判位置索引有效 { r = r->next; //指针后移 j++; //计数器加1 } if(r == *L || j > i) //判空 判位置索引无效 return ERROR; r->date = e; //使r的数据域等于 e return OK; } /* 循环双链表的查找 */ Status GetElem(LoopDList L, int i, ElemType *e) { int j = 0; //计数器 LoopDList p = L->next; //指向第一个结点 while(p != L && j < i) //判非空 判位置索引有效 { p = p->next; //指针后移 j++; //计数器加1 } if(p == L || j > i) //判空 判位置索引无效 return ERROR; *e = p->date; //将p的数据域内容赋值给e return OK; } /* 循环双链表的正序遍历 */ void PrintList1(LoopDList L) { LoopDList p = L->next; //指向L第一个结点 if(p == L) //判空 printf("表空\n"); while(p != L) //判非空 { if(p->next != L) printf("[%d] -> ", p->date); else printf("[%d]",p->date); p = p->next; } printf("\n"); } /* 循环双链表的倒序遍历 */ void PrintList2(LoopDList L) { LoopDList p = L->prior; //指向L倒数第一个结点 if(p == L) //判空 printf("表空\n"); while(p != L) //判非空 { if(p->prior != L) printf("[%d] -> ", p->date); else printf("[%d]",p->date); p = p->prior; } printf("\n"); } int main() { LoopDList L = NULL; //建立链表L int i, e; //i为元素位置,e为元素内容 int n = 0; int arr[10] = {0,1,2,3,4,5,6,7,8,9}; n = sizeof(arr)/sizeof(arr[0]); 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: if(CreatList(L, arr, n)) 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 -1; default: printf("选择错误\n"); break; } } return 0; }
图解链表函数
循环单链表oop