【快速排序、归并排序、整数&浮点数二分查找】思路讲解及代码实现

Halo,这里是Ppeua。平时主要更新C语言,C++,数据结构算法......感兴趣就关注我吧!你定不会失望。

🌈个人主页:主页链接

🌈算法专栏:专栏链接

     现已更新完KMP算法,之后我会继续往里填充内容哒。

🌈LeetCode专栏:专栏链接 

    目前在刷初级算法的LeetBook 。若每日一题当中有力所能及的题目,也会当天做完发出

🌈代码仓库:Gitee链接

🌈点击关注=收获更多优质内容🌈

用一篇Blog来讲解下最近学到的快速排序,归并排序,二分查找等处理数据的方式,为日后的刷题打下坚实的基础。

快速排序:

不同于之前所见到的冒泡、插入等排序方式,快速排序的时间复杂度最好的情况为O(nlogn),最坏的情况为O(n^2),所以通常状况下,我们描述他的复杂度为O(n)。

void quick_sort(int* a,int l,int r)
{
    if(l>=r)return;
    int pri=a[(l+r)>>1];
    int i=l-1,j=r+1;
    while(i<j)
    {
        while(a[++i]<pri);
        while(a[--j]>pri);
        if(i<j)
            swap(a[i],a[j]);
    }
    quick_sort(a,l,i-1);
    quick_sort(a,j+1,r);
}

思想:分治思想

对一串数字进行排序(这里以31254为例),选择基准数为中间(l+r>>1)那一个(其实选择任意一个都可以(例如第一个a[0]或者最后一个a[n-1])),将左右边界设置为i与j,这样我们就得到了下面的情况

接下来开始,当a[i]<=pri时,i++。直到不满足这个条件时,i停下

此时当a[j]>pri时,j--。直到不满足这个条件时,j停下

 这时候判断i<j,若满足则交换,若不满足则退出循环

第一次制作动图,属实难看,我会努力改进的(doge

 交换完成后继续进行i++,j--的循环,直到不满足i<j这个循环条件

 此时我们可以看到有left--[i-1]这个区级内满足<=pri,[j+1]--right满足>pri这一个规律,所以接下来,我们就以这两个区间为划分,进行下一阶段的快速排序。即【2 1】【5 4】这两个区间。细心的你肯定发现了,那3去哪了?3存在的位置是最开始基准数的位置,这个位置的数(要么是基准数,要么是已经排完序的数)所以不需要将他加入区间。

至此快排结束

归并排序: 

#include <cstdio>
#include<iostream>
using namespace std;
const int N=1000010;
int n;
int q[N];
int tmp[N];
void merge_sort(int *q,int left,int right)
{
    if(left>=right)return ;
    int mid=(left+right)>>1;//(left+right)/2
    merge_sort(q,left,mid);//左半边拆成两个小块
    merge_sort(q,mid+1,right);//右半边拆成两个小块
    int k=0,i=left,j=mid+1;//
    while(i<=mid&&j<=right)
    {
            if(q[i]<=q[j])tmp[k++]=q[i++];
            else tmp[k++]=q[j++];
    }
    while(i<=mid)tmp[k++]=q[i++];
    while(j<=right)tmp[k++]=q[j++];
    for(int i=left,j=0;i<=right;i++,j++)q[i]=tmp[j];

}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)cin>>q[i];
    merge_sort(q, 0,n-1);
    for(int i=0;i<n;i++)cout<<q[i];
    getchar();
}

思想:

与快速排序相同,归并排序利用的也是分治思想,但由于其稳定性,时间复杂度为O (nlogn)。

首先将数据从中间分开(类似快排取pri的过程)此时的mid是中间数组的下标

然后将数据以【left,mid】【mid+1,right】这样的规律分开,无限递归下去,最后就会得到一个只有两个数字的数组,这时取两个区间的首作为两个指针,即i=left,j=mid+1,也就是比较这两个部分,然后将较小的那一个放入tmp临时数组,最后判断这两部分是否都完成了比较。

若有一部分没比较完,即可证明这一部分存在的数都比已经比较完的数大,依次放入tmp数组即可。最后将tmp数组从头开始放入原数组【left,right】这一区间,即完成并这一操作

至此归并排序结束。

整数二分查找:

二分查找可以用来解决两种问题,假设有一组数122334,求出>=2的区间以及<=2的区间

 这时候就需要两个模板来解决这两种问题。

模板一:<=target

#include<iostream>
using namespace std;
// 整数对分查找模板
int BinarySearchInt()
{
    int n=100/*array size*/,target=0/*search target*/;
    int left=0,right=n-1,q[n];
    while(left<right)//模板1
    {
        int mid=(left+right+1)>>1;
        if(q[mid]<=target)/*边界为mid--right*/
        left=mid;
        else
            right=mid-1;
    }
}

有序的数列可以用二分查找,可以用二分查找的数列不一定需要有序。当需要找一个数(也可以是条件)的时候,取这组数的中间值mid,这时候会出现两种情况。注意模板一的mid一定要+1,若不加一当只有两个数的时候,/会向下取整,陷入无限循环。

1 q[mid]<=target

这时是如下图的这种情况,那么下回寻找的区间就是【mid,right】,也就是令left=mid

2 q[mid]>target

这时是如下图的这种情况,那么下回寻找的区间就是【left,mid-1】,也就是令right=mid-1,这里为什么要-1呢?是因为q[mid]已经大于target了此时的mid已经确定不是要找的target,所以可以减一,而上一种情况中,q[mid]可以等于target,也就是q[mid]可能是我们要的答案,所以不可以减一。

模板二:>=target

#include<iostream>
using namespace std;
// 整数对分查找模板
int BinarySearchInt()
{
    int n=100/*array size*/,target=0/*search target*/;
    int left=0,right=n-1,q[n];
   
    while (left<right) {
        int mid=(left+right)>>1;
        if(q[mid]<target)left=mid+1;
        else
          right=mid;
    }
}

1 q[mid]<target

这时是如下图的这种情况,那么下回寻找的区间就是【mid+1,right】,也就是令left=mid+1

2 q[mid]>=target

这时是如下图的这种情况,那么下回寻找的区间就是【left,mid】,也就是令right=mid。

浮点数二分查找:

浮点数二分查找就没有那么多的问题了,整体思想和整数一样,但是少了边界的问题。就显得很简单。

这里引用acwing上的一道题来解释

 这里的边界就设置为题目所给的-10000<=n<=10000,也就是说left=-10000 right=10000,然后用mid的三次方去看是否>=x或者<x

若>=x 则说明mid的值取大了,答案区间应该为【left,mid】反之。

注:因为计算机存储数据的原因,很难精确的表示出一个浮点数。所以根据题设,只要左右边界相减的值小于10^-6,就认为他满足条件。

#include<iostream>
using namespace std;
const double N=1e-7;
int main()
{
    double x;
    cin>>x;
    double left=-10000,right=10000,mid;
    
    while(right-left>N)
    {
         mid=(left+right)/2;
        if(mid*mid*mid<=x)left=mid;
        else right=mid;
    }
    printf("%lf",mid);
}

至此浮点数二分查找结束。

完结撒花:

🌈本篇博客的内容【【快速排序、归并排序、整数&浮点数二分查找、】模板与解析】已经结束。

🌈若对你有些许帮助,可以点赞、关注、评论支持下博主,你的支持将是我前进路上最大的动力。

🌈若以上内容有任何问题,欢迎在评论区指出。若对以上内容有任何不解,都可私信评论询问。

🌈诸君,山顶见

  • 13
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ppeua

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值