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

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

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


🌈个人主页:主页链接


🌈算法专栏:专栏链接


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


🌈LeetCode专栏:专栏链接


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


🌈代码仓库:Gitee链接


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


81019c1cb23444b38595b3e6309b12ba.jpg


用一篇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


dc7f3aa07d2141afba225a57c40a6675.gif


交换完成后继续进行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】这一区间,即完成并这一操作。


7fa6c8427329428fbb9856867bd0943d.gif


至此归并排序结束。


整数二分查找:


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

bba2c34f7dfa4c5995bb5931453d7663.jpg


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


模板一:<=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

ae3fd72c86f840b2beb98d10573692fd.jpg


2 q[mid]>target


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


a78b038958f144a19b51ff94d64592e3.jpg


模板二:>=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


e3bcd0080a1a4514bc1ebef3a26f357e.jpg


2 q[mid]>=target


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


2c532bcde65c4fc8b2f4cfaf7f77d84a.jpg


浮点数二分查找:


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

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


e05af998cdea4277ab072d6d408b0229.png


这里的边界就设置为题目所给的-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);
}


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


完结撒花:


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

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

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


🌈诸君,山顶见

目录
相关文章
|
6月前
|
机器学习/深度学习 存储 算法
【算法基础】常数操作 时间复杂度 选择排序 冒泡排序 插入排序 位运算
【算法基础】常数操作 时间复杂度 选择排序 冒泡排序 插入排序 位运算
第k小的数(2种快排解法、1种堆排解法)
第k小的数(2种快排解法、1种堆排解法)
59 0
|
4月前
|
算法
【算法】二分查找(整数二分和浮点数二分)
算法学习——二分查找(整数二分和浮点数二分)
42 0
【算法】二分查找(整数二分和浮点数二分)
|
机器学习/深度学习 算法
代码随想录Day02 数组基础2 leetcode T977有序数组的平方, T209 长度最小的子数组,T59 螺旋矩阵II
代码随想录Day02 数组基础2 leetcode T977有序数组的平方, T209 长度最小的子数组,T59 螺旋矩阵II
56 0
|
6月前
|
算法
简记二分算法模板与代码案例:整数二分和浮点数二分
本文介绍了两种算法模板,分别是整数二分和浮点数二分。
50 0
|
6月前
|
算法
算法基础——整数二分查找(二)
算法基础——整数二分查找(二)
58 0
算法基础——整数二分查找(二)
|
6月前
|
算法 索引
Leetcode算法系列| 1. 两数之和(四种解法)
Leetcode算法系列| 1. 两数之和(四种解法)
LeetCode: 167. 两数之和 II - 输入有序数组 | 双指针专题
LeetCode: 167. 两数之和 II - 输入有序数组 | 双指针专题
65 1
|
存储 人工智能 算法
【双指针、位运算、离散化、区间合并】思路讲解及代码实现
用一篇Blog来讲解下最近学到的双指针、位运算、离散化、区间合并等算法,为日后的刷题打下坚实的基础。
97 0
|
算法
双指针算法、位运算
双指针算法、位运算
67 0