[算法天地]关于单链表的操作有环无环判断
#include <stdio.h> #include <stdlib.h> // 有环链表的各种函数测试 typedef struct Node { int data; struct Node *next; }Node; typedef struct Node* LinkList; /*链表初始化*/ int InitList(LinkList *L) { *L = (LinkList)malloc(sizeof(Node)); if(!(*L)) return -1; (*L)->next = NULL; return 0; } /*求链表的长度*/ int ListLength(LinkList L) { int i = 0; LinkList p = L->next; while(p) { i++; p = p->next; } return i; } int CreateListHead(LinkList *L, int n) { LinkList p; int i; for(i=0; i<n; i++) { p = (LinkList)malloc(sizeof(Node)); p->data = i+1; p->next = (*L)->next; (*L)->next = p; } } int CreateListTail(LinkList *L, int n) { LinkList p, r; int i; r = *L; for(i=0; i<n; i++) { p = (LinkList)malloc(sizeof(Node)); p->data = i+1; r->next = p; r = p; } r->next = NULL; } /*打印链表*/ void ListTraverse(LinkList L) { LinkList p = L->next; while(p) { printf("%d ", p->data); p = p->next; } printf("\n"); } /*单链表反转*/ LinkList ListReverse(LinkList L) { LinkList current, pnext, prev; if(L == NULL || L->next == NULL) return L; current = L->next; pnext = current->next; current->next = NULL; while(pnext) { prev = pnext->next; pnext->next = current; current = pnext; pnext = prev; } L->next = current; return L; } LinkList ListReverse2(LinkList L) { LinkList current, p; if(L == NULL) return NULL; current = L->next; printf("current = %d\n", current->data); while(current->next != NULL) { /**举个例子 * p = current->next; // 9个数的话调换需要八次,第一次P等于8 * currnet->next = p->next; // P的下一个值7,付给current的下一个 * p->next = L->next; // 把L的第一个节点9赋值给P的下一个值 * L->next = p; // L的下一个值为8,因为上一步P的下一个已经为9 */ p = current->next; current->next = p->next; p->next = L->next; L->next = p; } return L; } int ListInsert(LinkList *L, int pos, int num) { int j; LinkList p, s; p = *L; j = 1; while(p && j<pos) { p = p->next; ++j; } if( !p || j>pos ) return -1; s = (LinkList)malloc(sizeof(Node)); s->data = num; s->next = p->next; p->next = s; return 0; } int IsEmpty(LinkList L) { if(L->next) return -1; else return 1; } int BuildListLoop(LinkList *L, int num) { int i = 0; LinkList cur = (*L)->next; LinkList tail= NULL; if(num <= 0 || L == NULL) return -1; for(i=1; i<num; ++i) { if(cur == NULL) { return -1; } cur = cur->next; } tail = cur; while(tail->next) { tail = tail->next; } tail->next = cur; return 0; } int ListTraveseLimit(LinkList L, int n) { int i = 0; LinkList p = L->next; while(p && i<n) { printf("%d ", p->data); p = p->next; i++; } printf("\n只显示%d个\n", n); return 0; } int HasLoop(LinkList L) { LinkList fast = L; LinkList slow = L; /** * 这里如果无环,则fast先到达终点 * 当链表长度为奇数时,fast->next为空 * 当链表长度为偶数时,fast为空 */ while( fast != NULL && fast->next != NULL ) { fast = fast->next->next; slow = slow->next; if( fast == slow ) break; } if( fast == NULL || fast->next == NULL ) return -1; else return 1; } int LoopLength(LinkList L) { if(-1 == HasLoop(L)) return 0; LinkList fast = L; LinkList slow = L; int length = 0; bool begin = false; bool again = false; while( fast != NULL && fast->next != NULL ) { fast = fast->next->next; slow = slow->next; // 超两圈后停止计数,跳出循环 if( fast == slow && again == true ) { break; } // 超一圈后开始计数 if( fast == slow && again == false ) { begin = true; again = true; } // 计数 if( begin == true ) ++length; } return length; } // 解决入口点的问题思路 // 8 O-O 7 // / // 9 O O 6 // \ / // O - O - O - O - O // 1 2 3 4 5 // 相遇点到连接点的距离等于头指针到连接点的距离 // 先让快慢指针相遇,然后慢指针重新指向头结点 // 分别从相遇点、头指针开始走,相遇的那个店就是连接点 LinkList findLoopEnterace(LinkList L) { LinkList fast = L; LinkList slow = L; while( fast != NULL && fast->next != NULL ) { fast = fast->next->next; slow = slow->next; // 如果有环,则fast会超过slow一圈 if(fast == slow) break; } if(fast == NULL || fast->next == NULL) return NULL; slow = L; while(slow != fast) { slow = slow->next; fast = fast->next; } return slow; } int GetMidNode(LinkList L, int *e) { LinkList fast = L; LinkList slow = L; while( fast->next != NULL ) { if( fast->next->next != NULL ) { fast = fast->next->next; slow = slow->next; } else { fast = fast->next; } } *e = slow->data; return 0; } int ClearList(LinkList *L) { LinkList p, q; p = (*L)->next; while(p) { q = p->next; free(p); p = q; } (*L)->next = NULL; return 0; } int main() { LinkList L; int i; int n; int e; i = InitList(&L); if(i != -1) printf("InitList() 初始化成功.\n"); printf("链表L初始化后, ListLength(L)=%d\n", ListLength(L)); for(i=0; i<10; i++) { ListInsert(&L, 1, i); } printf("IsEmpty = %d(1:空,-1:非空)\n", IsEmpty(L)); printf("ListLength(L)=%d\n", ListLength(L)); printf("打印链表:"); ListTraverse(L); // 给单链表逆向反转 ListReverse2(L); printf("逆向打印链表:"); ListTraverse(L); // 求链表的中间节点 GetMidNode(L, &e); printf("求链表的中间节点e=%d\n", e); printf("给链表建环, 请输入位置:"); scanf("%d", &n); BuildListLoop(&L, n); ListTraveseLimit(L, 20); // 判断链表是否有环 if( 1 == HasLoop(L) ) printf("链表有环\n"); else printf("链表无环\n"); // 计算环长 printf("计算环长, LoopLength(L)=%d\n", LoopLength(L)); // 求出环的入口点 LinkList enterance = findLoopEnterace(L); printf("入口点的值为: %d\n", enterance->data); //printf("采用头插法:\n", CreateListHead(&L, 10)); //ListTraverse(L); //printf("采用尾插法\n", CreateListTail(&L, 10)); //ListTraverse(L); //i = ClearList(&L); //if( i == 0 ) // printf("清空LinkList链表.\n"); //printf("IsEmpty = %d(1:空,-1:非空)\n", IsEmpty(L)); //printf("ListLength(L)=%d\n", ListLength(L)); return 0; }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。