数据结构与算法之归并、快速排序

本文深入探讨归并排序和快速排序两种基础排序算法。归并排序通过不断合并已排序的小段达到全局有序,时间复杂度为O(nlogn)。快速排序则通过选取主元并调整其位置,逐步使数组有序,平均时间复杂度同样为O(nlogn),但在特定情况下可能退化至O(n^2)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据结构与算法之归并、快速排序

  这是排序问题中的两个重要且基础的排序算法。之所以拿来一起介绍使用为他俩有着异曲同工之妙,只要理解了归并排序,就知道了快排是咋回事的了。
 归并排序就是从局部无序变有序,最后全局无序变有序。基本思想就是先俩俩一组,通过合并排序,保证组内有序后,我们在将相邻的两组合并排序(将两组链接并排序)成为新的一组。然后再合并排序,再依次循环,直到一组的长度是整个待排序数组的长度。
 传统的排序算法就是写两个嵌套的循环,然后一个个的对比,那么此时的算法的时间复杂度就是O(nn),当要求排序的数组是非常大的时候,这是不可接受的。而归并排序的时间复杂度是O(nlogn),显然是优于传统的排序算法。
  代码实现:
1,我们先设计出合并排序代码,即将两组数组合并的同时进行排序。

const int maxn=100;
void merge(int a[],int l1,int r1,int l2,int  r2){
    int temp[maxn];
    int i=l1;
    int j=l2;
    int index=i;
    while(i<=r1&&j<=r2){
        if(a[i]<a[j]){
            j++;
            
            temp[i]=a[i];
            index+=1;
        }
        else{
            i++;
            temp[index]=a[j];
            index+=1;
        }
    }
    if(i<=r1){
        for(int k=r1;k<=r1;k++){
            temp[index]=a[k];
            index+=1;
        }
    }
    if(j<=r2){
        for(int k=r2;k<=r2;k++){
            temp[index]=a[k];
            index+=1;
        }

    }
    for(int i=l1;i<=r2;i++){
        a[i]=temp[i];
    }
}

 归并排序的非递归实现:

void mergesort(int a[]){
for(int step=1;step<=n/2;step=step*2){
    for(int i=0;i<n;i=i+step;){
        merge(a,i,i+step-1,i+step,min(n,i+2*step-1))
    }
}
}

  递归实现:

void mergesort(int a[],int left ,int right){
    if(left<right){
        int mid=(right+left)/2;
        mergesort(a,left,mid);
        mergesort(a,mid+1,right);
        merge(a,left,mid,mid+1,right);//相当于二叉树的后序遍历
    }
}

 注意递归代码如果看不懂的话,可以结合二叉树的后序遍历,来画一下二叉搜索树模拟一下。
  下面我们在介绍一下快速排序。第一步是选择主元,那啥是主元呢?说白了就是待排序的那个元素。第二步是将主元放在正确的位置。下面结合一个例子:
待排序的数组:5 7 2 3 6 ,要求按增序顺序

排序过程:将5作为主元,然后核心思想就是将大于5的放在5的右边,小于5的放在5的左边。操作后就变为:3 2 5 7 6。
我们发现现在离成功进了一步,因为元素5的位置已经正确。继续观察,元素5两侧的序列仍是无序状态,所以我们以5为界限,拆成两个子序列,然后对两个子序列分别再进行一次,仍然选择子序列的第一个元素为主元。。。。。依次进行,直至子序列的长度为1。代表排序完成。所以不难算出该算法的时间复杂度为O(n*logn)。
  快速排序代码如下:



 为啥说有点相似呢?因为他俩都有二分的一影子,前者是数量二分,后者是位置二分。他俩又是不同的,归并排序“目光短浅”,他一开始就让小段小段的有序,直至后来全局有序。而快速排序“目光长远”,先让混沌无序的数组变得有一点有序,即有一个元素处于正确的位置,然后整体有序。
  另外当数组中的元素越随机时,快速排序算法的效率越高。特别的,当待排序的数组已经是增序或者减序时,该算法的时间复杂度是O(n*n),该算法完全退化为一般的排序算法(即相当于两层for循环)。因为每次的子序列就是它母序列本身。
 以下是快速排序的递归实现的代码:

void qucksort(int a[],int left,int right){
    int temp;
    a[left]=temp;
    int i=left;
    int j=right;
    int mid;
    while(i<j){
        while(a[j]>=temp&&i<j){
            j--;
        }
        a[i]=a[j];
        while(a[i]<temp&&i<j){
            i++;
        }
        a[j]=a[i];
    }
    mid=j;
    a[j]=temp;
    qucksort(a,left,mid-1);
    qucksort(a,mid+1,left);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值