准备知识点
1. 块交换
对数组a[0, ..., i-1, i, ..., n-1]的0...i-1部分和(i...n-1}部分进行交换得到 a[i, ..., n-1, 0, ..., i-1]。
例如,交换数组{0,1,2,3,4}的前半部分{0,1}与后半部分{2,3,4}得到数组
{2,3,4,0,1},如下图所示。
(顺便提一下,近年考研题目恰巧有这道算法题)
思路:
逆序{0, ..., i-1}的部分得{i-1, ..., 0}
逆序{i, ..., n-1}的部分得{n-1, ..., i}
此时的数组变为{i-1,..., 0, i, n-1, ...., i}
再对整个数组进行一次逆序得
{i, ..., n-1, 0, ..., i-1}
时间复杂度是O(n)。
块交换的3个算法:
Juggling | Gries-Mills | Reversal |
---|
http://blog.csdn.net/zzran/article/details/8125826#t2
原地归并排序
不需要辅助数组即可归并。
关键在于merge这个函数。两段递增的子数组arr[begin…mid-1]和arr[mid…end],i=begin,j=mid,k=end
i往后移动,找到第一个arr[i]>arr[j]的索引
j往后移动,再找第一个arr[j]>arr[i]的索引
然后我们将i到mid的部分和mid到j-1的部分对调,较小的部分就调到前面去了,然后从后面的部分与j到k的部分又是两个递增的子数组,继续迭代即可。
C/C++实现#include <iostream>
using namespace std;
//交换两个数
void swap(int *a,int *b)
{
int temp=*a;
*a=*b;
*b=temp;
}
//将长度为n的数组逆序
void reverse(int *arr,int n)
{
int i=0,j=n-1;
while(i<j)
{
swap(arr[i],arr[j]);
i++;
j--;
}
}
//将数组向左循环移位i个位置
void exchange(int *arr,int n,int i)
{
reverse(arr,i);
reverse(arr+i,n-i);
reverse(arr,n);
}
//数组两个有序部分的归并
void merge(int *arr,int begin,int mid,int end)
{
int i=begin,j=mid,k=end;
while(i<j && j<=k)
{
int step=0;
while(i<j && arr[i]<=arr[j])
++i;
while(j<=k && arr[j]<=arr[i])
{
++j;
++step;
}
exchange(arr+i,j-i,j-i-step);
i=i+step;
}
}
void MergeSort(int *arr,int l,int r)
{
if(l<r)
{
int mid=(l+r)/2;
MergeSort(arr,l,mid);
MergeSort(arr,mid+1,r);
merge(arr,l,mid+1,r);
}
}
int main()
{
int arr[]={6,4,3,1,7,8,2,9,5,0};
int len=sizeof(arr)/sizeof(arr[0]);
MergeSort(arr,0,len-1);
for(int i=0;i<len;++i)
cout <<arr[i]<<" ";
cout <<endl;
return 0;
}
参考网址:
http://www.cnblogs.com/daniagger/archive/2012/07/25/2608373.html
http://www.cnblogs.com/zhanglanyun/archive/2012/09/10/2679370.html
http://zju3053027087.blog.163.com/blog/static/13064377720124732052698/