排序算法之(6)--归并排序

介绍

归并排序(Merging Sort)就是利用归并的思想实现的排序方法。它的原理是假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到⌈n/2⌉(⌈x⌉表示不小于x的最小整数)个长度为2或1的有序子序列;再两两归并,……,如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2路归并排序。

一开始,我们把每两两个数据看成排好的序列,就能实现归并了,这也是递归的出口。所以一开始的递归入口是把数据分成两半,一直递归调用归并排序,最终就会触发两两数据就是两个序列的出口条件。(写过代码,理解这句不难,没写过就难了)
这里写图片描述
这张图直接从递归最深处开始画了。


代码

//辅助函数:交换两个变量
void swap(int*a,int*p)
{
    int temp = *a;
    *a = *p;
    *p = temp;
}

//归并排序
//本质上是把两个已经排好的序列合并成一个
//如果对一个随机序列的两两元素来看,那么每个元素都是排好的序列
//可以把一个数组拆分成前后两半来做这件事
//这个算法需要额外的辅助空间,用来存放归并好的结果
void mergeSort(int* arr,int start,int end)
{
    if(start>=end)
    {
        return;
    }
    int i = start;
    int mid = (start+end)/2;
    int j = mid + 1;
    mergeSort(arr,i,mid);
    mergeSort(arr,j,end);

    //合并
    //其实我觉得不用这个额外的空间也行,两个子序列再排一次能减少空间,不过速度肯定会有影响
    int* temp = (int*)malloc((end-start+1)*sizeof(int));
    int index = 0;
    //开始对比两个子序列,头部最小的那个数放到新空间
    while(i<=mid&&j<=end)
    {
        if(arr[i]<=arr[j])
        {
            temp[index++] = arr[i++];
        }else
        {
            temp[index++] = arr[j++];
        }
    }
    //总有一个序列是还没有放完的,这里再遍历一下没放完的
    while(i<=mid)
    {
        temp[index++] = arr[i++];
    }
    while(j<=end)
    {
        temp[index++] = arr[j++];
    }
    //排完再把新空间的元素放回旧空间
    int k = start;
    for(k;k<=end;k++)
    {
        //哎,temp的下标写错,排查了一个钟,真菜
        arr[k] = temp[k-start];
    }
    free(temp);
}

猜你喜欢

转载自blog.csdn.net/hiudawn/article/details/80378075