基础算法(快排、归并、二分)

 1、什么是算法

  1、首先我们从定义上来看,算法是为了解决某类问题而规定的一个有限长的操作序列。我们看出来这个定义好像我们也看的不是很懂说的直白一点,就是高效率速度更快,时间复杂度更小。(直白的说就是用的时间最短,调用函数的次数最少)。

  2、那我们要写一个算法要怎么评价这个算法是好还是坏呢?①首先我们要保证算法的正确性,且要在有限的时间内完成。②可读性:我们写一个算法不仅要写给我们看,而且要给别人看要让人家看的懂就是简洁易懂。③高效性:高效性包括时间复杂度和空间复杂度。这2个东西是相对的,我们无法评价这2个那个更好,我们只要取最好的情况就可以了,时间和空间这2个是相互矛盾的。

注意:我们要写算法如果是竞赛题目之类的东西,我们追求高效和速度,我们就不要去考虑空间的问题。(也不是说不要考虑,是少考虑这不是绝对的)。

 2、基础算法

  接下来我们就来看基础算法(快排、归并、二分)

        首先,我们先来分析下题目是给一个数据进行排序,让我们想想如果我们用暴力的做法是怎么做呢?我们肯定是先找第一个数然后把它存储在一个临时值里面然后遍历整个数据进行比较。然后把比它还小的数存在里面。最后遍历完全部数据后找到最小的值。然后再次遍历重复循环这种操作。我们发现这种操作,调用函数的次数非常频繁。那我们就要想办法让它变的不用怎么麻烦。接下来我们进入正题。

1、快速排序

        我们来看下快排的模板,其实快排就是运用了先排序,在递归的原理。其实这里我们可以把l和r看作一个指针l代表的是数组的头,r代表数组的尾部。r还在l的右边的时候,我们就继续移动这个指针。当然我们还要找一个数来划分r和l交换的条件。我们要找一个比较的数。我们这就那k来例子。(找了一个中间值)比它小的数在左边,比它大的在右边。

void sort(int math[],int x,int y)
{
    if(x>=y)return;//当2个指针相交(也就是r在l的左边)或者指向同一个位置的位置的时候
    int l = x-1; int r=y+1;int k=math[(x+y+1)/2];//注意边界问题 不要随机更换
    while(r>l)
    {
    do l++;while(math[l]<k);//这个就是判断条件如果比这个比较值大就停止移动
    do r--;while(math[r]>k);//比这个值小就停止移动
    if(r>l)//进行判断当r>l也就是r指针还在l指针右边时我们还要继续移动但是这个时候我们要交换位置让小的在左边,大的在右边。
    {
    int tem=0;
    tem=math[r];
    math[r]=math[l];
    math[l]=tem;}
    }
    sort(math,x,l-1);sort(math,l,y);//先排序再递归 注意边界问题
}

注意:这里有个非常严重的边界问题,如果边界设置不好就会导致超时,一个是k,一个是最下面2个sort函数中的边界取值。当你的k如果不+1那么你下面的l-1就应当换成r,l换成r+1。如果不换要造成死循环。

2、归并排序

        这个跟快排很像,快排是先排序在递归,而归并排序就运用了先递归在排序的思想。这边我们引入了一个新的数组来存放排序的值,在函数的最后,我们把存储的临时值在返还到原来的函数中。我们也可以把这个归并看作2个指针的思想但是要注意我们把它分成了2个数组。(一个指针对应着一个数组!!!!!!!!)2个指针都在自己的数组里指向自己数组的一个数谁小就存在临时数组里面,然后就移动到下一位。

void add_sort(int sort[],int x,int y)
{
    if(x>=y)return;//当mid=0时停止循环也就是当x和y只有2个数或者1个数时停止循环
    int temp[N];
    int mid=(x+y)/2;//缩小mid值直到只有2个数为止
    add_sort(sort,x,mid);add_sort(sort,mid+1,y);//先递归再排序
    int k=0;//k每次都要进行初始化
    int i=x;int j=mid+1;
    while(i<=mid&&j<=y)//相当于2个指针指向2个不同的数组执行比较
    {if(sort[i]>sort[j]) temp[k++]=sort[j++];
    else temp[k++]=sort[i++];}
    while(i<=mid)temp[k++]=sort[i++];
    while(j<=y)  temp[k++]=sort[j++];
    for(int l=0;l<k;l++)
    sort[x+l]=temp[l];
}

3、二分查找法

        

        我感觉二分查找是比较好的一个查找方法因为它直接找中间值然后就可以划分出范围。我们先来看代码也就是模板。我们要做这道题就要先确定

        1、确定mid的位置。

        2、确定它的范围。((只要r>l)我们就继续遍历循环缩小mid的范围直到一直找到所找的数)

1、基于整数
#include<stdio.h>
#define N 100000
int main()
{
    int n,m,i,l,r,k;int find[N];int mid;
    scanf("%d",&n);
    scanf("%d",&m);
    for(i=0;i<n;i++)
    scanf("%d",&find[i]);
    while(m--)
    {scanf("%d",&k);l=0;r=n-1;
    while(r>l){mid=(l+r)/2;if(find[mid]>=k)r=mid;//注意边界问题
    else l=mid+1;}
    if(find[r]!=k){printf("-1 -1\n");}
    else{printf("%d ",l);l=0;r=n-1;
    while(r>l){mid=(l+r+1)/2;if(find[mid]<=k)l=mid;else r=mid-1;}printf("%d\n",l);}}
   //边界l为mid时要注意mid要+1
}

  这里我们要注意2种情况

mid的范围这个就是我们要考虑的边界问题。
1、当我们mid=l+r时我们的r=mid l=mid+1.
2、当我们mid=l+r+1时,l=mid,r=mid-1.
2、基于浮点数

当然我们也有浮点数二分也就是可以求开根立方根都可以我们这以开立方根为例子。

#include<stdio.h>
int main()
{
    double n;
    scanf("%lf",&n);
    double r=10000,l=-10000;
    while(r-l>1e-8)//主要思想就是r-l这个数越小表示算出来的数越精准
    {
        double mid=(l+r)/2;
        if(mid * mid * mid>n)r=mid;
        else l=mid;}
    printf("%.6lf",l);
    
}

  • 18
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值