1樓:十步天下
幾乎所有的程式設計師都寫過類似於「洗牌」的演算法,也就是將一個陣列隨機打亂後輸出,雖然很簡單,但是深入研究起來,這個小小的演算法也是大有講究。我在面試程式設計師的時候,就會經常讓他們當場寫一個洗牌的函式,從中可以觀察到他們對於這個問題的理解和寫程式的基本功。
在深入討論之前,必須先定義出一個基本概念:究竟洗牌演算法的本質是什麼?也就是說,什麼樣的洗牌結果是「正確」的?
雲風曾經有一篇博文,專門討論了這個問題,他也給出了一個比較確切的定義,在經過洗牌函式後,如果能夠保證每一個資料出現在所有位置的概率是相等的,那麼這種演算法是符合要求的。在這個前提下,儘量降低時間複雜度和空間複雜度就能得到好的演算法。
第一個洗牌演算法:
隨機抽出一張牌,檢查這張牌是否被抽取過,如果已經被抽取過,則重新抽取,直到找到沒被抽出過的牌,然後把這張牌放入洗好的佇列中,重複該過程,直到所有的牌被抽出。
大概是比較符合大腦對於洗牌的直觀思維,這個演算法經常出現在我遇到的面試結果中,雖然它符合我們對於洗牌演算法的基本要求,但這個演算法並不好,首先它的複雜度為o(n2),而且需要額外的記憶體空間儲存已經被抽出的牌的索引。所以當資料量比較大時,會極大降低效率。
第二個演算法:
設牌的張數為n,首先準備n個不容易碰撞的隨機數,然後進行排序,通過排序可以得到一個打亂次序的序列,按照這個序列將牌打亂。
這也是一個符合要求的演算法,但是同樣需要額外的儲存空間,在複雜度上也會取決於所採用的排序演算法,所以仍然不是一個好的演算法。
第三個演算法:
每次隨機抽出兩張牌交換,重複交換一定次數次後結束
void shuffle(int* data, int length)
}很明顯,這個演算法是符合我們先前的要求的,時間複雜度為o(n),而且也不需要額外的臨時空間,似乎我們找到了最優的演算法,然而事實並非如此,看下一個演算法。
第五個演算法:
void shuffle(int* data, int length)
}一個有意思的情況出現了,這個演算法和第三種演算法非常相似,從直覺來說,似乎使資料「雜亂」的能力還要弱於第三種,但事實上,這種演算法要強於第三種。要想嚴格的證明這一點並不容易,需要一些數學功底,有興趣的朋友可以參照一下這篇**,或者matrix67大牛的博文,也可以這樣簡單理解一下,對於n張牌的資料,實際排列的可能情況為n! 種,但第四種演算法能夠產生n^n種排列,遠遠大於實際的排列情況,而且n^n不能被n!
整除,所以經過演算法四所定義的牌與牌之間的交換程式,很可能一張牌被換來換去又被換回到原來的位置,所以這個演算法不是最優的。而演算法五輸出的可能組合恰好是n!種,所以這個演算法才是完美的。
事情並沒有結束,如果真的要找一個最優的演算法,還是請出最終的冠軍吧!
第六個演算法:
void shuffle(int* data, int length)
沒錯,用c++的標準庫函式才是最優方案,事實上,std::random_shuffle在實現上也是採取了第四種方法,看來還是那句話,「不要重複製造輪子」
不想寫 - -
2樓:匿名使用者
我也是學習「十步天下」演算法寫的如下**,希望對你有幫助!
#include //與#include 有定義的衝突,這裡是為stew()函式提供標頭檔案
//#include
#include
#include
using namespace std;
#define num 52
void reset(int* data,int n)
}void prn(int* data,int n)
}cout< }int swap_counts=140;//洗牌次數,越大其排序越亂 void shuffle3(int* data, int length) }void shuffle2(int* data, int length) }void shuffle1(int* data, int length) void main() prn(data,num); //演算法二 cout<<"演算法二:"< reset(data,num); shuffle2(data,num); prn(data,num); //演算法三 cout<<"演算法三:"< reset(data,num); shuffle3(data,num); prn(data,num); //此為演算法三的牌分發,可改變上面三種的順序,這裡為最後一個演算法的排序分發的 const number=4;//分牌的人數 const number=num/number;//每個人的牌的張數 int shuffle[number][number]; for (int j=0;j }for (j=0;j cout< 3樓:匿名使用者 #include #include #include #define n 10 #define m 4 #define invalid -1 void xi(int a[n], int nplayer, int player[m][n]) j = 0; while(n > 0) j++;}} void show(int nplayer, int player[m][n]) printf("\n"); }printf("\n"); }int main() ;int player[m][n]; srand(time(null)); xi(a, 2, player); show(2, player); xi(a, 3, player); show(3, player); xi(a, 4, player); show(4, player); return 0;} c語言中用結構體設計一個可以顯示花色和編號的撲克牌,並實現對這副撲克牌洗牌、整牌和發牌三個功能 4樓:橡皮泥捏個你我 #include #include using namespace std; //全域性變數,一副牌 int g_cards[54] = ; void xipai() //洗牌全域性函式 }void showcards() //顯示全域性函式 }switch(g_cards[i]/10)}} struct cardmessage case 3: case 4: case 5: case 6: case 7: }break; }switch(value%10) switch(value/10)}}; class ccard ;void ccard::getonecard(int card , int index ) void ccard::show() }switch(cardarray[i]/10)}} ccard::ccard() }ccard::~ccard() void ccard::getcards() cardnum = 17; }void ccard::sortcard()}} void fapai(ccard& player1,ccard& player2,ccard& player3) }int main() 以前學的時候寫的不知道有沒有用 5樓:影子二號 哎。。。。。貌似是作業題吧!哈哈。。。。樓上的哥們貌似是用c++做的吧,class都出來了! 樓上的答案加個 define n 5 void sort int a void main sort a 編寫函式用氣泡排序法對陣列中的n個資料進行從小到大的排序。1 新建一個163.php。2 輸入php網頁的結構 3 宣告php與瀏覽器互動的檔案型別和編碼。4 使用 array 函式定義一個 nu... 你看看bai這du 個,裡zhi面dao 好像就回有答 能不能幫忙寫一下c 類的建構函式,拷貝建構函式,賦值運算子 號的操作符過載,解構函式?求教 class test test test void test test test item 拷貝this data new char itemlen p... include define pi 3.14159 float getarea float nr int main include float area float r int main include define n 3.14 圓周率float s float r 計算面積void main 編...用c語言程式設計編寫函式,用冒泡法對主函式中的陣列進行從小到大的排序
用c編寫類string的建構函式拷貝建構函式析
c語言編寫函式用來計算圓的面積,c語言 編寫一個函式,用來計算圓的面積。