归并排序

什么是归并排序??

归并排序的实现过程如图:



递归形式的代码如下所示:

#!/usr/bin/python
#coding: utf-8

def Merge_Sort(res):
	if len(res) <= 1:
		return res

	num = len(res) // 2
	left = Merge_Sort(res[ : num])
	right = Merge_Sort(res[num : ])
	return Merge(left, right)

def Merge(left, right):
	l, r = 0, 0
	result = []
	while l < len(left) and r < len(right):
		if left[l] < right[r]:
			result.append(left[l])
			l += 1
		else:
			result.append(right[r])
			r += 1

	result.extend(left[l : ])
	result.extend(right[r : ])

	return result 

if __name__ == "__main__": 
    result = [95, 45, 15, 78, 84, 51, 24, 12]  
    print Merge_Sort(result)
    # result = [95, 45, 15, 78, 84, 51, 24, 12]  
    # print MergeSort(result)


归并排序在用递归实现的过程中,会产生很大的内存开销,可以通过迭代来实现归并排序,减小内存开销

归并排序的另一种实现方式:

对于一个给定的无序数组,把元素实行分组(其实就是在递归过程中的把列表每次平分的过程),开始的时候一个元素一组,然后每次扩大2倍,直到不能实行分组为止,循环结束。

假设分组的步长为i,n个元素,所以每一次分组以后分的组数为 n/i,每次取其中两组进行讨论,把这两组的元素从小到大排序。依次重复这个过程即可。

归并排序迭代实现的C++代码

#include <stdio.h>
#include <stdlib.h>

using namespace std;

void Merge_Sort(int k[], int n)
{
    // left_min 和 left_max 分别表示左边分组的最小值和最大值
    // right_min 和 right_max 分别表示右边分组的最小值和最大值
    int left_min, left_max, right_min, right_max;
    // 开辟一个临时数组
    int *temp = (int *)malloc(n * sizeof(int));

    // i 为迭代的步长
    for(int i = 1;i < n;i *= 2)
    {
        for(left_min = 0;left_min < n - i; left_min = right_max)
        {
            // 获取左边分组的最大值和最小值
            right_min = left_max = left_min + i;
            right_max = left_max + i;

            // 每一次分组以后各个分组的元素个数可能和最后一个分组不相等,
            // 所以要对最后一个分组进行讨论,防止越界
            if(right_max > n)
                right_max = n;

            int next = 0; // 临时数组的下表
            // 归并算法的两个分组元素的合并操作
            while(left_min < left_max && right_min < right_max)
            {
                if(k[left_min] < k[right_min])
                    temp[next ++] = k[left_min ++];
                else
                    temp[next ++] = k[right_min ++];
            }
            /*
            注意:
                当上面合并算法结束以后,可能会存在下面的两种情况
                1. 左边的分组元素没有取完,右边的分组元素全部取完
                    此时,要把左边部分没有取到的元素全部后移,放到k数组的结尾
                2. 右边的分组元素没有取完,左边的分组元素全部取完
                    此时, 不需要对没有取到的元素进行讨论,因为这些元素已经在 k 数组的结尾
            */
            // 右边的数据取完了,此时 right_min = right_max
            // 对上面注意事项中的 1 进行实现
            while(left_min < left_max)
                k[-- right_min] = k[-- left_max];
            //把 temp 临时数组的元素重新放入 k 数组中
            // 如果说上面的 while 语句没有执行的话,则证明是注意事项中 2 的这种情况,只需要把temp数组中
            // 当前的元素赋值给k数组即可,k数组后面没有变化的元素就是最开始while循环中右边分组没有取完的元素
            while(next > 0)
                k[-- right_min] = temp[-- next];
        }
    }
}

int main()
{
    int n = 10;
    int a[11];
    for(int i = 10;i >= 0;i --)
        a[10 - i] = i;

    printf("排序之前\n");
    for(int i = 0;i < 10;i ++)
        printf("%d ", a[i]);
    printf("\n");

    Merge_Sort(a, n);

    printf("排序之后\n");
    for(int i = 0;i < 10;i ++)
        printf("%d ", a[i]);
    printf("\n");

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值