1、2009 级数据结构实验报告实验名称: 使用链表实现各种排序算法学生姓名: 桂柯易班 级: 2009211120班内序号: 07学 号: 09210580日 期: 2010 年 12 月 19 日1.实验要求【实验目的】通过选择实验内容中的两个题目之一,学习、实现、对比各种排序算法,掌握各种排序算法的优劣,以及各种算法的使用的情况。【实验内容】使用链表实现下面各种排序算法,并进行比较。排序算法如下: 插入排序; 冒泡排序; 快速排序; 简单选择排序; 其他。具体要求如下。 测试数据分成三类:正序、逆序、随机数据。 对于这三类数据,比较上述排序算法中关键字的比较次数和移动次数(其中关键字交换计为
2、 3 次移动) 。 对于这三类数据,比较上述排序算法中不同算法的执行时间,精确到微秒(选作) 。 对和的结果进行分析,验证上述各种算法的时间复杂度。 编写 main()函数测试各种排序算法的正确性。2.程序分析2.1 存储结构存储结构:链表2.2 关键算法分析【设计思想】以直接插入排序为例:首先将待排序数据建立一个带头结点的单链表。在单链表中进行直接插入排序的基本思想是:将单链表划分为有序区和无序区,有序区只包含一个元素节点,依次取无序区中的每一个结点,在有序区中查找待插入结点的插入位置,然后把该结点从单链表中删除,再插入到相应位置。分析上述排序过程,需设一个工作指针 q 在无序区中指向待插入
3、的结点,为了查找正确的插入位置,每趟排序前需将工作指针 pre 和 p 指向头结点和开始结点,在找到插入位置后,将结点 q 插在结点 pre 和 p 之间。这相当于在单链表中删除结点 q,因此为了保证链表不断开,须在删除结点 q 之前保留结点 q 的后继结点的地址。【复杂度】(1)建立链表存储数据的算法:Node *CreateSortNode(int count,int *array)Node *p1,*p2,*head;int i;head=NULL; for(i=0;idata=arrayi;p1-next=NULL;if (i=0)head=p1;else p2-next=p1;p2=
4、p1;p2-next=NULL;return head;该算法的时间复杂度为 T(N)=O(N)(2)输出数据的算法:void ListSortNode(Node *start)Node *p;p=start;while(p!=NULL)coutdatanext;coutdatadata)pre=p,p=p-next;b1+=2,a1+=2;s=s-next;if(p=newhead)a1+,b1+=2;newhead=min;newhead-next=p;elsea1+,b1+=2;pre-next=min;min-next=p;QueryPerformanceCounter(return
5、newhead;该算法的时间复杂度 T(N)=O(N2)(4)冒泡排序算法:Node *Ebullient_Sort_LinkTable(Node *head) _LARGE_INTEGER time_start; _LARGE_INTEGER time_over; double dqFreq; LARGE_INTEGER f; QueryPerformanceFrequency(dqFreq=(double)f.QuadPart;QueryPerformanceCounter(Node *q,*tail,*p,*t;q=new Node;q-next=head;head=q;b2+=3;fo
6、r(tail=NULL;tail!=head;tail=p)b2+=2,a2+=2;for(p=q=head;q-next-next!=tail;q=q-next)b2+=3,a2+=2;if(q-next-dataq-next-next-data) a2+,b2+=5;t=q-next-next;q-next-next=t-next;t-next=q-next;q-next=t;p=q-next-next;q=head;head=head-next;b2+=2;delete q;QueryPerformanceCounter( return head;该算法的时间复杂度 T(N)=O(N2)
7、(5)快速排序算法:Node *Fast_Sort_LinkTable(Node *head,Node *tail) _LARGE_INTEGER time_start; _LARGE_INTEGER time_over; double dqFreq; LARGE_INTEGER f; QueryPerformanceFrequency(dqFreq=(double)f.QuadPart;QueryPerformanceCounter(if(head=NULL|tail=NULL)return NULL; if(head=tail)return NULL;Node *p, *r, *pre;
8、pre=head;p=head-next;r=head;b3+=3;while(pif(p-datadata) a3+,b3+=5;r=pre;pre=pre-next;swamp(pre-data,p-data);p=p-next;b3+;swamp(head-data,pre-data);b3+=3;Fast_Sort_LinkTable(head,r); Fast_Sort_LinkTable(pre-next,tail); QueryPerformanceCounter( return head; 该算法的时间复杂度 T(N)=O(NlogN)(6)简单选择排序算法:Node *Sel
9、ect_Sort_LinkTable(Node *head) _LARGE_INTEGER time_start; _LARGE_INTEGER time_over; double dqFreq; LARGE_INTEGER f; QueryPerformanceFrequency(dqFreq=(double)f.QuadPart;QueryPerformanceCounter(Node *newhead, *tail, *p, *pre,*min;newhead=NULL;b4+;while(head!=NULL)a4+;for(p=min=head;p-next!=NULL;p=p-ne
10、xt)a4+,b4+=3;if(p-next-datadata)a4+,b4+=2;pre=p; min=p-next;if(min=head)head=head-next;a4+,b4+;elsepre-next=min-next;a4+,b4+;if(newhead=NULL)tail=newhead=min;a4+,b4+;elsetail=tail-next=min;a4+,b4+;if(newhead!=NULL)tail-next=NULL;a4+,b4+; QueryPerformanceCounter( return newhead;该算法的时间复杂度 T(N)=O(N2)2.
11、3 其他由于程序源代码在上述时间复杂度分析中已基本全部提及,此处不再附加。3.程序运行结果1.测试主函数流程:2.测试条件:如上图所示,输入的数据为 10 个乱序数据:45,678,22,4,17,98,77,56,234,780。3.测试结论:依次测试了插入排序,冒泡排序,快速排序,简单选择排序,结果都为正序,而且全部给出了算法运行时间和关键字的比较及移动次数,应可得出函数正常工作的结论。4.总结 1.调试时出现的问题及解决办法:(1)由于选择的是第二个,书上没有任何的参考代码,甚至在一些存储和实现方法上由于使用的是链表,因而出现了和数组不太一样的思想。遇到的第一个难题是插入排序,因为使用的
12、是单链表,不可能从后往前遍历,所以不适合使用书上的插入排序算法,对此我做了一些调整,把每次往前寻找改成每次从头往后寻找合适的插入点,由于测试数据包括正序、乱序、逆序,因此这样修改并不会导致算法整体时间复杂度的增加。(2)第二个遇到的问题是快速排序算法,按照书上的算法,快速排序需要从双向往中间靠拢,最后定下权值的位置,对此我曾一度想要改成用双向链表存储数据以实现书上的算法。但是后来感觉到这样会使整个程序显得异常臃肿(编完还需要加入时间算法和关键字统计算法) ,于是我又上网搜了一下,发现单链表的快速排序是有的,和书上的改进的快速排序算法思想是一样的,先将所有的数据根据权值左右分开,最后留下中间的位
13、置给权值,然后不断递归求得最终结果。根据这个思想我顺利地编出了快速排序的算法。(3)在加入时间函数的时候也出现了一些问题,这主要是由于缺乏经验,不知道什么样的函数能够显示微秒级别的程序运行时间,这个问题在和同学讨论并上网搜索的过程中顺利地解决了。(4)再有就是关键字的统计方面,由于是最后加入,所以从整个程序来看,加入了 8 个静态全局变量,用来分别记录 4 个排序算法的关键字比较次数和移动次数。在具体的函数内部实现上,可能由于测试数据数量太小,线性或者平方的关系表现的并不是很明显。2.心得体会:这次编写代码延续了上次编写哈夫曼的良好风格,几乎是全程独自编写,只参考了网上的个别算法思想。这对我的
14、编程能力又是一次极大的加强,以前编的程序简单,可以参考的代码多,几乎编出来的就已经是正确的,几乎很少调试。但是现在全是自己编,出现的问题很多,经常编译出来是一长串的问题,即时编译通过,运行时也经常达不到想要的效果,所以不得不多次使用但不调试 F11 来查找程序错误。在这个过程中有苦有乐,但是不管怎样,编译通过,运行成功那一时刻的喜悦,我想每一个喜欢编程的人都是能够理解的!3.下一步的改进:其实有个第五项其他选项我没有完成,原因是虽然只编 4 个函数,但已花费了大量时间。从时间上来说确实是不允许的。如果时间足够,我想再多编几个函数,实现链表的其他排序。话又说回来,链表的排序确实没有数组来的方便,我想有机会还是多和书上的数组的排序算法亲近亲近。