(一)合并两个循环链表
p = rearA->next; //A的头结点,一会还要使用 rearA->next = rearB->next->next; //是A的尾结点指向B的第一个结点 q = rearB->next; //存放B的头结点,需要释放 rearB->next = p; //使B的尾结点指向A的头结点 free(q); //释放B的头结点
(二)判断单链表中是否有环
方法一:使用两个指针,循环嵌套,A指针在外层循环,一步一步向下走,B指针在内层循环,循环到A的位置,当两者的位置相同时判断走的步数是否一致,不一致则代表有环。且能够得到准确的环路节点。其中A是要将链表从头走到尾,B是一直在内层进行循环,时间复杂度为O(n^2)
//两层循环进行判断 Status HasCircle01(List L,int *seq) { List la, lb; int stepa, stepb; la = lb = L; //la在外层循环,lb在内层循环 stepa = stepb = 1; while (la) { while (lb!=la) { lb = lb->next; stepb++; } if (stepa != stepb) break; stepa++; la = la->next; lb = L; stepb = 1; } if (la!=NULL) { *seq = stepb; return TRUE; } return FALSE; }
方法二:使用快慢指针若是有环那么快指针会一直在环中循环,当慢指针进入环中节点后,一定会出现快指针在慢指针后面(或者相等)的情况,就可以判断是否有环,不过这种方法不容易获取到环路节点位置,时间复杂度按照慢指针来算,为O(n)
//快慢指针进行判断 Status HasCircle02(List L) { List high, low; high = low = L; while (low&&high&&high->next) { if (high->next) high = high->next->next; low = low++; if (high == low) return OK; } return FALSE; }
方法三:判断地址的大小
1.栈的地址是由高向低增长的. 2.堆得地址增长方向是由低到高向上增长的
我们创建链表时,一般是使用堆区进行,所以一般机器都是地址向上增长,若是有环,则地址会减小,我们可以使用一个指针,或者一个快指针,将每次的结点地址比较,这样时间复杂度为O(n/2),若是环足够大,我们设置的指针增长步长够大,也会优化更多。
不过有限制,就是我们创建的链表需要地址增长是单向的,就是只能使用尾插法或者头插法,不能使用中间插入或者联合使用
//地址字节进行判断,为了这种方法实现,上面无论是创建直链表还是循环链表都是使用的尾插法 Status HasCircle03(List L) { List high=L; int MaxAddr = 0; while (high&&high->next) { if (high->next) { high = high->next->next; if (MaxAddr < high) MaxAddr = high; else break; } } if (high&&high->next) return TRUE; return FALSE; }
//判断堆增长方向 int StackGrow() { int *a,*b; int flag; a = (int *)malloc(sizeof(int)); b = (int *)malloc(sizeof(int)); if (a > b) flag = 0; else flag = 1; free(a); free(b); return flag; }
使用一个小例子来判断堆的增长方向
其他方法还需要再继续回顾知识后才有思路.....
全部实现代码
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <time.h> #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 typedef int ElemType; typedef int Status; typedef struct Node { ElemType data; struct Node* next; }Node; typedef struct Node* List; //创建一个列表,有无环,若是有环,将单链表和循环链表合并即可 Status InitList(List* L, int flag, int* sep); //创建一个单链表 Status CreateList(List* L, int n); //创建一个循环链表 Status CreateCList(List* L, int n); //开始进行判断是否有环 //两层循环进行判断 Status HasCircle01(List L,int *seq); //快慢指针进行判断 Status HasCircle02(List L); //地址字节进行判断,为了这种方法实现,上面无论是创建直链表还是循环链表都是使用的尾插法 Status HasCircle03(List L); //用来打印链表 void PrintList(List L,int flag, int seq); int main() { List L = NULL; int seq = 0; //分割点 int flag = 1; printf("create cList?(1/0):"); scanf("%d", &flag); if (!InitList(&L, flag, &seq)) //现在L指向第一个结点 return 0; PrintList(L,flag,seq); if (HasCircle01(L, &seq)) printf("has Circle:%d\n", seq); else printf("no Circle\n"); if (HasCircle02(L)) printf("has Circle\n"); else printf("no Circle\n"); if (HasCircle03(L)) printf("has Circle\n"); else printf("no Circle\n"); system("pause"); return 0; } //创建一个列表,有无环,若是有环,将单链表和循环链表合并即可,这里单链表和循环链表都没有头结点 Status InitList(List* L, int flag,int* sep) { int n; List SL,CL; List q; srand(time(0)); printf("please enter the length of list:"); scanf("%d", &n); *sep = n; if (!CreateList(&SL, n)) //链表创建失败,直接退出 return ERROR; if (flag) //创建一个有环链表 { printf("please enter the length of Clist:"); scanf("%d", &n); if (!CreateCList(&CL, n)) //CL是循环链表头指针 return ERROR; q = SL; for (n = 1; n < *sep; n++) q = q->next; //直接指向单链表的末尾,下面开始合并 q->next = CL; } *L = SL; return OK; } //创建一个单链表 Status CreateList(List* L, int n) { int i; List q,p; if (n < 1) return ERROR; *L = (List)malloc(sizeof(Node)); (*L)->data = rand() % 100; q = *L; for (i = 1; i < n; i++) { p = (List)malloc(sizeof(Node)); p->data = rand() % 100; q->next = p; q = p; } q->next = NULL; return OK; } //创建一个循环链表 Status CreateCList(List* L, int n) { List q,p; ElemType item; if (n < 1) return ERROR; *L = (List)malloc(sizeof(Node)); if (*L == NULL) return ERROR; (*L)->data = rand() % 100; p = *L; p->next = p; //形成回环 for (int i = 1; i < n;i++) { //生成新的节点,根据尾指针添加节点,并实时更新尾指针。注意这里数据插入是尾插法 q = (List)malloc(sizeof(Node)); q->data = rand()%100; q->next = p->next; p->next = q; p = q; } return OK; } //两层循环进行判断 Status HasCircle01(List L,int *seq) { List la, lb; int stepa, stepb; la = lb = L; //la在外层循环,lb在内层循环 stepa = stepb = 1; while (la) { while (lb!=la) { lb = lb->next; stepb++; } if (stepa != stepb) break; stepa++; la = la->next; lb = L; stepb = 1; } if (la!=NULL) { *seq = stepb; return TRUE; } return FALSE; } //快慢指针进行判断 Status HasCircle02(List L) { List high, low; high = low = L; while (low&&high&&high->next) { if (high->next) high = high->next->next; low = low++; if (high == low) return OK; } return FALSE; } //地址字节进行判断,为了这种方法实现,上面无论是创建直链表还是循环链表都是使用的尾插法 Status HasCircle03(List L) { List high=L; int MaxAddr = 0; while (high&&high->next) { if (high->next) { high = high->next->next; if (MaxAddr < high) MaxAddr = high; else break; } } if (high&&high->next) return TRUE; return FALSE; } //用来打印链表 void PrintList(List L, int flag, int seq) { List CHead; List q = L; //获取头指针 int i; if (!flag) { while (q) { printf("%d ", q->data); q = q->next; } } else { for (i = 1; i <= seq; i++) { printf("%d ", q->data); q = q->next; } //for循环退出就进入了循环链表范围内 printf("-|- "); CHead = q; while (q->next != CHead) { printf("%d ", q->data); q = q->next; } printf("%d", q->data); } printf("\n"); }
测试结果
原文地址:https://www.cnblogs.com/ssyfj/p/9427702.html
时间: 2024-10-25 04:27:35