C++数据结构实验四:排序

目录

一、实验目的

二、问题分析及数据结构设计

三、算法设计

四、功能模块程序流程图

五、实验结果

六、算法分析

七、操作说明

八、源代码


近来有空闲,把前几个学期做的实验上传上来。如有错误的地方欢迎大佬批评指正,有更好的方法也期待您的分享~


实验内容

输入一组关键字序列,分别实现下列排序算法:

1.编写函数,实现简单选择排序、直接插入排序和冒泡排序算法。

2.编写函数,实现希尔排序算法。

3.编写函数,实现快速排序算法。

4.编写函数,实现堆排序算法。

5.编写函数,实现折半插入排序算法。

6.编写一个主函数,在主函数中设计一个简单的菜单,分别调试上述算法。


一、实验目的

1.学习排序的基本概念,包括排序的稳定性、内排序和外排序之间的差异;

2.掌握常见的排序算法(插入排序、交换排序、选择排序、归并排序、基数排序等)的思想、特点及其适用条件和算法实现;

3.灵活运用各种排序算法解决一些综合应用问题。

二、问题分析及数据结构设计

本次开发任务要求我们编写一个能调试七种排序算法的系统。该任务需要实现以下功能:简单选择排序、直接插入排序、冒泡排序、希尔排序、快速排序、堆排序、折半插入排序。

其次是数据结构设计,为了实现这些功能,我们需要构建数据模型。每次排序前随机生成10个1-1000之间的元素的数组array。

对于每个功能,我们需要设计相应的函数,函数的输入参数和返回值根据具体的需求进行设计。例如,简单选择排序的函数使用数组array和元素个数作为输入,返回一个根节点的指针;希尔排序函数使用节点指针arr和元素个数作为输入,输出遍历的结果等。另外,在实现堆排序功能的过程中,需要使用辅助的数组来建立堆。从最后一个非叶子节点开始向上遍历,建立堆,每交换一次之后,就把最大值拿出,不再参与调整堆。

三、算法设计

1.简单选择排序 selectSort():

在待排序的数列中寻找最大(或者最小)的一个数,与第 1 个元素进行交换,接着在剩余的待排序的数列中继续找最大(最小)的一个数,与第 2 个元素交换。以此类推,一直到待排序的数列中只有一个元素时为止。

步骤:

(1)新建一个索引k为标记索引,用于保存最大值或者最小值的索引;

(2)将第一个元素索引用k保存,将k索引所在元素和剩下元素一一比较,将其中的较小值用k保存其索,遍历结束后可以取得最小值的索引k;

(3)将索引为k的元素和第一个元素进行位置交换,重复步骤2从第二个元素继续,直到遍历完成。

2.冒泡排序 popSort():

将关键字较大的记录向序列尾部移动,关键字较小的记录向序列前部移动。

步骤:

(1)比较相邻的元素。如果第一个比第二个大,就交换他们两个;

(2) 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数;

(3) 针对所有的元素重复以上的步骤,除了最后一个;

(4) 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

图 1  冒泡排序

3. 直接插入排序 InsertSort():

将原序列分为两个序列,一个序列是有序序列,一个序列为无序序列。假设一共有n个无序数,那么,我们第一次选择一个数据元素作为有序序列(我们知道,一个元素本身肯定是有序的),将其他n-1个元素都作为无序序列,那么,我们每一次从无序序列中取出一个数,通过某种方法找到合适的位置插入,这样,有序序列的元素总数就多了一个,无序序列的元素总数就少了一个。通过n-1次放置之后,就可以得到数据元素总数为n的有序序列了,排序完成。

步骤:假设有一组无序序列 R0, R1,…, RN-1;

(1)我们先将这个序列中下标为 0 的元素视为元素个数为 1 的有序序列。

(2)然后,我们要依次把 R1, R2,…, RN-1 插入到这个有序序列中。所以,我们需要一个外部循环,从下标 1 扫描到 N-1 ;

(3)接下来描述插入过程。假设这是要将 Ri 插入到前面有序的序列中。由前面所述,我们可知,插入Ri时,前 i-1 个数肯定已经是有序了;

所以我们需要将Ri 和R0 ~ Ri-1 进行比较,确定要插入的合适位置。这就需要一个内部循环,我们一般是从后往前比较,即从下标 i-1 开始向 0 进行扫描。

4. 希尔排序 ShellSort():

希尔排序是记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

步骤:初始时,有一个大小为 10 的无序序列。

(1)在第一趟排序中,我们不妨设 gap1 = N / 2 = 5,即相隔距离为 5 的元素组成一组,可以分为 5 组;

(2)接下来,按照直接插入排序的方法对每个组进行排序;

在第二趟排序中,我们把上次的 gap 缩小一半,即 gap2 = gap1 / 2 = 2 (取整数)。这样每相隔距离为 2 的元素组成一组,可以分为 2 组;

(3)按照直接插入排序的方法对每个组进行排序;

(4)在第三趟排序中,再次把 gap 缩小一半,即gap3 = gap2 / 2 = 1。 这样相隔距离为 1 的元素组成一组,即只有一组;

(5)按照直接插入排序的方法对每个组进行排序。此时,排序已经结束。

图2  希尔排序

5. 快速排序 QuickSort():

通过一趟划分将要排序的序列分割成独立的三个部分,即左部、基准值、右部。其中左部的所有数据都比基准值小,右部的所有数据都比基准值大。然后再按此方法分别对左部和右部进行划分,整个排序过程通过递归进行。

步骤:

(1)首先我们从数组的left位置取出该数(2)作为参照物(base);

