写在前面的话

今天我介绍的主题是贪心算法。这是相对比较容易的一种算法。我这里不给出定义,因为大家可以自行网络搜索。咱们直接看例子。

贪心算法,如果不用手动证明一个问题的数学性质的话,其实是比较简单的。看这样一个例子:假设有一个背包,其最大容量是50KG,现在有各种不同价值的液体,比方说,有水,其价值是10 每千克,共100KG;酒精,其价值是20 每千克,共30KG;有油,价值25每千克,共30KG。问什么样的方案才能使得背包里装的液体的总价值最大?显然,这是一道小学生都会的题目,拣贵的装呗。这谁不会。那就是把30KG油先装了,因为油最贵嘛,剩下20KG的容量装酒精,因为酒精比水贵。

好,那么,这个思维过程就是贪心:每一阶段做决策都找出当前条件下的最优解。当然这个问题,这种解法的正确性显而易见,贪心类的问题最难的地方在于正确性无法证明。这个我们先不管。毕竟我们不是在做算法研究,我们只要能用贪心去解决具体的编程问题就行了。

再看一个简单的例子。

在商店找零,比如说,售货员要找给你37块钱,那什么样的方案才是找钱的张数最少的方案呢?肯定是找回的零钱面值越大,最后的张数越少。所以我们可以使用贪心的方法来解决这个问题。先找一张20的,如果再找一张20的,那就超过37了,这不行,所以就再找一张10块的,然后是5块的和两张一块的。最终的方案就得到了,这也是一次典型的贪心计算方案。

排序

在贪心的思想的指导下,也设计了一种排序算法,这种算法被称为选择排序。排序的思想很简单。既然我的目标是把一堆数字从小到大排,那么我按阶段解决这个问题不就好了么?第一步找到最小的那个数把它放到第一位,第二步在剩下的所有数里再找最小的,把它放到第二位,依次类推。

public class ChooseSort implements  Sorter {
    public void sort(int[] arr) {
        int pivot, pos = -1;

        for (int i = 0; i < arr.length; i++) {
            pivot = Integer.MAX_VALUE;
            for (int j = i; j < arr.length; j++) {
                if (pivot > arr[j]) {
                    pivot = arr[j];
                    pos = j;
                }
            }
            arr[pos] = arr[i];
            arr[i] = pivot;
        }
    }
}

我们从第一趟迭***始看,这时 i 为0,内部的那个循环,就是从 0 到数组的末尾找到数组中的最小值。然后把这个最小值与第 i 位,这里就是第 0 位,交换。这样,我们就把第一小的数放到数组的第0位了。

第二趟迭代呢,就把从第一位到数组末尾最小的数放到了数组的第1位。

这个过程不断地进行,直到完成 n 趟迭代。明显的,选择排序的时间复杂度是O(n^2)。

看,从算法设计的角度来看排序的问题,是不是感觉排序问题一下子就有章可循了。