数据结构课程设计.docx
《数据结构课程设计.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计.docx(36页珍藏版)》请在冰豆网上搜索。
![数据结构课程设计.docx](https://file1.bdocx.com/fileroot1/2023-1/2/5621fba3-877c-40be-a9b0-eb8e4e0d9d67/5621fba3-877c-40be-a9b0-eb8e4e0d9d671.gif)
数据结构课程设计
数据结构课程设计实习报告
题目:
几种排序算法的演示
一、需求分析
1.运行环境(软、硬件环境)
ØVisualStudio2005;
2.程序所实现的功能:
Ø运用相关排序算法实现一组数据重排(按从小到大显示);
3.程序的输入:
Ø本程序要求使用者先选择输入测试数的个数,再输入对应数目的一组整形数据;
Ø输入数据过程中请以空格分隔各元素并以回车键结尾;
4.程序的输出:
Ø本程序将根据不同算法输出每一趟排序所对应的结果;
Ø每个选择运行完成之后将会有提示选择是否继续;
5.测试数据,如果程序输入的数据量比较大,需要给出测试数据:
8-465902(7个)
二、设计说明
1.算法设计的思想
●冒泡排序
Ø将第1个记录的关键字与第2个记录的关键字进行比较,若为逆序,即Arr[0].Key>Arr[1].Key,则交换;然后比较第2个记录与第3个记录;依次类推,直至第n-1个记录和第n个记录比较为止——第一趟冒泡排序,结果是关键字最大的记录被安置在最后一个记录位置上
Ø将第1个记录的关键字与第2个记录的关键字进行比较,若为逆序,即Arr[0].Key>Arr[1].Key,则交换;然后比较第2个记录与第3个记录;依次类推,直至第n-1个记录和第n个记录比较为止——第一趟冒泡排序,结果是关键字最大的记录被安置在最后一个记录位置上
Ø重复上述过程,直到“在一趟排序过程中没有进行过交换记录的操作”为止
●快速排序
Ø任取排序表中的某个数据元素(例如取第一个数据元素)作为基准,按照该数据元素的关键字大小,将整个排序表划分为左右两个子表:
左侧子表中所有数据元素的关键字都小于基准数据元素的关键字,右侧子表中所有数据元素的关键字都大于或等于基准数据元素的关键字,基准数据元素则排在这两个子表中间(这也是该数据元素最终应安放的位置),然后分别对这两个子表重复施行上述方法的快速排序,直到所有的子表长度为1,则排序结束。
●直接插入排序
Ø每一次设法把一个数据元素插入到已经排序的部分序列的合适位置,使得插入后的序列仍然是有序的。
Ø开始时建立一个初始的有序序列,它只包含一个数据元素。
Ø然后,从这个的初始序列开始不断进行插入数据元素,直到最后一个数据元素插入到有序序列后,整个排序工作就完成了。
●折半插入排序
Ø每一次设法把一个数据元素插入到已经排序的部分序列的合适位置,使得插入后的序列仍然是有序的。
Ø开始时建立一个初始的有序序列,它只包含一个数据元素。
Ø然后,从这个的初始序列开始不断利用折半查找方法寻找Arr[i]的插入位置。
进行插入数据元素,直到最后一个数据元素插入到有序序列后,整个排序工作就完成了。
●简单选择排序
Ø第一趟在有n个数据元素的排序表中选出关键字最小的数据元素,然后在剩下n-1个数据元素中再选取关键字最小(整个数据表中次小)的数据元素,依次重复,每一趟(例如第i趟,i=1,…,n-1)总是在当前剩下的n-i+1个待排序数据元素中选出关键字最小的数据元素,作为有序数据元素序列的第i个数据元素。
Ø等到第n-1趟选择结束,待排序数据元素仅剩下1个时就不用再选了,按选出的先后次序所得到的数据元素序列即为有序序列,排序即告完成。
●堆排序
(1)对排序表中的数据元素,利用堆的调整算法形成初始堆。
(2)输出堆顶元素。
(3)对剩余元素重新调整形成堆。
(4)重复执行第
(2)、(3)步,直到所有数据元素被输出。
●归并排序
Ø假设初始排序表有n个数据元素,首先把它看成是长度为1的首尾相接的n个有序子表(以后称它们为归并项),先做两两归并,得n/2个长度为2的归并项(如果n为奇数,则最后一个归并项的长度为1);
Ø再做两两归并,……,如此重复,最后得到一个长度为n的有序序列。
2.主要的数据结构设计说明
用顺序表作为排序表的抽象数据类型;另外还包括7个排序函数的模板类
3.程序的主要流程图
4.程序的主要模块,要求对主要流程图中出现的模块进行说明
templateclasssortlist;//对函数的操作
templateclasselement;//数据元素关键字及其他信息
voidmerge(sortlist&sourcetable,sortlist&mergedtable,constintleft,constintmid,constintright);//归并
voidmergepass(sortlist&sourcetable,sortlist&mergedtable,constintlen);//一趟归并
voidmergesort(sortlist&table);//两路归并
templatevoidBubbleSort(sortlist&table)//冒泡排序
templatevoidQuickSort(sortlist&table,intlow,inthigh)//快速排序
templatevoidInsertion(sortlist&table)//直接插入排序
templatevoidBinaryInsert(sortlist&table)//折半插入排序
templatevoidselectsort(sortlist&table)//选择排序
templatevoidsift(sortlist&table,intlow,inthigh)//堆排序调整
templatevoidheapSort(sortlist&table,intn)//堆排序
5.程序的主要函数及其伪代码说明(不需要完整的代码)
✧sortlist构造函数
sortlist(TypeA[],intd)
{
Arr=newelement[d];
for(inti=0;i{
Arr[i].key=A[i];
}
CurrentSize=d;
}
✧交换函数
voidswap(element&x,element&y)
{
elementtemp=x;x=y;y=temp;
}
✧输出函数
voidprint()
{
for(inti=0;i{
cout<<(Arr+i)->getKey()<<"";
}
cout<}
✧归并排序模板类
a)归并
voidmerge(sortlist&sourcetable,sortlist&
mergedtable,constintleft,constintmid,constintright)
{
inti=left,j=mid+1,k=left;
while(i<=mid&&j<=right)
{
if(sourcetable.Arr[i].getKey()<=sourcetable.Arr[j].getKey())
{mergedtable.Arr[k]=sourcetable.Arr[i];i++;k++;}
else
{mergedtable.Arr[k]=sourcetable.Arr[j];j++;k++;}
}
if(i<=mid)
{
for(intp=k,q=i;q<=mid;p++,q++)
mergedtable.Arr[p]=sourcetable.Arr[q];
}
else
{
for(intp=k,q=j;q<=right;p++,q++)
mergedtable.Arr[p]=sourcetable.Arr[q];
}
}
b)一趟归并
voidmergepass(sortlist&sourcetable,sortlist&
mergedtable,constintlen)
{
inti=0;
while(i+2*len{
merge(sourcetable,mergedtable,i,i+len-1,i+2*len-1);
i+=2*len;
}
if(i+len<=CurrentSize-1)
merge(sourcetable,mergedtable,i,i+len-1,CurrentSize-1);
elsefor(intj=i;j<=CurrentSize-1;j++)mergedtable.Arr[j]=sourcetable.Arr[j];
for(intj=0;j<=CurrentSize-1;j++)
sourcetable.Arr[j]=mergedtable.Arr[j];
}
c)二路归并
voidmergesort(sortlist&table)
{
cout<<"归并排序:
"<sortlisttemptable;
intlen=1;
intu=1;
while(len
{
mergepass(table,temptable,len);
len*=2;
cout<<"第"<
";
u++;
print();
}
}
✧冒泡排序
templatevoidBubbleSort(sortlist&table)
{
cout<<"冒泡排序:
"<inti=1;intfinish=0;
ints=0,t=0;
while(i
finish)
{
t++;
finish=1;
for(intj=0;j
{
if(table.Arr[j].getKey()>table.Arr[j+1].getKey())
{
swap(table.Arr[j],table.Arr[j+1]);
finish=0;
s++;
}
}
cout<<"第"<
";
table.print();
i++;
}
cout<<"移动次数"<
};
✧快速排序
templatevoidQuickSort(sortlist&table,intlow,inthigh)
{
inti=low,j=high;staticinty(0);
elementtemp=table.Arr[low];
if(i{
q++;
while(iq++;
while(iif(iwhile(i=table.Arr[i].getKey())i++;
if(i}
p++;
table.Arr[i]=temp;
QuickSort(table,low,i-1);
QuickSort(table,i+1,high);
cout<<"第"<<++y<<"趟排序结果为:
";
table.print();
}
};
templatevoidQuickSort(sortlist&table,intn)
{
cout<<"快速排序"<QuickSort(table,0,n-1);
cout<<"移动次数="<
}
✧直接插入排序
templatevoidInsertion(sortlist&table)
{
ints=0,t=0;
cout<<"直接插入排序"<elementtemp;
intj;
for(inti=1;i
t++;
temp=table.Arr[i];j=i;
while(j>0&&temp.getKey()
{table.Arr[j]=table.Arr[j-1];t++;
j--;
}
table.Arr[j]=temp;
s++;
cout<<"第"<
";
table.print();
}
cout<<"移动次数="<
};
✧折半插入排序
templatevoidBinaryInsert(sortlist&table)
{
ints=0,t=0;
cout<<"折半插入排序:
"<elementtemp;
intleft,right;
for(inti=1;i
{
t++;
left=0;right=i-1;temp=table.Arr[i];s++;
while(left<=right){
t++;
intmid=(right+right)/2;
if(temp.getKey()
else{left=mid+1;t++;}}
for(intk=i-1;k>=left;k--)
{table.Arr[k+1]=table.Arr[k];t++;s++;}
table.Arr[left]=temp;s++;
cout<<"第"<
";
table.print();}
cout<<"移动次数="<
};
✧简单选择排序
templatevoidselectsort(sortlist&table)
{
cout<<"简单选择排序:
"<intk;
ints(0),n(0);
for(inti=0;i
{
k=i;s++;
for(intj=i+1;j
{
s++;
if(table.Arr[j].getKey()
{
k=j;s++;
}
}
if(k!
=i)
{
swap(table.Arr[i],table.Arr[k]);n++;s++;
}
cout<<"第"<
";
table.print();
}
cout<<"移动次数="<}
✧堆排序
template
voidsift(sortlist&table,intlow,inthigh)
{
inti=low;
intj=2*i+1;
elementtemp=table.Arr[i];
while(j<=high)
{
q++;
if(jj++;
q++;
if(temp.getKey()
{
table.Arr[i]=table.Arr[j];
i=j;
j=2*i+1;
p++;
}
else
j=high+1;
}
table.Arr[i]=temp;
p++;
}
template
voidheapSort(sortlist&table,intn)
{
staticintg
(1);
cout<<"堆排序"<inti;
for(i=n/2-1;i>=0;i--)
sift(table,i,n-1);
cout<<"第"<";
table.print();
for(i=n-1;i>0;i--)
{
elementtemp=table.Arr[0];
table.Arr[0]=table.Arr[i];
table.Arr[i]=temp;
p++;
sift(table,0,i-1);
cout<<"第"<";
table.print();
}
cout<<"移动次数="<
}
三、上机结果及体会
1.实际完成的情况说明(完成的功能,支持的数据类型等)
全部可以实现排序;归并排序和快速排序的输出趟数可能会有小的误差。
本段程序支持整数类型的排序;
2.程序的性能分析,包括时空分析;
●冒泡序
Ø时间复杂度
a)最好情况(正序)
b)比较次数:
n-1(只要进行一趟即可)
c)移动次数:
0
d)最坏情况(逆序)
比较次数:
(需n-1趟,每趟达到最大比较次数)
移动次数:
Ø空间复杂度:
S(n)=O
(1)
Ø稳定性:
冒泡排序算法是一种稳定的排序方法
●快速排序
Ø时间复杂度
最好情况(每次总是选到中间值作枢轴)T(n)=O(nlog2n)
最坏情况(每次总是选到最小或最大元素作枢轴)T(n)=O(n²)
Ø空间复杂度:
需栈空间以实现递归
•最坏情况:
S(n)=O(n)
•一般情况:
S(n)=O(log2n)
Ø稳定性:
•快速排序是一种不稳定的排序方法。
●直接插入排序
Ø时间复杂度
1.若待排序记录按关键字从小到大排列(正序)
1关键字比较次数:
2记录移动次数:
2(n-1)
2.若待排序记录按关键字从大到小排列(逆序)
1关键字比较次数:
2记录移动次数:
3.若待排序记录是随机的,取最好和最坏情况的平均值
1关键字比较次数(约为):
2记录移动次数(约为):
T(n)=O(n²)
Ø空间复杂度:
S(n)=O
(1)
Ø稳定性:
直接插入排序是一种稳定的排序方法
●折半插入排序
Ø就平均性能而言,因为折半查找优于顺序查找,所以折半插入排序也优于直接插入排序。
Ø折半插入排序的算法只能在顺序表存储结构下实现。
Ø折半插入排序是一个稳定的排序方法。
●简单选择排序
Ø比较次数=(n-1)+(n-2)+…+1=n(n-1)/2
Ø当这组数据元素的初始状态是按其关键字从小到大有序的时候,数据元素的移动次数为0,达到最小值;
Ø直接选择排序总的时间复杂度为O(n2)。
Ø直接选择排序总的空间复杂度为S
(1)。
Ø直接选择排序是一种不稳定的排序方法。
●堆排序
Ø堆排序的时间复杂性为O(nlog2n)。
Ø该算法的空间复杂性为O
(1)。
Ø堆排序是一种不稳定的排序方法。
●归并排序
Ø两路归并排序算法总的时间复杂度为O(nlog2n)。
Ø两路归并排序占用附加存储较多,需要另外一个与原待排序数据元素数组同样大小的辅助数组,所以其空间复杂度为O(n)。
Ø两路归并排序是一个稳定的排序方法。
3.打印程序运行时的初值和运行结果:
直接插入排序
折半插入排序
冒泡排序
简单选择排序
快速排序
堆排序
归并排序
4.上机过程中出现的问题及其解决方案
问题:
归并排序时缺少缺少第二趟的显示
解决方案:
只调用一次mergepass函数,具体代码下面:
voidmergepass(sortlist&sourcetable,sortlist&mergedtable,constintlen)
{
inti=0;
while(i+2*len<=CurrentSize-1)
{h++;
merge(sourcetable,mergedtable,i,i+len-1,i+2*len-1);
i+=2*len;
}
if(i+len<=CurrentSize-1)
merge(sourcetable,mergedtable,i,i+len-1,CurrentSize-1);
elsefor(intj=i;j<=CurrentSize-1;j++)mergedtable.Arr[j]=sourcetable.Arr[j];
for(intj=0;j<=CurrentSize-1;j++)
sourcetable.Arr[j]=mergedtable.Arr[j];
//if(i+len<=CurrentSize-1)
{h++;
merge(sourcetable,mergedtable,i,i+len-1,CurrentSize-1);}
else
{h++;
for(intj=i;j<=CurrentSize-1;j++)
{h++;l++;
mergedtable.Arr[j]=sourcetable.Arr[j];}
}
}
voidmergesort(sortlist&table)
{
cout<<"归并排序:
"<sortlisttemptable;
intlen=1;
intu=1;
while(len
{
mergepass(table,