归并排序的表现形式有多种,最常见的当然是递归归并排序,这里不再赘述。我们主要来实现两种不常用的归并排序形式:非递归归并排序和原地归并排序。
非递归归并排序
void Merge(int num[], int size)//size表示长度,因此索引应该最大是size-1
{
int len = 1;
while(len <= size)
{
for(int i = 0; i <= size - len; i+=2*len)
{
int low = i,mid = i+len-1,high = i+2*len-1;
if(high > size-1)
high = size-1;
merge_sort(num,low,mid,high);
}
len = len * 2;
}
}
void merge_sort(int num[], int l, int m, int h)
{
int temp[h-l+1];
int temp_iter = 0;
int lb = l;
int rb = m + 1;
while(lb <= m && rb <= h)
{
if(num[lb] < num[rb])
temp[temp_iter++] = num[lb++];
else
temp[temp_iter++] = num[rb++];
}
while(lb <= m)
temp[temp_iter++] = num[lb++];
while(rb <= h)
temp[temp_iter++] = num[rb++];
for(int j = l,i=0; j <= h,i < h-l+1; i++,j++)
num[j]=temp[i];
}
原地归并排序(关于理论知识,童鞋们可以在网上查找):
//原地归并排序
void swap(int &first,int &second)
{
//交换数组中两数的值
int temp;
temp = first;
first = second;
second = temp;
}
void reverse(int a[],int begin,int end)
{
//反转数组
while(begin < end)
{
swap(a[begin++],a[end--]);
}
}
void exchange(int a[],int begin,int mid,int end)
{
//分别反转前段和后段,之后反转整体
reverse(a,begin,mid);
reverse(a,mid+1,end);
reverse(a,begin,end);
}
void merge(int a[],int begin,int mid,int end) //mid是第一段的最后一个
{
int i = begin;
int j = mid + 1;
while( i < j && j <= end)
{
while(i < j && a[i] <= a[j]) //前段中小于中间值的数,索引后移;
{
i++;
}
int old_j = j;
while(j <= end && a[j] < a[i]) //后段中小于当前a[i]的数,索引后移
{
j++;
}
exchange(a,i,old_j-1,j-1);//两段数置换
i += (j - old_j);//前段数的后半段,应该向后移动的位数
}
}
void merge_sort(int a[],int begin,int end)
{
if(begin < end) //递归的自上向下进行处理
{
int mid = begin + (end - begin)/2;
merge_sort(a,begin,mid);
merge_sort(a,mid+1,end);
merge(a,begin,mid,end);
}
}