问题描述 :
对于顺序存储的线性表(假定顺序表非空),使用vector或数组,实现二次归并排序的非递归算法,并输出中间及最终的排序结果。
参考函数原型:(vector版本)
(1)//一趟归并排序算法: (两路有序并为一路)
template<class ElemType>
void Merge( vector<ElemType> &A, int low,int mid,int high); //low为第1有序区的第1个元素,mid为第1有序区的最后1个元素
(2)非递归形式的两路归并排序算法
template<class ElemType>
void MergeSort( vector<ElemType> &A);
输入说明 :
第一行:顺序表A的数据元素的数据类型标记(0:int,1:double,2:char,3:string)
第二行:待排序顺序表A的数据元素(数据元素之间以空格分隔)
输出说明 :
如第一行输入值为0、1、2、3之外的值,直接输出“err”
否则:
第一行:第一趟的排序结果(数据元素之间以","分隔)
...
第n行: 最终的排序结果(数据元素之间以","分隔)
输入范例 :
0
21 25 49 25 93 62 72 8 37 16 54
输出范例 :
21,25,25,49,62,93,8,72,16,37,54
21,25,25,49,8,62,72,93,16,37,54
8,21,25,25,49,62,72,93,16,37,54
8,16,21,25,25,37,49,54,62,72,93
思路:
基本思想:将两个(或以上)的有序表组成新的有序表。
理论操作:可以把一个长度为n 的无序序列看成是 n 个长度为 1 的有序子序列 ,首先做两两归并,得到 【n / 2】(下取整)个长度为 2 的有序子序列 ;再做两两归并,…,如此重复,直到最后得到一个长度为 n 的有序序列。实际操作:(该处给出递归做法,下方代码实现用的是非递归)
(1)调用递归,先递归左序列(L,mid),再递归有序列(mid+1,R)。此时两个子序列各自有序了,然后再调用一个归并函数将左右序列归并为一个有序序列即可
(2)归并方法:先设定一个长度为L-R+1的空的辅助空间,然后设定两个游标分别指向两个子序列的首元素,比较两个游标指向的元素大小,小的拷贝进辅助空间,然后对应游标后移一位。直到两个子序列归并结束,再将辅助空间里排好序的元素一一拷贝(覆盖)原数组。
时间效率:O(nlog2n)
空间效率:O(n) 需要一个与原始序列同样大小的辅助序列(TR)。这正是此算法的缺点。
稳定性:稳定
图解:
代码实现:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <stdlib.h>
#include <cmath>
#include <vector>
#include <sstream> //用于ostringstream、istringstream、stringstream这三个类
#include<stack>
#include<vector>
#include<queue>
#include<list>
using namespace std;
template<class ElemType>
void createvector( vector<ElemType> &A )
{
ElemType tmp;
string temp;
getline(cin,temp);
stringstream input(temp); //输入流
while(input>>tmp)
A.push_back(tmp);
}
//一趟归并排序算法: (两路有序并为一路)
template<class ElemType>
void Merge( vector<ElemType> &A,int low,int mid,int high) //low为第1有序区的第1个元素,mid为第1有序区的最后1个元素
//A包含了以mid为分界的两个连续有序区
{
vector<ElemType>B;
int i=0,j=0;
for(i=low-1,j=mid;i<mid&&j<high;){
if(A[i]<A[j])
B.push_back(A[i++]);
else
B.push_back(A[j++]);
}
while(i<mid)
B.push_back(A[i++]);
while(j<high)
B.push_back(A[j++]);
for(int m=low-1,k=0;m<high;m++)
//干了件蠢事,此处和下面的for循环条件都设为 最大值<high+low-1 相当于最大值小于dk才能循环,导致只有第一次归并能进行,后续start都大于dk了一次循环都无法实现
A[m]=B[k++];
/* for(int i=low-1;i<high;i++)
cout<<A[i]<<" ";
cout<<endl;*/
}
//非递归形式的两路归并排序算法
template<class ElemType>
void MergeSort( vector<ElemType> &A)
{
int start=1;
int dk=1;//dk为一组有序区长度,每次待归并的为两组长度共2*dk
int length=A.size();
if(length==1)
cout<<A[0]<<endl;
while(dk<length){
start=1;
while(start+dk<=length){ //保证剩余的长度至少要大于一组有序区的长度,才需要去归并
int mid=start+dk-1,high=(mid+1)+dk-1;
if(high>length) high=length ; //最后一组长度不一定够dk个
Merge( A,start, mid, high);
start=high+1; //每两组依次进行一次归并
}
for(int i=0;i<length-1;i++)
cout<<A[i]<<",";
cout<<A[length-1]<<endl;
dk*=2;
}
}
int main()
{
int kd;
cin>>kd;
cin.ignore();
if(kd==0){
vector<int> A;
createvector( A );
MergeSort( A );
}
else if(kd==1){
vector<double>A;
createvector( A );
MergeSort( A );
}
else if(kd==2){
vector<char>A;
createvector( A );
MergeSort( A );
}
else if(kd==3){
vector<string >A;
createvector( A );
MergeSort( A );
}
else
cout<<"err"<<endl;
return 0;
}