生活随笔
收集整理的這篇文章主要介紹了
Linux C 数据结构—-循环链表
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前面我們學習了單向鏈表,現在介紹單向循環鏈表,單向循環鏈表是單鏈表的一種改進,若將單鏈表的首尾節點相連,便構成單向循環鏈表結構,如下圖:
? ???對于一個循環鏈表來說,其首節點和末節點被連接在一起。這種方式在單向和雙向鏈表中皆可實現。要轉換一個循環鏈表,可以選擇開始于任意一個節點然后沿著列表的任一方向直到返回開始的節點。再來看另一種方法,循環鏈表可以被視為“無頭無尾”。這種列表很利于節約數據存儲緩存, 假定你在一個列表中有一個對象并且希望所有其他對象迭代在一個非特殊的排列下。指向整個列表的指針可以被稱作訪問指針。
? ? 循環鏈表中第一個節點之前就是最后一個節點,反之亦然。循環鏈表的無邊界使得在這樣的鏈表上設計算法會比普通鏈表更加容易。對于新加入的節點應該是在第一個節點之前還是最后一個節點之后可以根據實際要求靈活處理,區別不大。當然,如果只會在最后插入數據(或者只會在之前),處理也是很容易的。
? ? ??
? ??? 循環鏈表的應用
一、Joseph問題(約瑟夫環):
? ? ?據說著名猶太歷史學家 Josephus有過以下的故事:在羅馬人占領喬塔帕特后,39 個猶太人與Josephus及他的朋友躲到一個洞中,39個猶太人決定寧愿死也不要被敵人找到,于是決定了一個自殺方式,41個人排成一個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺,然后再由下一個重新報數,直到所有人都自殺身亡為止。然而Josephus 和他的朋友并不想遵從,Josephus要他的朋友先假裝遵從,他將朋友與自己安排在第16個與第31個位置,于是逃過了這場死亡游戲。?
? ? ?約瑟夫環用數學問題來描述就是:已知n個人(以編號1,2,3...n分別表示)圍坐在一張圓桌周圍。從編號為k的人開始報數,數到m的那個人出列;他的下一個人又從1開始報數,數到m的那個人又出列;依此規律重復下去,直到圓桌周圍的人全部出列。如何用循環鏈表來求解Josephu問題?
? ? 下面我們用單向循環鏈表來模擬這個問題:
[cpp]?view plaincopy
#include?<stdio.h>?? #include?<stdlib.h>?? ?? typedef?int?data_t;?? ?? typedef?struct?node_t?? {?? ????data_t?data;?? ????struct?node_t?*next;?????? }linknode_t,*linklist;?? ?? linklist?CreateList(int?n)?? {?? ????int?i;?? ????linklist?p,head,tail;?? ????head?=?NULL;?? ?????? ????for(i?=?1;i?<=?n;i++)?? ????{?? ????????p?=?(linklist)malloc(sizeof(linklist));?? ????????if(p?==?NULL)?? ????????{?? ????????????printf("malloc?fails!\n");?? ????????}?? ?????????????? ????????p->data?=?i;?? ????????if(head?==?NULL)?? ????????{?? ????????????head?=?p;?? ????????????tail?=?head;?? ????????}?? ????????else?? ????????{?? ????????????tail->next?=?p;?? ????????}????????????????? ?????????? ????????tail?=?p;?? ????}?? ?????? ????tail->next?=?head;?? ?? ????return?head;??? }?? ?? void?Joseph(int?n,int?k,int?m)?? {?? ????int?i;?? ????linklist?p,r;?? ????p?=?CreateList(n);?? ?? ????for(i?=?1;i?<?k;i++)??? ????{?? ????????p?=?p->next;?? ????}?? ?? ????while(p->next?!=?p)?? ????{?? ????????for(i?=?1;i?<=?m-2;i++)???? ????????????p?=?p->next;?? ?? ????????r?=?p->next;?? ????????p->next?=?r->next;?? ????????printf("%d->",r->data);?? ?????????? ????????free(r);?? ????????p?=?p->next;?? ????}?? ?????? ????printf("%d\n",p->data);?? }?? ?? int?main()?? {?? ????Joseph(41,1,3);?? ?? ????return?0;?? }??
輸出結果如下:
[cpp]?view plaincopy
fs@ubuntu:~/qiang/linklist$?./list1?? 3->6->9->12->15->18->21->24->27->30->33->36->39->1->5->10->14->19->23->28->32->37->41->7->13->20->26->34->40->8->17->29->38->11->25->2->22->4->35->16->31??
我們可以看到,最后兩個是16和31,這樣,約瑟夫和他的朋友就躲過了一劫!
二、判斷一個鏈表是不是循環鏈表(如何判定這個鏈表當中是否包含有環路)
?解決方法:
? ? ??判斷是否是循環鏈表時,也設置兩個指針,慢指針和快指針,讓快指針比慢指針每次移動快兩次。如果快指針追趕上慢指針,則為循環鏈表,否則不是循環鏈表,如果快指針或者慢指針指向NULL,則不是循環鏈表。
代碼如下:
[cpp]?view plaincopy
#include?<stdio.h>?? #include?<stdlib.h>?? ?? typedef?int?data_t;?? ?? typedef?struct?node_t?? {?? ????data_t?data;?? ????struct?node_t?*next;?????? }linknode_t,*linklist;?? ?? linklist?CreateList(int?n)?? {?? ????int?i;?? ????linklist?p,head,tail;?? ????head?=?NULL;?? ?????? ????for(i?=?1;i?<=?n;i++)?? ????{?? ????????p?=?(linklist)malloc(sizeof(linklist));?? ????????if(p?==?NULL)?? ????????{?? ????????????printf("malloc?fails!\n");?? ????????}?? ?????????????? ????????p->data?=?i;?? ????????if(head?==?NULL)?? ????????{?? ????????????head?=?p;?? ????????????tail?=?head;?? ????????}?? ????????else?? ????????{?? ????????????tail->next?=?p;?? ????????}????????????????? ?????????? ????????tail?=?p;?? ????}?? ?????? ????tail->next?=?head;?? ?? ????return?head;??? }?? ?? int?JudgeIsloop(linklist?list)?? {?? ????int?flag?=?0;?? ????linknode_t?*slow,*fast;?? ?? ????if(list?==?NULL)?? ????????return?0;?? ?? ????slow?=?list;?? ????fast?=?list->next;?? ?? ????while(slow)?? ????{?? ????????if(fast?==?NULL?||?fast->next?==?NULL)?? ????????????return?0;?? ????????else?if(fast?==?slow?||?fast->next?==?slow)?? ????????{????? ????????????flag?=?1;?? ????????????return?1;?? ????????}?? ????????else?? ????????{?? ????????????slow?=?slow->next;?? ????????????fast?=?fast->next->next;?? ????????}?? ????}?? ?? ????return?0;?? }?? ?? int?main()?? {?? ????int?i;?? ????int?flag?=?0;?? ????linklist?list;?? ????list?=?CreateList(10);?? ?????? ????JudgeIsloop(list);?? ?? ????if(flag?=?0)?? ????????printf("The?list?is?not?a?looplist!\n");?? ????else?? ????{?? ????????printf("The?list?is?a?looplist!\n");?? ????????for(i?=?0;i?<?10;i++)?? ????????{?? ????????????printf("%d->",list->data);?? ????????????list?=?list->next;?? ????????}?? ????????printf("%d\n",list->data);?? ????}?? ?? ????return?0;?? }??
結果如下:
[cpp]?view plaincopy
fs@ubuntu:~/qiang/linklist$?./list2?? The?list?is?a?looplist!?? 1->2->3->4->5->6->7->8->9->10->1?? fs@ubuntu:~/qiang/linklist$?
總結
以上是生活随笔為你收集整理的Linux C 数据结构—-循环链表的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。