《程式設計之法》 完美洗牌演算法

2021-07-28 23:15:58 字數 2174 閱讀 3786

有乙個長度為2n的陣列,希望排序後變成。

書上講了先用完美洗牌演算法將陣列排序為,然後再兩兩交換,就變為題目所要求的那樣。

書上完美洗牌演算法講得很好,我這裡就簡單記錄下。

注意,陣列下標是從1開始儲存要求排序的資料。

首先,對於將排序為,通過觀察可以發現這樣乙個事實:任意的第i個元素都最終換到了(2i)%(2n+1)的位置。即

第1個->第2個,

第2個->第4個,

第3個->第6個,

第4個->第8個,

第5個->第1個,

第6個->第3個,

第7個->第5個,

第8個->第7個。

並且還有這樣乙個事實,讓原始序列中的每乙個元素置換到最終序列裡的位置時,形成了兩個圈:乙個是1->2->4->8->7->5->1,另乙個是3->6->3。因此,只要知道圈裡最小位置編號的元素(即圈的頭部),順著圈走一遍就可以達到目的。

有大神得出了這樣乙個結論:若2n=3^k-1,則可確定圈的個數及各自頭部的位置,即恰好只有k個圈,且每個圈頭部的起始位置分別是1,3,9,…,3^(k-1)。

所以對於給定的任意n,可將整個陣列一分為二,讓一部分的長度滿足上述結論,剩下的n-m部分單獨計算。

也就是如下所示,數字指的都是下標:

1,…,m,m+1,…,n,n+1,…,n+m,n+m+1,…,2n

且為了能讓前部分的序列滿足結論2m=3^k-1,可以把中間兩段長度為n-m和m的段交換位置,即相當於把m+1,…,n,n+1,…,n+m的段迴圈右移m次,這樣操作後,陣列的前部分的長度為2m,這部分就恰好有k個圈。

最後的完整流程就是:

輸入:陣列a[1,2,…,2n]。

第1步:找到2m=3^k-1,使得3^k <= 2n <= 3^(k+1)。

第2步:把陣列中的a[m+1,…,n+m]那部分迴圈右移m位。

第3步:因對於2m長度的陣列,剛好有k個圈,且每個圈的頭部為3^i,其中i=0,1,2,…,k-1,所以對每個圏執行走環演算法cycleleader,且因陣列長度為m,所以需要對2m+1取模。

第4步:對陣列的後面部分a[2m+1,…,2n]繼續使用本演算法,這相當於n減少了m。

//

// created by huxijie on 17-3-18.

// 完美洗牌演算法

#include

using

namespace

std;

//注意,陣列從下標1處開始存資料

//翻轉陣列

void reverse(int

array,int from,int to)

}//迴圈右移m位

void rightshifting(int

array,int n,int m)

//走環演算法:i->2i mod (2n+1)

//陣列下標從1開始,from是圈的頭部,mod是要取模的數,因此mod應該為2n+1

void cycleleader(int

array,int from,int mod)

}int *perfectshuffle(int

array,int n)

m /= 2;

//第2步

rightshifting(array + m, n, m);

//第3步

for (i = 0, t = 1; i < k; ++i, t *= 3)

//第4步

array += 2 * m;

n -= m;

}//n=1時

t = array[1];

array[1] = array[2];

array[2] = t;

return start;

}int *shuffle(int

array,int n)

return result;

}int main()

int *result = shuffle(array, n);

for (int i = 1; i < 2 * n + 1; ++i)

cout

0;}

162

7384

9510process finished with

exit code 0

完美洗牌演算法

原文 完美洗牌問題 給定乙個陣列a1,a2,a3,an,b1,b2,b3.bn,把它最終設定為b1,a1,b2,a2,bn,an這樣的。分析 首先,有的問題要求把它換成a1,b1,a2,b2,an,bn。其實也差不多。我們可以 迴圈n次交換a1,b1,a2,b2,把陣列變為b1,b2.bn,a1,a...

完美洗牌演算法

沒把空間複雜度o 1 的搬過來 問題描述 有乙個長度為2n的陣列,希望排序後變成,請考慮有沒有時間複雜度為o n 而空間複雜度為o 1 的解法。string a string temp new string len for int i 1 i len i temp 2 i len a i 經過上面處...

完美洗牌演算法

完美洗牌就是將一副牌平均分成兩份 26張 來交錯洗牌,如此迴圈反覆一定次數後,又變回洗牌前的順序了。即 a 1,a 2.a n,b 1,b 2.b n的序列變為b 1,a 1,b 2,a 2.b n,a n 我知道這 很shi,只是拋磚,向各位高人請教更好的演算法,謝謝 完美洗牌就是將一副牌平均分成...