3.3 分治模式的完美诠释:归并排序

Chapter3: 更好的查找与排序算法

3. 分治模式的完美诠释:归并排序

1. 基本思想

对于一次递归的调用来说

  • 划分

    • 取中间坐标,将原数组划分为两部分
    • 分别递归对左右数组进行排序,该层调用的结果为左边数组有序,右边数组有序,但是左边数组的元素不一定比右边数组的小,如 [1,3,4,6,2,4,6,8]
  • 合并

    • 比如对于数组arr=[1,5,3,7,2,6,8,4] 进行一次归并排序调用(包括划分和左右数组排序)后,得到左数组 arr1=[1,3,5,7] ,右数组 arr2=[2,4,6,8]
    • 初始化: 让 left 指针指向做数组第一个元素,right 数组指向右数组第一个元素,设置一个辅助数组 tmpArr=int [8] ;
    • arr1[left]arr2[right] 比较,arr1[left]=1arr2[right]=2 小,将 arr1[left] 存入 tmpArr[0] ; arr1[left]指针下移1位,即left++, 此时 arr1[left]=3arr2[right]=2大,则将arr2[right] 存入tmpArr[1]; right++...循环直至其中一个数组的元素全部存入临时数组,另一个数组剩下的元素直接赋值到临时数组后面
归并排序示意图
某层递归调用上的合并示意图

2. 代码实现

#include<iostream>
#include<cstdlib>
using namespace std;

void mergeSort(int* arr,int begin,int end); 
void merge(int* arr,int begin,int mid,int end);

int main(){
    int arr[6]={1,3,2,5,4,7};
    int arrLen=sizeof(arr)/sizeof(arr[0]);
    
    mergeSort(arr,0,arrLen-1);
    
    for(int i=0;i<arrLen;i++){
        printf("%d ",arr[i]);
    }
    return 0;
} 

void mergeSort(int* arr,int begin,int end){
    if(begin<end){//注意这个出口条件,不然会陷入死循环 
        int mid=begin+((end-begin)>>1);
        mergeSort(arr,begin,mid);//递归调用起到划分作用
        mergeSort(arr,mid+1,end);
        merge(arr,begin,mid,end);
    }
}

//合并函数
void merge(int* arr,int begin,int mid,int end){
    int len=end-begin+1;//当前划分状态下的数组长度 
    int tmpArr[len];//辅助数组
     
    int leftP=begin;//左指针 
    int rightP=mid+1;//右指针 
    int i=0;//辅助数组当前存取的下标 
    //printf("initial. len=%d\n",len);
    
    while((leftP<=mid)&&(rightP<=end)){
        if(arr[leftP]<=arr[rightP]){
            tmpArr[i]=arr[leftP];
            i++;
            leftP++;
            //或直接写为 tmpArr[i++]=arr[leftP++];
        }
        else{
            tmpArr[i]=arr[rightP];
            i++;
            rightP++; 
        }
    }
    while(leftP<=mid){//如果左数组有剩余元素 
        tmpArr[i]=arr[leftP];
        i++; 
        leftP++;
    }
    while(rightP<=end){//如果右数组有剩余元素 
        tmpArr[i]=arr[rightP];
        i++;
        rightP++;
    }
    /*将排序好的辅助数组复制到原数组中,
    因为递归要用到上一层排好序的原数组,并所以这一步必不可少*/ 
    i=0;  
    while(begin<=end){
        arr[begin++]=tmpArr[i++];
    }
    //注意每次递归数组的开始位置不一样,为begin,不一定是0,所以不能用下面的赋值方法 
//  for(i=0;i<len;i++){
//      arr[i]=tmpArr[i];
//  }       

}

3. 快速排序和归并排序的比较

快速排序关键在于划分,归并排序关键在于合并

快速排序划分的左右两个数组左边数组的元素一定小于右边数组的元素,但是在左数组或右数组内元素不一定有序

归并排序划分的左右两个数组左边的数组的元素不一定小于右边的元素,但是在左右数组内的元素分别是有序的

快速排序的思想

  • 分解

    数组 A[p..r] 被划分为两个子数组 A[p...q-1]A[q+1,r] , 使得 A[q] 为大小居中的数,左侧 A[p..q-1] 中的每个元素都 <= 它, 而右侧 A[q+1,r] 中的每个元素都 >= 它。其中计算下标 q 也是划分过程的一部分。

  • 解决

    通过递归调用快速排序,分别对子数组 A[p...q-1] 和 A[q...r] 进行排序

  • 合并

    不存在合并的问题

4. 参考资料

[1] 图解排序算法(四)之归并排序

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容

  • 在Java常见排序基础 - 上中主要介绍了冒泡排序、选择排序、插入排序三种基础排序,本篇文章主要介绍的是 快速排序...
    骑小猪看流星阅读 1,027评论 0 13
  • 分治策略 本文包括分治的基本概念二分查找快速排序归并排序找出伪币棋盘覆盖最大子数组 源码链接:https://gi...
    廖少少阅读 1,850评论 0 7
  • 1 初级排序算法 排序算法关注的主要是重新排列数组元素,其中每个元素都有一个主键。排序算法是将所有元素主键按某种方...
    深度沉迷学习阅读 1,404评论 0 1
  • Category是一个Objective-C语法中允许你用额外的方法扩展类的一个很不错的的特性;它通过直接为类添加...
    Jimmy_L_Wang阅读 1,345评论 0 7
  • 1、提醒鼓动: 她强忍眼前的苟且,就等你一起驱车前往远方的田野 2、增加附加值:孩子的成长只有一次,一定要亲自带...
    shining_33bf阅读 270评论 3 2