生活随笔
收集整理的這篇文章主要介紹了
一摞烙饼的排序(搜索树)
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
前兩個(gè)星期就看編程之美的一摞烙餅排序問題,剛開始看其代碼沒看懂什么意思,后來看了人家的博客才知道是怎么回事了,自己寫了一遍其代碼做各種各樣的測(cè)試,嚇我一跳,一個(gè)剪枝操作竟然省了那么多的時(shí)間,想起上一道題的將帥問題,頓時(shí)讓我領(lǐng)悟到這編程之美的書籍,題目不但有意思,其代碼真的優(yōu)雅和美,好了接下來看這個(gè)烙餅排序問題。
題目:
星期五的晚上,一幫同事在希格瑪大廈附近的“硬盤酒吧”多喝了幾杯。程序員多喝了幾杯之后談什么呢?自然是算法問題。有個(gè)同事說:“我以前在餐館打工,顧客經(jīng)常點(diǎn)非常多的烙餅。店里的餅大小不一,我習(xí)慣在到達(dá)顧客飯桌前,把一摞餅按照大小次序擺好——小的在上面,大的在下面。由于我一只手托著盤子,只好用另一只手,一次抓住最上面的幾塊餅,把它們上下顛倒個(gè)個(gè)兒,反復(fù)幾次之后,這摞烙餅就排好序了。我后來想,這實(shí)際上是個(gè)有趣的排序問題:假設(shè)有n塊大小不一的烙餅,那最少要翻幾次,才能達(dá)到最后大小有序的結(jié)果呢?”
你能否寫出一個(gè)程序,對(duì)于n塊大小不一的烙餅,輸出最優(yōu)化的翻餅過程呢?
編程之美的代碼:
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);
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
int main()
{CprefixSorting test;
int aa[
3]={
3,
1,
2};test.Run(aa,
3);test.Output();
}
運(yùn)行結(jié)果:
2 1
|Search Times : 19
Total Swap times= 2
剪枝操作的關(guān)鍵就是看其上界和下界兩個(gè)邊界,如果下界越大,上界越小其運(yùn)行效率越高,測(cè)試:
修改上界值較大(調(diào)整更大的上界):
//最大的上界
int UpperBound(int mCakecnt)
{
return 2*mCakecnt;
}
運(yùn)行結(jié)果
2 1
|Search Times : 31
修改下界值較小(調(diào)整更小的下界)
lowCnt=-1;
運(yùn)行結(jié)果:
2 1
|Search Times : 31
Total Swap times= 2
從結(jié)果可以看出,上界和下界的數(shù)值對(duì)其所搜次數(shù)的影響,這里如果你傳入的數(shù)組數(shù)目越多,影響會(huì)更明顯的,因?yàn)檫@里涉及了一種搜索樹的結(jié)構(gòu),該樹深度越高,樹的節(jié)點(diǎn)就越多,越密集那么消耗的時(shí)間的次數(shù)就越高,這時(shí)利用分支限界法(即巧妙的利用邊界才停止其往下搜索),控制搜索深度,這樣就可以大大的減少時(shí)間效率了,如圖:
參考博客:
http://blog.csdn.net/zuiaituantuan/article/details/6056601
總結(jié)
以上是生活随笔為你收集整理的一摞烙饼的排序(搜索树)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。