减小
增大
默认
护眼
夜间
默认
数组最大值和最小值
所谓“找数组中的最大值和最小值”问题,是指在长度为 n 的数字序列中找到最大的数和最小的数。
普通算法
解决这个问题,我们最常想到的算法是:将序列中首个数字分别赋值给两个变量 max 和 min,从第 2 个数字开始遍历整个序列,如果遍历到的数字比 max 大,将其赋值给 max,如果遍历到数字比 min 小,将其赋值给 min。整个序列遍历完成后,max 记录的是序列中最大的数字,min 记录的是序列中最小的数字。如下为上述算法对应的伪代码:
输入 arr[n] // 输入 n 个数字
max <- arr[1] , min <- arr[1] // 将第 1 个数字分别赋值给 max(表示最大值)和 min(表示最小值)
for i<- 2 to n: // 从第 2 个数字开始遍历
if arr[i]>max: // 如果 max 小于遍历到的数字,则更新 max 的值
max <- arr[i]
if arr[i]<min: // 如果 min 小于遍历到的数字,则更新 min 的值
min <- arr[i]
print max , min // 输出 max 和 min 的值
为了找到最大值和最小值,该算法实现过程中进行了大量的数值比较操作,对于一个长度为 n 的序列来说,数字间的比较操作共进行了
2*n-2次。相比该算法,采用“分而治之”的思想解决这个问题,比较次数将大大减少。
分治算法
如下是采用分治算法解决“找数组中最大值和最小值”的伪代码:
输入 arr[n] // 输入 n 个数字
max_min(x , y) : // 设计一个递归函数,[x , y] 用来限定查找最大数和最小数的范围
if y-x ≤ 1 : // 如果 y-x 的值小于等于 1,则比较 arr[x] 和 arr[y] 的值,大的就是最大值,小的就是最小值
return max(arr[x] , arr[y]) , min(arr[x] , arr[y])
else :
max1 , min1 = max_min (x , ⌊(x+y)/2⌋ ) // 将 [x , y] 区域划分为 [x , ⌊(x+y)/2⌋ ] 和 [ ⌊(x+y)/2+1⌋ , y] 两个区域,分别求出两个区域内各自的最大值和最小值
max2 , min2 = max_min( ⌊(x+y)/2+1⌋ , y)
return max(max1 , max2) , min(min1 , min2) // 比较两个区域的最大值和最小值,最终找出 [x , y] 中的最大值和最小值
- 将 arr 序列中的 [x , y] 区域等分为 [x , ⌊(x+y)/2⌋ ] 和 [ ⌊(x+y)/2+1⌋ , y] 这两个小区域,各自找到两个小区域内的最大值和最小值,最终通过比较两个最大值和两个最小值,即可找出 [x , y] 整个区域内的最大值和最小值;
- 对于 [x , ⌊(x+y)/2⌋ ] 区域,继续划分,直至各个小区域内的数字个数小于等于 2;同样 [ ⌊(x+y)/2+1⌋ , y] 区域也做同样的处理。
- 通过第 2 步,所有的小区域内的数字个数都小于等于 2,比较 2 个数字的大小是非常容易实现的,最终即可求出整个 [x , y] 区域内的最大值和最小值。
以 [1,3,5,4,2,6,0,9] 为例,下图给您演示了分治算法“找数组中最大值”的过程:

图 1 分治法找最大值
如图所示,借助“分而治之”的思想,我们将“求 [1,3,5,4,2,6,0,9] 中最大值和最小值”的问题,划分成了分别“求 [1 , 3]、[5 , 4]、[2 , 6]、[0 , 9] 中最大值和最小值”的问题, 极大地简化了问题的难度。
结合图 1,如下为分治法实现“找序列中最大值”的 C 语言程序:相比普通算法,采用分治法解决此问题只需要比较
3*n/2-2次(由于涉及很复杂的数学推理过程,这里不做详细解释)。
#include <stdio.h>
//自定义函数,其中 [left,right] 表示 arr 数组中查找最大值的范围
int get_max(int arr[8], int left, int right) {
int max1 = 0, max2 = 0, middle = 0;
//如果数组不存在
if (arr == NULL) {
return -1;
}
//如果查找范围中仅有一个数字
if (right - left == 0) {
return arr[left];
}
//如果查找范围中仅有 2 个数字,则直接比较即可
if (right - left <= 1) {
if (arr[left] >= arr[right]) {
return arr[left];
}
return arr[right];
}
//等量划分成 2 个区域
middle = (right - left) / 2 + left;
//得到左侧区域中的最大值
max1 = get_max(arr, left, middle);
//得到右侧区域中的最大值
max2 = get_max(arr, middle + 1, right);
//比较左、右两侧的最大值,找到 [left,right] 整个区域的最大值
if (max1 >= max2) {
return max1;
}
else {
return max2;
}
}
int main() {
int arr[8] = { 1,3,5,4,2,6,0,9 };
int max = get_max(arr, 0, 7);
printf("最大值:%d", max);
return 0;
}
如下为分治法实现“找序列中最大值”的 Java 程序:
public class Demo {
public static int get_max(int [] arr,int left,int right) {
//如果数组不存在或者数组内没有元素
if (arr == null || arr.length == 0) {
return 0;
}
//如果查找范围中仅有 2 个数字,则直接比较即可
if(right - left <=1) {
if(arr[left] >= arr[right]) {
return arr[left];
}
return arr[right];
}
//等量划分成 2 个区域
int middle = (right-left)/2 + left;
int max_left = get_max(arr,left,middle);
int max_right = get_max(arr,middle+1,right);
if(max_left >= max_right) {
return max_left;
}else {
return max_right;
}
}
public static void main(String[] args) {
int [] arr = new int[] { 1,3,5,4,2,6,0,9 };
int max = get_max(arr,0,7);
System.out.println("最大值:"+max);
}
}
如下为分治法实现“求序列中最大值”的 Python 程序:
def get_max(arr,left,right):
#列表中没有数据
if len(arr) == 0:
return 0
#如果查找范围中仅有 2 个数字,则直接比较即可
if right - left <= 1:
if arr[left] >= arr[right]:
return arr[left]
return arr[right]
#等量划分成 2 个区域
middle = int((right-left)/2 + left)
max1 = get_max(arr,left,middle)
max2 = get_max(arr,middle+1,right)
if max1 >= max2:
return max1
else:
return max2
arr = [1,3,5,4,2,6,0,9]
max = get_max(arr,0,7)
print("最大值:",max,sep='')
以上代码的输出结果均为:
最大值:9
读者可根据伪代码以及以上给出的实现代码,尝试编写出用分治法实现“找数组中最小值”的代码。
ICP备案:
公安联网备案: