内部排序算法的性能分析
一 需求分析
1) 对起泡排序、直接排序、简单选择排序、快速排序、希尔排序、堆排序算法进行比较;
2) 排序表中数据数目不小于100 ,表中数据随机产生,至少用5组不同数据集作比较,比较指标有:关键字参加比较次数和关键字的移动次数(关键字交换记为3次移动);
3) 输出比较结果。
二 系统设计
对于排序算法的比较采取关键字参加比较次数和关键字的移动次数还有利用time.h中(int)GetTickCount()函数对cpu运用该排序算法所采用时间进行比较。
在表中数据随机产生部分,设置了一个void RandomNum()函数,运用
srand(2000);产生了2000个随机数。
在程序的执行方面
首先定义了一个界面显示函数void SelectSort()
void SelectSort(){
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. 退出程序 *\n”);
printf(” —————————-\n\n “);
printf(“Please Select the Operate:”);
}
对操作界面进行了一定的优化
使用户可以很方便的进行一定的交互。
然后针对各种排序算法,写出函数,对算法进行实现。
例如void ShellInsert()//希尔排序 int Partition()//快速排序
void HeapAdjust ()//堆排序 void BubbleSort()//冒泡排序
int SelectMinKey()//选择排序
增添了一个对所有算法进行一次实现的函数void AllAbove()
程序模块调用图
三 代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //memset() memcpy() 头文件
#include <conio.h>
#include <time.h> //计时器 clock-t 记录函数初始时间 结束时间 来记录算法在cpu内部运行时间
#include <windows.h>
#include <winbase.h>
#define MAXSIZE 5000 //顺序表的最大长度
#define TRUE 1
#define FALSE 0
typedef int BOOL;
typedef struct{
int key; //记录关键字项
} RedType; //记录类型
typedef struct LinkList{
RedType r[MAXSIZE+1];
int Length; //顺序表长度
} LinkList;
int RandArray[MAXSIZE+1]; //全局变量数组 便于内部操作
void RandomNum(){
int i;
srand(2000); //标准库<cstdlib>(被包含于<iostream>中)提供两个帮助生成伪随机数的函数:
//void srand(unsigned seed);参数seed是rand()的种子,用来初始化rand()的起始值。
for (i = 1; i <= MAXSIZE; i++)
RandArray[i] = (int)rand(); //构造随机序列
//函数一:int rand(void);从srand (seed)中指定的seed开始,返回一个[seed, RAND_MAX(0x7fff))间的随机整数
}
void InitLinkList(LinkList *L){ //构造线性表
int i;
memset(L, 0, sizeof(LinkList)); //memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法。
//void *memset(void *s,int c,size_t n) 总的作用:将已开辟内存空间 s 的首 n 个字节的值设为值 c。
RandomNum(); //随机函数
for (i = 1; i <= MAXSIZE; i++)
L->r[i].key = RandArray[i]; //随机数赋值给
L->Length = i; //赋值
}
bool LT(int i, int j, int *CmpNum){ //比较关键字大小
(*CmpNum)++; //关键字比较次数
if (i < j)
return TRUE;
else
return FALSE;
}
void Display(LinkList *L){ //储存表到txt文件中
FILE *f;
int i;
if ((f = fopen(“c:\\SortRes.txt”, “w”)) == NULL){ //fopen(文件名,打开方式) w只写
printf(“can’t open file\n”);
exit(0);
}
for (i = 0; i < L->Length; i++)
fprintf(f, “%d\n”, L->r[i].key); //fprintf(文件指针变量,格式控制字符串,变量地址列表)
fclose(f);
}
//希尔排序
void ShellInsert(LinkList *L, int dk, int *CmpNum, int *ChgNum)
{
int i, j;
RedType Temp;
for (i = dk; i < L->Length; i++){
if (LT(L->r[i].key, L->r[i – dk].key, CmpNum)){
memcpy(&Temp, &L->r[i], sizeof(RedType)); //
for (j = i – dk; j >= 0 && LT(Temp.key, L->r[j].key, CmpNum); j -= dk){
(*ChgNum)++;
memcpy(&L->r[j + dk], &L->r[j], sizeof(RedType));
}
memcpy(&L->r[j + dk], &Temp, sizeof(RedType));
}
}
}
void ShellSort(LinkList *L, int dlta[], int t, int *CmpNum, int *ChgNum){
int k;
for (k = 0; k < t; k++)
ShellInsert(L, dlta[k], CmpNum, ChgNum);
}
//快速排序
int Partition(LinkList *L, int low, int high, int *CmpNum, int *ChgNum){
RedType Temp;
int PivotKey;
memcpy(&Temp, &L->r[low], sizeof(RedType));
PivotKey = L->r[low].key;
while (low < high){
while (low < high && L->r[high].key >= PivotKey){
high–;
(*CmpNum)++;
}
(*ChgNum)++;
memcpy(&L->r[low], &L->r[high], sizeof(RedType));
while (low < high && L->r[low].key <= PivotKey){
low++;
(*CmpNum)++;
}
(*ChgNum)++;
memcpy(&L->r[high], &L->r[low], sizeof(RedType));
}
memcpy(&L->r[low], &Temp, sizeof(RedType));
return low;
}
void QSort(LinkList *L, int low, int high, int *CmpNum, int *ChgNum){
int PivotLoc = 0;
if (low < high){
PivotLoc = Partition(L, low, high, CmpNum, ChgNum);
QSort(L, low, PivotLoc – 1, CmpNum, ChgNum);
QSort(L, PivotLoc + 1, high, CmpNum, ChgNum);
}
}
void QuickSort(LinkList *L, int *CmpNum, int *ChgNum){
QSort(L, 0, L->Length – 1, CmpNum, ChgNum);
}
//堆排序
void HeapAdjust(LinkList *L, int s, int m, int *CmpNum, int *ChgNum){
RedType Temp;
int j = 0;
s++;
memcpy(&Temp, &L->r[s – 1], sizeof(RedType));
for (j = 2 * s; j <= m; j *= 2){
if (j < m && LT(L->r[j – 1].key, L->r[j].key, CmpNum))
++j;
if (!LT(Temp.key, L->r[j – 1].key, CmpNum))
break;
(*ChgNum)++;
memcpy(&L->r[s – 1], &L->r[j – 1], sizeof(RedType));
s = j;
}
memcpy(&L->r[s – 1], &Temp, sizeof(RedType));
}
void HeapSort(LinkList *L, int *CmpNum, int *ChgNum){
int i = 0;
RedType Temp;
for (i = L->Length / 2-1; i >= 0; i–)
HeapAdjust(L, i, L->Length, CmpNum, ChgNum);
for (i = L->Length; i > 1; i–){
memcpy(&Temp, &L->r[0], sizeof(RedType));
(*ChgNum)++;
memcpy(&L->r[0], &L->r[i – 1], sizeof(RedType));
memcpy(&L->r[i – 1], &Temp, sizeof(RedType));
HeapAdjust(L, 0, i – 1, CmpNum, ChgNum);
}
}
//冒泡排序
void BubbleSort(LinkList *L, int *CmpNum, int *ChgNum){
int i, j;
RedType temp;
for (i = 1; i <= MAXSIZE; i++){
for (j = 1; j <= MAXSIZE – i; j++){
if (!LT(L->r[j].key, L->r[j + 1].key, CmpNum)){
(*ChgNum)++;
memcpy(&temp, &L->r[j], sizeof(RedType));
memcpy(&L->r[j], &L->r[j + 1], sizeof(RedType));
memcpy(&L->r[j + 1], &temp, sizeof(RedType));
}
}
}
}
//选择排序
int SelectMinKey(LinkList *L, int k, int *CmpNum)
{
int Min = k;
for (; k < L->Length; k++){
if (!LT(L->r[Min].key, L->r[k].key, CmpNum))
Min = k;
}
return Min;
}
void SelSort(LinkList *L, int *CmpNum, int *ChgNum){
int i, j;
RedType temp;
for (i = 0; i < L->Length; i++){
j = SelectMinKey(L, i, CmpNum);
if (i != j){
(*ChgNum)++;
memcpy(&temp, &L->r[i], sizeof(RedType));
memcpy(&L->r[i], &L->r[j], sizeof(RedType));
memcpy(&L->r[j], &temp, sizeof(RedType));
}
}
}
void SelectSort(){
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. 退出程序 *\n”);
printf(” —————————-\n\n “);
printf(“Please Select the Operate:”);
}
void AllAbove(LinkList *L, int *CmpNum, int *ChgNum){
int TempTime, i,j;
int SpendTime;
int dlta[3] = {
7, 3, 1
};
int Indata[1] = {
1
};
for (i = 1; i <= MAXSIZE; i++)
L->r[i].key = RandArray[i]; //随机数列复位
printf(“\n插入排序:\n”);
TempTime = (int)GetTickCount(); //cpu运行初始时间
ShellSort(L, Indata, 1, &CmpNum[0], &ChgNum[0]);
SpendTime = (int)GetTickCount() – TempTime;
printf(“\n关键字比较次数=%d\t关键字移动次数=%d\t运行时间=%dms\n”, CmpNum[0], ChgNum[0],SpendTime);
for (i = 1; i <= MAXSIZE; i++)
L->r[i].key = RandArray[i]; //随机数列复位
printf(“\n希尔排序:\n”);
TempTime = (int)GetTickCount();
ShellSort(L, dlta, 3, &CmpNum[1], &ChgNum[1]);
SpendTime = (int)GetTickCount() – TempTime;
printf(“\n关键字比较次数=%d\t关键字移动次数=%d\t运行时间=%dms\n”, CmpNum[1], ChgNum[1],SpendTime);
for (i = 1; i <= MAXSIZE; i++)
L->r[i].key = RandArray[i]; //随机数列复位
printf(“\n快速排序:\n”);
TempTime = (int)GetTickCount();
QuickSort(L, &CmpNum[2], &ChgNum[2]);
SpendTime = (int)GetTickCount() – TempTime;
printf(“\n关键字比较次数=%d\t关键字移动次数=%d\t运行时间=%dms\n”, CmpNum[2], ChgNum[2],SpendTime);
for (i = 1; i <= MAXSIZE; i++)
L->r[i].key = RandArray[i]; //随机数列复位
printf(“\n堆排序:\n”);
TempTime = (int)GetTickCount();
HeapSort(L, &CmpNum[3], &ChgNum[3]);
SpendTime = (int)GetTickCount() – TempTime;
printf(“\n关键字比较次数=%d\t关键字移动次数=%d\t运行时间=%dms\n”, CmpNum[3], ChgNum[3],SpendTime);
for (i = 1; i <= MAXSIZE; i++)
L->r[i].key = RandArray[i]; //随机数列复位
printf(“\n冒泡排序:\n”);
TempTime = (int)GetTickCount();
BubbleSort(L, &CmpNum[4], &ChgNum[4]);
SpendTime = (int)GetTickCount() – TempTime;
printf(“\n关键字比较次数=%d\t关键字移动次数=%d\t运行时间=%dms\n”, CmpNum[4], ChgNum[4],SpendTime);
for (i = 1; i <= MAXSIZE; i++)
L->r[i].key = RandArray[i]; //随机数列复位
printf(“\n选择排序:\n”);
TempTime = (int)GetTickCount();
SelSort(L, &CmpNum[5], &ChgNum[5]);
SpendTime = (int)GetTickCount() – TempTime;
printf(“\n关键字比较次数=%d\t关键字移动次数=%d\t运行时间=%dms\n”, CmpNum[5], ChgNum[5],SpendTime);
}
void main()
{
int i,j;
int select = 0;
int dlta[3] = {7, 3, 1};
int Indata[1] = {1};
int CmpNum[8], ChgNum[8]; //记录比较次数 移动次数
int SpendTime = 0; //cpu运行初始时间
int TempTime;
LinkList L;
InitLinkList(&L); //构造线性表
memset(CmpNum, 0, sizeof(CmpNum)); //数组cmpnum 置空
memset(ChgNum, 0, sizeof(ChgNum)); //数组chgnum置空
do{
printf(“please press any keys continue!”);
getch();
system(“cls”);
SelectSort(); //排序算法选择菜单
for (i = 0; i < MAXSIZE; i++)
L.r[i].key = RandArray[i]; //随机数列复位
scanf(“%d”, &select);
switch (select){
case 1:
printf(“\n插入排序:\n”);
TempTime = (int)GetTickCount(); //GetTickCount返回的是到目前为止CPU的Tick数
ShellSort(&L, Indata, 1, &CmpNum[select], &ChgNum[select]);
SpendTime = (int)GetTickCount() – TempTime;
for(i=1;i<=MAXSIZE;i++){
printf(“%5d “,L.r[i].key);
if(++j%10==0)printf(“\n”);
}
printf(“\n\n关键字比较次数=%d\t关键字移动次数=%d\t运行时间=%dms\n”, CmpNum[select],ChgNum[select], SpendTime);
break;
case 2:
printf(“\n希尔排序:\n”);
TempTime = (int)GetTickCount();
ShellSort(&L, dlta, 3, &CmpNum[select], &ChgNum[select]);
SpendTime = (int)GetTickCount() – TempTime;
for(i=1;i<=MAXSIZE;i++){
printf(“%5d “,L.r[i].key);
if(++j%10==0)printf(“\n”);
}
printf(“\n\n关键字比较次数=%d\t关键字移动次数=%d\t运行时间=%dms\n”, CmpNum[select],ChgNum[select], SpendTime);
break;
case 3:
printf(“\n快速排序:\n”);
TempTime = (int)GetTickCount();
QuickSort(&L, &CmpNum[select], &ChgNum[select]);
SpendTime = (int)GetTickCount() – TempTime;
for(i=1;i<=MAXSIZE;i++){
printf(“%5d “,L.r[i].key);
if(++j%10==0)printf(“\n”);
}
printf(“\n\n关键字比较次数=%d\t关键字移动次数=%d\t运行时间=%dms\n”, CmpNum[select],ChgNum[select], SpendTime);
break;
case 4:
printf(“\n堆排序:\n”);
TempTime = (int)GetTickCount();
HeapSort(&L, &CmpNum[select], &ChgNum[select]);
SpendTime = (int)GetTickCount() – TempTime;
for(i=1;i<=MAXSIZE;i++){
printf(“%5d “,L.r[i].key);
if(++j%10==0)printf(“\n”);
}
printf(“\n\n关键字比较次数=%d\t关键字移动次数=%d\t\t运行时间=%dms\n”,CmpNum[select], ChgNum[select], SpendTime);
break;
case 5:
printf(“\n冒泡排序:\n”);
TempTime = (int)GetTickCount();
BubbleSort(&L, &CmpNum[select], &ChgNum[select]);
SpendTime = (int)GetTickCount() – TempTime;
for(i=1;i<=MAXSIZE;i++){
printf(“%5d “,L.r[i].key);
if(++j%10==0)printf(“\n”);
}
printf(“\n\n关键字比较次数=%d\t关键字移动次数=%d\t运行时间=%dms\n”, CmpNum[select],ChgNum[select], SpendTime);
break;
case 6:
printf(“\n选择排序:\n”);
TempTime = (int)GetTickCount();
SelSort(&L, &CmpNum[select], &ChgNum[select]);
SpendTime = (int)GetTickCount() – TempTime;
for(i=1;i<=MAXSIZE;i++){
printf(“%5d “,L.r[i].key);
if(++j%10==0)printf(“\n”);
}
printf(“\n\n关键字比较次数=%d\t关键字移动次数=%d\t运行时间=%dms\n”, CmpNum[select],ChgNum[select], SpendTime);
break;
case 7:
AllAbove(&L, CmpNum, ChgNum);
break;
}
}while (select != 0);
Display(&L); //存储线性表
}
四 总结
数据结构是在整个计算机科学与技术领域上广泛被使用的术语。它用来反映一个数 据的内部构成,即一个数据由那些成分数据构成,以什么方式构成,呈什么结构。数据结构有逻辑上的数据结构和物理上的数据结构之分。逻辑上的数据结构反映成分数据之间的逻辑关系,而物理上的数据结构反映成分数据在计算机内部的存储安排。数据结构是数据存在的形式。 数据结构是信息的一种组织方式,其目的是为了提高算法的效率,它通常与一组算法的集合相对应,通过这组算法集合可以对数据结构中的数据进行某种操作。数据结构课程的主要目的是介绍一些常用的数据结构,阐明数据结构内在的逻辑 关系,讨论它们在计算机中的存储表示,并结合各种数据结构,讨论对它们实行的各种 运算的实现算法。 通过这次数据结构课程设计,让我学到了好多东西。在实际操作过程中犯了一些错 误却让我有了意外的收获,所学数据结构理论知识得到了巩固。通过实际操作,学会数据结构程序编程的基本步骤、基本方法,开发了自己的逻辑思维能力,培养了分析问题、解决问题的能力。此次课程设计使我对数据结构有了进一步的认识。
五 参考文献
[1] 严蔚敏、吴伟民主编 《数据结构》(C 语言版) 清华大学出版社 2002
[2] 高一凡 《数据结构算法解析》 清华大学出版社 2008