34. 在序列中查找最大值(递归手法)

一. 问题

给定一组序列,找出其中的最大元素。

二. 实例分析

1.循环手法

(1)思路

给定一组序列, data = (1, 3, 4, 9, 12, 3)。我们一眼看出,最大值是 12 ,但是计算机并不能一眼看出。我们用一个变量来保存最大值,并将序列中的每个元素与之比较,如果大于这个最大值,就将它赋值给最大值,否则不用理会,继续处理下一个。

(2)代码实现

 1 int find_max(const vector<int>& data) {
 2     const int MIN = numeric_limits<int>::min();
 3     int max = MIN;
 4 
 5     for (auto& x : data) {
 6         if (x > max) {
 7             max = x;
 8         }
 9     }
10 
11     return max;
12 }

不难看出,算法的时间复杂度为O(n)。只需要查看一遍序列,就能够找到最大值(要找最小值也是同理)。但是如果需要多次查找,这样就不划算了,每次都要查看所有的元素,显然做了很多的无用功。在这种情况下,我们应该先将序列排序,然后就能直接找到对应元素。排序的时间复杂度是O(nlogn),因为我们用的是快速排序。

(3)算法正确性证明

最开始,令 max 是小于元素中所有序列的值,那么第一次循环, max 的值必将是序列首元素的值。在前 n 次迭代中,max 的值也是这 n 个元素中的最大值,那么到序列末尾,结束循环以后,max 的值必将保存的是整个序列的最大值。(此处证明用的是数学归纳法)

 

2. 递归手法

(1)思路

当序列只有一个元素时,最大值就是这个元素,这就是基准情况。如果序列有多个元素,我们需要逐步削减,直到元素个数为 1(不是真的削减,只是将参数减少 1 而已),这是层层深入。等到序列只有 1 个元素时,我们就可以将该元素返回,然后与上一个元素作比较,找到一个最大的,这是层层返回。

(2)代码实现

1 int find_max_recursive(const vector<int>& data, int n) {
2     if (n == 1) {
3         return data[n];
4     }
5 
6     return max(find_max_recursive(data, n- 1), data[n - 1]);
7 }

(3)算法正确性证明

现在我们分析一下这段代码。不难看出,第 2-4 行就是基准情况,只有一个元素时直接返回结果。第 6 行就是返回并进行比较,选出一个最大的元素。先把最后一个元素留下,因此是 data[ n - 1 ],再进行层层深入,传入的还是那个序列,只不过大小少了一个(将最后一个元素排除在外)。这样返回的时候,是第一个元素和第二个元素比较,选出一个大的,然后依次向后推。最后一次是第 n - 1 个元素和第 n 个元素比较,留下一个大的,那么算法结束以后,得到的结果必将是整个序列当中的最大值。

posted @ 2020-08-23 06:10  Hello_Nolan  阅读(907)  评论(0编辑  收藏  举报