求出数组的最大值和次大值

求数组的最大值相对来说是比较简单,只需要遍历一遍数组,不断更新数组的最大值,直到遍历完成。自然语言描述:

 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,但是后来发现程序还不够完美,当测试最大值就恰好就是第一个值时,结果次大值也是最大值,显然不满足算法的确定性原则,于是在原来基础上改进,先确定两组索引,从第三个元素开始比较,结果符合预期了。

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值