(1)问题描述
分别采用直接插入排序、希尔排序、简单选择排序、堆排序、冒泡排序、快速排序、归并排序算法进行排序,并对比较次数与移动次数进行比较。
(2)功能与界面要求
对随机序列、正序和逆序的进行上述各种排序算法的比较测试和分析。
待排序的记录不从键盘输入。随机序列应该是随机生成的 1—N 之间的 n 个整数。
要求设置菜单,在菜单提示下,输入 1-7 之间的整数,选择某一种排序方法进行排序,
输入 8,进行统计分析(比较上述 7 种内部排序算法的关键字比较次数和移动次数,以
取得直观感受),输入 0,则退出。
归并排序算法要求用递归的分治算法实现。
当选择功能 1-7 时:
输入:待排序元素个数 n,输入 m(关键字取值范围为 1-m)。
输出:输出自动生成的 n 个整数的初始序列。
输出排序后的序列。
输出初态分别是随机序列、正序和逆序时的比较次数、移动次数。
当选择功能 8 时:
输入:无。
n 不需要输入,在 1000-3000 之间随机产生,m 也不需要输入,表中关键字在 100-300 之
间随机产生。
至少用 5 组不同数据作比较。
比较指标有:关键字参加比较次数和关键字的移动次数。
(关键字交换记为 3 次移动)。
输出:显示比较结果。
代码如下
#include<bits/stdc++.h>
using namespace std;
#define Maxsize 10000+1
typedef int KeyType;
int mov; //移动次数
int com; //比较次数
int Light = 1; //控制输入
typedef struct{
KeyType key;//关键字
}RedType;
typedef struct{
RedType r[Maxsize];//r[0]是暂存单元,不是哨兵;
int Length;//顺序表长度
}SqList;
//菜单
void manu();
void manu1();
// 插入排序
void InserSort(int a[],int N);
// 选择排序
void SelectSort(int a[],int N);
// 冒泡排序
void bubble_sort(int* arr, int len);
// 快速排序
void QSort(int low,int high,KeyType arr[]);
// 归并排序
void Merge(KeyType R[],KeyType T[],int low,int mid,int high);
void MSort(KeyType R[],KeyType T[],int low,int high);
void MergeSort(KeyType arr[],int n);
// 堆排序
void HeapAdjust(SqList &L,int s,int m);//调整堆,假设r[s+1..m]已经是堆,则将r[s..m]调整r[s]为根的堆
void BuildHeap(SqList &L); //建立堆
void HeapSort(SqList &L); //堆排序
void Paixu(SqList &L);
// 希尔排序
void ShellInsert(SqList &L,int dk);
void ShellSort(SqList &L,int dt[],int t);
//初始化数组,产生随机序列
void InitArr(int arr[],int n,int m);
void CreatSq(SqList &L,int n,int m);
void CreatSq(SqList &L,int n);
// 逆置函数
void NiZhi(KeyType arr[],int n);
void Nizhi(SqList &L);
// 清空数组
void ClearList(SqList &L);
int main(){
int choose,flag = 1;
int arr[Maxsize];
int n,m;
while(flag){
if(Light){
system("cls");
manu();
}
cout<<"请选择排序方法:";
cin>>choose;
if(choose == 8)
Light = 0;
switch(choose){
case 1:{
mov = 0,com = 0;
if(Light){
cout<<"请分别输入数据个数和范围:";
cin>>n>>m;
}
InitArr(arr,n,m);
cout<<"排序前序列:"<<endl;
for(int i = 1;i <= n;i++)
cout<<arr[i]<<" ";
cout<<endl;
cout<<"排序后序列:"<<endl;
InserSort(arr,n);
for(int i = 1;i <= n;i++)
cout<<arr[i]<<" ";
cout<<endl;
cout<<"---------------------------------"<<endl;
cout<<"初态为随机序列"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
cout<<"---------------------------------"<<endl;
mov = 0,com = 0;
InserSort(arr,n);
cout<<"初态为正序"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
cout<<"---------------------------------"<<endl;
mov = 0,com = 0;
NiZhi(arr,n);
InserSort(arr,n);
cout<<"初态为逆序"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
system("pause");
Light = 1;
break;
}
case 2:{
mov = 0,com = 0;
if(Light){
cout<<"请分别输入数据个数和范围:";
cin>>n>>m;
}
InitArr(arr,n,m);
cout<<"排序前序列:"<<endl;
for(int i = 1;i <= n;i++)
cout<<arr[i]<<" ";
cout<<endl;
cout<<"排序后序列:"<<endl;
SelectSort(arr,n);
for(int i = 1;i <= n;i++)
cout<<arr[i]<<" ";
cout<<endl;
cout<<"---------------------------------"<<endl;
cout<<"初态为随机序列"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
cout<<"---------------------------------"<<endl;
mov = 0,com = 0;
SelectSort(arr,n);
cout<<"初态为正序"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
cout<<"---------------------------------"<<endl;
mov = 0,com = 0;
NiZhi(arr,n);
SelectSort(arr,n);
cout<<"初态为逆序"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
Light = 1;
system("pause");
break;
}
case 3:{
mov = 0,com = 0;
if(Light){
cout<<"请分别输入数据个数和范围:";
cin>>n>>m;
}
InitArr(arr,n,m);
cout<<"排序前序列:"<<endl;
for(int i = 1;i <= n;i++)
cout<<arr[i]<<" ";
cout<<endl;
cout<<"排序后序列:"<<endl;
bubble_sort(arr,n);
for(int i = 1;i <= n;i++)
cout<<arr[i]<<" ";
cout<<endl;
cout<<"---------------------------------"<<endl;
cout<<"初态为随机序列"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
cout<<"---------------------------------"<<endl;
mov = 0,com = 0;
bubble_sort(arr,n);
cout<<"初态为正序"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
cout<<"---------------------------------"<<endl;
mov = 0,com = 0;
NiZhi(arr,n);
bubble_sort(arr,n);
cout<<"初态为逆序"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
Light = 1;
system("pause");
break;
}
case 4: {
mov = 0,com = 0;
if(Light){
cout<<"请分别输入数据个数和范围:";
cin>>n>>m;
}
InitArr(arr,n,m);
cout<<"排序前序列:"<<endl;
for(int i = 1;i <= n;i++)
cout<<arr[i]<<" ";
cout<<endl;
cout<<"排序后序列:"<<endl;
QSort(1,n,arr);
for(int i = 1;i <= n;i++)
cout<<arr[i]<<" ";
cout<<endl;
cout<<"---------------------------------"<<endl;
cout<<"初态为随机序列"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
cout<<"---------------------------------"<<endl;
mov = 0,com = 0;
QSort(1,n,arr);
cout<<"初态为正序"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
cout<<"---------------------------------"<<endl;
mov = 0,com = 0;
NiZhi(arr,n);
QSort(1,n,arr);
cout<<"初态为逆序"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
Light = 1;
system("pause");
break;
}
case 5: {
mov = 0,com = 0;
if(Light){
cout<<"请分别输入数据个数和范围:";
cin>>n>>m;
}
InitArr(arr,n,m);
cout<<"排序前序列:"<<endl;
for(int i = 1;i <= n;i++)
cout<<arr[i]<<" ";
cout<<endl;
cout<<"排序后序列:"<<endl;
MergeSort(arr,n);
for(int i = 1;i <= n;i++)
cout<<arr[i]<<" ";
cout<<endl;
cout<<"---------------------------------"<<endl;
cout<<"初态为随机序列"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
cout<<"---------------------------------"<<endl;
mov = 0,com = 0;
MergeSort(arr,n);
cout<<"初态为正序"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
cout<<"---------------------------------"<<endl;
mov = 0,com = 0;
NiZhi(arr,n);
MergeSort(arr,n);
cout<<"初态为逆序"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
Light = 1;
system("pause");
break;
}
case 6: {
if(Light){
cout<<"请分别输入数据个数和范围:";
cin>>n>>m;
}
SqList L;
com=0;
mov=0;
CreatSq(L,n,m);
HeapSort(L);//堆排序
cout<<"排序后的顺序"<<endl;
for(int i=1;i<=n;i++)//输出堆排序后的顺序
cout<<L.r[i].key<<" ";
cout<<endl;
cout<<"---------------------------------"<<endl;
cout<<"初态为随机序列"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
cout<<"---------------------------------"<<endl;
com=0;
mov=0;
Paixu(L);
HeapSort(L);//推排序
cout<<"初态为正序"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
cout<<"---------------------------------"<<endl;
com=0;
mov=0;
Nizhi(L);
HeapSort(L);//堆排序
cout<<"初态为逆序"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
ClearList(L);
Light = 1;
system("pause");
break;
}
case 7: {
SqList L;
com=0;
mov=0;
int t,dt[t],a;
if(Light){
cout<<"请分别输入数据个数和范围:";
cin>>n>>m;
}
cout<<"输入t,增量序列的每个增量a:"<<endl;
cin>>t;
for(int i=0;i<t;i++){
cin>>a;
dt[i]=a;
}
CreatSq(L,n,m);
ShellSort(L,dt,t);
cout<<"排序后序列:"<<endl;
for(int i=1;i<=n;i++)
cout<<L.r[i].key<<" ";
cout<<endl;
cout<<"---------------------------------"<<endl;
cout<<"初态为随机序列"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
cout<<"---------------------------------"<<endl;
mov=0;
com=0;
ShellSort(L,dt,t);
cout<<"初态为正序"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
cout<<"---------------------------------"<<endl;
mov=0;
com=0;
Nizhi(L);
ShellSort(L,dt,t);
cout<<"初态为逆序"<<endl;
cout<<"比较次数:"<<com<<endl;
cout<<"移动次数:"<<mov<<endl;
Light = 1;
system("pause");
break;
}
case 8:{
mov = 0,com = 0;
n = rand()%2000 + 1000;
m = 201;
system("cls");
manu1();
Light = 0;
break;
}
default:
cout<<"请重新输入!"<<endl;
system("pause");
break;
}
}
}
void manu(){
cout<<"*************************************************"<<endl;
cout<<"* 1. 插入排序 *"<<endl;
cout<<"* 2. 选择排序 *"<<endl;
cout<<"* 3. 冒泡排序 *"<<endl;
cout<<"* 4. 快速排序 *"<<endl;
cout<<"* 5. 归并排序 *"<<endl;
cout<<"* 6. 堆排序 *"<<endl;
cout<<"* 7. 希尔排序 *"<<endl;
cout<<"* 8. 无输入 *"<<endl;
cout<<"*************************************************"<<endl;
}
void manu1(){
cout<<"*************************************************"<<endl;
cout<<"* 1. 插入排序 *"<<endl;
cout<<"* 2. 选择排序 *"<<endl;
cout<<"* 3. 冒泡排序 *"<<endl;
cout<<"* 4. 快速排序 *"<<endl;
cout<<"* 5. 归并排序 *"<<endl;
cout<<"* 6. 堆排序 *"<<endl;
cout<<"* 7. 希尔排序 *"<<endl;
cout<<"*************************************************"<<endl;
}
// -------------------------------------------------------------------------------------------------------
// 插入排序
void InserSort(int a[],int N){
int j;
for(int i=2;i<=N;i++){
int t=a[i];
for(j=i-1;j>=1&&t<a[j];j--){
a[j+1]=a[j];
com++;
mov++;
}
com++;
a[j+1]=t;
}
}
// -------------------------------------------------------------------------------------------------------
// 选择排序
void SelectSort(int a[],int N){
int i,j,temp;
for(i=1;i<=N-1;i++){
for(j=i+1;j<=N;j++){
if(a[i]>a[j]){
temp=a[i];
a[i]=a[j];
a[j]=temp;
mov += 3;
}
com++;
}
}
}
// -------------------------------------------------------------------------------------------------------
// 冒泡排序
void bubble_sort(int* arr, int len)
{
for (int i = len - 1; i >= 1; i--){
for (int j = 1; j <= i; j++){
if (arr[j] > arr[j + 1]){
int t = arr[j];
arr[j] = arr[j+1];
arr[j+1] = t;
mov += 3;
}
com++;
}
}
}
// -------------------------------------------------------------------------------------------------------
// 快速排序
void QSort(int low,int high,KeyType arr[]){
if(low >= high)
return;
int i,j,base,temp;
i = low,j = high;
base = arr[low];
while(i < j){
while(arr[j] >= base && i < j){
com++;
j--;
}
while(arr[i] <= base && i < j){
com++;
i++;
}
if(i < j){
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
mov += 3;
}
com++;
}
//基准数归位
arr[low] = arr[i];
arr[i] = base;
mov += 2;
QSort(low,i-1,arr); //递归左边
QSort(i+1,high,arr); //递归右边
}
// -------------------------------------------------------------------------------------------------------
// 归并排序
void Merge(KeyType R[],KeyType T[],int low,int mid,int high){
int i = low;
int j = mid + 1;
int k = low;
while(i <= mid && j <= high){
if(R[i] <= R[j])
T[k++]=R[i++];
else
T[k++] = R[j++];
mov++;
com++;
}
while(i<=mid){
T[k++]=R[i++];
mov++;
}
while(j<=high){
T[k++]=R[j++];
mov++;
}
}
void MSort(KeyType R[],KeyType T[],int low,int high){
int mid;
int S[Maxsize];
if(low == high)
T[low] = R[low];
else{
mid = (low+high)/2;
MSort(R,S,low,mid);
MSort(R,S,mid+1,high);
Merge(S,T,low,mid,high);
}
}
void MergeSort(KeyType arr[],int n){
MSort(arr,arr,1,n);
}
// -------------------------------------------------------------------------------------------------------
// 堆排序
void HeapAdjust(SqList &L,int s,int m)
{
RedType rc;
rc=L.r[s];
mov++;
for(int j=2*s;j<=m;j*=2)//沿着key较大的孩子结点向下筛选
{
com+=2;
if(j<m&&L.r[j].key<L.r[j+1].key) ++j;//j 为 key 较大的记录下标
if(rc.key>=L.r[j].key) break; //rc应插在位置s上
L.r[s]=L.r[j];
mov++;
s=j;
}
mov++;
L.r[s]=rc;//交换
}
void BuildHeap(SqList &L)
{
int n;
n=L.Length;
for(int i=n/2;i>0;i--)
{
HeapAdjust(L,i,n);
}
}
void HeapSort(SqList &L)
{
RedType x;
BuildHeap(L);
for(int i=L.Length;i>1;--i)
{
x=L.r[1];//将堆顶记录和当前未经排序的子序列L.[1...i]中最后一个记录交换
L.r[1]=L.r[i];
L.r[i]=x;
mov+=3;
HeapAdjust(L,1,i-1);//将L.r[1...i-1]重新调整为大根堆
}
}
void Paixu(SqList &L){
int m=L.Length-1;
int flag=1;
while((m>0)&&(flag==1)){
flag=0;
for(int j=0;j<=m;j++){
if(L.r[j].key>L.r[j+1].key){
RedType t;
flag=1;
t=L.r[j];
L.r[j]=L.r[j+1];
L.r[j+1]=t;
}
}
}
}
// -------------------------------------------------------------------------------------------------------
// 希尔排序
void ShellInsert(SqList &L,int dk){
for(int i=dk+1;i<=L.Length;++i){
if(L.r[i].key<L.r[i-dk].key){
L.r[0]=L.r[i];
int j;
for(j=i-dk;j>0&&L.r[0].key<L.r[j].key;j-=dk){
L.r[j+dk]=L.r[j];
mov++;
}
L.r[j+dk]=L.r[0];
}
com++;
}
com++;
}
void ShellSort(SqList &L,int dt[],int t)
{//按增量序列·dt[0..t-1]对顺序表L作t趟希尔排序
for(int k=0;k<t;++k)
ShellInsert(L,dt[k]);
}
// -------------------------------------------------------------------------------------------------------
// 其他函数
void InitArr(int arr[],int n,int m){
if(Light)
for(int i = 1;i <= n;i++)
arr[i] = rand()%m + 1;
else
for(int i = 1;i <= n;i++)
arr[i] = rand()%200 + 100;
}
void CreatSq(SqList &L,int n,int m){
L.Length=n;
srand((int)time(NULL));
for(int i=1;i<=n;i++){
L.r[i].key=rand()%m+1;
for(int j=1;j<i;j++){
if(Light)
L.r[i].key=rand()%m+1;
else
L.r[i].key=rand()%m+100;
}
}
cout<<"排序前序列: "<<endl;
for(int i=1;i<=n;i++)
cout<<L.r[i].key<<" ";
cout<<endl;
}
void CreatSq(SqList &L,int n){
L.Length=n;
cout<<"请输入推排序,关键字取值范围\n1:100\n2:1000\n3:10000"<<endl;
srand((int)time(NULL));
int i,t;
cin>>t;
for(i=1;i<=n;i++){
if(t==1)
L.r[i].key=rand()%100;
if(t==2)
L.r[i].key=rand()%1000;
if(t==3)
L.r[i].key=rand()%10000;
}
cout<<"输出随机顺序"<<endl;
for(i=1;i<=n;i++)
cout<<L.r[i].key<<" ";
cout<<endl;
}
void NiZhi(KeyType arr[],int n){
int l = n/2;
int t;
for(int i = 1;i<=l;i++){
t = arr[i];
arr[i] = arr[n-i+1];
arr[n-i+1] = t;
}
}
void Nizhi(SqList &L){
RedType t;
int q=L.Length/2;
for(int i=1;i<=q;i++){
t=L.r[i];
L.r[i]=L.r[L.Length-i+1];
L.r[L.Length-i+1]=t;
}
}
void ClearList(SqList &L){
L.Length=0;
}