求数组的最大值相对来说是比较简单,只需要遍历一遍数组,不断更新数组的最大值,直到遍历完成。自然语言描述:
1. 初始化最大值的角标
2. 遍历数组,比较当前的最大值角标的元素和遍历得到数组元素的大小;
如果数组元素大于当前最大值,更新最大值角标为遍历到的数组元素角标,
直到遍历完成
程序设计语言描述:
int getMax(int[] arr){
int max = 0; //定义最大值角标
for (int i = 0; i < arr.length; i++) { //遍历数组
if (arr[max] < arr[i]) { //比较当前最大值和遍历元素
max = i; //更新最大值角标
}
}
return arr[max];
}
分析算法,基本语句共执行n次(假设数组长度为n),时间复杂度O(n)。
如果要找出次大值,一开始先是考虑的是用2次冒泡,次大值就能找出下面是简单的程序代码
int getSubMax(int[] arr) {
for (int i = 0; i < 2; i++) { //两次冒泡
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j+1]) swap(j, j+1, arr);//交换
}
}
return arr[arr.length - 2];
}
但是要遍历数组两次,效率肯定还是不好,所以采用下面的描述:
1. 设置最大值和次大值的角标maxIndex,subMaxIndex
2. 比较头两个元素大小来初始化两个角标
3. 从第3个元素开始遍历,取数组元素arr[i],如果maxIndex<arr[i],
次大值取代最大值,subMaxIndex = maxIndex,更新最大值maxIndex = i;
反之,如果subMaxIndex<arr[i],更新次大值subMaxIndex = i;
程序语言描述:
int getSubMax(int[] arr) {
//定义最大值角标
int maxIndex = 0;
//定义次大值角标
int subMaxIndex = 0;
//比较头两个元素初始化最大,次大值得角标
if (arr[0] >= arr[1]) {
maxIndex = 0;
subMaxIndex = 1;
} else {
maxIndex = 1;
subMaxIndex = 0;
}
//注意从第三个元素开始比较
for (int i = 2; i < arr.length; i++) {
// 如果遍历到当前的数大于最大值时
if (arr[i] > arr[maxIndex]) {
// 出现新的最大值,最大值变为次大值
subMaxIndex = maxIndex;
// 新的最大值
maxIndex = i;
// 如果再次出现一个大于次大值且小于最大值的数,更新次大值
} else if (arr[i] > arr[subMaxIndex]) {
subMaxIndex = i;
}
}
return arr[subMaxIndex];
}
通过这样的比较,能同时得出最大值与次大值,而且基本语句执行的次数仅为n-2次,所以时间复杂度为O(n)。
一开始并没有加入前两个元素的比较,直接初始化两个索引都为0,但是后来发现程序还不够完美,当测试最大值就恰好就是第一个值时,结果次大值也是最大值,显然不满足算法的确定性原则,于是在原来基础上改进,先确定两组索引,从第三个元素开始比较,结果符合预期了。