(2)从数组的right位置向前找,一直找到比(base)小的数,如果找到,将此数赋给left位置(也就是将1赋给2),此时数组为:1,4,5,1,3,left和right指针分别为前后的1;

(3)从数组的left位置向后找,一直找到比(base)大的数,如果找到,将此数赋给right的位置(也就是4赋给1),此时数组为:1,4,5,4,3,left和right指针分别为前后的4;

(4):重复“第二,第三“步骤,直到left和right指针重合,最后将(base)插入到4的位置,此时数组值为: 1,2,5,4,3,至此完成一次排序。第五步:此时2已经潜入到数组的内部,2的左侧一组数都比2小,2的右侧作为一组数都比2大,以2为切入点对左右两边数按照"第一,第二,第三,第四"步骤进行。

图3  快速排序

6. 堆排序 HeapSort():

堆排序是在直接选择排序的基础上借助于堆的一种排序方法。在选择排序中,为找出最小的记录需要作n-1次比较,但比较的信息没有保存下来,然后为寻找关键字次小的记录要对剩下的

数据结构实验 #include #include #include #define NULL 0 #define OK 1 #define ERROR -1 #define STACK_INIT_SIZE 100 #define STACKINCREMENT 20 /*定义字符类型栈*/ typedef struct{ int stacksize; char *base; char *top; } Stack; //栈的类型 /* 定义整型栈*/ typedef struct{ int stacksize; //栈类型个数 int *base; int *top; } Stack2; /* ----------------- 全局变量--------------- */ Stack OPTR; /* 定义运算符栈*/ Stack2 OPND; /* 定义操作数栈*/ char expr[255] = ""; /* 存放表达式串*/ char *ptr = expr; int InitStack(Stack *s) //构造运算符栈 { s->base=(char *)malloc(STACK_INIT_SIZE*sizeof(char)); //建立新结点 if(!s->base) return ERROR; s->top=s->base; s->stacksize=STACK_INIT_SIZE; return OK; } int InitStack2(Stack2 *s) //构造操作数栈 { s->base=(int *)malloc(STACK_INIT_SIZE*sizeof(int)); if(!s->base) return ERROR; s->stacksize=STACK_INIT_SIZE; s->top=s->base; return OK; } int In(char ch) //判断字符是否是运算符,运算符即返回1 { return(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='('||ch==')'||ch=='#'); } int Push(Stack *s,char ch) //运算符栈插入ch为新的栈顶元素 { *s->top=ch; s->top++; return 0; } int Push2(Stack2 *s,int ch)//操作数栈插入ch为新的栈顶元素 { *s->top=ch; s->top++; return 0; } char Pop(Stack *s) //删除运算符栈s的栈顶元素,用p返回其值 { char p; s->top--; p=*s->top; return p; } int Pop2(Stack2 *s)//删除操作数栈s的栈顶元素,用p返回其值 { int p; s->top--; p=*s->top; return p; } char GetTop(Stack s)//的栈顶元素 { char p=*(s.top-1); return p; } int GetTop2(Stack2 s) //用p返回操作数栈s的栈顶元素 { int p=*(s.top-1); return p; } /* 判断运算符优先权,返回优先权高的*/ char Precede(char c1,char c2) { int i=0,j=0; static char array[49]={ //array是数组 '>', '>', '<', '<', '', '>', '>', '>', '<', '<', '', '>', '>', '>', '>', '>', '', '>', '>', '>', '>', '>', '', '>', '<', '<', '<', '<', '', '>', '>', '>', '!', '>', '>', '<', '<', '<', '<', '<', '!', '='}; switch(c1) { /* i为下面array的横标 */ case '+' : i=0;break; case '-' : i=1;break; case '*' : i=2;break; case '/' : i=3;break; case '(' : i=4;break; case ')' : i=5;break; case '#' : i=6;break; } switch(c2) { /* j为下面array的纵标 */ case '+' : j=0;break; case '-' : j=1;break; case '*' : j=2;break; case '/' : j=3;break; case '(' : j=4;break; case ')' : j=5;break; case '#' : j=6;break; } return (array[7*i+j]); /* 返回运算符 */ } /*操作函数 */ int Operate(int a,char op,int b) { switch(op) { case '+' : return (a+b); case '-' : return (a-b); case '*' : return (a*b); case '/' : return (a/b); } return 0; } int num(int n)//返回操作数的长度 { char p[10]; itoa(n,p,10);//把整型转换成字符串型 n=strlen(p); return n; } int EvalExpr()//主要操作函数 { char c,theta,x; int n,m; int a,b; c = *ptr++; while(c!='#'||GetTop(OPTR)!='#') { if(!In(c)) { if(!In(*(ptr-1))) ptr=ptr-1; m=atoi(ptr);//取字符串前面的数字段 n=num(m); Push2(&OPND,m); ptr=ptr+n; c=*ptr++; } else switch(Precede(GetTop(OPTR),c)) { case '': //退栈并将运算结果入栈 theta=Pop(&OPTR); b=Pop2(&OPND); a=Pop2(&OPND); Push2(&OPND,Operate(a,theta,b)); break; } } return GetTop2(OPND); } int main( ) { printf("请输入正确的表达式以'#'结尾:"); do{ gets(expr); }while(!*expr); InitStack(&OPTR); /* 初始化运算符栈 */ Push(&OPTR,'#'); /* 将#压入运算符栈 */ InitStack2(&OPND); /* 初始化操作数栈 */ printf("表达式结果为:%d\n", EvalExpr()); return 0; }
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值