【经典算法】:烙饼排序

原理非常简单,看视频即可


给一个为排序的数组,你只能再改对该数组做如下操作: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] */
05void 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] 内最大的元素的下标 */
19int 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 
28int 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/* 打印数组 */
46void printArray(int arr[], int n)
47{
48    for (int i = 0; i < n; ++i)
49        printf("%d ", arr[i]);
50}
51 
52int 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}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值