归并排序-就地排序

题目要求:对归并排序进行修改,要求合并过程的空间复杂度为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;

}

时间: 2024-12-18 20:08:41

归并排序-就地排序的相关文章

常见的排序算法(四)( 归并排序,计数排序 , 基数排序)

 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得到完全有序的序列:即先使每个子序列有序,再使子序列段间有序.若将两个有序表合并成一个有序表,称为二路归并. (如果读者不太了解什么叫分治法,可以去看看<算法导论>第一二章.) 归并过程为:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1:否则将第

归并排序-八大排序三大查找汇总(7)

基本思想 归并排序简单的说就是递归后合并,该算法是分治法(Divide and Conquer)的一个典型应用. 基本思想为:将待排序序列R[0...n-1]看成是n个长度为1的有序序列,两两有序表成对归并,得到n/2个长度为2的有序表:将这些有序序列再次归并,如此反复进行下去,最后得到一个长度为n的有序序列. 综上可知: 归并排序其实要做两件事: (1)“分解”——将序列每次折半划分. (2)“合并”——将划分后的序列段两两合并后排序. 性能 排序类别 排序方法 时间复杂度 空间复杂度 稳定性

排序 归并排序 分配排序

归并排序          基本思想:将两个或两个以上的有序子序列"归并"为一个有序子序列.在内部排序中,通常采用的是2-路归并排序,即将两个位置相邻的有序子序列"归并"为一个有序序列.类似于快排,其使用的也是分治的策略. 二路归并排序 基本思想:将有n个记录的原始序列看做n个有序子序列,每个子序列的长度为1,然后从第1个子序列开始,把相邻的子序列两两合并,得到n/2个长度为2或1的子序列(当子序列的个数为奇数是,最后一组合并得到的序列长度为1),我们把这一过程称为

数据结构单链表就地排序

void LinListSort(LinList<T> &L) { ListNode<T> *curr, *pre, *p, *q; p = L.head->next; //原单链表L.head->next = NULL; //新单链表 while(p != NULL) { curr = L.head->next; pre = L.head; while(curr != NULL && curr->data <= p->d

我的Java开发学习之旅------&amp;gt;Java经典排序算法之归并排序

一.归并排序 归并排序是建立在归并操作上的一种有效的排序算法,该算法是採用分治法(Divide and Conquer)的一个很典型的应用.将已有序的子序列合并,得到全然有序的序列.即先使每一个子序列有序.再使子序列段间有序.若将两个有序表合并成一个有序表.称为二路归并. 归并过程为:比較a[i]和a[j]的大小.若a[i]≤a[j],则将第一个有序表中的元素a[i]拷贝到r[k]中,并令i和k分别加上1.否则将第二个有序表中的元素a[j]拷贝到r[k]中,并令j和k分别加上1.如此循环下去.直

排序算法总结之归并排序

基本思想 设归并排序的当前区间是R[low..high],分治法的三个步骤是: ①分解:将当前区间一分为二,即求分裂点 ②求解:递归地对两个子区间R[low..mid]和R[mid+1..high]进行归并排序: ③组合:将已排序的两个子区间R[low..mid]和R[mid+1..high]归并为一个有序的区间R[low..high]. 递归的终结条件:子区间长度为1(一个记录自然有序). 将两个有序序列合并成一个新的有序序列. ①把 n 个记录看成 n 个长度为 1的有序子表: ②进行两两归

如何给10^7个数据量的磁盘文件进行排序--归并排序

接上面的题目,假若待排序的数据有重复的呢?这里采用的是归并排序. 1.算法分析:     1.稳定性:归并排序是一种稳定的排序.    2.存储结构要求:可用顺序存储结构.也易于在链表上实现.    3.时间复杂度: 对长度为n的文件,需进行lgn趟二路归并,每趟归并的时间为O(n),故其时间复杂度无论是在最好情况下还是在最坏情况下均是O(nlgn)..    4.空间复杂度:需要一个辅助向量来暂存两有序子文件归并的结果,故其辅助空间复杂度为O(n),显然它不是就地排序. 2.总结 与快速排序相

我的Java开发学习之旅------&gt;Java经典排序算法之归并排序

一.归并排序 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得到完全有序的序列:即先使每个子序列有序,再使子序列段间有序.若将两个有序表合并成一个有序表,称为二路归并. 归并过程为:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1:否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直

排序算法的C语言实现(上 比较类排序:插入排序、快速排序与归并排序)

总述:排序是指将元素集合按规定的顺序排列.通常有两种排序方法:升序排列和降序排列.例如,如整数集{6,8,9,5}进行升序排列,结果为{5,6,8,9},对其进行降序排列结果为{9,8,6,5}.虽然排序的显著目的是排列数据以显示它,但它往往可以用来解决其他的问题,特别是作为某些成型算法的一部分. 总的来说,排序算法分为两大类:比较排序 和 线性时间排序. 比较排序依赖于比较和交换来将元素移动到正确的位置上.它们的运行时间往往不可能小于O(nlgn). 对于线性时间排序,它的运行时间往往与它处理