数据结构实验八
南昌航空大学实验报告
二0 21 年 6 月 19 日
课程名称: 数据结构实验 实验名称: 内部排序
班级: 姓名: 同组人:
指导教师评定: 签名:
一、 需求分析
题目:验证下列排序算法:(必做题)直接插入排序、折半插入排序、希尔排序、冒泡排序、快速排序、简单选择排序、堆排序;(选做题)归并排序、基数排序。
1、输入数据数目,随机生成数据,在根据选择哪种排序方式进行排序,输出排序以及移动次数和比较次数。
2. 演示程序以用户和计算机对话的方式进行,即在计算机终端上显示“提示信息”之后,进行输入。
3. 程序执行的命令包括:
(1) 输入数据数目;
(2) 直接插入排序;
(3) 折半插入排序;
(4) 希尔排序;
(5) 冒泡排序;
(6) 快速排序;
(7) 简单选择排序;
(8) 堆排序;
(9) 归并排序
(10) 输出
(11) 结束
二、 概要设计
1. 抽象数据类型定义
为实现上述程序功能,需要一个抽象数据类型:图。
ADT Graph{
基本操作:
InsertSort(SqList &l)
操作结果:直接插入
BInsertSort(SqList &l)
操作结果:折半插入
ShellInsert(SqList &l)
操作结果:希尔排序
SelectSort(SqList &l)
操作结果:简单选择排序
BubbleSort(SqList &l)
操作结果:冒泡排序
QuickSort(SqList &l,int low,int high)
操作结果:快速排序
mergeSort(SqList &l, int left, int right, SqList &l1)
操作结果:归并排序
HeapSort(SqList &l)
操作结果:堆排序
show(SqList l)
操作结果:输出排序后结果
Sort(SqList &l)
操作结果:选择排序方式
creat(SqList &l)
操作结果:随机生成数据
2.程序模块
(1)主程序流程
void main{
初始化结构体;
输入数数目;
随机生成数;
选择排序方式;
}
(2) 直接插入排序;
(3) 折半插入排序;
(4) 希尔排序;
(5) 冒泡排序;
(6) 快速排序;
(7) 简单选择排序;
(8) 堆排序;
(9) 归并排序
(10)选择排序方式
(11)随机生成数
3.程序结构图
各模块之间的调用关系如图所示。
图1 模块之间调用关系图
三、 详细设计
1.数据类型及结构体
typedef struct{
int r[MAXSIZE+1];//r[0]闲置或者作哨兵或作暂存单元
int length;//长度
}SqList;
void InsertSort(SqList &l){//直接插入排序
void BInsertSort(SqList &l){//折半插入排序
void ShellInsert(SqList &l){//希尔排序
void SelectSort(SqList &l){//简单选择排序
void BubbleSort(SqList &l){//冒泡排序
void QuickSort(SqList &l,int low,int high) {//快速排序
void mergeSort(SqList &l, int left, int right, SqList &l1){//归并排序
void HeapSort(SqList &l){//堆排序
void show(SqList l){//输出
void Sort(SqList &l){//选择排序方式
void creat(SqList &l){//随机生成数据
2.主函数
int main(){
SqList l;
printf("请输入数据总个数:");
scanf("%d",&l.length);
creat(l);
Sort(l);
return 0;
}
四、 调试分析
1.经分析冒泡排序平均时间复杂度O(n^2),选择排序平均时间复杂度O(n^2),插入排序时间复杂度为:O(n^2),希尔排序时间复杂度O(n^1.5),快速排序、堆排序、归并排序时间复杂度为O(nlogn)。
2.分析各算法比较次数和移动次数如下表:
随机生成500个数据。
五、 用户手册
1. 本程序的运行环境为DOS操作系统,执行文件为:main.exe。
2. 进入演示程序后即显示文本方式的用户界面。
3. 程序运行后,按照提示信息输入信息。
4. 选择排序方式输出。
六、 测试结果
测试结果
七、 附录
源代码:#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define MAXSIZE 5000
typedef struct{
int r[MAXSIZE+1];//r[0]闲置或者作哨兵或作暂存单元
int length;//长度
}SqList;
void show(SqList);
void InsertSort(SqList &l){//直接插入排序
int i,j,k=0;
int move=0,compare=0;
if(l.length<2){
return;
}
for(i=2;i<=l.length;++i){
if(l.r[i]<l.r[i-1]){//前面小则说明这个数无需在排
l.r[0] = l.r[i];//将r[i]放入哨兵位
move++;
l.r[i] = l.r[i-1];
move++;
for(j=i-2;l.r[0]<l.r[j];j--,compare++)//不断向前比较,比哨兵大的数后挪,小的等的停止,j+1为哨兵该放入位置
{
l.r[j+1] = l.r[j];
move++;
}
l.r[j+1] = l.r[0];
move++;
}
compare++;
if(l.length<10){
printf("第%d趟:",++k);
show(l);
printf("\n");
}
}
printf("移动次数为:%d\n比较次数为:%d\n",move,compare);
return;
}
void BInsertSort(SqList &l){//折半插入排序
int i,j,k=0,low,high,m;
int move=0,compare=0;
if(l.length<2){
return;
}
for(i=2;i<=l.length;++i){
l.r[0] = l.r[i];
move++;
low = 1;
high = i-1;
while(low <= high){
m = (low+high)/2;
if(l.r[0]<l.r[m]){//大的话往小缩范围
high = m-1;
}
else{
low = m+1;
}
compare++;
}
for(j=i-1;j>=high+1;--j){//找到位置后将前面的依次往后推一位
l.r[j+1] = l.r[j];
move++;
}
l.r[high+1] = l.r[0];
move++;
if(l.length<10){
printf("第%d趟:",++k);
show(l);
printf("\n");
}
}
printf("移动次数为:%d\n比较次数为:%d\n",move,compare);
return;
}
void ShellInsert(SqList &l){//希尔排序
int i,j,k=0,gap,temp;
int move=0,compare=0;
if(l.length<2){
return;
}
for (gap = l.length/2;gap>0;gap/=2){//增量设为gap起始为length/2
for (i = gap;i<=l.length;i++){
j = i;
temp = l.r[j];
if (l.r[j]<l.r[j-gap]){
while(j-gap>0 && temp<l.r[j-gap]){//用于排除第一个和r[0]比较的交换,同时找到插入temp的位置
compare++;
l.r[j] = l.r[j-gap];
move++;
j = j-gap;
}
compare++;
l.r[j] = temp;
move++;
}
}
if(l.length<10){
printf("第%d趟:",++k);
show(l);
printf("\n");
}
}
printf("移动次数为:%d\n比较次数为:%d\n",move,compare);
return;
}
void SelectSort(SqList &l){//简单选择排序
int i,j,k,temp,flag;
int move=0,compare=0;
if(l.length<2){
return;
}
for(i=1;i<=l.length;i++){//不断找最排序的最小的
flag=i;
l.r[0]=l.r[i];
move++;
for(j=i;j<=l.length;j++,compare++){
if(l.r[0]>l.r[j]){
l.r[0]= l.r[j];
move++;
flag=j;
}
}
l.r[flag]=l.r[i];
move++;
l.r[i]=l.r[0];
move++;
if(l.length<10){
printf("第%d趟:",++k);
show(l);
printf("\n");
}
}
printf("移动次数为: %d\n",move);
printf("比较次数为: %d\n",compare);
return;
}
void BubbleSort(SqList &l){//冒泡排序
int i,j,k,flag,temp;
int move=0,compare=0;
if(l.length<2){
return;
}
for(i=1;i<=l.length;i++){
flag = 0;//是否经过移动,未经移动则说明后面已经排好没必要继续
for(j=1;j<=l.length-i;j++){
if(l.r[j+1]<l.r[j]){
flag = 1;
temp= l.r[j];
l.r[j] = l.r[j+1];
l.r[j+1] = temp;
move++;
move++;
}
compare++;
}
if(flag==0){
printf("移动次数为: %d\n",move);
printf("比较次数为: %d\n",compare);
return;
}
if(l.length<10)
{
printf("第%d趟:",++k);
show(l);
printf("\n");
}
}
return;
}
int Quickmove=0,Quickcompare=0;
void QuickSort(SqList &l,int low,int high) {//快速排序
int i,j,key; //选第一个做基准
if(low < high){
i = low;
j = high;
key = l.r[i];
while(i < j){ //不断缩拢 范围i-j
while(i < j && l.r[j] >= key){// 从右向左找第一个小于key的数,记录这个点 j
j--;
Quickcompare++;
}
if (i < j){
l.r[i] = l.r[j];
Quickmove++;
}
while(i < j && l.r[i] < key){//从左向右找第一个大于等于key的数,记录这个点i
i++;
Quickcompare++;
}
if (i < j){
l.r[j] = l.r[i];
Quickmove++;
}
}
l.r[i] = key;
Quickmove++;
QuickSort(l, low, i - 1);
QuickSort(l, i + 1, high);
}
}
int mergecompare=0,mergemove=0;
void merge(SqList &l , int left, int mid, int right,SqList &l1){
int i = left; //初始化i,左边有序序列的初始索引
int j = mid + 1; //初始化j,右边有序序列的初始索引
int t = 0; //指向temp数组的当前索引
while(i <= mid && j<= right)
{
if(l.r[i] <= l.r[j])
{
l1.r[t] = l.r[i];
i++;
t++;
}
else //反之右边的小于左边的当前元素
{
l1.r[t] = l.r[j];
j++;
t++;
}
mergecompare++,mergemove++;
}
while(i <= mid)
{
l1.r[t] = l.r[i];
t++;
i++;
mergemove++;
}
while(j <= right) //右边有剩余
{
l1.r[t] = l.r[j];
j++;
t++;
mergemove++;
}
t = 0;
int tempLeft = left;
while(tempLeft <= right)
{
l.r[tempLeft] = l1.r[t];
t++;
tempLeft++;
mergemove++;
}
}
void mergeSort(SqList &l, int left, int right, SqList &l1){//归并排序
if(left < right)
{
int mid = (left + right) / 2;
//向左进行递归分解
mergeSort(l, left, mid, l1);
//向左进行递归分解
mergeSort(l, mid + 1, right, l1);
//合并
merge(l, left, mid, right, l1);
}
}
int Heapcompare=0,Heapmove=0;
void HeapAdjust(SqList &l, int s, int length) {
int temp,i,j;
temp = l.r[s];
for(j=2*s;j<=length;j*=2){//找到非叶子结点的两个子节点,把三者中最大的换到非叶子节点内
if(j<length &&(l.r[j]<l.r[j+1])){
++j;
}
Heapcompare++;
if(temp>=l.r[j]){
Heapcompare++;
break;
}
l.r[s] = l.r[j];
Heapmove++;
s = j;
}
l.r[s] = temp;
Heapmove++;
}
void HeapSort(SqList &l){//堆排序
int i;
for(i=l.length/2;i>0;--i){
HeapAdjust(l,i,l.length);
}
for(i=l.length;i>1;--i){//把第一个最大的往后放
int temp = l.r[i];
l.r[i] = l.r[1];
Heapmove++;
l.r[1] = temp;
Heapmove++;
HeapAdjust(l,1,i-1);//不断把未排序的最大的放到第一个
}
}
void show(SqList l){
int i;
printf("最终排序为:");
for(i=1;i<=l.length;i++){
printf("%d ",l.r[i]);
}
printf("\n");
}
void Sort(SqList &l){
int a;
SqList l1,l2;
printf("0.结束 1.直接插入 2.折半插入 3.希尔 4.冒泡 5.快速排序 6.简单选择 7.堆 8.归并\n请输入:\n");
scanf("%d",&a);
while(a!=0){
l1 = l;
switch(a){
case 1:InsertSort(l1);break;
case 2:BInsertSort(l1);break;
case 3:ShellInsert(l1);break;
case 4:BubbleSort(l1);break;
case 5:QuickSort(l1,1,l1.length);printf("移动次数为:%d\n比较次数为:%d\n",Quickmove,Quickcompare);break;
case 6:SelectSort(l1);break;
case 7:HeapSort(l1);printf("移动次数为:%d\n比较次数为:%d\n",Heapmove,Heapcompare);break;
case 8:l2 = l1; mergeSort(l1,1,l.length,l2);printf("移动次数为:%d\n比较次数为:%d\n",mergemove,mergecompare);break;
}
printf("\n");
show(l1);
printf("\n0.结束 1.直接插入 2.折半插入 3.希尔 4.冒泡 5.快速 6.简单选择 7.堆 8.归并\n请输入:\n");
scanf("%d",&a);
}
}
void creat(SqList &l){
int i,a1;
srand(time(NULL));
printf("输入要排序的数:");
for(i=1;i<=l.length;i++){
a1=rand()%(10000)+1;//随机生成一个[1,10000)区间内的整数
//scanf("%d",&a1);
l.r[i] = a1;
}
}
int main(){
SqList l;
printf("请输入数据总个数:");
scanf("%d",&l.length);
creat(l);
Sort(l);
return 0;
}

浙公网安备 33010602011771号