日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

一摞烙饼的排序(搜索树)

發布時間:2023/12/8 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一摞烙饼的排序(搜索树) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前兩個星期就看編程之美的一摞烙餅排序問題,剛開始看其代碼沒看懂什么意思,后來看了人家的博客才知道是怎么回事了,自己寫了一遍其代碼做各種各樣的測試,嚇我一跳,一個剪枝操作竟然省了那么多的時間,想起上一道題的將帥問題,頓時讓我領悟到這編程之美的書籍,題目不但有意思,其代碼真的優雅和美,好了接下來看這個烙餅排序問題。
題目:
星期五的晚上,一幫同事在希格瑪大廈附近的“硬盤酒吧”多喝了幾杯。程序員多喝了幾杯之后談什么呢?自然是算法問題。有個同事說:“我以前在餐館打工,顧客經常點非常多的烙餅。店里的餅大小不一,我習慣在到達顧客飯桌前,把一摞餅按照大小次序擺好——小的在上面,大的在下面。由于我一只手托著盤子,只好用另一只手,一次抓住最上面的幾塊餅,把它們上下顛倒個個兒,反復幾次之后,這摞烙餅就排好序了。我后來想,這實際上是個有趣的排序問題:假設有n塊大小不一的烙餅,那最少要翻幾次,才能達到最后大小有序的結果呢?”
你能否寫出一個程序,對于n塊大小不一的烙餅,輸出最優化的翻餅過程呢?
編程之美的代碼:

class CprefixSorting {public://初始化CprefixSorting(){mCakecnt=0;mMaxSwap=0;};//釋放數組內存空間virtual ~CprefixSorting(){if(mCakeArray!=NULL)delete mCakeArray;if(mReverseCakeArraySwap!=NULL)delete mReverseCakeArraySwap;if(mSwapArray!=NULL)delete mSwapArray;if(mReverseCakeArray!=NULL)delete mReverseCakeArray;};//最大的上界int UpperBound(int mCakecnt){//這里修正了編程之美的上界return 2*(mCakecnt-1);}//最小的下界int LowerBound(int *reverseCake,int cakeCnt ){int t;int reverseCnt=0;//統計最少需要翻轉的次數for(int i=1;i<cakeCnt;i++){//判斷是否相鄰t=reverseCake[i]-reverseCake[i-1];if(t==1||t==-1){}else{reverseCnt++;}}return reverseCnt;}//判斷烙餅是否排好序bool IsSorted(int* reverseCakeArray,int cakeCnt ){for(int i=1;i<cakeCnt;i++){if(reverseCakeArray[i-1]>reverseCakeArray[i]){return false;}}return true;}//初始化信息void Init(int * cakeArray,int cakeCnt){assert(cakeArray!=NULL);assert(cakeCnt>0);mCakecnt=cakeCnt;mCakeArray=new int[mCakecnt];assert(mCakeArray!=NULL);for(int i=0;i<mCakecnt;i++){mCakeArray[i]=cakeArray[i];}//設置最大存儲空間mMaxSwap=UpperBound(mCakecnt);mSwapArray=new int[mMaxSwap+1];assert(mSwapArray!=NULL);mReverseCakeArray=new int[mCakecnt];for(int i=0;i<mCakecnt;i++){mReverseCakeArray[i]=mCakeArray[i];}mReverseCakeArraySwap=new int[mMaxSwap];}//排序的核心函數void Search(int step){//存儲最小搜索次數int lowCnt;mSearch++;lowCnt=LowerBound(mReverseCakeArray,mCakecnt);//這里也修正了編程之美的剪枝//當當前的搜索和最小的下界若比前面最小次數的還要大//就停止搜索,以便減少時間的開銷//這剪枝是遞歸分支限界法的核心if(step+lowCnt>mMaxSwap||step>=mMaxSwap){return;}if(IsSorted(mReverseCakeArray,mCakecnt)){if(step<mMaxSwap){mMaxSwap=step;for(int i=0;i<mCakecnt;i++){mSwapArray[i]=mReverseCakeArraySwap[i];}}return;}//遍歷遞歸進行翻轉for(int i=1;i<mCakecnt;i++){//翻轉Reserver(0,i);//儲存當前搜索值對應翻轉月餅的索引mReverseCakeArraySwap[step]=i;//搜索下一個節點Search(step+1); // printf("step:%d\n",step+1); // for(int j=0;j<mCakecnt;j++) // { // printf("%d ",mReverseCakeArray[j]); // } // printf("\n");//返回上一層Reserver(0,i);}}//翻轉烙餅信息void Reserver(int begin,int end){for(int i=begin,j=end;i<j;i++,j--){int t=mReverseCakeArray[i];mReverseCakeArray[i]=mReverseCakeArray[j];mReverseCakeArray[j]=t;}}//運行函數接口void Run(int *cakeArray,int cakeCnt){Init(cakeArray,cakeCnt);mSearch=0;Search(0);}void Output(){for(int i=0;i<mMaxSwap;i++){//輸出每層翻轉其烙餅的索引printf("%d ",mSwapArray[i]);}//輸出搜索次數printf("\n |Search Times : %d\n",mSearch);//輸出需翻轉最少的次數printf("Total Swap times= %d\n",mMaxSwap);}private:int * mCakeArray;//儲存對應索引烙餅大小信息數組int mCakecnt;//烙餅的個數int mMaxSwap;//烙餅的最大交換次數int * mReverseCakeArray;//儲存當前翻轉后對應索引烙餅的大小信息int mSearch; //當前搜索次數int * mReverseCakeArraySwap;//儲存當前對應搜索值的被翻轉的烙餅索引int * mSwapArray;//存儲已經完全排好序的所有對應搜索值得被烙餅索引 };#endif // CPREFIXSORTING_H int main() {CprefixSorting test;int aa[3]={3,1,2};test.Run(aa,3);test.Output(); }

運行結果:
2 1
|Search Times : 19
Total Swap times= 2
剪枝操作的關鍵就是看其上界和下界兩個邊界,如果下界越大,上界越小其運行效率越高,測試:
修改上界值較大(調整更大的上界):
//最大的上界
int UpperBound(int mCakecnt)
{
return 2*mCakecnt;
}
運行結果
2 1
|Search Times : 31
修改下界值較小(調整更小的下界)
lowCnt=-1;
運行結果:
2 1
|Search Times : 31
Total Swap times= 2
從結果可以看出,上界和下界的數值對其所搜次數的影響,這里如果你傳入的數組數目越多,影響會更明顯的,因為這里涉及了一種搜索樹的結構,該樹深度越高,樹的節點就越多,越密集那么消耗的時間的次數就越高,這時利用分支限界法(即巧妙的利用邊界才停止其往下搜索),控制搜索深度,這樣就可以大大的減少時間效率了,如圖:

參考博客:
http://blog.csdn.net/zuiaituantuan/article/details/6056601

總結

以上是生活随笔為你收集整理的一摞烙饼的排序(搜索树)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。