算法導論14-2習題解答 Josephus排列(約瑟夫環)


CLRS 14-2 Josephus問題的定義如下:假設n個人排成環形,且有以正整數m<=n。從某個制定的人開始,沿環報數,每遇到第m個人就讓其出列,且報數進行下去。這個過程一直進行到所有人都出列為止。每個人出列的次序定義了整數1,2,...,n的(n, m)-Josephus排列。例如,(7,3)-Josephus排列為<3,6,2,7,5,1,4>。
a)假設m為整數。請描述一個O(n)時間的算法,使之對給定的整數n,輸出(n, m)-Josephus排列。
b)假設m不是個常數。請描述一個O(nlgn)時間的算法,使給定的整數n和m,輸出(n, m)-Josephus排列。

解答:
a)首先,我們很容易想到用一個循環鏈表,即最后一個結點指向頭結點的單鏈表。然后,選定一個結點,走m步,輸出此結點的值,然后刪除之,然后再走m步,依次循環下去,由於建立鏈表時間為O(n),而刪除的過程為O(m*n),由於m為常數,故總的時間復雜度為O(n)。
(偽)偽代碼:

//i為起始點
1
PROCESS(list, i) 2 { 3 node = list.get(i); 4 while (list != NULL) 5 { 6 for (i = 0; i < m-1; i++) 7 { 8 node = node->link; 9 } 10 tmp = node;//保存node的副本 11 print node->key;//輸出值 12 node = node->link;//在刪除之前指向下一個結點 13 delete tmp;//從鏈表刪除,當然,之前還有指針之間的鏈接轉變 14 } 15 }


b)第二問,由於在這一章,所以會采用基於紅黑樹的順序統計樹。
這里可以結合着偽代碼和下面的例子看整個流程是怎么走的。
(偽)偽代碼:

 1 //建立順序統計樹,在題設中,原始數據是一個排好序的數組,即{1,2,3...n}
 2 CreateTree()
 3 {
 4   for (i = 1; i <= n; i++)
 5     insert(T, node[i]);//node存儲的是數組元素
 6 }
 7 
 8 //T為順序統計樹,i為選擇的起始點,這里的i表示的是位置,不是node里面的key值,可以理解為第i小的數
 9 Process(T, i)
10 {
11   while (T != NULL)
12   {
13     i = (i+m-2)%(n--) + 1;//在這里,我們不用(i+m-1)%(n--),是因為這個表達式可能計算的結果等於0,但i != 0;
14     print key[OS-SELECT(T, i)];
15     OS-DELETE(T, i);
16   }
17 }

我們來對數組{1,2,3,4,5,6,7}走一遍,我們選擇第一個數為起始點,i=1,選擇m=3,則
i = (i+m-2)%(n--) + 1 = 3,好的,輸出第3個數,即3,然后去除3,剩下{1,2,4,5,6,7},n=6接着
i = (i+m-2)%(n--) + 1 = 5,好的,輸出第5個數(這里不是5,在樹中剩下的元素中,是第五小的數),即為6,然后刪除6,現在剩下元素為{1,2,4,5,7},n=5,接着
i = (i+m-2)%(n--) + 1 = 2,好的,輸出第2個數,即為2,然后刪除2,現在剩下元素為{1,4,5,7},n=4,接着
i = (i+m-2)%(n--) + 1 = 4,輸出第四個數,即為7,然后刪除7,現在剩下元素為{1,4,5},n=3,接着
......
我們發現,這個算法的執行是正確的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM