小鲤算法之归并排序介绍

小鲤的碎碎念

归并的思路是什么呢?

叫你让两个数按升序排序,好排吧?

不就是大的数放后面,小的数放前面吗?如果第一个数比第二个数大,就交换!

你可能不加思索就给出了答案。那么,我给你四个数呢?当然,你一眼就可以看出来,但是小鲤希望用计算机的思维来解决哦。

欸,之前不是把两个数给排好序了吗?我把四个数拆成两组数,一比较就排好序了。然后看一下,这两组数第一个数谁更小放前面,大的再比较······

没错啦,那么更大规模的数呢,是不是也是以此类推呢?

你已经理解了归并,但是怎么实现呢?

动图演示(来源于网络)

归并模板

#include <stdio.h>
#include <malloc.h>
 
#define maxn 1000001

int a[maxn];

void Input(int n, int *a) {
    for(int i = 0; i < n; ++i) {
        scanf("%d", &a[i]);
    }
}

void Output(int n, int *a) {
    for(int i = 0; i < n; ++i) {
        if(i)
            printf(" ");
        printf("%d", a[i]);
    }
    puts("");
}

void MergeSort(int *nums, int l, int r) {
    int i, mid, p, lp, rp;
    int *tmp = (int *)malloc( (r-l+1) * sizeof(int) );    // (1)  
    if(l >= r) {
        return ;                                          // (2) 
    }
    mid = (l + r) >> 1;                                   // (3) 
    MergeSort(nums, l, mid);                              // (4) 
    MergeSort(nums, mid+1, r);                            // (5) 
    p = 0;                                                // (6) 
    lp = l, rp = mid+1;                                   // (7) 
    while(lp <= mid || rp <= r) {                         // (8) 
        if(lp > mid) {
            tmp[p++] = nums[rp++];                        // (9) 
        }else if(rp > r) {
            tmp[p++] = nums[lp++];                        // (10) 
        }else {
            if(nums[lp] <= nums[rp]) {                    // (11) 
                tmp[p++] = nums[lp++];
            }else {
                tmp[p++] = nums[rp++];
            }
        }
    }
    for(i = 0; i < r-l+1; ++i) {
        nums[l+i] = tmp[i];                               // (12) 
    } 
    free(tmp);                                            // (13) 
}

int main() {
    int n;
    while(scanf("%d", &n) != EOF) {
        Input(n, a);
        MergeSort(a, 0, n-1);
        Output(n, a);
    }
    return 0;
} 

代码来自大神英雄哪里出来,之《算法零基础100讲》(第36讲) 排序进阶 - 归并排序。

代码解释

(简化版附上我个人理解,详细请看大神博客)

主要讲解整体思路,这样看注释更容易理解;

首先,我们申请了一个内存空间,用来临时存放归并后数组;

然后,我们先开始递归分组(直到每组只有两个元素),对两个数的排序比较大小即可;

接着,我们开始归并,注意,此时的每一组数已经排好序。

考虑如果左边数组已经全部归并完,那么右边数组依此填入。右边情况同。

重置到原先的数组,然后释放空间。

over!

顺便安利一波:

学习算法的捷径:关注英雄哪里出来,参加万人千题社区,里面有大牛常驻,还有各种学习渠道;

刷题累了,可以看看英雄哪里出来的个人空间_哔哩哔哩_Bilibili,里面有激情澎湃的Bgm,还有算法视频;然后,可以来给小鲤的文章挑错

题目:

912. 排序数组

 



/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
 void mergesort(int *nums,int l,int r){
   int i,mid,p,lp,rp;
   int *tmp =(int*)malloc((r-l+1)*sizeof(int));
   if(l>=r){
       return ;
   }
   mid=(l+r)>>1;
   mergesort(nums,l,mid);
   mergesort(nums,mid+1,r);
   p=0;
   lp=l,rp=mid+1;
   while(lp<=mid||rp<=r){
       if(lp>mid){
           tmp[p++] = nums[rp++];
       }else if(rp > r){
           tmp[p++] =nums[lp++];
       }else{
           if(nums[lp]<=nums[rp]){
               tmp[p++]=nums[lp++];
           }else{
               tmp[p++]=nums[rp++];
           }
       }
   }
   for(i=0;i<r-l+1;++i){
       nums[l+i]=tmp[i];
   }free(tmp);
 }
