分治法求数组最大最小数

又是一年好时光要过去,作为刚刚报名蓝桥杯的我开始学习一些算法知识,从现在开始我要来一些算法的博客,希望积少成多,在明年4月份的时候可以积累到一定的水平.同时也感谢韦佳栋和杜帅两个基友.不然作为非计算机院的我都不知道还有一个比赛叫蓝桥杯~~.希望可以跟他们好好学习,取得进步~

昨天学习了分治策略.也是算法之中比较简单但却重要的思想了~

结合书上和网上,听课内容:

分治算法由两部分组成:

(1).分:递归解决较小的问题(基本情况除外)

(2)治:从子问题构建原问题的解

要注意的是子问题一般是不想交的.

如果把分治形象化那么就可以看作是一颗树,根节点是总问题,而他的子节点是大问题的分解,一个父节点的子节点个数不限.


开始我们今天的问题:求一个数组的最大和最小元素.

思路:设置min和max指针指向最大最小元素,开始时一直分治,直到数组左和右的差小于等于1的一部分,分治后所有部分可以组成原来的数组,让min指向较小元素,max指向较大元素.

每个最小单位都比较一遍.就得到了max指向的最大值和min指向的最小值

例如  1  8  7  6  5       5个元素

经过分治策略开始是了

1 8

7 6 5两部分

然后 7 6 5在分治

变为7 6和5两部分.

最后变成三部分

这时开始判断.先让min指向的元素和1 8中较小元素1比较,取小的值.

max指向的元素1 8中较大元素8比较,取大的值.

在经过min.max在剩余两部分中的比较.得出最大和最小值


再给出代码前,说一些自己的心得体会~这个问题是昨天上课讲的一道题,通过这道题真真明白了眼过千变不如手动一遍,上课是听懂了.课下我又仔细的上网看了研究了一下,但是今天敲出来还是有一些问题,我觉得一些问题是值得注意的

(1)max和min指针指向的问题,max和min初始化是不能直接等于数组的一个值的,因为并不知道值的地址,如果单纯的要min = &a[0],那你就错了,因为当你改变*min时a[0]也就被改变了,所以我的方法是用两个临时变量来存储a[0],让min和max分别指向临时变量1,2

(2).返回的问题,要注意是最小部分并且给*max和*min赋值后一定要return ;因为不返回的话会无限循环

(3).越界问题:我现在依然有这个毛病,写出的代码经常越界访问,希望大家不要犯我的错误

#include <stdio.h>

//分治发求最大值最小值,先把数组的一个元素的拷贝为两份,让*min和*max分别指向.
//使用分治的思想,拆分成最小块为1或2个元素,然后让*min与小的数比较,*max与大的
//数比较,如果小的数比*min还要小,则*min存小的数,*max亦然.
#define MAX(a,b) (a > b ? a : b)
#define MIN(a,b) (a < b ? a : b)
void get_min_max(int a[],int *max,int *min,int left,int right);

void get_min_max(int a[],int *max,int *min,int left,int right)
{
    if(a == NULL || left > right){
        return ;
    }
    //一个元素
    if(left == right){
        *max = MAX(*max,a[left]);
        *min = MIN(*min,a[left]);
        return ;
    }
    //两个元素,*max和较大元素比较,*min和较小元素比较
    else if(right-left == 1){
        if(a[right] > a[left]){
            *max = MAX(*max,a[right]);
            *min = MIN(*min,a[left]);
            return ;
        }
        else{
            *max = MAX(*max,a[left]);
            *min = MIN(*min,a[right]);
            return ;
        }
    }
    get_min_max(a,max,min,left,(left+right)/2);
    get_min_max(a,max,min,(left+right)/2+1,right);
}
int main(int argc,char *argv[])
{
    int a[] = {1,9,4,7,3,8,4};
    int temp1 = a[0];
    int temp2 = a[0];
    int *max = &temp1;
    int *min = &temp2;
    get_min_max(a,max,min,0,sizeof(a)/sizeof(a[0])-1);
    printf("max = %d  min = %d\n",*max,*min);
    return 0;
}


下面说一下时间复杂度:

因为如果是一个最小部分是两个元素,那么就需要2次判断

是一个元素就1次判断就好了.

所以平均时间复杂度应该是O(3/2n)

网上有的是O(3/2n-2),我觉得我的是对的,比如数组有三个元素,那么我判断是2+1+1 = 4次,3/2 * 3 = 4.

要是普通算法的话,大的数需要遍历一遍n-1

小的依旧遍历一遍n-1

时间复杂度O(2n-2)

所以分治是吃香的~~

  • 6
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值