归并排序
1. 将若干有序序列逐步归并为一个有序序列。
2. 二路归并:最简单,将若干有序序列两两归并,直至形成一个有序序列。
3. 采用的分治法。
4. 二路归并非递归思路:
1. 将序列分成n个序列,每个序列一个元素,这样可以任务每个序列都是有序序列。
2. 逐一合并两个相邻的序列,使得每个序列长度为2.
3. 重复步骤2,直到序列的长度为n。
4. 子序列合并过程中有三种情况
1. 子序列数目为偶数且子序列长度相等。
2. 子序列数目为偶数且最后一个子序列长度小于其他子序列。
3. 子序列数目为奇数(最后剩下一个子序列)。
5.比较占内存、效率高、稳定的排序算法。
复杂度
1. 一趟归并排序:O(n)。
2. 整个归并排序,需要【log2n】取整趟,例如:8个数三趟。
3. 所以总的视觉代价是O(nlogn),最好、最坏、平均的时间性能。
4. 空间复杂度:非递归时候只需要O(n),小于递归时候占的内存,实际使用中推荐使用非递归方法。
5. 排序每次都是在相邻的数据中进行操作,所以归并排序在O(N*logN)的几种排序方法(快速排序,归并排序,希尔排序,堆排序)也是效率比较高的。
图示
代码实现
非递归方法
void Merge(int r[ ], int r1[ ], int s, int m, int t)
{
/*
一次归并算法
s:start m:middle t:tail
r数组分为s——m,和m+1——t,两个部分。
r1为归并好的数组。*/
int i=s;
int j=m+1;
int k=s;
while (i<=m && j<=t)
{
if (r[i]<=r[j])
{
r1[k++]=r[i++]; //取r[i]和r[j]中较小者放入r1[k]
}
else
{
r1[k++]=r[j++];
}
}
if (i<=m) while (i<=m) //若第一个子序列没处理完,则进行收尾处理
{
r1[k]=r[i];
i++;
k++;
}
else while (j<=t) //若第二个子序列没处理完,则进行收尾处理
{
r1[k]=r[j];
k++;
j++;
}
}
void MergePass(int r[ ], int r1[ ], int n, int h)
{
//根据步长将相邻的两个子序列合并
int i=1;
//待归并记录至少有两个长度为h的子序列,之所以n+1,是因为我们从r[1]开始
while(i<=(n-2*h+1))
{
//若每个子序列相等且是偶数个,则一直走这个循环1 3 …… n-2*h+1 n+1(不成立跳出循环)
//将相邻的有序序列合并成一个有序序列
Merge(r, r1, i, i+h-1, i+2*h-1);
i = i + 2*h;
}
//待归并序列中有一个长度小于h,此时分为两段i——i+h-1,i+h——n,可推得i>(n-2*h+1)
if (i<n-h+1)
{ //当最后一个子序列长度小于其他子序列,且子序列数目为偶数
//n+1-2h<i<n+1-h
Merge(r, r1, i, i+h-1, n);
}
else
{
//待归并序列中只剩一个子序列,子序列数目为奇数,剩下的孤零零的一个子序列(长度<=h)
for (int k=i; k<=n; k++)
{
r1[k]=r[k];
}
}
}
void MergeSort1(int r[ ], int r1[ ], int n )
{
cout<<"MergeSort:"<<endl;
int h=1;//初始序列长度为1,当序列长度达到n时候,意味着排序完成,此时h>=n
while (h<n)
{
int i ;
MergePass(r, r1, n, h);
cout<<"步长h:"<<h<<endl;
for (i = 1;i<10;i++)
{
cout<<r1[i]<<" ";
}
cout<<endl;
h=2*h;//每次序列合并之后,第一个单个序列长度为2h
int *p = r;
r = r1;
r1 = p;
}
}
递归方法
void Merge(int r[ ], int r1[ ], int s, int m, int t)
{
/*
一次归并算法
s:start m:middle t:tail
r数组分为s——m,和m+1——t,两个部分。
r1为归并好的数组。*/
int i=s;
int j=m+1;
int k=s;
while (i<=m && j<=t)
{
if (r[i]<=r[j])
{
r1[k++]=r[i++]; //取r[i]和r[j]中较小者放入r1[k]
}
else
{
r1[k++]=r[j++];
}
}
if (i<=m) while (i<=m) //若第一个子序列没处理完,则进行收尾处理
{
r1[k]=r[i];
i++;
k++;
}
else while (j<=t) //若第二个子序列没处理完,则进行收尾处理
{
r1[k]=r[j];
k++;
j++;
}
}
void MergeSort2(int r[ ], int r1[ ], int s, int t)
{
int m;
if (s==t)
{
r1[s]=r[s];
}
else
{
m=(s+t)/2;
MergeSort2(r, r1, s, m); //归并排序前半个子序列
MergeSort2(r, r1, m+1, t); //归并排序后半个子序列
Merge(r1, r, s, m, t); //将两个已排序的子序列归并
}
}
注意:代码中的排序都是从r[1]开始的。
时间: 2024-10-04 16:35:13