归并排序-就地排序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了归并排序-就地排序相关的知识,希望对你有一定的参考价值。

题目要求:对归并排序进行修改,要求合并过程的空间复杂度为O(1)

解题思路:

假设a[beg, mid]和b[mid+1,end]是两段有序的子段,分别记做A和B,现要对其进行合并

1) 首先对A进行搜索,找到比B[0]大的第一个位置,记录为i,即A[0~i-1] < B[0],而A[i] > B[0];

2) 对B进行搜索,找到大于A[i]的第一个位置,记录为j,则B[0~j-1]<B[i]

3) 将A[i,mid], B[0,j-1] 进行旋转,使得B[0,j-1]旋转到左边,得到B[0,j-1] A[i, mid]

4)A[i, mid] B[j, end]是原来问题的一个子问题,继续上述1)-3)的步骤

下面是具体实现的代码:

#include <iostream>

using namespace std;

 

void reverse(int *array, int beg, int end)

{

    while(beg < end)

    {

        int tmp = array[beg];

        array[beg] = array[end];

        array[end] = tmp;

        ++beg;

        --end;

    }

}

 

void rotate(int *array, int beg, int end, int len)

{

    len = len % (end - beg + 1);

    reverse(array, beg, end - len);

    reverse(array, end - len + 1, end);

    reverse(array, beg, end);

}

 

void merge(int *array, int beg, int mid, int end)

{

    int i = beg;

    int j = mid + 1;

    while(i <= end && j <=end && i < j)

    {

        while(i <= end && array[i] < array[j])

        {

            ++i;

        }        

        int k = j;

        while(j <= end && array[j] < array[i])

        {

            ++j;

        }        

        if(j > k)   // 注意这个条件

        {

            rotate(array, i, j-1, j-k);

        }

        

        i += (j -k + 1);

    }

}

 

void mergeSort(int *array, int beg, int end)

{

    if(beg == end)

        return;

        

    int mid = (beg + end) >> 1;

    mergeSort(array, beg, mid);

    mergeSort(array, mid + 1, end);

    merge(array, beg, mid, end);

}

 

int main()

{

    int array[] = {8, 7, 6, 5, 4, 3, 2, 1};

    int beg = 0;

    int end = sizeof(array) / sizeof(int) - 1;

    mergeSort(array, beg, end);

    

    for(int i=beg; i<=end; ++i)

    {

        cout << array[i] << " ";

    }

    cout << endl;

    

    return 0;

}

以上是关于归并排序-就地排序的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中实现归并排序

各种排序算法的时间复杂度

堆与堆排序

排序之归并排序的算法思想及实现代码

排序算法之快速排序Java实现

排序之外部排序