数据结构课程设计.docx
- 文档编号:25716179
- 上传时间:2023-06-11
- 格式:DOCX
- 页数:17
- 大小:61.25KB
数据结构课程设计.docx
《数据结构课程设计.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计.docx(17页珍藏版)》请在冰豆网上搜索。
数据结构课程设计
数据结构课程设计
实习报告
2003学年-2004学年第二学期
班级:
计算机科学与技术02103409班
姓名:
刘靓
学号:
021*******
完成日期:
2004.6.28
实习报告
题目:
假设定义堆为满足如下性质的完全三叉树:
(1)空树为堆;
(2)根结点的值不小于所有子树根的值,且所有子树均为堆。
编写利用上述定义的堆进行排序的算法,并分析推导算法的时间复杂度。
班级:
计算机02103409班姓名:
刘靓学号:
021*******完成日期:
04.6.28
一,需求分析
1,程序功能
利用定义的堆进行堆排序,定义的堆为满足如下性质的完全三叉树:
(1)空树为堆;
(2)根结点的值不小于所有子树根的值,且所有子树均为堆。
输入一组数据,可以按照大顶堆的方式排序输出的到一组新的数据。
2,执行方式及结果
①先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区
②再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key
③由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。
然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。
……
直到无序区只有一个元素为止。
待排序的数据元素的关键字为整数。
用三叉树的堆排序和不同乱序程度的不同数据做测试比较
3,程序执行的命令
①初始化操作:
将R[1..n]构造为初始堆;
②每一趟排序的基本操作:
将当前无序区的堆顶记录R[1]和该区间的最后一个记录交换,然后将新的无序区调整为堆(亦称重建堆)。
演示程序以用户和计算机的对话方式执行,即在计算机终端上显示“提示信息”下,用户可由键盘输入待排序表的表长(1-20)和不同测试数据。
每次测试完毕,列表显示各种比较指标值。
4,测试数据
程序执行过程中输入一组整形数据即可
二,概要设计
1,抽象数据类型定义
ADTOrderableList{
数据对象:
D={ai|ai∈IntegerSet,i=1,2,…,n,n≥0}
数据关系:
R1={
基本操作:
InitList(n)
操作结果:
构造一个长度为n,元素值依次为1,2,…,n的有序表。
RandomizeList(d,isInverseOrder)
操作结果:
首先根据isInverseOrder为True或False,将表置为逆序或正序,然后将表进行d(0≤d≤8)级随机打乱。
d为0时表不打乱,d越大,打乱程度越高。
RecallList()
操作结果:
恢复最后一次用RandomizeList随打乱得到的可排序表。
ListLength()
操作结果:
返回可排序表的长度。
ListEmpty()
操作结果:
若可排序表为空表,则返回True,否则返回False。
BubbleSort(&c,&s)
操作结果:
进行起泡排序,返回关键字比较次数c和移动次数s。
InsertSort(&c,&s)
操作结果:
进行插入排序,返回关键字比较次数c和移动次数s。
SelectSort(&c,&s)
操作结果:
进行选择排序,返回关键字比较次数c和移动次数s。
QuickSort(&c,&s)
操作结果:
进行快速排序,返回关键字比较次数c和移动次数s。
ShellSort(&c,&s)
操作结果:
进行希尔排序,返回关键字比较次数c和移动次数s。
HeapSort(&c,&s)
操作结果:
进行堆排序,返回关键字比较次数c和移动次数s。
ListTraverse(visit())
操作结果:
依次对L中的每个元素调用函数Visit()。
}ADTOrderableList
2,单元模块
本程序包含两个模块:
1)主程序模块:
voidmain(){
初始化;
do{
接受命令;
处理命令;
}while(“命令”!
=“退出”);
}
2)可排序表单元模块——实现可排序表的抽象数据类型;
3,各模块之间的关系如下:
主程序模块
可排序单元模块
三,详细设计
1,各种类型定义
//***************Myproject.h声明文件***************
HeapSort(SeqIAstR)//对R[1..n]进行堆排序,不妨用R[0]做暂存单元/
BuildHeap(R)//将R[1-n]建成初始堆
sift(intA[],intn,intm)
heapsort(intA[],intn)
//***************堆排序的算法***************
voidHeapSort(SeqIAstR)
{//对R[1..n]进行堆排序,不妨用R[0]做暂存单元
inti;
BuildHeap(R);//将R[1-n]建成初始堆
for(i=n;i>1;i--){//对当前无序区R[1..i]进行堆排序,共做n-1趟。
R[0]=R[1];R[1]=R[i];R[i]=R[0];//将堆顶和堆中最后一个记录交换
Heapify(R,1,i-1);//将R[1..i-1]重新调整为堆,仅有R[1]可能违反堆性质
}//endfor
}//HeapSort
BuildHeap和Heapify函数的实现
因为构造初始堆必须使用到调整堆的操作,先讨论Heapify的实现。
①Heapify函数思想方法
每趟排序开始前R[l..i]是以R[1]为根的堆,在R[1]与R[i]交换后,新的无序区R[1..i-1]中只有R[1]的值发生了变化,故除R[1]可能违反堆性质外,其余任何结点为根的子树均是堆。
因此,当被调整区间是R[low..high]时,只须调整以R[low]为根的树即可。
"筛选法"调整堆
R[low]的左、右子树(若存在)均已是堆,这两棵子树的根R[2low]和R[2low+1]分别是各自子树中关键字最大的结点。
若R[low].key不小于这两个孩子结点的关键字,则R[low]未违反堆性质,以R[low]为根的树已是堆,无须调整;否则必须将R[low]和它的两个孩子结点中关键字较大者进行交换,即R[low]与R[large](R[large].key=max(R[2low].key,R[2low+1].key))交换。
交换后又可能使结点R[large]违反堆性质,同样由于该结点的两棵子树(若存在)仍然是堆,故可重复上述的调整过程,对以R[large]为根的树进行调整。
此过程直至当前被调整的结点已满足堆性质,或者该结点已是叶子为止。
上述过程就象过筛子一样,把较小的关键字逐层筛下去,而将较大的关键字逐层选上来。
因此,有人将此方法称为"筛选法"。
②BuildHeap的实现
要将初始文件R[l..n]调整为一个大根堆,就必须将它所对应的完全二叉树中以每一结点为根的子树都调整为堆。
显然只有一个结点的树是堆,而在完全二叉树中,所有序号
的结点都是叶子,因此以这些结点为根的子树均已是堆。
这样,我们只需依次将以序号为
,
-1,…,1的结点作为根的子树都调整为堆即可。
//***************利用三叉树形式的堆进行排序的部分操作的伪码算法***************
voidTriHeap_Sort(Heap&H)//利用三叉树形式的堆进行排序的算法
{
for(i=H.length/3;i>0;i--)
Heap_Adjust(H,i,H.length);
for(i=H.length;i>1;i--)
{
H.r[1]<->H.r[i];
Heap_Adjust(H,1,i-1);
}
}//TriHeap_Sort
voidHeap_Adjust(Heap&H,ints,intm)//顺序表H中,H.r[s+1]到H.r[m]已经是堆,把H.r[s]插入并调整成堆
{
rc=H.r[s];
for(j=3*s-1;j<=m;j=3*j-1)
{
if(j if(j H.r[s]=H.r[j]; s=j; } H.r[s]=rc; }//Heap_Adjust 2,实现代码 #include usingnamespacestd;//标准命名空间 #defineNULL0//空地址常量 constintLIST_INIT_SIZE=100;//线性表存储空间的初始分配量 enumstatus{OK,ERROR,OVERFLOW,UNDERFLOW};//状态枚举变量 typedefintElemType; typedefstructSqList{ ElemType*elem;//存储空间基址 intlength;//当前表长 intlistsize;//当前分配的存储容量 }SqList; typedefSqListHeapType;//堆采用顺序表存储表示 boolInitList(HeapType&L) //Pre: None. //Post: TheListobjectcontainsaconfigurationspecifiedbytheuser. { L.elem=newElemType[LIST_INIT_SIZE+1];//事先分配一块很大的内存空间 if(! L.elem)returnfalse;//分配内存失败则返回false L.length=0;//初始长度置为0 L.listsize=LIST_INIT_SIZE;//最大长度为LIST_INIT_SIZE returntrue; } boolDestroyList(HeapType&L) //Pre: TheListobjectcontainsaconfiguration. //Post: None. { if(L.elem){ delete[]L.elem;//销毁表内所有元素 L.elem=NULL;//将空间基址设为空 returntrue; } else returnfalse; } boolClearList(HeapType&L) //Pre: TheListobjectContainssomeelems. //Post: Alltheelemsaredeleted. { if(L.length>0){ for(L.length;L.length>0;L.length--) L.elem[L.length]=NULL;//从尾部开始删除元素 returntrue; } else returnfalse; } voidPrint(HeapType&L)//打印该表的相关信息 //Pre: TheListobjectcontainsaconfiguration. //Post: Theconfigurationiswrittenfortheuser. { cout<<"表的当前配置信息: "< "; for(inti=1;i<=L.length;i++) cout< cout< "< "< } boolListAppend(HeapType&L){//从尾部追加元素 if(L.length L.length++; cout<<"请输入第"< "; cin>>L.elem[L.length]; cout<<"追加成功..."< returntrue; } else{ cout<<"追加溢出..."< returnfalse; } } voidHeapAdjust(HeapType&H,ints,intm)//调整为大顶堆 { intj,max; H.elem[0]=H.elem[s]; for(j=s*3-1;j<=m;j=j*3-1) { max=j; if(max+2<=m){ if(H.elem[max+1]>H.elem[max])max=max+1; if(H.elem[j+2]>H.elem[max])max=j+2; } elseif(max+1==m){ if(H.elem[max+1]>H.elem[max])max=max+1; } j=max;//获取较大记录的下标 if(H.elem[0]>H.elem[j])break;//H.elem[0]应插在位置s上 H.elem[s]=H.elem[j]; s=j; } H.elem[s]=H.elem[0]; }//HeapAdjust voidHeapSort(HeapType&H)//堆排序算法 { inti; for(i=(H.length/3)+1;i>0;i--) HeapAdjust(H,i,H.length); for(i=H.length;i>1;i--) { H.elem[0]=H.elem[1]; H.elem[1]=H.elem[i]; H.elem[i]=H.elem[0]; HeapAdjust(H,1,i-1); } } voidframe()//输出用户界面 { cout< <<"该演示程序利用三叉树堆排序算法对有序线性表进行排序运算"< <<"================="< <<"[c]创建有序线性表"< <<"[p]清空线性表"< <<"[q]退出该程序"< <<"================="< } booluser_says_yes()//输入yORn确定是否执行口令 { intc; boolinitial_response=true; do{//Loopuntilanappropriateinputisreceived. if(initial_response) cout<<"(y,n)? "< else cout<<"Respondwitheitheryorn: "< do{//Ignorewhitespace. c=cin.get(); }while(c=='\n'||c==''||c=='\t'); initial_response=false; }while(c! ='y'&&c! ='Y'&&c! ='n'&&c! ='N'); return(c=='y'||c=='Y'); } charGet_command()//读入一个操作命令符 { charcommand; boolwaiting=true; cout<<"请选择一个操作符,按回车键 "; while(waiting){ cin>>command; if(command=='c'||command=='p'||command=='q')//判断用户口令是否正确 waiting=false; else{ cout<<"请输入一个有效的操作符: "< <<"[c]创建有序线性表"< <<"[p]清空线性表"< <<"[q]退出该程序"< } } returncommand; } boolDo_command(charcommand,HeapType&H)//解释执行操作命令符 { inti;//循环标识 intn=0;//标识元素个数 switch(command){ case'c': while(n<1||n>100) { cout<<"请输入元素个数(1--100): "; cin>>n; } for(i=1;i<=n;i++) ListAppend(H); cout<<"排序前的线性表信息为: "< Print(H); HeapSort(H); cout<<"排序后的线性表信息为: "< Print(H); ClearList(H); cout<<"继续创建新表"; while(user_says_yes()) Do_command('c',H); break; case'p': Print(H); break; case'q': cout<<"正在退出该程序..."< returnfalse; } returntrue; } voidmain() { frame();//提示界面 HeapTypeH; InitList(H);//初始化一个线性表 while(Do_command(Get_command(),H));//读取并执行用户命令 DestroyList(H);//销毁堆并释放内存 }//main 四,调试分析 1,存在的问题 本算法思想与二叉树堆排序思想类似,只是多了一个孩子节点,本题是要求按大顶堆排序,要实现这个功能需要经过两个步骤,一个是要排序,在排序的过程中调用调整函数,所以另一个步骤就是调整堆。 最后在主函数中调用排序函数即可把输入的待排序数组按照大顶堆的顺序排序后输出。 本算法在初次执行命令时卡在了调用排序函数上,每次程序执行到此则停止,无法继续执行下去,经过仔细检查和跟踪调试,发现在排序函数中出现死循环,此问题自己检查了很久,并试图用其他方法实现相同功能,但程序仍旧无法继续,最后发现,由于调整堆的其实位置未定义正确导致排序无法进行,于是进行了调整。 2,程序的优缺点 本程序的优点有: 实现时占用的空间比较小,而且此堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。 本程序的缺点有: 实现起来循环次数较多,且反复建堆对空间开销较大。 3,算法的时空复杂度分析 堆排序的时间,主要由建立初始堆和反复重建堆这两部分的时间开销构成,它们均是通过调用Heapify实现的。 堆排序的最坏时间复杂度为O(nlgn)。 堆排序的平均性能较接近于最坏性能。 由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。 堆排序是就地排序,辅助空间为O (1), 它是不稳定的排序方法。 4,设计总结 本实习作业采用三叉树堆排序的方式对输入数据进行排序,全过程分为三个过程,排序,调整和主控制过程,整个程序的思路清晰,原理明了,但是实现的过程想了很久才最终实现,在设计的过程中遇到很多问题,借助图书馆的辅导资料和同学的帮助最终得以解决,所有程序均为自己独立完成。 感觉在自己在设计过程中收获很多,得到了很好的锻炼! 五,用户手册 1,程序的执行环境和可执行文件名 本程序的运行环境为DOS控制台,执行文件为: liujing.cpp 2,用户界面 进入演示程序后,即显示文本方式的用户界面(见图) 2,操作说明 输入命令C按回车键可以看到以下界面,输入待排序的具体数据元素(如示例为62,53,-51,-49,0)再按回车,即可得到排序结果(如示例为-51,-49,0,53,62) 4,各操作执行后的相应运算和显示结果 见上图的执行过程和相应显示结果 六,测试结果 1,执行测试命令后的运算结果 可在执行程序后,输入一组数据元素,即可进行堆排序,方法前面已详细介绍。 七,附录 1,源程序文件名清单 liujing.cpp//主体执行文件 Readme.txt//说明文档
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 课程设计