排序:归并排序(C)

1.思想

1.1 思想流程图

在这里插入图片描述

1.2 思路解释

归并排序思路:
1.总体思路:将待排序数组进行拆分成多个分组,然后将拆分后的分组有序的合并.
2.现将数组拆分成分组长度(length=1)最小分组.然后将相邻分组两两进行有序合并.
2.1 如果总的分组数为偶数,那么正好两两合并.
2.2 如果总的分组数为奇数,那么剩下的单个的直接拼在新数组的后面即可.
2.3.生成一个按照长度为length合并后的新数组.
3.将新的数组进行第二步的操作(length=length*2).直到length>=待排序数组的长度,那么归并结束.也就是最新的归并的数组中只有一个分组,并且是排序好的数组.

2.算法执行过程

归并前数组:3,7,4,2,8,6,10,11,5,1
-------------开始归并:分组长度:length:1------------
待合并分组1角标范围:[0~0],下面是角标范围内的值:
3
待合并分组2角标范围:[1~1],下面是角标范围内的值:
7
分组合并的有序结果:3,7
待合并分组1角标范围:[2~2],下面是角标范围内的值:
4
待合并分组2角标范围:[3~3],下面是角标范围内的值:
2
分组合并的有序结果:2,4
待合并分组1角标范围:[4~4],下面是角标范围内的值:
8
待合并分组2角标范围:[5~5],下面是角标范围内的值:
6
分组合并的有序结果:6,8
待合并分组1角标范围:[6~6],下面是角标范围内的值:
10
待合并分组2角标范围:[7~7],下面是角标范围内的值:
11
分组合并的有序结果:10,11
待合并分组1角标范围:[8~8],下面是角标范围内的值:
5
待合并分组2角标范围:[9~9],下面是角标范围内的值:
1
分组合并的有序结果:1,5
-------------该此归并结束:分组长度:length:1-------------
3,7,2,4,6,8,10,11,1,5
-------------开始归并:分组长度:length:2------------
待合并分组1角标范围:[0~1],下面是角标范围内的值:
3,7
待合并分组2角标范围:[2~3],下面是角标范围内的值:
2,4
分组合并的有序结果:2,3,4,7
待合并分组1角标范围:[4~5],下面是角标范围内的值:
6,8
待合并分组2角标范围:[6~7],下面是角标范围内的值:
10,11
分组合并的有序结果:6,8,10,11
待合并分组1角标范围:[8~9],下面是角标范围内的值:
1,5
分组合并的有序结果:1,5
-------------该此归并结束:分组长度:length:2-------------
2,3,4,7,6,8,10,11,1,5
-------------开始归并:分组长度:length:4------------
待合并分组1角标范围:[0~3],下面是角标范围内的值:
2,3,4,7
待合并分组2角标范围:[4~7],下面是角标范围内的值:
6,8,10,11
分组合并的有序结果:2,3,4,6,7,8,10,11
待合并分组1角标范围:[8~9],下面是角标范围内的值:
1,5
分组合并的有序结果:1,5
-------------该此归并结束:分组长度:length:4-------------
2,3,4,6,7,8,10,11,1,5
-------------开始归并:分组长度:length:8------------
待合并分组1角标范围:[0~7],下面是角标范围内的值:
2,3,4,6,7,8,10,11
待合并分组2角标范围:[8~9],下面是角标范围内的值:
1,5
分组合并的有序结果:1,2,3,4,5,6,7,8,10,11
-------------该此归并结束:分组长度:length:8-------------
1,2,3,4,5,6,7,8,10,11
总的归并结束,数组:1,2,3,4,5,6,7,8,10,11

3.算法实现

3.1 方法定义

mergeGroup:相邻放个分组合并
mergePassByLength:数组中指定分组长度,将所有分组进行合并,称为一次归并
mergeArray:归并算法
printArray:打印数组,为了查看算法执行过程

#define SIZE 10
/*
 数组中的指定两个分组合并
 将原来数组中的通过两个位置分成的数组有序合并到一个新的数组中对应的位置
 oArray: [oStartPosition,oMiddlePosition],[oMiddlePosition+1,oEndPosition]
 oArray:待排序的数组
 oStartPosition:第一个组的其实位置
 oMiddlePosition:第一个组的结束位置
 oEndPosition:第二个组的结束位置
 */
