实验七 排序技术的编程实现
【实验目的】
排序技术的编程实现
要求:
排序技术的编程实现(2学时,综合型),掌握排序技术的编程实现,可以实现一种,也可以实现多种。也鼓励学生利用基本操作进行一些应用的程序设计。
【实验性质】
综合性实验,其综合性体现在本实验的内容具有的实际应用价值,多种数据结构的综合应用,各种具有代表性的算法设计和程序实现。(学时数:2H)
【实验内容】
- 使用冒泡排序法设计一个排序程序。
- 使用快速排序法设计一个排序程序。
- 使用堆排序法设计一个排序程序。
- 鼓励同时开发多种排序的程序,并且用菜单管理。
【注意事项】
- 建议把数据先存在文件中,避免调试程序时反复输入,同时增加程序的通用性。
- 建议把排序的中间过程显示出来体现排序的原理和过程。
【注意事项】
1.开发语言:使用C。
2.可以自己增加其他功能。
【实验分析、说明过程】
冒泡排序是交换排序中一种简单的排序方法。 它的基本思想是对所有相邻记录的关键字值进行比效,如果是逆顺(a[j]>a[j+1]),则将其交换,最终达到有序化; 其处理过程为: (1)将整个待排序的记录序列划分成有序区和无序区,初始状态有序区为空,无序区包括所有待排序的记 录。 (2)对无序区从前向后依次将相邻记录的关键字进行比较,若逆序将其交换,从而使得关键字值小的记录向上”飘浮”(左移),关键字值大的记录好像石块,向下“堕落”(右移)。 每经过一趟冒泡排序,都使无序区中关键字值最大的记录进入有序区,对于由n个记录组成的记录序列,最多经过n-1趟冒泡排序,就可以将这n个记录重新按关键字顺序排列。 2.原始的冒泡排序算法 对由n个记录组成的记录序列,最多经过(n-1)趟冒泡排序,就可以使记录序列成为 有序序列,第一趟定位第n个记录,此时有序区只有一个记录;第二趟定位第n-1个记录,此时有序区有两个记录;以此类推,算法框架为: for(i=n;i>1;i—) { 定位第i个记录; } |
【思考问题】
排序算法通常更注重时间,有些情况下会适当的牺牲一些时间,所以排序的数据结构一般都选择比较简单的;用时间换空间,比如直接使用数组;
性能分析: 最好的情况:表的初态恰好是正序排列 最坏的情况:表的初态恰好是逆序排列
3.性能分析: 折半插入排序算法是一种稳定的排序算法,比直接插入算法明显减少了关键字之间比较的次数,因此速度比直接插入排序算法快,但记录移动的次数没有变,所以折半插入排序算法的时间复杂度仍然为O(n^2),与直接插入排序算法相同。附加空间O(1)。
性能分析:
性能分析: 最好的情况:表的初态恰好是正序排列,第一趟扫描没有移动发生 最坏的情况:表的初态恰好是逆序排列,需要进行n-1趟排序,每趟都要移动整个区间。
性能分析: 就平均性能而言,快速排序的时间复杂度是O(n)。 →快速排序被认为是所有O(n)级别的排序方法中平均性能最好的。 快速排序由于是递归实现的,需要消耗运行栈的空间。
性能分析: 比较次数与表的初态无关:
一种基于将两个有序表异地归并成一个有序表的排序策略。
算法思想: 设排序区间为R[ low . . high ]; 在排序区间任选一个记录Rx做为基准; 经过一趟排序后,将排序区间分为左、右两个子区间: R[low . . i-1 ] Rx R[i+1 . . high ]; 使得:R[ low. .i-1 ].key≤Rx.key≤R[ i+1. .high ].key; 然后再用相同的方法分别对左、右区间进行排序,直至每个区间长度都是1为止。
答:排队,给图片染色,表格按日期排序等等。 |
【实验小结】 (总结本次实验的重难点及心得、体会、收获)
排序分两类,内部排序和外部排序。内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存,通过借助内存调整数在外存储的排放顺序,内部排序适用于记录个数不很多的较小待排序文件的排序;外部排序则适用于记录个数太多不能一次全部放入内存的较大待排序文件的排序。 通过本次实验,让我巩固了各种排列的算法和基本思想,以及不同排序算法之间的差异性和适用性。 |
【附录-实验代码】
#include<stdio.h> #include<stdlib.h> #include<conio.h> #include<time.h> #define MAX 1000 void bubbleSort(int *list, int index) { //利用冒泡排序算法,完成对数组list中的index个数进行排序。 int i,j,count=0; int change=0; int temp; while (!change) { change=1; for(j=index;j>0;j--) { for(i=0;i<j-1;i++) { if(list[i]>list[i+1]) { temp=list[i+1]; list[i+1]=list[i]; list[i]=temp; change=0; } } } } for(i=0;i<index;i++) { printf("%5d",list[i]); count++; if(count%5==0) printf("\n"); } } //快速排序程序构思: //1.读入欲排序的数值。 //2.使用快速排序法 // (1)设置左右端指针(i-左指针,j-右指针) // (2)设分割指针pivot // (3)i往右找比pivot大时停止,j往左找比pivot小时停止 // (4)若i<j,list[i]和list[j]内容值对调 // i>=j,list[left]和list[j]内容值对调 / // (5)pivot找到其位置,并打输出对调后的排序结果 // (6)排序pivot左边的元素 QuickSort(左边) // (7)排序pivot右边的元素 QuickSort(右边) //3.打印最终排序结果 void QuickSort(int *list,int left,int right,int index) { //利用快速排序算法,完成对数组list中的index个数进行排序。 int i,j; i=left; j=right; int a; int pivot=list[i]; if(i>=j) return; while(i<j) { while(list[j]>=pivot&&i<j) j--; if(i<j) { list[i++]=list[j]; } while(list[i]<=pivot&&i<j) i++; if(i<j) { list[j--]=list[i]; } } list[i]=pivot; for(a=0;a<index;a++) { printf("%d ",list[a]); } printf("\n"); QuickSort(list,left,i-1,index); QuickSort(list,i+1,right,index); } void produce_data(int data[],int num) //随机产生一批数 { int i; srand((unsigned)time(NULL)); for(i=0;i<num;i++) data[i]=rand()%100; } void produce1_data(int data[],int num) //随机产生一批数 { //专门用于堆排序,数据从data[1]开始存放 int i; srand((unsigned)time(NULL)); for(i=1;i<=num;i++) data[i]=rand()%100; } void print_data(int data[],int num) //输出数据 { int i; int count; for(i=0;i<num;i++) { printf("%5d",data[i]); count++; if(count%10==0) printf("\n"); } } void print1_data(int data[],int num) //输出数据 { //专门用于堆排序,数据从data[1]开始输出 int i; int count; for(i=1;i<=num;i++) { printf("%5d",data[i]); count++; if(count%10==0) printf("\n"); } } void createHeap (int *heap, int root, int index) { int i,j; int temp; //于数值交换时的暂存变量 int finish; //判断堆是否建立完成 j=2*root; //子结点的index temp=heap[root]; //暂存heap的root值 finish=0; //默认堆建立尚未完成 while (j<=index && finish==0) { //找最大的子结点 if (j<index) if (heap[j]<heap[j+1]) j++; if (temp>=heap[j]) finish=1; //堆建立完成 else { heap[j/2]=heap[j]; //父结点=目前结点 j=2*j; } } heap[j/2]=temp; //父结点=root值 } //堆排序程序构思: //1.读取数值存入二叉树数组list中 //2.将二叉树转成最大堆 //3.堆的最大值和数组最后一个数值交换 //4.其余数值进行堆重建,并打印目前排序结果 //5.重复3、4,直到所有值均已排序完成 //6.打印最终排序结果 void HeapSort(int *heap,int index) { //堆排序 int i,j,temp; for(i=(index/2);i>=1;i--) //将二叉树转成heap createHeap(heap,i,index); for(i=index-1;i>=1;i--) //开始进行堆排序 { temp=heap[i+1]; //heap的root值和最后一个值交换 heap[i+1]=heap[1]; heap[1]=temp; createHeap(heap, 1, i); //对其余数值重建堆*/ printf("\n目前的排序为:"); //打印堆处理过程*/ for(j=1;j<=index;j++) printf("%3d",heap[j]); //printf("\n"); } } void showmenu() { //显示菜单 printf(" 欢迎使用数据排序小软件\n"); printf("\t1、冒泡排序\n"); printf("\t2、快速排序\n"); printf("\t3、堆排序\n"); printf("\t4、退出程序\n"); } void main() { int list[MAX]; //默认数组最大长度为20 int i,num; //数组索引/ int node; //读入输入值所使用的暂存变量 int choice; while(1) { showmenu(); printf(" 请输入你的选择:"); scanf("%d",&choice); switch(choice) { case 1: printf("请输入需要排序的元素个数:"); scanf("%d",&num); produce_data(list,num); printf("排序前的数据为:\n"); print_data(list,num); bubbleSort(list,num); printf("\n最终的排序结果为:\n"); print_data(list,num); printf("\n"); system("pause"); system("cls"); break; case 2:printf("请输入需要排序的元素个数:"); scanf("%d",&num); produce_data(list,num); printf("排序前的数据为:\n"); print_data(list,num); printf("\n排序过程如下:\n"); QuickSort(list,0,num-1,num); printf("\n最终的排序结果为:\n"); print_data(list,num); printf("\n"); system("pause"); system("cls"); break; case 3:printf("请输入需要排序的元素个数:"); scanf("%d",&num); produce1_data(list,num); printf("排序前的数据为:\n"); print1_data(list,num); printf("\n排序过程如下:\n"); HeapSort(list,num); printf("\n最终的排序结果为:\n"); print1_data(list,num); printf("\n"); system("pause"); system("cls"); break; case 4: return; default: printf("你的选择有误,请从新输入!\n"); } } } |