实验四 排序 实验报告文档格式.docx
《实验四 排序 实验报告文档格式.docx》由会员分享,可在线阅读,更多相关《实验四 排序 实验报告文档格式.docx(14页珍藏版)》请在冰豆网上搜索。
编写测试main()函数测试线性表的正确性.
2、程序分析
2.1存储结构
说明:
本程序排序序列的存储由链表来完成.
其存储结构如下图所示。
(1)单链表存储结构:
A[2]
1080H
……
A[0]
10C0H
……
A[3]
NULL
A[1]
1000H
(2)结点结构
structNode
{
ﻩintdata;
ﻩNode*next;
};
示意图:
2。
2关键算法分析
一:
关键算法
(一)直接插入排序 voidLinkSort:
:
InsertSort()
直接插入排序是插入排序中最简单的排序方法,其基本思想是:
依次将待排序序列中的每一个记录插入到一个已排好的序列中,直到全部记录都排好序。
(1)算法自然语言
1.将整个待排序的记录序列划分成有序区和无序区,初始时有序区为待排序记录序列中的第一个记录,无序区包括所有剩余待排序的记录;
2.将无须去的第一个记录插入到有序区的合适位置中,从而使无序区减少一个记录,有序区增加一个记录;
3。
重复执行2,直到无序区中没有记录为止。
(2)源代码
voidLinkSort:
:
InsertSort()ﻩ //从第二个元素开始,寻找前面那个比它大的
ﻩNode*P=front->next;
ﻩ //要插入的节点的前驱
ﻩwhile(P—>
next)
{
ﻩNode*S =front;
ﻩﻩ //用来比较的节点的前驱
ﻩwhile
(1)
ﻩ{
ﻩﻩﻩCompareCount++;
ﻩﻩif(P—〉next->
data〈S—〉next->
data)ﻩ// P的后继比S的后继小则插入
ﻩ{
ﻩﻩﻩinsert(P,S);
break;
ﻩ}
ﻩﻩS= S—>
next;
ﻩﻩif(S==P)ﻩﻩﻩ//若一趟比较结束,且不需要插入
ﻩﻩ{
ﻩﻩP=P-〉next;
ﻩﻩbreak;
}
ﻩﻩ}
ﻩ}
}
(3)时间和空间复杂度
最好情况下,待排序序列为正序,时间复杂度为O(n)。
最坏情况下,待排序序列为逆序,时间复杂度为O(n2)。
直接插入排序只需要一个记录的辅助空间,用来作为待插入记录的暂存单元和查找记录的插入位置过程中的“哨兵”。
直接插入排序是一种稳定的排序方法.直接插入排序算法简单容易实现,当序列中的记录基本有序或带排序记录较少时,他是最佳的排序方法。
但当待排序的记录个数较多时,大量的比较和移动操作使直接插入排序算法的效率减低。
(二)冒泡排序voidLinkSort:
BubbleSort()
冒泡排序是交换排序中最简单的排序方法,其基本思想是:
两两比较相邻记录的关键码,如果反序则交换,直到没有反序的记录为止。
本程序采用改进的冒泡程序。
(1)算法自然语言
1。
将整个待排序的记录序列划分成有序区和无序区,初始状态有序区为空,无序区包括所有待排序的记录.
2.对无序区从前向后依次将相邻记录的关键码进行比较,若反序则交换,从而使得关键码小的记录向前移,关键码大的记录向后移(像水中的气泡,体积大的先浮上来)。
将最后一次交换的位置pos,做为下一趟无序区的末尾.
4。
重复执行2和3,直到无序区中没有反序的记录。
voidLinkSort:
BubbleSort()
{
ﻩNode*P=front—〉next;
ﻩwhile(P->next)ﻩ //第一趟排序并查找无序范围
{
ﻩCompareCount++;
ﻩif(P-〉data >
P—>
next-〉data)
ﻩﻩswap(P,P-〉next);
ﻩP =P->
next;
}
ﻩNode * pos =P;
P=front-〉next;
while(pos!
=front-〉next)
ﻩ{
ﻩﻩNode* bound=pos;
ﻩpos=front->
while(P->next !
=bound)
ﻩﻩ{
ﻩCompareCount++;
ﻩif( P->
data>
P—>
next—〉data)
ﻩﻩﻩ{
ﻩﻩswap(P,P—>next);
ﻩﻩpos=P->next;
ﻩﻩ}
ﻩP=P->next;
ﻩﻩ
ﻩ}
P= front->next;
在最好情况下,待排序记录序列为正序,算法只执行了一趟,进行了n-1次关键码的比较,不需要移动记录,时间复杂度为O(n);
在最坏情况下,待排序记录序列为反序,时间复杂度为O(n2),空间复杂度为O(1).
冒泡排序是一种稳定的排序方法.
初始键值序列[5013559727384965]
第一趟排序结果[13505527384965]97
第二趟排序结果[1350273849]556597
第三趟排序结果[13273849]50556597
第四趟排序结果1327384950556597
冒泡排序过程
(三)快速排序 voidLinkSort:
Qsort()
1.首先选一个轴值(即比较的基准),将待排序记录分割成独立的两部分,左侧记录的关键码均小于或等于轴值,右侧记录的关键码均大于或等于轴值。
2.然后分别对这两部分重复上述过程,直到整个序列有序。
整个快速排序的过程递归进行。
voidLinkSort:
Qsort()
Node *End=front;
ﻩwhile(End->next)
{
ﻩﻩEnd=End->
next;
}
Partion(front,End);
}
voidLinkSort:
Partion(Node*Start, Node*End)
ﻩif(Start—〉next==End||Start==End)ﻩﻩ//递归返回
ﻩﻩreturn;
ﻩNode *Mid=Start;
ﻩﻩ //基准值前驱
ﻩNode*P= Mid->next;
ﻩwhile(P!
=End&
&
P!
=End->next)
CompareCount++;
ﻩif(Mid->
next-〉data>P-〉next->
data)ﻩ//元素值小于轴点值,则将该元素插在轴点之前
ﻩ{
ﻩﻩif( P—>next==End)ﻩﻩ//若该元素为End,则将其前驱设为End
ﻩEnd= P;
ﻩﻩinsert(P,Mid);
ﻩMid =Mid->
next;
ﻩ}
ﻩelseP=P—>
next;
ﻩPartion(Start,Mid);
ﻩ //递归处理基准值左侧链表
Partion(Mid-〉next,End);
ﻩ //递归处理基准值右侧链表
在最好的情况下,时间复杂度为O(nlog2n)。
在最坏的情况下,时间复杂度为O(n2)。
快速排序是一种不稳定的排序方法.
(四)简单选择排序
基本思想为:
第i趟排序通过n-i次关键码的比较,在n—i+1(1≤i≤n—1)各记录中选取关键码最小的记录,并和第i个记录交换作为有序序列的第i个记录。
1.将整个记录序列划分为有序区和无序区,初始状态有序区为空,无序区含有待排序的所有记录。
2.在无序区中选取关键码最小的记录,将它与无序区中的第一个记录交换,使得有序区扩展了一个记录,而无序区减少了一个记录。
不断重复2,直到无序区之剩下一个记录为止。
voidLinkSort:
SelectSort()
ﻩNode* S=front;
while(S—>next—〉next)
ﻩ{
ﻩﻩNode*P=S;
ﻩNode*Min = P;
while(P—〉next) //查找最小记录的位置
ﻩﻩCompareCount++;
ﻩif(P—〉next—>
data〈 Min->next->
data)
ﻩﻩﻩMin=P;
ﻩP=P-〉next;
ﻩﻩinsert(Min,S);
S =S—>next;
ﻩ}
(3)时间和空间复杂度
简单选择排序最好、最坏和平均的时间复杂度为O(n2)。
简单选择排序是一种不稳定的排序方法.
(五)输出比较结果函数(含计算函数体执行时间代码)
1、依次调用直接插入排序、冒泡排序、快速排序、简单选择排序的函数体,进行序列的排序,并输出相应的比较次数、移动次数。
2、获取当前系统时间。
在调用函数之前设定一个调用代码前的时间,在调用函数之后再次设定一个调用代码后的时间,两个时间相减就是代码运行时间。
说明:
运用QueryPerformanceFrequency()可获取计时器频率;
QueryPerformanceCounter()用于得到高精度计时器的值。
voidprintResult(LinkSort&a,LinkSort&b, LinkSort&
c,LinkSort&d)
{
_LARGE_INTEGERtime_start;
//开始时间
_LARGE_INTEGERtime_over;
//结束时间
double dqFreq;
//计时器频率
LARGE_INTEGERf;
//计时器频率
QueryPerformanceFrequency(&
f);
dqFreq=(double)f。
QuadPart;
a.print();
doubleTimeCount;
ﻩCompareCount=0;
MoveCount=0;
TimeCount= 0;
QueryPerformanceCounter(&
time_start);
//记录起始时间
ﻩa.InsertSort();
ﻩQueryPerformanceCounter(&time_over);
//记录结束时间
TimeCount=((time_over.QuadPart-ti