void  mergeGroup(int oArray[],int oStartPosition,int oMiddlePosition,int oEndPosition,int nArray[]);
/*
 按照指定分组长度,进行一次归并
 一般:长度为1,长度为2,...长度为n.
 当长度为n时,说明归并的结果就是一个整个有序的数组
 oArray:待归并的数组
 nArray:归并后的数组
 groupLength:分组的长度
 */
void  mergePassByLength(int oArray[],int nArray[],int groupLength);
/*
 归并排序,将指定数组进行归并排序
 oArray:待排序数组
 这里为了方便,将数组长度定义为了全局的:SIZE=10
 */
void mergeArray(int oArray[]);
//打印数组
void printArray(int array[],int start,int end);

3.2 方法实现


void  mergeGroup(int oArray[],int oStartPosition,int oMiddlePosition,int oEndPosition,int nArray[]){
    //1.oArray的分组
    //[oStartPosition,oMiddlePosition],
    //[oMiddlePosition+1,oEndPosition]
    printf("待合并分组1角标范围:[%d~%d],下面是角标范围内的值:\n",oStartPosition,oMiddlePosition);
    printArray(oArray,oStartPosition,oMiddlePosition);
    if(oMiddlePosition+1<=oEndPosition){
         printf("待合并分组2角标范围:[%d~%d],下面是角标范围内的值:\n",oMiddlePosition+1,oEndPosition);
         printArray(oArray,oMiddlePosition+1,oEndPosition);
    }
    int  i=oStartPosition;
    int  j=oMiddlePosition+1;
    int  k=oStartPosition;
    //2.遍历两个分组
    while (i<=oMiddlePosition && j<=oEndPosition) {
        if(oArray[i]<oArray[j]){
            nArray[k++]=oArray[i];
            i++;
        }else{
            nArray[k++]=oArray[j];
            j++;
        }
    }
    //3.只会剩下一个分组有数据
    //如果第一个分组剩下数组,新数组后面.如果第二个分组剩下数组,新数组后面
    while(i<=oMiddlePosition){
         nArray[k++]=oArray[i++];
    }
    while(j<=oEndPosition){
         nArray[k++]=oArray[j++];
    }
    //4.合并结束.有序合并到了nArray的[oStartPosition,oEndPosition]
    printf("分组合并的有序结果:");
    printArray(nArray, oStartPosition,oEndPosition);
}

void  mergePassByLength(int oArray[],int nArray[],int groupLength){
    int start;
    int middle;
    int end;
    //按照分组长度进行合并
    printf("-------------开始归并:分组长度:length:%d------------\n",groupLength);
    for(int i=0;i<SIZE;i=i+2*groupLength){
         start=i;
         middle=i+groupLength-1;
         end=i+2*groupLength-1;
         if(middle>=SIZE){
            middle=SIZE-1;
         }
         if(end>=SIZE){
            end=SIZE-1;
         }
         mergeGroup(oArray, start,middle, end, nArray);
     }
    printf("-------------该此归并结束:分组长度:length:%d-------------\n",groupLength);
    printArray(nArray,0,9);
}

void mergeArray(int oArray[]){
    printf("归并前数组:");
    printArray(oArray, 0, 9);
    int nArray[SIZE];
    int length=1;
    int flag=1;
    while (length<SIZE) {
        //这里待归并和归并数组进行替换,复用.
        if(flag==1){
            //oArray:是待归并数组,nArray:归并后数组.oArray->nArray 进行归并
            mergePassByLength(oArray,nArray,length);
            flag=0;
        }else{
             mergePassByLength(nArray,oArray,length);
             flag=1;
        }
        length=length*2;
    }
    printf("总的归并结束,数组:");
    if(flag==0){
         printArray(nArray, 0, 9);
    }else{
         printArray(oArray, 0, 9);
    }
}

void printArray(int array[],int start,int end){
    for(int i=start;i<=end;i++){
        if(i==start){
            printf("%d",array[i]);
        }else{
            printf(",%d",array[i]);
        }
    }
    printf("\n");
}

3.3 方法调用

int main(int argc, const char * argv[]) {
    int oArray[]={3,7,4,2,8,6,10,11,5,1};
    mergeArray(oArray);
    return 0;
}

4.复杂度

时间复杂度:O(n log ⁡ 2 n \log_2{n} log2n)
控件复杂度:O(n),因为创建了一个新数组和待排序数组进行交替归并.

源码下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值