数据结构课程设计报告.docx
《数据结构课程设计报告.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计报告.docx(33页珍藏版)》请在冰豆网上搜索。
![数据结构课程设计报告.docx](https://file1.bdocx.com/fileroot1/2022-12/29/2c7b6ad0-6919-4915-a35b-e57facd74bbc/2c7b6ad0-6919-4915-a35b-e57facd74bbc1.gif)
数据结构课程设计报告
七种排序算法的演示
班级:
姓名:
学号:
完成日期:
一:
需求分析
1.程序所实现的功能
对直接插入排序、冒泡排序、选择排序、快速排序、归并排序、堆排序、基数排序算法的演示,并且输出每一趟的排序情况。
2.程序的输入
排序种类的输入
排序数的个数的输入
所需排序的具体数字的输入
3.程序的输出
主菜单的输出
每一趟排序的输出,即排序过程的输出
二:
设计说明
1.算法设计思想
<1>交换排序(冒泡排序、快速排序)
交换排序的基本思想是:
对排序表中的数据元素按关键字进行两两比较,如果发生逆序(即排列顺序与排序后的次序正好相反),则两者交换位置,直到所有数据元素都排好序为止。
<2>直接插入排序
直接插入排序的基本思想是:
每一次设法把一个数据元素插入到已经排序的部分序列的合适位置,使得插入后的序列仍然是有序的。
开始时建立一个初始的有序序列,它只包含一个数据元素。
然后,从这个初始序列出发不断插入数据元素,直到最后一个数据元素插到有序序列后,整个排序工作完成。
<3>选择排序(选择排序、堆排序)
选择排序的基本思想是:
第一趟在有n个数据元素的排序表中选出关键字最小的数据元素,然后在剩下的n-1个数据元素中再选出关键字最小(整个数据表中次小)的数据元素,依次重复,每一趟(例如第i趟,i=1,…,n-1)总是在当前剩下的n-i+1个待排序数据元素中选出关键字最小的数据元素,作为有序数据元素序列的第i个数据元素。
等到第n-1趟选择结束,待排序数据元素仅剩下一个时就不用再选了,按选出的先后次序所得到的数据元素序列即为有序序列,排序即完成。
<4>归并排序
归并排序的基本思想是:
假设初始排序表有n个数据元素,首先把它看成是长度为1的首尾相接的n个有序子表(以后称它们为归并项),先做两两归并,得n/2上取整个长度为2的归并项(如果n为奇数,则最后一个归并项的长度为1);再做两两归并,……,如此重复,最后得到一个长度为n的有序序列。
<5>基数排序
基数排序是完全不同于前面几种排序的一种排序方法,基数排序不需要对关键字间的比较,也称为多关键字排序,基数排序的基本思想:
最高位优先法:
先对最高位关键字k1(如花色)排序,将序列分成若干子序列,每个子序列有相同的k1值;然后让每个子序列对次关键字k2(如面值)排序,又分成若干更小的子序列;依次重复,直至就每个子序列对最低位关键字kd排序;最后将所有子序列依次连接在一起成为一个有序序列。
最低位优先法:
从最低位关键字kd起进行排序,然后再对高一位的关键字排序,……依次重复,直至对最高位关键字k1排序后,便成为一个有序序列。
2.程序的主要流程图
3.程序的主要模块(要求对主要流程图中出现的模块进行说明)
程序的主要模块主要分为主菜单模块和排序算法演示模块。
<1>主菜单
主要功能:
程序运行时,可使运行者根据提醒输入相关操作,从而进行数据的输入或者不同的排序方法或者退出。
<2>排序方法及输出
根据运行者对排序的不同选择,进入排序过程
a.直接插入排序:
根据直接排序的算法,输出排序过程
b.冒泡排序:
根据冒泡排序算法,输出排序过程
c.选择排序:
根据选择排序的算法,输出排序过程
d.快速排序:
根据快速排序的算法,输出排序过程
e.归并排序:
根据归并排序的算法,输出排序过程
f.堆排序:
根据堆排序的算法,输出排序过程
g.基数排序:
根据基数排序的算法,输出排序过程
4.程序的主要函数及其代码说明
<1>函数的定义
voidInsert_sort(ListL);//直接插入排序
voidBubble_sort(ListL);//冒泡排序
voidSelection_sort(ListL);//选择排序
voidQuick_sort(List&L,int&num,intlow,inthigh);//快速排序
intQuick_sort_Partition(List&L,int&num,intlow,inthigh);
voidPrint_Quick(ListL,intnum);
voidPass_parameter(Listx,List&L);
voidOrdering_by_merging(List&L,int&num);
voidMSort(intSR[],intTR1[],ints,intt,int&num);//归并排序
voidHeap_sort(List&L);//堆排序
voidHeapAdjust(List&L,ints,intm);//堆排序调整
voidRadix_sort(List&L);//基数排序
voidcounting_sort(ListL,intA[],intB[],intn,inti);
voidRadix_number(intnumber[],intG[],intbase,ListL);
voidInput_data(List&L);//输入数据
<2>直接插入排序
直接插入排序的基本思想:
开始时把第一个数据元素作为初始的有序序列,然后从第二个数据元素开始依次把数据元素按关键字大小插入到已排序的部分排序表的适当位置。
当插入第i(1
如此进行n-1次插入,就完成了排序。
在进行直接插入排序时,当插入第i(1
代码如下:
voidInsert_sort(ListL)
{
inti,x=0,num=1;
intR_output[Max_length];
for(;num<=L.length;num++)
{
R_output[0]=L.R[num];
for(i=x;i>=0;i--)
{
if(R_output[i]<=L.R[num])
{
R_output[i+1]=L.R[num];
x++;
break;
}
R_output[i+1]=R_output[i];
}
printf("第%d趟插入排序后的结果为:
\n",num);
for(intj=1;j<=x;j++)
printf("%4d",R_output[j]);
printf("\n");
}
}
<3>冒泡排序
冒泡排序的基本思想是:
设排序表中有n个数据元素。
首先对排序表中第一,二个数据元素的关键字L.R[0]和L.R[1]进行比较。
如果前者大于后者,则进行交换;然后对第二,三个数据做同样的处理;重复此过程直到处理完最后两个相邻的数据元素。
我们称之为一趟冒泡,它将关键字最大的元素移到排序表的最后一个位置,其他数据元素一般也都向排序的最终位置移动。
然后进行第二趟排序,对排序表中前n-1个元素进行与上述同样的操作,其结果使整个排序表中关键字次大的数据元素被移到L.R[n-2]的位置。
如此最多做n-1趟冒泡就能把所有数据元素排好序。
代码如下:
voidBubble_sort(ListL)
{
inti,j,W,num=0,lastexchangeindex,R_out[Max_length];
for(i=1;i<=L.length;i++)
R_out[i]=L.R[i];//复制数据
i=L.length;
while(i>1){
lastexchangeindex=1;
for(j=1;jif(R_out[j]>R_out[j+1])
{W=R_out[j];
R_out[j]=R_out[j+1];
R_out[j+1]=W;//互换记录
lastexchangeindex=j;
}
printf("\n第%d趟冒泡排序结果是\n",++num);
for(intm=1;m<=L.length;m++)
printf("%d",R_out[m]);//输出排序
i=lastexchangeindex;
}
}
<4>选择排序
直接选择排序的算法基本思想是:
(a)开始时设i的初始值为0。
(b)如果i(c)若L.R[k]不是这组数据元素中的第一个数据元素(i≠k),则将L.R[k]与L.R[i]这两数据元素的位置对调;
(d)令i=i+1转步骤(b).
代码如下:
voidSelection_sort(ListL)
{
inti,min,j,W;
for(i=1;i<=L.length;i++)
{min=i;
for(j=i;j<=L.length;j++)
{
if(L.R[min]>L.R[j])
min=j;
}
if(i!
=min)
{
W=L.R[min];
L.R[min]=L.R[i];
L.R[i]=W;
}
printf("\n第%d趟选择排序结果是\n",i);
for(intr=1;r<=L.length;r++)
printf("%d",L.R[r]);
}
}
<5>快速排序
快速排序(Quick_Sort)其算法基本思想是:
任取排序表中的某个数据元素(例如取第一个数据元素)作为基准,按照该数据元素的关键字大小,将整个排序表划分为左右两个子表:
左侧子表中所有数据元素的关键字都小于基准数据元素的关键字。
右侧子表中所有数据元素的关键字都大于或等于基准数据元素的关键字,基准数据元素则排在这两个子表中间(这也是该数据元素最终应安放的位置),然后分别对这两个子表重复施行上述方法的快速排序,直到所有的子表长度为1,则排序结束。
代码如下:
intQuick_sort_Partition(List&L,int&num,intlow,inthigh)
{
intx,i,j;
i=low;j=high;
L.R[0]=L.R[i];//取第一个数为基准枢纽
x=L.R[i];
while(i{
while(i=x)
j--;
if(iL.R[i++]=L.R[j];//将比枢轴记录小的记录移到低端
while(ii++;
if(iL.R[j--]=L.R[i];//将比枢轴记录大的记录移到高端
}
L.R[i]=L.R[0];//将枢轴记录放入合适位置
num++;
returni;//返回枢轴位置
}
voidQuick_sort(List&L,int&num,intlow,inthigh)//快速排序递归算法
{intx;
if(low{x=Quick_sort_Partition(L,num,low,high);
Print_Quick(L,num);
Quick_sort(L,num,low,x-1);
Quick_sort(L,num,x+1,high);
}
}
<6>归并排序
在两路归并排序算法中,初始排序表存放在数组SR[]中,第一趟归并将SR[]中的归并项两两归并,结果存放在辅助数组TR[]中。
第二趟将TR[]中的归并项两两归并,结果放回原数组SR[]中,如此反复进行。
为了将最后归并结果仍放在数组TR1[]中,归并趟数应为偶数。
如果做奇数趟就能完成时,最后还要执行一次一趟归并过程,由于这时的归并项长度len>=n,因此在则趟归并中while循环不执行,只做把TR[]中的数据元素复制到TR1[]的工作。
代码如下:
voidMerge(intSR[],intTR[],inti,intm,intn)
{intj,k;
intg,h;
g=i;
h=m;
//将有序的SR[i..m]和SR[m+1..n]归并为有序的TR[i..n]
for(j=m+1,k=i;i<=m&&j<=n;++k)
{//将SR中记录由小到大地并入T
if(SR[i]<=SR[j])
TR[k]=SR[i++];
else
TR[k]=SR[j++];
}
while(i<=m)
TR[k++]=SR[i++];//将剩余的SR[i..m]复制到TR
while(j<=n)
TR[k++]=SR[j++];//将剩余的SR[j..n]复制到TR
printf("\n|归并排序结果为\n|");
for(intM=g;M<=n;M++)
printf("%d",TR[M]);
}
voidMSort(intSR[],intTR1[],ints,intt,intnum){
intTR2[Max_length],m;//开设用于存放归并排序中间结果的辅助空间
if(s==t)TR1[s]=SR[s];
else{
m=(s+t)/2;//将SR[s..t]平分为SR[s..m]和SR[m+1..t]
MSort(SR,TR2,s,m,num);//递归地将SR[s..m]归并为有序的TR2[s..m]
MSort(SR,TR2,m+1,t,num);//递归地将SR[m+1..t]归并为有序的//TR2[m+1..t]
Merge(TR2,TR1,s,m,t);//将TR2[s..m]和TR2[m+1..t]归并到TR1[s..t]
}
}
voidOrdering_by_merging(List&L,int&num)
{MSort(L.R,L.R,1,L.length,L.length);
printf("\n最终归并排序结果为\n");
for(inti=1;i<=L.length;i++)
printf("%d",L.R[i]);
}
<7>堆排序(包括建立最大堆和堆排序两个过程)
堆排序算法的基本思想是:
a.对排序表中的数据元素,利用堆的调整算法形成初始堆。
b.输出堆顶元素。
c.对剩余元素重新调整形成堆。
d.重复执行第b、c步,直到所有数据元素被输出。
建立最大堆的代码如下:
voidHeapAdjust(List&L,ints,intm)//一次堆排序后重新调整大顶堆
{inti,j;
i=L.R[s];//暂存根结点的记录
for(j=2*s;j<=m;j*=2)//沿key较大的孩子结点向下筛选
{if(j++j;
if(i>=L.R[j])
break;//不需要调整
L.R[s]=L.R[j];s=j;//把大关键字记录往上调
}
L.R[s]=i;
}
堆排序:
如果建立的堆满足最大堆的条件,则堆的第一个数据元素L.R[0]具有最大的关键字,将L.R[0]与L.R[n-1]对调,把具有最大关键字的数据元素交换到最后,再对前面的n-1个数据元素使用堆的调整算法,重新建立最大堆,结果把具有次最大关键字的数据元素又上浮到堆顶,即L.R[0]的位置,再对调L.R[0]和L.R[n-2],…,如此反复执行n-1次,最后得到全部排序好的数据元素序列。
代码如下:
voidHeap_sort(List&L)
{inti,j,num=0;
for(i=L.length/2;i>0;--i)
{//把L.R[1..H.length]建成大顶堆
HeapAdjust(L,i,L.length);
num++;
}
j=L.R[1];
L.R[1]=L.R[L.length];
L.R[L.length]=j;//交换堆顶和堆底记录
for(i=L.length-1;i>1;--i)
{
HeapAdjust(L,1,i);//重新调整为大顶堆
num++;
j=L.R[1];
L.R[1]=L.R[i];
L.R[i]=j;//将堆顶记录和当前的"堆底"记录相互交换使已有序的记录堆积到底部
printf("\n第%d趟堆排序结果为\n",L.length-i);
for(intx=1;x<=L.length;x++)
printf("%d",L.R[x]);
}
}
<8>基数排序
基数排序首先要确定数据中的最大基数,然后进行分配收集
代码如下:
voidRadix_sort(List&L)
{inti=1;
intc[Max_length];
while(i<=L.base)
{counting_sort(L,L.R,c,L.length,i);
i++;
if(i>=1){
counting_sort(L,c,L.R,L.length,i);
i++;
}
else
for(into=1;o<=L.length;o++)
L.R[o]=c[o];
}
}
voidcounting_sort(ListL,intA[],intB[],intn,inti)
{intj,k;
intcount[10];
intnumber[Max_length];
Radix_number(number,A,i,L);
for(j=0;j<10;j++)
count[j]=0;
for(k=1;k<=n;k++)
count[number[k]]++;
for(j=1;j<=9;j++)
count[j]=count[j]+count[j-1];
for(k=n;k>=1;--k)
{
j=number[k];
B[count[j]]=A[k];
count[j]--;
}
printf("\n|第%d趟基数排序结果为\n|",i);
for(intf=1;f<=L.length;f++)
printf("%d",B[f]);
}
voidRadix_number(intnumber[],intG[],intbase,ListL)
{
for(inttoobad=1;toobad<=L.length;toobad++)
number[toobad]=(int(G[toobad]/(int(pow(10,base-1)))))%10;
}
<8>主函数菜单
主要功能是显示主菜单,以及对各种排序的调用
代码如下:
intMenu()
{
inta;
charmenu[]=
{
菜单\n
----------------------------------------------------------------\n
1输入数据\n
2直接插入排序\n
3冒泡排序\n
4选择排序\n
5快速排序\n
6归并排序\n
7堆排序\n
8基数排序\n
9退出程序\n
};
printf("%s",menu);
printf("--------------------------------------------------------------\n");
printf("请输入您要进行的选项(1-9):
");
printf("--------------------------------------------------------------\n");
scanf("%d",&a);
returna;
}
三:
上机结果及体会
1.实际完成的情况说明
此程序实现了对不同排序算法的演示,并详细给出了每一趟的变化情况。
2.程序运行时的结果
主菜单:
输入数据:
直接插入排序:
冒泡排序:
选择排序:
快速排序:
归并排序;
堆排序;
基数排序:
3.上机过程中出现的问题及其解决方案
<1>快速排序时出现多一次排序的情况解决方法:
在进行循环体时,多运行了一次,将运行次序减1即可。
<2>堆排序时也出现与上一条相同的情况解决方法:
由于缺少一个判断语句导致输出只能是偶数倍趟数,因此加一条if判断语句就可以使程序正常输出结果。
<3>基数排序无法判断输入的数据基数是多少,解决方法:
在数据输入函数中就进行基数的比较判断。
<4>因为我把数据存放在数组里,如果进行一种排序后,无法再