【經典演算法】:烙餅排序
原理非常簡單,看視訊即可
給一個為排序的陣列,你只能再改對該陣列做如下操作:flip(arr, i): 將陣列arr[0...i]進行逆置。如何對該陣列進行排序?
這個問題在程式設計之美一書也有提及:
星期五的晚上,一幫同事在希格瑪大廈附近的“硬碟酒吧”多喝了幾杯。程式設計師多喝了幾杯之後談什麼呢?自然是演算法問題。有個同事說:“我以前在餐館打工,顧客經常點非常多的烙餅。店裡的餅大小不一,我習慣在到達顧客飯桌前,把一摞餅按照大小次序擺好——小的在上面,大的在下面。由於我一隻手託著盤子,只好用另一隻手,一次抓住最上面的幾塊餅,把它們上下顛倒個個兒,反覆幾次之後,這摞烙餅就排好序了。我後來想,這實際上是個有趣的排序問題:假設有n塊大小不一的烙餅,那最少要翻幾次,才能達到最後大小有序的結果呢?”
你能否寫出一個程式,對於n塊大小不一的烙餅,輸出最優化的翻餅過程呢?
關於這個問題的最優化解法是比較困難的,大家可以參考書上的解法。
這裡只給出直接的解法。演算法思想類似選擇排序,每次找到一個最大的元素,對其進行兩次 flip操作,可將最大的放在最後面,讓後縮小陣列的範圍。因此最大需要 2*(n-1)次flip操作。
可以通過下面的視訊理解這個操作過程:
C++程式碼實現如下:
01 |
#include <stdlib.h> |
02 |
#include <stdio.h> |
03 |
04 |
/* 逆置陣列 arr[0..i] */ |
05 |
void
flip( int
arr[], int
i) |
06 |
{ |
07 |
int
temp, start = 0; |
08 |
while
(start < i) |
09 |
{ |
10 |
temp = arr[start]; |
11 |
arr[start] = arr[i]; |
12 |
arr[i] = temp; |
13 |
start++; |
14 |
i--; |
15 |
} |
16 |
} |
17 |
18 |
/* 找出 arr[0..n-1] 內最大的元素的下標 */ |
19 |
int
findMax( int
arr[], int
n) |
20 |
{ |
21 |
int
mi, i; |
22 |
for
(mi = 0, i = 0; i < n; ++i) |
23 |
if
(arr[i] > arr[mi]) |
24 |
mi = i; |
25 |
return
mi; |
26 |
} |
27 |
28 |
int
pancakeSort( int
*arr, int
n) |
29 |
{ |
30 |
// 每次翻轉可以定位一個做大的元素 |
31 |
for
( int
curr_size = n; curr_size > 1; --curr_size) |
32 |
{ |
33 |
// 在 arr[0..curr_size-1] 找到最大的元素 |
34 |
int
mi = findMax(arr, curr_size); |
35 |
36 |
//記性兩次flip操作,將最大的元素翻轉到最後 |
37 |
if
(mi != curr_size-1) |
38 |
{ |
39 |
flip(arr, mi); |
40 |
flip(arr, curr_size-1); |
41 |
} |
42 |
} |
43 |
} |
44 |
45 |
/* 列印陣列 */ |
46 |
void
printArray( int
arr[], int
n) |
47 |
{ |
48 |
for
( int
i = 0; i < n; ++i) |
49 |
printf ( "%d " , arr[i]); |
50 |
} |
51 |
52 |
int
main() |
53 |
{ |
54 |
int
arr[] = {23, 10, 20, 11, 12, 6, 7}; |
55 |
int
n = sizeof (arr)/ sizeof (arr[0]); |
56 |
57 |
pancakeSort(arr, n); |
58 |
59 |
puts ( "Sorted Array " ); |
60 |
printArray(arr, n); |
61 |
62 |
return
0; |
63 |
} |
相關推薦
【經典演算法】:烙餅排序
原理非常簡單,看視訊即可 給一個為排序的陣列,你只能再改對該陣列做如下操作:flip(arr, i): 將陣列arr[0...i]進行逆置。如何對該陣列進行排序? 這個問題在程式設計之美一書也有提及: 星期五的晚上,一幫同事在希格瑪大廈附近的“硬碟酒吧”多喝了幾杯。程式設
【經典演算法】:希爾排序的實現
希爾排序我感覺並沒有什麼用 = =因為希爾排序事實上是對插入排序的一個複雜化,在插入排序的基礎上引入了一種分組機制,所以這種排序事實上是複雜了。 並且這種排序和插入排序的實現機制非常相似,只要稍微增加
【NOJ1002】【演算法實驗一】【分治演算法】歸併排序
1002.歸併排序 時限:1000ms 記憶體限制:10000K 總時限:3000ms 描述 給定一個數列,用歸併排序演算法把它排成升序。 輸入 第一行是一個整數n(n不大於10000),表示要排序的數的個數; 下面一行是用空格隔開的n個整數。 輸出
【C++演算法】選擇排序
#include <iostream> using namespace std; void myswap2(int &a, int &b) { int temp = b;
【經典演算法】:BFS與DFS
寫在最前的三點: 1、所謂圖的遍歷就是按照某種次序訪問圖的每一頂點一次僅且一次。 2、實現bfs和dfs都需要解決的一個問題就是如何儲存圖。一般有兩種方法:鄰接矩陣和鄰接表。這裡為簡單起 見,均採用鄰接矩陣儲存,說白了也就是二維陣列。 3、本文章的小測試部分的測試例項
【經典演算法】:如何判斷整數和浮點數是否相等
這個問題來自於我解決一個叫做五猴分桃的問題 其中會出現這麼一些資料 我需要在右邊第二欄資料裡面找到整數型的資料,比如說 3121這類的資料 但是我給第二欄定義的是float型的資料,如何判斷這個float型的資料是不是整數呢? 用瞭如下方法,注意看!
【經典演算法】: 羅馬數字
關於羅馬數字,一到10可以介紹給大家一個簡單的記法 I 代表 1 V 代表 5 X 代表 10 4 9 特殊記 在 V 和 X 的左邊放一個 I 代表減去 1 thus : 4 —>
【經典演算法】:關於大小寫的轉換問題
tips: 知道一點即可,所有字元都是0-255之間的值,所以大小寫的轉換隻需要對其進行數值上面的加減運算就可以了 小寫字母的值比大寫字母的值大32 展示一個程式碼: 這個就可以把a轉換為大A,
【經典演算法】——KMP,深入講解next陣列的求解
前言 之前對kmp演算法雖然瞭解它的原理,即求出P0···Pi的最大相同前後綴長度k;但是問題在於如何求出這個最大前後綴長度呢?我覺得網上很多帖子都說的不是很清楚,總感覺沒有把那層紙戳破,後來翻看演算法導論,32章 字串匹配雖然講到了對前字尾計算的正確性,但是大量的推理證明不大好理解,沒有與程式結合
【經典演算法】:愛因斯坦臺階問題
愛因斯坦臺階問題 愛因斯坦曾經提出過這樣一道有趣的數學題:有一個長階梯,若每步上2階,最後剩下1階;若每步上3階,最後剩2階;若每步上5階,最後剩下4階;若每步上6階,最後剩5階;只有每步上7階,最後剛好一階也不剩。請問該階梯至少有多少階。 解題思路 不是
【經典演算法】:把String變為double型的方法
題目 如題,假設資料為:63.2558的string型別,如何把它變為double型 處理辦法 直接細節入手,前面先找到前置位,後面找到後置位,都是一些普通的辦法,然後把它一起加起來,最後就得到
【分治演算法】歸併排序,快速排序和漢諾塔
1介紹 分治演算法已經是本人所寫的常用算法系列的第三個了,可能只會寫這一節,對比動態規劃與貪心演算法我們來認識一下分治演算法。 從思路上來看: (1)動態規劃:多階段過程轉化為一系列單階段問題,利用各階段之間的關係,逐個求解。每一個階段的最優解是基於前一個階段的最優解。
【經典演算法】:蛇形填數,最簡單的方法了。。。
問題概述 什麼是蛇形填數,百度一下即可 解法 你能發現這裡面的數為1到 n*n; 所以寫個迴圈即可 while(count<n*n){ while(x+1&l
【經典演算法】:Dijskstra演算法與Floyd演算法
Dijkstra演算法利用的是一個經典的東西,叫做保持好的最短路徑,目的就是為了在尋找最短路徑的時候的保持最短化的過程 Floyd演算法利用的是一個經典的公式 D[I,J]>D[I,K] + D[K,J] 則 D[I J] = D[I K] + D[K J]
【經典排序演算法】八大排序對比總結
針對前面討論的八大經典排序演算法:氣泡排序、插入排序、選擇排序、堆排序、歸併排序、快速排序、希爾排序、桶排序。 關於各種什麼時間複雜度,空間複雜度的對比總結,網上一大堆,別人也總結的很好,這裡就不贅述了,這裡主要通過對大量資料進行排序測試,測試各排序演算法的執行時間,來比較
【排序演算法】選擇排序(Selection sort)
0. 說明 選擇排序(Selection sort)是一種簡單直觀的排序演算法。 它的工作原理如下。 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然後,再從剩餘未排序元素中繼續尋找最小(大)元素,然後放到已排序序列的末尾。以此類推,直到所有元素均排序完
【資料結構與演算法】插入排序
插入排序是演算法中的基礎入門和氣泡排序、選擇排序都是必要掌握的。他們都是對比排序,需要通過比較大小交換位置,進行排序。 插入排序的實現思路: 1、 從第一個元素開始,這個元素可以認為已經被排序。 2、取出下一個元素,在已排序的序列中從後往前掃描。 3、如果該元素小於小於前
【資料結構與演算法】 ---快速排序
快速排序流程: 1.從數列中挑出一個基準值 2.將所有比基準值小的擺放在基準前面,所有比基準值大的擺在後面(相同的數可以放到任一邊);在這個分割槽退出之後,該基準就處於數列的中間位置。 3.遞迴地把“基準值前面的子數列”和“基準值後面的子數列”進行排序。 下面以數列
【資料結構與演算法】------氣泡排序
學習開發一年的時間裡,很少去了解排序演算法,氣泡排序也是最開始學習的樣子,靠死記硬背,沒有引入自己的理解。 對於什麼時間複雜度和空間複雜度和穩定性也不清楚其原委,或許在程式碼方面少了幾許的天分: 氣泡排序: 氣泡排序每一輪的比較都是前面的數和後面的數進行比較,並交
【一起學習排序演算法】氣泡排序
氣泡排序 Bubble sort 本系列的文章列表和相關說明,請檢視【一起學習排序演算法】0.序言 也可以直接到github上檢視完整的文章和原始碼! 原理 先看看Wikipedia的定義: Bubble sort is a simple sorting algorithm that