一、实验目的
1.掌握常见的内部排序算法的思想及其适用条件;
2.掌握常见的内部排序算法的程序实现;
二、实验内容及要求
1、任务描述
设计一个内部排序算法模拟系统,利用该系统实现常用的 7 种排序算法,并测试
各种排序算法的性能。
实验内容:通过一个简单的菜单,分别实现下列排序要求,采用几组不同数据测试各排
序算法的性能(比较次数和移动次数)及稳定性。
◆ 实现简单选择排序、直接插入排序和冒泡排序;
◆ 实现折半插入排序;
◆ 实现希尔排序算法;
◆ 实现快速排序算法(递归和非递归);
◆ 实现堆排序算法
输入和输出:
(1)输入形式:根据菜单提示选择排序算法,输入一组带排序数据。
(2)输出形式:输出排序结果(体现排序过程),及排序过程中数据的比较次数和移动次数,判断排序算法的稳定性。
实验要求:
实现一个简单的交互式界面,包括系统菜单、清晰的输入提示等。
◆ 要输出每一趟排序的结果。
◆ 能够上机编辑、调试出完整的程序。
2、主要数据类型与变量
typedef struct
{
int r[MAXSIZE + 1]; /* 用于存储要排序数组,r[0]用作哨兵或临时变量 */
int length; /* 用于记录顺序表的长度 */
}SqList;
#define MAXSIZE 10000 /* 用于要排序数组个数最大值,可根据需要修改 */
3、算法或程序模块
1. void SelectSort(SqList* L)
通过n-1次关键词间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i个记录进行交换。
2.void InsertSort(SqList* L)
将一个记录插入到已经排好序的有序表中,从而得到一个新的,记录数增1的有序表。
3.void BubbleSort(SqList* L)
两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。
4.void BinarySort(SqList* L)
不断的依次将元素插入前面已排好序的序列中。由于前半部分为已排好序的数列,因此不用按顺序依次寻找插入点,可以采用折半查找的方法来加快寻找插入点的速度。
5. void ShellSort(SqList* L)
将相距某个增量的记录组成一个子序列,保证在子序列内分别进行直接插入排序后得到的结果是基本有序而不是局部有序。
6. void QSort(SqList* L, int low, int high)
通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到对整个序列有序的目的。
7. void QSort(SqList* L, int low, int high)
将待排序的序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根结点。将它移走,然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次大值。
三、测试
1、方案
2.结果
1选择排序:
2.直接插入排序:
3.冒泡排序:
4.折半插入排序:
5.希尔排序:
6.快速排序:
7.堆排序:
测试结果都正确,程序设计无误。
四、总结与讨论
此实验主要应用于对六种内部排序算法移动和比较次数的比较。通过对冒泡排序、直接插入插排序、简单选择排序、折半插入排序、快速排序、希尔排序、堆排序这几种内部排序算法进行比较,加深了我对这些排序的基本思想及排序算法的掌握和理解。同时通过该题目的设计过程,我也加深理解各种数据结构的逻辑结构、存储结构及相应上运算的实现,进一步理解和熟练掌握课本中所学的各种数据结构,进一步提升了自身的动手能力。
在之前的编程应用中我经常用的是选择法排序,第一个for循环用来控制选择的轮数,第二个for循环用来不断地选择最小或最大的值来放入指定的位置,实现也很方便。同时也掌握了冒泡法排序的思想和具体的代码实现过程,因为平常编写的程序排序的数据都比较少,因此也不太能明显地感受到时间复杂度的不同对于程序的影响,但经过本章排序算法的学习后,我了解到虽然冒泡法排序和选择法排序的时间复杂度都是O(n²),但是选择法排序的性能要稍微优于冒泡法排序。
同时我也了解了三种时间复杂度更为优越的算法,分别是希尔排序、堆排序和快速排序,它们都将时间复杂度提升到了O(nlogn),对于前两个我大致了解了其排序的思路,认识到希尔排序相当于直接插入排序的升级,堆排序相当于简单选择排序的升级,但对于快速排序我了解到它被列为20世纪十大算法之一,因此我仔细熟悉了其算法的具体实现过程,尤其是利用Partition函数去获得枢轴所在的位置的思想确实让我收获很大,感受到了这种算法的便利。因此今后在面对较多数据的排序时,我会再进一步熟悉并利用这种排序算法,以实现程序更加高效的执行。文章来源:https://www.toymoban.com/news/detail-469763.html
附:程序的源代码文章来源地址https://www.toymoban.com/news/detail-469763.html
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAX_LENGTH_INSERT_SORT 7 /* 用于快速排序时判断是否选用插入排序阙值 */
typedef int Status;
#define MAXSIZE 10000 /* 用于要排序数组个数最大值,可根据需要修改 */
typedef struct
{
int r[MAXSIZE + 1]; /* 用于存储要排序数组,r[0]用作哨兵或临时变量 */
int length; /* 用于记录顺序表的长度 */
}SqList;
/* 交换L中数组r的下标为i和j的值 */
void swap(SqList* L, int i, int j)
{
int temp = L->r[i];
L->r[i] = L->r[j];
L->r[j] = temp;
}
void print(SqList L)
{
int i;
for (i = 1; i < L.length; i++)
printf("%d,", L.r[i]);
printf("%d", L.r[i]);
printf("\n");
}
/* 对顺序表L作冒泡排序 */
void BubbleSort(SqList* L)
{
int i, j,k=0;
for (i = 1; i < L->length; i++)
{
for (j = L->length - 1; j >= i; j--) /* 注意j是从后往前循环 */
{
if (L->r[j] > L->r[j + 1]) /* 若前者大于后者(注意这里与上一算法的差异)*/
{
swap(L, j, j + 1);/* 交换L->r[j]与L->r[j+1]的值 */
printf(" 第%d趟排序结果: ", ++k);
print(*L);
}
}
}
}
/* 对顺序表L作简单选择排序 */
void SelectSort(SqList* L)
{
int i, j,k=0;
for (i = 1; i < L->length; i++)
{
for (j = i + 1; j <= L->length; j++)/* 循环之后的数据 */
{
if (L->r[i] > L->r[j])
{
swap(L, i, j);/* 交换L->r[i]与L->r[j]的值 */
printf(" 第%d趟排序结果: ", ++k);
print(*L);
}
}
}
}
/* 对顺序表L作直接插入排序 */
void InsertSort(SqList* L)
{
int i, j,k=0;
for (i = 2; i <= L->length; i++)
{
if (L->r[i] < L->r[i - 1]) /* 需将L->r[i]插入有序子表 */
{
L->r[0] = L->r[i]; /* 设置哨兵 */
for (j = i - 1; L->r[j] > L->r[0]; j--)
L->r[j + 1] = L->r[j]; /* 记录后移 */
L->r[j + 1] = L->r[0]; /* 插入到正确位置 */
printf(" 第%d趟排序结果: ", ++k);
print(*L);
}
}
}
//折半插入排序
void BinarySort(SqList* L)
{
int i, j, low = 0, high = 0, mid,k=0;
int temp = 0;
for (i = 2; i < L->length+1; i++) {
low = 1;
high = i-1;
temp = L->r[i];
//采用折半查找法判断插入位置,最终变量 low 表示插入位置
while (low <= high) {
mid = (low + high) / 2;
if (L->r[mid] > temp) {
high = mid - 1;
}
else {
low = mid + 1;
}
}
//有序表中插入位置后的元素统一后移
for (j = i; j > low; j--) {
L->r[j] = L->r[j - 1];
printf(" 第%d趟排序结果: ", ++k);
print(*L);
}
L->r[low] = temp;//插入元素
}
}
/* 对顺序表L作希尔排序 */
void ShellSort(SqList* L)
{
int i, j, k = 0;
int increment = L->length;
do
{
increment = increment / 3 + 1;/* 增量序列 */
for (i = increment + 1; i <= L->length; i++)
{
if (L->r[i] < L->r[i - increment])/* 需将L->r[i]插入有序增量子表 */
{
L->r[0] = L->r[i]; /* 暂存在L->r[0] */
for (j = i - increment; j > 0 && L->r[0] < L->r[j]; j -= increment)
L->r[j + increment] = L->r[j]; /* 记录后移,查找插入位置 */
L->r[j + increment] = L->r[0]; /* 插入 */
}
}
printf(" 第%d趟排序结果: ", ++k);
print(*L);
} while (increment > 1);
}
/* 堆排序********************************** */
/* 已知L->r[s..m]中记录的关键字除L->r[s]之外均满足堆的定义, */
/* 本函数调整L->r[s]的关键字,使L->r[s..m]成为一个大顶堆 */
void HeapAdjust(SqList* L, int s, int m)
{
int temp, j;
temp = L->r[s];
for (j = 2 * s; j <= m; j *= 2) /* 沿关键字较大的孩子结点向下筛选 */
{
if (j < m&& L->r[j] < L->r[j + 1])
++j; /* j为关键字中较大的记录的下标 */
if (temp >= L->r[j])
break; /* rc应插入在位置s上 */
L->r[s] = L->r[j];
s = j;
}
L->r[s] = temp; /* 插入 */
}
/* 对顺序表L进行堆排序 */
void HeapSort(SqList* L)
{
int i,k=0;
for (i = L->length / 2; i > 0; i--) /* 把L中的r构建成一个大顶堆 */
HeapAdjust(L, i, L->length);
for (i = L->length; i > 1; i--)
{
swap(L, 1, i); /* 将堆顶记录和当前未经排序子序列的最后一个记录交换 */
HeapAdjust(L, 1, i - 1); /* 将L->r[1..i-1]重新调整为大顶堆 */
printf(" 第%d趟排序结果: ", ++k);
print(*L);
}
}
/* 快速排序******************************** */
/* 交换顺序表L中子表的记录,使枢轴记录到位,并返回其所在位置 */
/* 此时在它之前(后)的记录均不大(小)于它。 */
int Partition(SqList* L, int low, int high)
{
int pivotkey;
pivotkey = L->r[low]; /* 用子表的第一个记录作枢轴记录 */
while (low < high) /* 从表的两端交替地向中间扫描 */
{
while (low < high && L->r[high] >= pivotkey)
high--;
swap(L, low, high);/* 将比枢轴记录小的记录交换到低端 */
while (low < high && L->r[low] <= pivotkey)
low++;
swap(L, low, high);/* 将比枢轴记录大的记录交换到高端 */
}
return low; /* 返回枢轴所在位置 */
}
/* 对顺序表L中的子序列L->r[low..high]作快速排序 */
int t = 0;
void QSort(SqList* L, int low, int high)
{
int pivot;
if (low < high)
{
pivot = Partition(L, low, high); /* 将L->r[low..high]一分为二,算出枢轴值pivot */
QSort(L, low, pivot - 1); /* 对低子表递归排序 */
QSort(L, pivot + 1, high); /* 对高子表递归排序 */
}
printf(" 第%d趟排序结果: ", ++t);
print(*L);
}
/* 对顺序表L作快速排序 */
void QuickSort(SqList* L)
{
QSort(L, 1, L->length);
t = 0;
}
/* **************************************** */
#define N 9
int main()
{
int i, n;
//int d[N] = { 50,10,90,30,70,40,80,60,20 };
int d[MAXSIZE];
printf("请输入待排序元素的个数:\n");
scanf("%d", &n);
printf("请依次输入元素:\n");
SqList sq1,sq2,sq3,sq4,sq5,sq6,sq7,sq8;
for (i = 0; i < n; i++)
{
scanf("%d", &sq1.r[i + 1]);
}
sq1.length = n;
sq2=sq3=sq4=sq5=sq6=sq7=sq8 = sq1;
printf("排序前:\n");
print(sq1);
while (1)
{
int flag;
printf("---------------操作命令集---------------\n");
printf("****************************************\n");
printf("* 1.选择排序 *\n");
printf("* 2.直接插入排序 *\n");
printf("* 3.冒泡排序 *\n");
printf("* 4.折半插入排序 *\n");
printf("* 5.希尔排序 *\n");
printf("* 6.快速排序 *\n");
printf("* 7.堆排序 *\n");
printf("* 0.Return *\n");
printf("****************************************\n");
scanf("%d", &flag);
switch (flag)
{
case 1:
printf("选择排序:\n");
SelectSort(&sq2);
print(sq2);
break;
case 2:
printf("直接插入排序:\n");
InsertSort(&sq3);
print(sq3);
break;
case 3:
printf("冒泡排序:\n");
BubbleSort(&sq4);
print(sq4);
break;
case 4:
printf("折半插入排序:\n");
BinarySort(&sq5);
print(sq5);
break;
case 5:
printf("希尔排序:\n");
ShellSort(&sq6);
print(sq6);
break;
case 6:
printf("快速排序:\n");
QuickSort(&sq7);
print(sq7);
break;
case 7:
printf("堆排序:\n");
HeapSort(&sq8);
print(sq8);
break;
default:
break;
}
}
return 0;
}
到了这里,关于数据结构第四次实验-常用的内部排序算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!