int* sortArray(int* nums, int numsSize, int* returnSize){
  mergesort(nums,0,numsSize-1);
  *returnSize=numsSize;
  return nums;
}

本题完全套用模版,难度不大,所用就不做讲解了。

164. 最大间距

 

 void mergesort(int *nums,int l,int r){
   int i,mid,p,lp,rp;
   int *tmp =(int*)malloc((r-l+1)*sizeof(int));
   if(l>=r){
       return ;
   }
   mid=(l+r)>>1;
   mergesort(nums,l,mid);
   mergesort(nums,mid+1,r);
   p=0;
   lp=l,rp=mid+1;
   while(lp<=mid||rp<=r){
       if(lp>mid){
           tmp[p++] = nums[rp++];
       }else if(rp > r){
           tmp[p++] =nums[lp++];
       }else{
           if(nums[lp]<=nums[rp]){
               tmp[p++]=nums[lp++];
           }else{
               tmp[p++]=nums[rp++];
           }
       }
   }
   for(i=0;i<r-l+1;++i){
       nums[l+i]=tmp[i];
   }free(tmp);
 }
int maximumGap(int* nums, int numsSize){
  
  if(numsSize<2){
      return 0;
  }else{
      mergesort(nums,0,numsSize-1);
      int max=0;
      for(int i=0;i<numsSize-1;i++){
           if(nums[i+1]-nums[i]-max>0){
               max=nums[i+1]-nums[i];
           }
    }return max;
  }
}

思路🤔为什么要写成nums[i+1]-nums[i]-max>0形式

😎测试案例过大将不会通过,与变量内存限制有关。

 

今天的内容已经结束了>_<

如果我的文章对你有帮助,不要吝惜你的点赞,小鲤希望得到你的支持ლ(´ڡ`ლ)

求三连和关注!!!

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
归并排序(Merge Sort)是一种稳定的、基于比较的排序算法,最坏时间复杂度为 O(nlogn)。其基本思想是将待排序序列分成若干个子序列,每个子序列都是有序的,然后将子序列合并成整体有序的序列。 归并排序的实现方法有两种:自顶向下和自底向上。 自顶向下的归并排序算法实现: 1. 将待排序序列分成两个子序列,分别对这两个子序列进行递归排序。 2. 将两个已经排好序的子序列合并为一个有序序列。 自底向上的归并排序算法实现: 1. 将待排序序列每个元素看成一个独立的有序序列,进行两两合并。 2. 得到 n/2 个长度为 2 的有序序列,再两两合并。 3. 重复步骤 2,直到得到一个长度为 n 的有序序列。 下面是自顶向下的归并排序算法的实现代码(使用了递归): ``` void MergeSort(int arr[], int left, int right) { if (left >= right) return; int mid = left + (right - left) / 2; MergeSort(arr, left, mid); MergeSort(arr, mid + 1, right); int* temp = new int[right - left + 1]; int i = left, j = mid + 1, k = 0; while (i <= mid && j <= right) { if (arr[i] <= arr[j]) temp[k++] = arr[i++]; else temp[k++] = arr[j++]; } while (i <= mid) temp[k++] = arr[i++]; while (j <= right) temp[k++] = arr[j++]; for (int p = 0; p < k; p++) arr[left + p] = temp[p]; delete[] temp; } ``` 下面是自底向上的归并排序算法的实现代码(使用了迭代): ``` void MergeSort(int arr[], int n) { int* temp = new int[n]; for (int len = 1; len < n; len *= 2) { for (int left = 0; left < n - len; left += len * 2) { int mid = left + len - 1; int right = min(left + len * 2 - 1, n - 1); int i = left, j = mid + 1, k = 0; while (i <= mid && j <= right) { if (arr[i] <= arr[j]) temp[k++] = arr[i++]; else temp[k++] = arr[j++]; } while (i <= mid) temp[k++] = arr[i++]; while (j <= right) temp[k++] = arr[j++]; for (int p = 0; p < k; p++) arr[left + p] = temp[p]; } } delete[] temp; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值