/*
一摞烙餅的排序:
把一摞並按照大小次序擺好,小的在上面,大的在下面。由於我乙隻手托著盤子,只好用另乙隻手,一次抓住最
上面的幾塊餅。把它們上下顛倒一下,反覆幾次,烙餅就排好序了。
請寫乙個程式,對於n塊大小不一的烙餅,輸出最優化的翻餅過程。
分析:每次我們只能選擇最上方的一摞餅,一起翻轉。不能一張一張直接抽取出來,然後進行插入,也不能交換任意兩塊
餅。因此,基本的排序方法不好用。
每次操作都是針對最上面的餅,如果最底層的餅已經排序,只需要處理上面的n-1個餅。問題變為n-2,n-3,...,
直到最上面的兩個餅排好序。
解法1:
為了把最大的烙餅放在最下面,我們走兩步:
1將最上面和最大的烙餅(包括這兩張餅)一起反轉
2將整坨烙餅全部翻轉
之後我們對上面n-1,n-2個餅重複上述過程
經過兩次反轉可以把最大的烙餅翻轉到最下面,最多需要把上面的n-1,
個烙餅一次翻轉兩次。至多需要2(n-1)次翻轉就可以把所有烙餅排好序。
因為第二小的烙餅排好的時候,最小的烙餅已經在最上面了(參見冒泡)。
改進:假如這坨烙餅中幾個不同部分相對有序,我們先把小些的烙餅反轉,比每次翻轉最大的烙餅要快。
考慮每次翻轉的時候,把原本應該相鄰的烙餅換到一起,等所有烙餅都換到一起後,就完成排序了。
每次反轉最大的烙餅實際上是:把最大的和次最大的交換到一起。
分析演算法的主要流程:
設定了烙餅組,當前組,交換組,最終交換組,個數,最大次數,搜尋次數
1原始資料賦給烙餅組,交換組,個數->最大數
2搜尋:估算最小交換次數(檢驗相鄰位置烙餅大小是否相鄰),檢驗是否超過最大次數,檢驗是否已經排好序->檢驗是否小於最大次數->交換組賦給
最終交換組
遞迴翻**從小向大翻,先逆置,在設定交換組的第幾步為第幾張餅。遞迴搜尋,再逆置(?為什麼)
輸入:10
3 2 1 6 5 4 9 8 7 0
輸出:4 8 6 8 4 9
1721266*/
/*關鍵:
1 考慮每次翻轉的時候,把原本應該相鄰的烙餅換到一起,等所有烙餅都換到一起後,就完成排序了。
每次反轉最大的烙餅實際上是:把最大的和次最大的交換到一起。
2 搜尋:估算最小交換次數(檢驗相鄰位置烙餅大小是否相鄰),檢驗是否超過最大次數,檢驗是否已經排好序->檢驗是否小於最大次數->交換組賦給
最終交換組
遞迴翻**從小向大翻,先逆置,在設定交換組的第幾步為第幾張餅。遞迴搜尋,再逆置(?為什麼)
3 int iminsearchtimes = lowerbound(_pcurcakearr,_icakesize);//對當前陣列,判定最少的交換次數。
//在到達當前烙餅狀態之前,我們已經翻轉了step次,iminsearchtimes是我們至少還需要翻轉多少次才能成功
//iminsearchtimes越大,_imaxswaptimes越小,越容易剪枝。總結:上界越小,下界越大,剪枝越多
if(istep + iminsearchtimes > _imaxswaptimes)//如果已經搜尋的次數加上最少搜尋次數仍大於最大搜尋次數
//說明不符合要求,直接退出
4 if(issorted(_pcurcakearr,_icakesize))//遞迴出口,判斷當前烙餅組是否已經排好序了,把成員變數作為形參傳遞,難道是為了防止多執行緒的髒讀?
;templatecakesort::cakesort()
//cakesort::cakesort()
templatecakesort::~cakesort()
//cakesort::~cakesort()
//if(_pcurcakearr)
// //if(_preversearr)
// //if(_pswaparr)
//}templatevoid cakesort::run(int* pcakearr,int icakesize)
//void cakesort::run(int* pcakearr,int icakesize)
templatevoid cakesort::init(int* pcakearr,int icakesize)
//void cakesort::init(int* pcakearr,int icakesize)
_imaxswaptimes = upperbound(_icakesize);
//_pswaparr = new int[_imaxswaptimes + 1];//初始化交換結果陣列,交換結果次數等於最大次數加1?
_pswaparr.reset(new int[_imaxswaptimes + 1]);
//_preversearr = new int[_imaxswaptimes];
_preversearr.reset(new int[_imaxswaptimes]);
//assert(_pswaparr && _preversearr);
}templateint cakesort::upperbound(int icakesize)//最多交換次數為2*n
//int cakesort::upperbound(int icakesize)
templatevoid cakesort::search(int istep)
//void cakesort::search(int istep)
if(issorted(_pcurcakearr,_icakesize))//遞迴出口,判斷當前烙餅組是否已經排好序了,把成員變數作為形參傳遞,難道是為了防止多執行緒的髒讀?
}return;//注意,這裡要加return,否則就多搜尋了無用功了。都已經超出最大次數了,顯然是剪枝了
} for(int i = 1 ; i < _icakesize ; i++)//遞迴主體,從小到下依次反轉 }
//int cakesort::lowerbound(int* parrcake,int icakesize)
templateint cakesort::lowerbound(t parrcake,int icakesize)
//int cakesort::lowerbound(ptrarr parrcake,int icakesize)
else
}return iret;
}//bool cakesort::issorted(int* parrcake,int icakesize)
templatebool cakesort::issorted(t parrcake,int icakesize)
//bool cakesort::issorted(ptrarr parrcake,int icakesize)
} return true;
}templatevoid cakesort::output()//輸出具體反轉次數
//void cakesort::output()
printf("\nsearch times:%d\n",_isearchtimes);
printf("swap times:%d\n",_imaxswaptimes);
}templatevoid cakesort::reverse(int ibeg,int iend)
//void cakesort::reverse(int ibeg,int iend)
}void process()
cakesortcakesort;
cakesort.run(iarr,n);
cakesort.output(); }}
int main(int argc,char* argv)
程式設計之美1 3 一摞烙餅的排序
程式設計之美 讀書筆記 1.3 一摞烙餅的排序 問題 星期五的晚上,一幫同事在希格瑪大廈附近的 硬碟酒吧 多喝了幾杯。程式設計師多喝了幾杯之後談什麼呢?自然是演算法問題。有個同事說 我以前在餐館打工,顧客經常點非常多的烙餅。店裡的餅大小不一,我習慣在到達顧客飯桌前,把一摞餅按照大小次序擺好 小的在上...
程式設計之美 一摞烙餅排序
問題 星期五的晚上,一幫同事在希格瑪大廈附近的 硬碟酒吧 多喝了幾杯。程式設計師多喝了幾杯之後談什麼呢?自然是演算法問題。有個同事說 我以前在餐館打工,顧客經常點非常多的烙餅。店裡的餅大小不一,我習慣在到達顧客飯桌前,把一摞餅按照大小次序擺好 小的在上面,大的在下面。由於我乙隻手托著盤子,只好用另乙...
程式設計之美1 3 一摞烙餅的排序(Python)
問題 星期五的晚上,一幫同事在希格瑪大廈附近的 硬碟酒吧 多喝了幾杯。程式設計師多喝了幾杯之後談什麼呢?自然是演算法問題。有個同事說 我以前在餐館打工,顧客經常點非常多的烙餅。店裡的餅大小不一,我習慣在到達顧客飯桌前,把一摞餅按照大小次序擺好 小的在上面,大的在下面。由於我乙隻手托著盤子,只好用另乙...