算法之合并排序【分治法】【C语言】

分治法思想:

1、分解:将原问题分解成一系列子问题;

2、解决:递归地解决各个子问题。若子问题足够小,则直接求解。

3、合并:将子问题的结果合并成原问题的解。

循环不变式的证明在《算法导论》中P19。

最坏时间复杂度为O(nlgn).

#include <stdio.h>
#define MAXSIZE 10

void print(int array[]);
void merge_sort(int array[], int start_p, int end_p);
void merge_do(int array[], int start_p, int middle_p, int end_p);

/**
 * 合并:把两个已排序的数组
 * 从中间位置划分为两组数据,均从起始位置遍历两组数据并比较,那个数组的当前值小,放回原数组中,直到一个数组遍历完,如果剩下一个数组还有数据,则直接把该数组中数据无改变的放回至原数组
 */
void merge_do(int array[], int start_p, int middle_p, int end_p)
{
    int size1 = middle_p - start_p + 1;
    int size2 = end_p - middle_p;
    int left[MAXSIZE], right[MAXSIZE];
    int tmp_index,tmp_index_1,tmp_l_index, tmp_r_index;

    for(tmp_index = 0; tmp_index < size1; tmp_index ++)//划分的左数组
        left[tmp_index] = array[tmp_index + start_p];

    for(tmp_index = 0; tmp_index < size2; tmp_index ++)//划分的右数组
        right[tmp_index] = array[tmp_index + middle_p + 1];

    tmp_l_index = 0;
    tmp_r_index = 0;
    for(tmp_index = 0; (tmp_l_index < size1) &&(tmp_r_index < size2);tmp_index++)//遍历并比较
    {
        if(left[tmp_l_index] <= right[tmp_r_index])//左数组数据小于等于右数组数据
        {
           array[tmp_index + start_p] = left[tmp_l_index];
           tmp_l_index++;
        }
        else//左数组数据大于右数组数据
        {
            array[tmp_index+start_p] = right[tmp_r_index];
            tmp_r_index++;
        }
    }

    if(tmp_l_index == size1)//左数组遍历完
    {
        while(tmp_r_index < size2)//把右数组数据放回原数组
        {
            array[tmp_index +start_p] = right[tmp_r_index];
            tmp_index++;
            tmp_r_index++;
        }
    }
    else if(tmp_r_index == size2)//右数组遍历完
    {
        while(tmp_l_index < size1)//把左数组数据放回原数组
        {
            array[tmp_index +start_p] = left[tmp_l_index];
            tmp_index++;
            tmp_l_index++;
        }
    }
}
/**
 * 分治法
 */
void merge_sort(int array[], int start_p, int end_p)
{
    int middle_p;//中间位置

    if(start_p < end_p)//起始位置小于结束位置
    {
        middle_p = (start_p+end_p)/2;//计算中间位置,整数相除,向下取整

        merge_sort(array, start_p, middle_p);//划分[起始位置, 中间位置]
        merge_sort(array, middle_p+1,end_p);//划分[中间位置+1, 结束位置]
        merge_do(array, start_p, middle_p, end_p);//合并两个已排好序的数组

    }
    else if(start_p == end_p)//起始位置等于结束位置
    {
        return;
    }
    else//起始位置大于结束位置,报错
    {
        printf("Error: Start_p > End_p\n");
    }
}
/**
 * 打印程序
 */
void print(int array[])
{
    int index = 0;
    while(index < MAXSIZE)
    {
        printf("%d ", array[index]);
        index ++;
    }
    printf("\n");
}


/**
 * 主程序
 */
int main()
{
    int array[MAXSIZE] = {4,-2,2,0,-1,3,5,1,4,7};//待排序的数组

    printf("Oringin array: ");
    print(array);

    merge_sort(array,0,MAXSIZE-1);

    printf("Sort array: ");
    print(array);

   return 0;

}


  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值