無論是靜態鍊錶
還是動態鍊錶
,有時在解決具體問題時,需要我們對其結構進行稍微地調整。比如,可以把鍊錶的兩頭連線,使其成為了乙個環狀鍊錶,通常稱為迴圈鍊錶。
和它名字的表意一樣,只需要將表中最後乙個結點的指標指向頭結點,鍊錶就能成環兒,如圖 1 所示。
圖1 迴圈鍊錶
需要注意的是,雖然迴圈鍊錶成環狀,但本質上還是鍊錶,因此在迴圈鍊錶中,依然能夠找到頭指標和首元節點等。迴圈鍊錶和普通鍊錶相比,唯一的不同就是迴圈鍊錶首尾相連,其他都完全一樣。
約瑟夫環問題,是乙個經典的迴圈鍊錶問題,題意是:已知 n 個人(分別用編號 1,2,3,…,n 表示)圍坐在一張圓桌周圍,從編號為 k 的人開始順時針報數,數到 m 的那個人出列;他的下乙個人又從 1 開始,還是順時針開始報數,數到 m 的那個人又出列;依次重複下去,直到圓桌上剩餘乙個人。
如圖 2 所示,假設此時圓周周圍有 5 個人,要求從編號為 3 的人開始順時針數數,數到 2 的那個人出列:
圖 2 迴圈鍊錶實現約瑟夫環
出列順序依次為:
約瑟夫環問題有多種變形,比如順時針轉改為逆時針等,雖然問題的細節有多種變數,但解決問題的中心思想是一樣的,即使用迴圈鍊錶。
通過以上的分析,我們可以嘗試編寫 c 語言**,完整**如下所示:
#include#include
typedef struct nodeperson;
person * initlink(int n)
cyclic->next=head;//首尾相連
return head;
}void findandkillk(person * head,int k,int m)
person * p=head;
//找到編號為k的人
while (p->number!=k)
//從編號為k的人開始,只有符合p->next==p時,說明鍊錶中除了p結點,所有編號都出列了,
while (p->next!=p)
tail->next=p->next;//從鍊錶上將p結點摘下來
printf("出列人的編號為:%d\n",p->number);
free(p);
p=tail->next;//繼續使用p指標指向出列編號的下乙個編號,遊戲繼續
}printf("出列人的編號為:%d\n",p->number);
free(p);
}int main()
輸出結果:
輸入圓桌上的人數n:5
從第k人開始報數(k>1且k<5):3
數到m的人出列:2
出列人的編號為:4
出列人的編號為:1
出列人的編號為:3
出列人的編號為:2
出列人的編號為:5
最後出列的人,即為勝利者。當然,你也可以改進程式,令查詢出最後乙個人時,輸出此人勝利的資訊。
迴圈鍊錶和動態鍊錶唯一不同在於它的首尾連線,這也注定了在使用迴圈鍊錶時,附帶最多的操作就是遍歷鍊錶。
在遍歷的過程中,尤其要注意迴圈鍊錶雖然首尾相連,但並不表示該鍊錶沒有第乙個節點和最後乙個結點。所以,不要隨意改變頭指標的指向。
迴圈鍊錶(約瑟夫環)
約瑟夫環是乙個數學的應用問題 已知n個人 以編號1,2,3.n分別表示 圍坐在一張圓桌周圍。從編號為k的人開始報數,數到m的那個人出列 他的下乙個人又從1開始報數,數到m的那個人又出列 依此規律重複下去,直到圓桌周圍的人全部出列。要通過輸入n,m,k三個正整數,來求出列的序列。這個問題採用的是典型的...
約瑟夫環 C 單項迴圈鍊錶
約瑟夫問題的一種描述是 編號為1 2,n的n個人按順時針方向圍坐一圈,每人持乙個密碼 正整數 一開始任選乙個正整數作為報數上限值m,從第乙個人開始按順時針方向自1開始順序報數,報到m時停止報數。報m的人出列,將他的密碼作為新的m值,從他在順時針方向上的下乙個人開始重新從1報數,如此下去,直至所有人全...
迴圈鍊錶應用 約瑟夫環
約瑟夫環是乙個數學的應用問題 已知n個人 以編號1,2,3.n分別表示 圍坐在一張圓桌周圍。從編號為k的人開始報數,數到m的那個人出列 他的下乙個人又從1開始報數,數到m的那個人又出列 依此規律重複下去,直到圓桌周圍的人全部出列。include includetypedef struct node ...