快速排序和归并排序

目录

一、序言

二、快速排序

1.介绍

2.思路

3.代码实现

三、归并排序

1.介绍

2.思路

3.代码实现

四、小结


一、序言

快速排序和归并排序是我认为很常用的两个排序,而很多人对此仍然存在一些疑问与不解,所以今天让我带大家重新回顾一下这两个排序的代码实现。

二、快速排序

1.介绍

快速排序的原理基于分治法的思想,通过递归地将一个数组分成两个(或更多)较小的子数组,直到子数组的大小为1或0,此时子数组自然是有序的。然后,算法将这些有序的子数组合并成一个大的有序数组,但在这个特定的情况下,由于子数组已经是有序的,并且它们是按照大小顺序排列的(一个子数组中的所有元素都小于另一个子数组中的所有元素),所以合并步骤实际上不需要进行任何操作,整个数组就已经是有序的了。

2.思路

快速排序思路:(先排序再递归)

Step1. 定义left,right作为双指针(这么说可能不准确,但大概就是这个意思),一个从头遍历,一个从尾遍历。

Step2. 选择数据中一个数为参考值(一般默认第一个数的值),这里记作target。

Step3. 让left,right对应数据的值分别与之进行比较

           若left对应的值小于target就向后遍历,直到大于等于target时停下;

           若right对应的值大于target就向前遍历,直到小于等于target时停下。

           当left与right都停下时,交换left与right对应的数据的值。

Step4. 重复以上操作,直到两者相遇。

           两者会相遇到此时的right处,我们以right为界,同样对其左右序列进行相同排序操作(递               归)。循环往复,直至排序成功。

3.代码实现

快排函数部分:

void quick_sort(int begin,int end)
{
       if(begin >= end)     return ;      //注意
       int left = begin;    
       int right = end;
       int target = a[begin];      
       while(left < right)
       {
              while(a[left] < target)    left++;       //注意是while,而不是if(while在这里表示一直移动,直到不满足时才停止)
              while(a[right] > target)   right--;
              if(left < right)       swap(a[left],a[right]);       //这里必须要再次强调left < right,这样就避免了最后相遇的情况
       }
       //递归操作,对right左右区间进行同样操作(此时right左边全小于target,右边全大于target)
       quick_sort(begin,right);
       quick_sort(right+1,end);
}

完整代码:

#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N], n;
void quick_sort(int begin,int end)
{
       if(begin >= end)     return ;      
       int left = begin;    
       int right = end;
       int target = a[begin];      
       while(left < right)
       {
              while(a[left] < target)    left++;       
              while(a[right] > target)   right--;
              if(left < right)       swap(a[left],a[right]);       
       }
       quick_sort(begin,right);
       quick_sort(right+1,end);
}

int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; i++)    scanf("%d", &a[i]);
    quick_sort(0, n - 1);
    for (int i = 0; i < n; i++)    printf("%d ", a[i]);
    return 0;
}

三、归并排序

1.介绍

归并排序的基本思想是将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。

2.思路

归并排序--分治思想:(先递归再排序)

Step1. 定义tmp数组用于存放已经排好序的数据(放第一步主要是让后续思路更清晰)

Step2. 将原数组(我把它记作a[])数据分成两半:左区间(begin,mid)与 右区间(mid+1,end)

Step3. 递归,分别对左右两区间进行同样操作(这里直接调用该函数)--这里其实也好理解:

           因为归并排序是先分成两部分,这两部分再分别细分左区间和右区间,一直分到不能

           分为止,然后再按小块排序,排完序后再不断合并进行整体排序

Step4. 建立i,j,k

           i表示左区间起点;j表示右区间起点;k表示tmp数组下标,从最初(begin)开始

Step5. i处于左区间且j处于右区间(两区间的元素都还没全存入tmp数组)时,tmp数组用于存放                两者较小值,然后存放的值对应的i或j进行相应移动(i右移或j左移)

Step6. 当j不在右区间时或i不在左区间时(即某个区间的数全都已经排完序,存入tmp中了),

           这时只需要把剩下那个区间的数挨个填进tmp数组后边就行了

Step7. 最后不要忘记将tmp数组的值赋给原数组(a[])

3.代码实现

归并排序函数部分:

void merge_sort(int begin, int end) {
    int tmp[N];             //定义tmp数组用来存放已经排好序的数据

    if (begin >= end) return ;      //注意

    int mid = begin + end >> 1;         //位运算 >> 等价于除以2,将数据(数组)分成两半:左(begin,mid)与 右(mid+1,end)
    merge_sort(begin, mid);             //先递归,对左右区间进行同样操作
    merge_sort(mid + 1, end);

    int i = begin, j = mid + 1, k = begin;      //i,j分别初始化在左右区间起点处 ,k作为tmp数组序标,初始化为begin
    while (i <= mid && j <= end)        //循环条件:i在左区间 且 j在右区间(两个区间的数都还没排完序存入tmp数组中)
    {
        if (a[i] <= a[j])
            tmp[k ++ ] = a[i ++ ];          //tmp数组用于记录a[i]与a[j]两者的较小值,较小值对应的i或j进行+1,每次赋值后k++
        else    
            tmp[k ++ ] = a[j ++ ];
    }
    //j不在右区间时 或 i不在左区间时(即某个区间的数全都已经排完序,存入tmp中了),这时只需要把剩下那个区间的数挨个填进去就行
    while (i <= mid)    tmp[k ++ ] = a[i ++ ];
    while (j <= end)  tmp[k ++ ] = a[j ++ ];

    for (int i = begin; i <= end; i ++ )  
        a[i] = tmp[i];              //不要忘,这样就将a[i]排好序了
}

完整代码:

#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N],  n;

void merge_sort(int begin, int end) 
    int tmp[N];             

    if (begin >= end) return ;      

    int mid = begin + end >> 1;         
    merge_sort(begin, mid);             
    merge_sort(mid + 1, end);

    int i = begin, j = mid + 1, k = begin;     
    while (i <= mid && j <= end)       
    {
        if (a[i] <= a[j])
            tmp[k ++ ] = a[i ++ ];         
        else    
            tmp[k ++ ] = a[j ++ ];
    }
    while (i <= mid)    tmp[k ++ ] = a[i ++ ];
    while (j <= end)  tmp[k ++ ] = a[j ++ ];

    for (int i = begin; i <= end; i ++ )  
        a[i] = tmp[i];              
}

int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; ++ i)   scanf("%d", &a[i]);
    merge_sort(0, n - 1);
    for (int i = 0; i < n; ++ i)   printf("%d ", a[i]);
    return 0;
}

四、小结

以上就是我对于快速排序和归并排序的一些理解,希望能够帮助到你。明天将继续更新代码随想录训练营的打卡,希望我能够坚持下去。我是算法小白,但也希望终有所获。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值