求解数组中最大最小元素的几种优化方法

问题描述

给定一个一维数组,同时找到最大最小的元素,并给出优化方法

解法一:常规解法(O(n))

思路:遍历一遍一维数组,一次比较确定最大值和最小值。

代码实现:
#include<stdio.h>
#include<assert.h>

void Search_Op(int arr[], int len, int *out_min, int *out_max)
{
    assert(len > 0);//数组长度必然是大于0的
    int min = arr[0];
    int max = arr[0];
    for (int i = 1; i < len; i++)
    {
        if (arr[i] < min)
        {
            min = arr[i];
        }
        if (arr[i] > max )
        {
            max = arr[i];
        }
    }
    *out_min = min;//利用地址建立联系,改变函数外部的变量值
    *out_max = max;
}
int main()
{
    int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    size_t len = sizeof(arr) / sizeof(arr[0]);
    int min = 0;
    int max = 0;
    Search_Op(arr, len, &min, &max);
    printf("min=%d,max=%d", min, max);
    return 0;
}

假设数组的长度为n,则该算法的时间复杂度为O(n),确定最大值的比较次数为n-1次,确定最小值的比较次数也为n-1次,总共比较次数为2(n-1)。

解法二:优化(1)

思路:最小值的取值范围肯定是小于等于最大值时,也就是min<=max。那我们可以考虑到如果解法一中判断arr[i] < min 成立的话,就会有arr[i] < min<=max 成立。此时,判断arr[i] > max 是不可能成立的,那么这种优化是不是可以减少n-1的比较次数呢?

代码实现:

void Search_Op1(int arr[], int len, int *out_min, int *out_max)
{
    assert(len > 0);
    int min = arr[0];
    int max = arr[0];
    for (int i = 1; i < len; i++)
    {
        if (arr[i] < min)
        {
            min = arr[i];
        }
        else if (arr[i] > max)
        {
            max = arr[i];
        }
        //else 相等情况
    }
    *out_min = min;
    *out_max = max;
}

优化一最好的情况下,元素呈递减规律,只要执行第一个判断if (arr[i] < min) ,比较n-1次;最坏的情况元素递增规律,和解法一比较次数相同。

解法二:优化(2)

思路:既然我们可以一个一个元素遍历处理,那我们也可以对一对元素进行遍历。

代码实现:

void Search_Op2(int arr[], int len, int *out_min, int *out_max)
{
    assert(len > 0);
    if (1 == len)//处理数组中只有一个元素的情况
    {
        *out_min = arr[0];
        *out_max = arr[0];
        return;
    }
    int max, min;
    if (arr[0] < arr[1])//确定第一对的最大值和最小值
    {
        min = arr[0];
        max = arr[1];
    }
    else
    {
        min = arr[1];
        max = arr[0];
    }
    int i;
    for (i = 2; i < len - 1; i += 2)//按对循环比较
    {
        if (arr[i] < arr[i + 1])
        {
            if (arr[i] < min)
            {
                min = arr[i];
            }
            if (arr[i + 1]>max)
            {
                max = arr[i + 1];
            }
        }
        else
        {
            if (arr[i + 1] < min)
            {
                min = arr[i + 1];
            }
            if (arr[i] > max)
            {
                max = arr[i];
            }
        }
    }
    if (i != len)//如果是奇数,剩最后一个元素比较处理
    {
        if (arr[i] < min)
        {
            min = arr[i];
        }
        else if (arr[i] > max)
        {
            max = arr[i];
        }
        //else 相等情况
    }
    *out_min = min;
    *out_max = max;
}

优化二分两种情况:数组长度为偶数或者是奇数。当为偶数时,首先比较两个相连的元素,然后把较小的与min比较,较大的与max比较,每一对元素需要3次比较,一共是3(n)/2次,当为奇数时,最后剩下一个元素可能需要比较一次也可能是两次,所以总的次数为3(n)+1/2或者3(n)+2/2。

解法二:优化(3)

思路:利用递归的方法大事化小,分三种情况处理:有一个元素时,有两个元素时,有三个或三个以上(分两块递归查找)

代码实现:

void Search_Op3_D(int arr[], int len, int *out_min, int *out_max)
{
    assert(len > 0);
    if (1 == len)//(1)递归结束条件
    {
        *out_min = arr[0];
        *out_max = arr[0];
    }
    else if (len == 2)//(2)递归结束条件
    {
        if (arr[0] < arr[1])
        {
            *out_min = arr[0];
            *out_max = arr[1];
        }
        else
        {
            *out_min = arr[1];
            *out_max = arr[0];
        }
    }
    else//(3)
    {
        int mid = len / 2;
        int min1, max1, min2, max2;
        //递归查找第一部分min和max
        Search_Op3_D(arr, mid, &min1, &max1);
        //递归查找第二部分min和max
        Search_Op3_D(arr+mid, len-mid, &min2, &max2);
        //确定最终的min和max
        *out_min = min1 < min2 ? min1 : min2;
        *out_max = max1 > max2 ? max1 : max2;
    }
}

猜你喜欢

转载自blog.csdn.net/hansionz/article/details/81199321