【算法】分治法之归并排序实现

所谓分治:分而治之,中华民族智慧的结晶。对其联盟,使其分裂而利于各个击破;对其国使用,使其国分裂而利于控制;对其公司使用,使其公司分裂而利于控制;对其团队使用,使其团队分裂而利于控制。可见,分治法被运用于当今社会的方方面面。


既然分治法拥有那么大能量,有必要学习学习它。当然了,这里学习分治是用来如何解决问题的。

面对一个大问题,如果直接去解决,可能很复杂,不好解决。所以要把大的问题分解成小问题,先解决小问题,等小问题都解决了,再一梳理,可能就把大问题也解决了。

所以分治法的基本步骤就是:

1. 认清问题,问题是否能够使用分治法

2.分解问题,把问题分解成小规模的一系列子问题

3.求解问题,把小规模问题一一求解

4.合并


分治法的典型使用: 二分查找、归并排序

各种情况下时间复杂度都能达到O(nlgn),理论上O(nlgn)已经是最优性能了。


递归算法公式或者说主方法:

T(n)=aT(n/b)+f(n);

a 代表问题规模

b 代表每个问题是原来的1/b;


归并排序公式:

T(n)=2T(n/2)+f(n);

问题规模是2个,每次都是分半

那么根据算法主定理可以得到其时间复杂度是O(nlgn)

主定理请看:http://blog.chinaunix.net/uid-25267728-id-3802135.html


归并排序空间复杂度:

需要O(n)临时保存数据。



归并排序C 语言代码示例:

#include <stdio.h> 
#include <string.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <error.h> 
#include <errno.h> 
#include <sys/socket.h> 
#include <stdlib.h> 
 

void merge(int data[],int start,int middle, int end);

void mergeSort(int data[],int start, int end){
    if(data == NULL){
        printf("data == NULL");
        return;
    }
    if(start < end){
        int middle = 0;
        middle = (end + start)/2;
        mergeSort(data,start, middle);
        mergeSort(data,middle+1, end);
        merge(data,start,middle,end);
    }
    
}

void merge(int data[],int start,int middle, int end){
    int i = 0;
    int j = 0;
    int k = 0;
    int part1Size = middle -start+1;
    int part2Size = end - middle;
    int* data1 = (int*)malloc(sizeof(int)*part1Size);
    int* data2 = (int*)malloc(sizeof(int)*part2Size);
    if(data1 == NULL ||  data2 == NULL){
        printf("data1 or data2 is null\n ");
        return;
    }
    printf("\n");
    printf("merge start \n ");
    printf("merge data1 \n ");
    for(i=0; i < part1Size; i++){
        data1[i]= data[start+i];
        printf(" %d",data1[i]);
    }
    printf("\n ");
    printf("merge data2 \n ");
    for(j=0; j < part2Size; j++){
        data2[j]= data[middle+1+j];
        printf(" %d",data2[j]);
    }
    printf("\n ");
    i = 0;
    j = 0;
    for( k = start; k <= end && i< part1Size && j<part2Size; k++){
        if(data1[i] < data2[j]){
            data[k]=data1[i];
            i++;
        }else{
            data[k]=data2[j];
            j++;
        }
        
    }
    //再拷贝余下的
    for(i; i< part1Size; i++){ 
        data[k++]=data1[i];
    }
    for(j; j< part2Size; j++){
        data[k++]=data2[j];
    }
    //end
    free(data1);
    free(data2);
    printf("merge end \n ");
}

int main(){ 
    int i;
    int data[]={3,4,1,2,9,8,6,32,15,16,11,7};
    int len = sizeof(data)/sizeof(int);
    mergeSort(data,0,len -1);
    
    printf("\n");
    printf(" get sort result\n");
    for(i =0; i < len;i++){
        printf(" %d",data[i]);
    }
    printf("\n");
    return 0;
} 

从以下执行过程 log可以看出,最终分解为两两比较,然后合并,之后比较个数逐步体增再合并。

merge start 
 merge data1 
  3
 merge data2 
  4
 merge end 
 
merge start 
 merge data1 
  3 4
 merge data2 
  1
 merge end 
 
merge start 
 merge data1 
  2
 merge data2 
  9
 merge end 
 
merge start 
 merge data1 
  2 9
 merge data2 
  8
 merge end 
 
merge start 
 merge data1 
  1 3 4
 merge data2 
  2 8 9
 merge end 
 
merge start 
 merge data1 
  6
 merge data2 
  32
 merge end 
 
merge start 
 merge data1 
  6 32
 merge data2 
  15
 merge end 
 
merge start 
 merge data1 
  16
 merge data2 
  11
 merge end 
 
merge start 
 merge data1 
  11 16
 merge data2 
  7
 merge end 
 
merge start 
 merge data1 
  6 15 32
 merge data2 
  7 11 16
 merge end 
 
merge start 
 merge data1 
  1 2 3 4 8 9
 merge data2 
  6 7 11 15 16 32
 merge end 
 
 get sort result
 1 2 3 4 6 7 8 9 11 15 16 32




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值