北邮数据结构实验四-链表排序

合集下载

数据结构实验四题目一排序实验报告

数据结构实验四题目一排序实验报告

数据结构实验报告实验名称:实验四——排序学生:XX班级:班序号:学号:日期:1.实验要求实验目的:通过选择实验容中的两个题目之一,学习、实现、对比、各种排序的算法,掌握各种排序算法的优劣,以及各种算法使用的情况。

题目1:使用简单数组实现下面各种排序算法,并进行比较。

排序算法如下:1、插入排序;2、希尔排序;3、冒泡排序;4、快速排序;5、简单选择排序;6、堆排序;7、归并排序;8、基数排序(选作);9、其他。

具体要求如下:1、测试数据分成三类:正序、逆序、随机数据。

2、对于这三类数据,比较上述排序算法中关键字的比较次数和移动次数(其中关键字交换记为3次移动)。

3、对于这三类数据,比较上述排序算法中不同算法的执行时间,精确到微妙。

4、对2和3的结果进行分析,验证上述各种算法的时间复杂度。

5、编写main()函数测试各种排序算法的正确性。

2. 程序分析2.1 存储结构存储结构:数组2.2 关键算法分析一、关键算法:1、插入排序a、取排序的第二个数据与前一个比较b、若比前一个小,则赋值给哨兵c、从后向前比较,将其插入在比其小的元素后d、循环排序2、希尔排序a、将数组分成两份b、将第一份数组的元素与哨兵比较c、若其大与哨兵,其值赋给哨兵d、哨兵与第二份数组元素比较,将较大的值赋给第二份数组e、循环进行数组拆分3、对数据进行编码a、取数组元素与下一个元素比较b、若比下一个元素大,则与其交换c、后移,重复d、改变总元素值,并重复上述代码4、快速排序a、选取标准值b、比较高低指针指向元素,若指针保持前后顺序,且后指针元素大于标准值,后指针前移,重新比较c、否则后面元素赋给前面元素d、若后指针元素小于标准值,前指针后移,重新比较e、否则前面元素赋给后面元素5、简单选择排序a、从数组中选择出最小元素b、若不为当前元素,则交换c、后移将当前元素设为下一个元素6、堆排序a、生成小顶堆b、将堆的根节点移至数组的最后c、去掉已做过根节点的元素继续生成小顶堆d、数组倒置7、归并排序a、将数组每次以1/2拆分,直到为最小单位b、小相邻单位数组比较重排合成新的单位c、循环直至完成排序二、代码详细分析:1、插入排序关键代码:①取排序的第二个数据与前一个比较:if(r[i]<r[i-1])②若比前一个小,则赋值给哨兵:r[0]=r[i];③从后向前比较,将其插入在比其小的元素后:for(j=i-1;r[0]<r[j];j--){r[j+1]=r[j];a++;} r[j+1]=r[0];④循环排序2、希尔排序关键代码:①将数组分成两份:d=n/2②将第一份数组的元素与哨兵比较:for(int i=d+1;i<=n;i++)③若其大与哨兵,其值赋给哨兵:if(r[0]<r[i-d]){ r[0]=r[i];}④哨兵与第二份数组元素比较,将较大的值赋给第二份数组:for(j=i-d;j>0&&r[0]<r[j];j=j-d) {r[j+d]=r[j]; }⑤循环进行数组拆分:for(int;d>=1;d=d/2)3、冒泡排序关键代码:①取数组元素与下一个元素比较: for(int i=1;i<bound;i++)if(r[i]>r[i+1])②若比下一个元素大,则与其交换: r[0]=r[i]; r[i]=r[i+1]; r[i+1]=r[0];③后移,重复:for(int i=1;i<bound;i++)④改变总元素值,并重复上述代码:int bound=pos;4、快速排序关键代码:①选取标准值:r[0]=r[i]②比较高低指针指向元素,若指针保持前后顺序,且后指针元素大于标准值,后指针前移,重新比较:while(i<j&&r[j]>=flag) {j--;}③否则后面元素赋给前面元素:r[i]=r[j];④若后指针元素小于标准值,前指针后移,重新比较:while(i<j&&r[i]<=flag){i++;}⑤否则前面元素赋给后面元素:r[j]=r[i];5、简单选择排序关键代码:①从数组中选择出最小元素: for(int j=i+1;j<=n;j++)②{if(r[j]<r[index]) index=j; }③若不为当前元素,则交换:if(index!=i) {r[0]=r[i]; r[i]=r[index];r[index]=r[0];}④后移将当前元素设为下一个元素:for(int i=1;i<n;i++)6、堆排序关键代码:①生成小顶堆:while(j<=m) {if(j<m&&r[j]>r[j+1]) {j++;}②if(r[i]<r[j]) {break; }③else{ int x; x=r[i]; r[i]=r[j]; r[j]=x; i=j; j=2*i; }}④将堆的根节点移至数组的最后: x=r[1]; r[1]=r[n-i+1]; r[n-i+1]=x;⑤去掉已做过根节点的元素继续生成小顶堆:sift(r,1,n-i,x,y);⑥数组倒置输出: for(int i=n;i>0;i--)cout<<r[i]<<" ";7、归并排序关键代码:①将数组每次以1/2拆分,直到为最小单位: mid=(low+high)/2;②小相邻单位数组比较重排合成新的单位:while(i<=m&&j<=high)if(L.r[i]<=L.r[j]) t[k++]=L.r[i++];else t[k++]=L.r[j++];while(i<=m) t[k++]=L.r[i++];while(j<=high) t[k++]=L.r[j++];for(i=low,k=0;i<=high;i++,k++) L.r[i]=t[k];三、计算关键算法的时间、空间复杂度插入排序O(n2)希尔排序O(n2)冒泡排序O(n2)快速排序O(nlog2n)简单选择排序O(n2)堆排序O(nlog2n)归并排序O(nlog2n)3. 程序运行结果1、测试主函数流程:流程图如图所示流程图示意图程序运行结果图如下:2、测试条件:按题目要求分别输入同组数据的正序、逆序、随机序列进行测试。

北邮数据结构实验报告线性表

北邮数据结构实验报告线性表

北邮数据结构实验报告线性表实验报告;课程名称:数据结构班级:软件工程实验成绩:;1206;实验名称:打印机队列模拟学号:XX4848批;程序的设计;实验编号:实验一姓名:实验日期:XX年5月2;一、实验目的;对队列的理解;对STL中的queue的使用;实验仿真一个网络打印过程;二、实验内容与实验步骤流程图;这个任务队列的测试使用STL队列适配器;具体地说,每一行中包含的信息是实验报告课程名称:数据结构班级:软件工程实验成绩:1206实验名称:打印机队列模拟学号:XX4848 批阅教师签字:程序的设计实验编号:实验一姓名:实验日期:XX年5 月 24 日一、实验目的对队列的理解对STL中的queue的使用实验仿真一个网络打印过程二、实验内容与实验步骤流程图这个任务队列的测试使用STL队列适配器。

程序要求完成模拟的实现共享打印机。

这个打印机使用先进先出队列。

仿真是通过读取和处理事件数据文件的列表。

一个有效的数据文件中的每一行包含信息打印作业和提交这份工作的时间。

具体地说,每一行中包含的信息是提交工作的时间(以秒为单位),和在页面的工作长及工作的计算机的名称。

在模拟的开始,每个这些事件的每一个应该被程序所读,存储在继承工作负载队列。

程序应该通过循环递增计数器或while-loop模拟时间的流逝。

程序应该将计数器初始化为零,然后依次增加1秒。

当模拟等于当前时间的打印作业的提交时间在工作队列的前面,一个打印作业完成。

当这一切发生的时候,从工作队列取出这个事件,然后把它放在另一个队列对象。

这个队列对象存储已完成的打印作业。

当程序仿真其他的打印工作的时候,这些工作在队列等待。

Win8,Visual C++四、实验过程与分析(1)实验主要函数及存储结构包括主函数和主要的功能仿真类的声明仿真类的定义事件类的声明- 事件类的定义作业类的声明作业类的定义包括任意打印作业数的数据文件输出包括打印较大作业的数据文件输出(2)实验代码#ifndef FIFO_H //#define FIFO_H#include ""class fifo:public simulator{protected:queue waiting;priority_queue priority_waiting;public:fifo(int seconds_per_page);void simulate(string file);};bool operator #endif#include "" //#includeusing namespace std;fifo::fifo(intseconds_per_page):simulator(seconds_per_page){ } void fifo::simulate(string file){int finish_time = 0;float agg_latency = 0;int totaljob =0;event evt;if(("arbitrary")!= string::npos){string outfile ="";ofstream osf(_str());loadworkload(file);osf for(int time =1;!()||!();time++){ while(!() && time ==().arrival_time()){evt= ();osf ();}if(!() && time >= finish_time){totaljob ++;evt = ();agg_latency += time - _time();osf finish_time = time + ().getnumpages() * seconds_per_page;}}osf osf osf return;}if(("bigfirst") != string::npos){string outfile = "";ofstream osf(_str());loadworkload(file);osf for(int time=1;!priority_()||!();time++){while(!() && time ==().arrival_time()){evt= ();osf ();}if(!priority_() && time >= finish_time){totaljob ++;evt = priority_();agg_latency += time - _time();osf finish_time = time + ().getnumpages() * seconds_per_page; }}osf osf osf return;}cerr cerr bool operator return ().getnumpages() ().getnumpages();}五、实验结果总结经测试,功能较为完整。

链表的排序——精选推荐

链表的排序——精选推荐

链表的排序本次讨论单向链表的排序。

本质上讲,链表的排序与数组的排序在算法上有很多相通的地⽅,但是由于单向链表只能向后访问的特殊性,那些要求随机访问的排序算法在链表的排序上并不能施展⼿脚,所以只能采⽤相邻⽐较的排序⽅法:冒泡法,⽽且只能从前向后冒泡。

链表的另⼀个问题是由于长度不是已知的,所以终⽌条件只能通过节点是否为空进⾏判断,⽽每次的循环次数也是如此。

下⾯是两种排序⽅法,⼀种求出长度再排序,另⼀种直接进⾏排序。

另⼀种排序要求是倒序。

当然,我们可以修改count1(),使其不分青红皂⽩总是交换相邻节点,只是复杂度较⾼。

另⼀种优美简练的算法就是下⾯的reverse⽅法。

代码中添加了注释,应该能看明⽩。

核⼼思想就是化整为零,每次把即将要倒序的节点指向已倒序完成的节点序列,然后指针右移,直⾄结束。

// 计算链表长度public int count() {Node2<T> temp = head;int count = 0;while (temp != null) {count++;temp = temp.next;}return count;}// ⽤于两节点数据交换private void swap(Node2<T> Node21, Node2<T> Node2) {T temp = Node21.key;Node21.key = Node2.key;Node2.key = temp;}// 由链表长度控制循环判断条件public void sort1() {int n = count();if (n > 1) {// ⾄少两个节点才能排序;for (int i = 0; i < n; i++) {Node2<T> temp = head;for (int j = 0; j < n - i - 1; j++) {// 相邻⽐较,前者⼩则互换值。

排序算法---链表排序

排序算法---链表排序

排序算法---链表排序前⾔ 链表排序思想和数组排序类似,区别就是数组遍历容易,数据交换也容易;链表(单项链表)只能⼀个⽅向遍历,不能逆序遍历(也可以先反转在遍历),且不能随机访问,所以排序⽐较⿇烦,同时链表的数据交换也很⿇烦,如果交换两个节点,需要共涉及3个节点,⽆形中增加了复杂度,也可以直接交换节点中的数据,这种⽅式相对简单。

如下列出了⼏种相对⽐较好简单也好理解的链表排序算法,代码如下:1 #include <iostream>23using namespace std;45struct Node6{7struct Node *next;8int data;9};1011 Node *createNode(int x)12{13 Node *p = NULL;1415 p = new Node;16 p->next = NULL;17 p->data = x;1819return p;20}2122void addNode(Node **head, Node *p)23{24 Node *temp = NULL;25if(*head == NULL)26 {27 *head = p;28 }29else30 {31 temp = *head;32while(temp->next != NULL)33 {34 temp = temp->next;35 }36 temp->next = p;37 }38}3940void showList(Node *head)41{42while(head != NULL)43 {44 cout << head->data << "";45 head = head->next;46 }47 cout << endl;48}4950void swap(int& a, int& b)51{52int tmp = b;53 b = a;54 a = tmp;55}5657// 1. 直接选择排序 ------直接交换数据58void ListSort_1(Node **head)59{60 Node *p = NULL;61 Node *q = NULL;62 Node *t = NULL;6364if(*head == NULL || (*head)->next == NULL)65 {66return;67 }6869for(p = *head; p != NULL; p = p->next)70 {71 t = p;7273for(q = p->next; q != NULL; q = q->next)74 {75if(q->data < t->data)76 {77 t = q;78 }79 }8081if(t != p)82 {83 swap(p->data, t->data);84 }85 }8687return;88}8990// 2. 冒泡排序 ------直接交换数据91void ListSort_2(Node **head)92{93 Node *p = NULL;94 Node *q = NULL;95 Node *t = NULL;9697if(*head == NULL || (*head)->next == NULL)98 {99return;100 }101102for(p = *head; p != NULL; p = p->next)103 {104for(q = *head; q->next != NULL; q = q->next)105 {106if(q->data > q->next->data)107 {108 swap(q->data, q->next->data);109 }110 }111112 }113}114115// 3. 插⼊排序116void ListSort_3(Node **head)117{118//直接插⼊排序涉及到链表的反向遍历,⽐较⿇烦,不建议119}120121 Node *merge(Node *left, Node *right)122{123 Node *head = createNode(-1); // ⼩技巧124 Node *temp = head;125126while(left != NULL && right != NULL)127 {128if(left->data < right->data)129 {130 temp->next = left;131 temp = temp->next;132 left = left->next;133 }134else135 {136 temp->next = right;137 temp = temp->next;138 right = right->next;139 }140 }141142if(left != NULL)143 {144 temp->next = left;145 }146147if(right != NULL)148 {149 temp->next = right;150 }151152return head->next;153}154155 Node *_ListSort_4(Node *head)156{157 Node *pFast = NULL;158 Node *pSlow = NULL;159 Node *mid = NULL;160161if(head == NULL || head->next == NULL)162 {163return head;164 }165166 pFast = head;167 pSlow = head;168169while(pFast->next != NULL && pFast->next->next != NULL) 170 {171 pFast = pFast->next->next;172 pSlow = pSlow->next;173 }174175 mid = pSlow->next;176 pSlow->next = NULL;177178return merge(_ListSort_4(head), _ListSort_4(mid)); 179}180181// 4. 归并排序 ------交换节点182void ListSort_4(Node **head)183{184 Node *temp = *head;185 *head = _ListSort_4(temp);186}187188int main()189{190 Node *head = NULL;191192 addNode(&head, createNode(2));193 addNode(&head, createNode(5));194 addNode(&head, createNode(7));195 addNode(&head, createNode(4));196 addNode(&head, createNode(6));197 addNode(&head, createNode(3));198 addNode(&head, createNode(1));199 addNode(&head, createNode(9));200 addNode(&head, createNode(8));201202 cout << "Sort Before:" << endl;203 showList(head);204205//ListSort_1(&head);206//ListSort_2(&head);207 ListSort_4(&head);208209 cout << "Sort After:" << endl; 210 showList(head);211212while(1);213return0;214 }。

北邮数据结构实验四-排序

北邮数据结构实验四-排序

2008级数据结构实验报告实验名称:实验四排序学生姓名:班级:班内序号:学号:日期:实验要求a. 实验目的通过实现下述实验内容,学习、实现、对比各种排序算法,掌握各种排序算法的优劣,以及各种算法使用的情况。

b. 实验内容2 题目2使用链表实现下面各种排序算法,并进行比较。

排序算法:1、插入排序2、冒泡排序3、快速排序4、简单选择排序5、其他要求:1、测试数据分成三类:正序、逆序、随机数据2、对于这三类数据,比较上述排序算法中关键字的比较次数和移动次数(其中关键字交换计为3次移动)。

3、对于这三类数据,比较上述排序算法中不同算法的执行时间,精确到微秒(选作)4、对2和3的结果进行分析,验证上述各种算法的时间复杂度编写测试main()函数测试线性表的正确性2.程序分析:1.存储结构:单链表结点结构体为: struct Node{ int data ; Node * next } 2. 核心算法思想:1. 利用教材讲述的基本算法思想,实现四种排序算法,统计其运行相关数据。

2. 将四种排序函数入口地址作为函数头指针,实现快速调用和统计。

使得程序代码可读性增、结构更加优化。

3. 关键算法的实现: 关键算法1:实现四种算法的基本排序功能。

1、插入排序:依次将待排序的序列中的每一个记录插入到先前排序好的序列中,直到全部记录排头结点,排序完毕。

具体实现为:每次将s 赋值为头结点,而p 最初赋值为第一个含有data 的指针。

每次比较p 和s 的后继的数据大小,若是p 的数据小于s 的数据则将p 的后继结点插入到s 结点的后面同时s 返回到头结点重新比较插入,直至p 到达链表的尾部。

void LinkSort::InsertSort()//插入排序{Node * P = front->next; //要插入的节点的前驱while(P->next){Node * S = front; //用来比较的节点的前驱while(1){ CompareCount++;if( P->next->data < S->next->data ) // P后继比S后继小则把p的后继结点插入到s后继结点的后面,同时跳出这一层循环,将s重新赋值为front结点指针。

链表排序(冒泡、选择、插入、快排、归并、希尔、堆排序)

链表排序(冒泡、选择、插入、快排、归并、希尔、堆排序)

链表排序(冒泡、选择、插⼊、快排、归并、希尔、堆排序)这篇⽂章分析⼀下链表的各种排序⽅法。

以下排序算法的正确性都可以在LeetCode的这⼀题检测。

本⽂⽤到的链表结构如下(排序算法都是传⼊链表头指针作为参数,返回排序后的头指针)struct ListNode {int val;ListNode *next;ListNode(int x) : val(x), next(NULL) {}};插⼊排序(算法中是直接交换节点,时间复杂度O(n^2),空间复杂度O(1))class Solution {public:ListNode *insertionSortList(ListNode *head) {// IMPORTANT: Please reset any member data you declared, as// the same Solution instance will be reused for each test case.if(head == NULL || head->next == NULL)return head;ListNode *p = head->next, *pstart = new ListNode(0), *pend = head;pstart->next = head; //为了操作⽅便,添加⼀个头结点while(p != NULL){ListNode *tmp = pstart->next, *pre = pstart;while(tmp != p && p->val >= tmp->val) //找到插⼊位置{tmp = tmp->next; pre = pre->next;}if(tmp == p)pend = p;else{pend->next = p->next;p->next = tmp;pre->next = p;}p = pend->next;}head = pstart->next;delete pstart;return head;}};选择排序(算法中只是交换节点的val值,时间复杂度O(n^2),空间复杂度O(1))class Solution {public:ListNode *selectSortList(ListNode *head) {// IMPORTANT: Please reset any member data you declared, as// the same Solution instance will be reused for each test case.//选择排序if(head == NULL || head->next == NULL)return head;ListNode *pstart = new ListNode(0);pstart->next = head; //为了操作⽅便,添加⼀个头结点ListNode*sortedTail = pstart;//指向已排好序的部分的尾部while(sortedTail->next != NULL){ListNode*minNode = sortedTail->next, *p = sortedTail->next->next;//寻找未排序部分的最⼩节点while(p != NULL){if(p->val < minNode->val)minNode = p;p = p->next;}swap(minNode->val, sortedTail->next->val);sortedTail = sortedTail->next;}head = pstart->next;delete pstart;return head;}};快速排序1(算法只交换节点的val值,平均时间复杂度O(nlogn),不考虑递归栈空间的话空间复杂度是O(1))这⾥的partition我们参考(选取第⼀个元素作为枢纽元的版本,因为链表选择最后⼀元素需要遍历⼀遍),具体可以参考这⾥我们还需要注意的⼀点是数组的partition两个参数分别代表数组的起始位置,两边都是闭区间,这样在排序的主函数中:void quicksort(vector<int>&arr, int low, int high){if(low < high){int middle = mypartition(arr, low, high);quicksort(arr, low, middle-1);quicksort(arr, middle+1, high);}}对左边⼦数组排序时,⼦数组右边界是middle-1,如果链表也按这种两边都是闭区间的话,找到分割后枢纽元middle,找到middle-1还得再次遍历数组,因此链表的partition采⽤前闭后开的区间(这样排序主函数也需要前闭后开区间),这样就可以避免上述问题class Solution {public:ListNode *quickSortList(ListNode *head) {// IMPORTANT: Please reset any member data you declared, as// the same Solution instance will be reused for each test case.//链表快速排序if(head == NULL || head->next == NULL)return head;qsortList(head, NULL);return head;}void qsortList(ListNode*head, ListNode*tail){//链表范围是[low, high)if(head != tail && head->next != tail){ListNode* mid = partitionList(head, tail);qsortList(head, mid);qsortList(mid->next, tail);}}ListNode* partitionList(ListNode*low, ListNode*high){//链表范围是[low, high)int key = low->val;ListNode* loc = low;for(ListNode*i = low->next; i != high; i = i->next)if(i->val < key){loc = loc->next;swap(i->val, loc->val);}swap(loc->val, low->val);return loc;}};快速排序2(算法交换链表节点,平均时间复杂度O(nlogn),不考虑递归栈空间的话空间复杂度是O(1))这⾥的partition,我们选取第⼀个节点作为枢纽元,然后把⼩于枢纽的节点放到⼀个链中,把不⼩于枢纽的及节点放到另⼀个链中,最后把两条链以及枢纽连接成⼀条链。

链表排序——精选推荐

链表排序以O(n log n)的时间复杂度对链表进⾏排序。

⼀、归并排序采⽤分治思想的归并排序,主要需要的⽅法有寻找中间结点的函数ListNode Findmid(ListNode head)和归并两个有序链表的函数ListNode merge(ListNode head1, ListNode head2)。

然后采⽤递归的⽅式调⽤ListNode sortList(ListNode head)函数,找出中间结点,分别对右链和左链进⾏排序后,归并左链和右链。

1. Findmid(ListNode head)函数采⽤快慢指针,快指针到链尾时,慢指针到中间结点。

2. merge(ListNode head1, ListNode head2)函数从两个链表的第⼀个值开始⽐较,取⼩值存⼊新链表,取较⼩值链表的下⼀个值继续⽐较。

完整代码如下:/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode sortList(ListNode head) {if (head == null || head.next == null) {return head;}ListNode mid = Findmid(head);ListNode right = sortList(mid.next);mid.next = null;ListNode left = sortList(head);return merge(left, right);}private ListNode Findmid(ListNode head) {if (head == null || head.next == null) {return head;}ListNode fast = head.next;ListNode slow = head;while (fast != null && fast.next != null) {slow = slow.next;fast = fast.next.next;}return slow;}private ListNode merge(ListNode head1, ListNode head2) {if (head1 == null && head2 == null) {return null;}ListNode dummy = new ListNode(0);ListNode head = dummy;while (head1 != null && head2 != null) {if (head1.val < head2.val) {dummy.next = new ListNode(head1.val);head1 = head1.next;} else {dummy.next = new ListNode(head2.val);head2 = head2.next;}dummy = dummy.next;}while (head1 != null) {dummy.next = new ListNode(head1.val);head1 = head1.next;dummy = dummy.next;}while (head2 != null) {dummy.next = new ListNode(head2.val);head2 = head2.next;dummy = dummy.next;}return head.next;}}⼆、快速排序1采⽤三点切分的快速排序,先⽤ListNode Findmid(ListNode head)函数找到参考的中间结点,然后遍历链表,找到⼩于、等于和⼤于中间结点的结点分别形成左、中、右三个链表,递归调⽤ListNode sortList(ListNode head)函数将三个链表进⾏排序,之后利⽤ListNodeLink(ListNode head1, ListNode head2, ListNode head3)函数将三个链表拼接起来。

北邮数据结构实验—链表排序

数据结构实验报告实验名称:________链表排序___________ 学生姓名:_____________________班级:________________班内序号:_________________________ 学号:________________日期:_______________1.实验要求使用链表实现下面各种排序算法,并进行比较。

排序算法:1、插入排序2、冒泡排序3、快速排序4、简单选择排序5、其他要求:1、测试数据分成三类:正序、逆序、随机数据2、对于这三类数据,比较上述排序算法中关键字的比较次数和移动次数(其中关键字交换计为3次移动)。

3、对于这三类数据,比较上述排序算法中不同算法的执行时间,精确到微秒(选作)4、对2和3的结果进行分析,验证上述各种算法的时间复杂度编写测试main()函数测试排序算法的正确性2. 程序分析2.1 存储结构双向链表2.2 程序流程(或程序结构、或类关系图等表明程序构成的内容,一般为流程图等)2.3 关键算法分析定义节点:struct Node{int data;Node* next;Node* period;};插入排序:void InsertionSort(Node*q,int n){Node*first=q;Node*teq=q;Node*p=q->next;Node*point=p;int w,time=0,compar=0;while(p!=NULL){compar+=1;if(p->data<p->period->data){w=p->data;teq=p->period;while(teq!=NULL){compar+=1;if(teq->data>w){teq->next->data=teq->data;time+=1;if(teq->period==NULL){teq->data=w;time+=1;}}else{teq->next->data=w;time+=1;break;}teq=teq->period;}compar-=1;}p=p->next;}cout<<"插入排序后序列:";while(first!=NULL){cout<<first->data<<" ";first=first->next;}cout<<"\n插入排序比较次数为:"<<compar<<endl;cout<<"插入排序移动次数为:"<<time<<endl;}将链表分为有序区和无序区,分别将无序区的每一个元素插入到有序区的相应位置。

北邮数据结构实验--链表排序

北邮数据结构实验--链表排序链表排序数据结构实验报告1.实验要求实验目的:学习、实现、对比各种排序算法,掌握各种排序算法的优劣,以及各种算法使用的情况。

实验内容:使用链表实现下面各种排序算法,并进行比较。

排序算法:1、插入排序2、冒泡排序3、快速排序4、简单选择排序5、其他要求:1、测试数据分成三类:正序、逆序、随机数据2、对于这三类数据,比较上述排序算法中关键字的比较次数和移动次数(其中关键字交换计为3次移动)。

3、对于这三类数据,比较上述排序算法中不同算法的执行时间,精确到微秒(选作)4、对2和3的结果进行分析,验证上述各种算法的时间复杂度编写测试main()函数测试线性表的正确性2.程序分析2.1存储结构双循环链表:……..2.2关键算法分析1.1)插入排序:voidclit::inertort(){某=0;y=0;intm;node某p=front->ne某t->ne某t;while(p!=front){m=p->data;某++;//用于计比较次数的计数器if(m<p->prior->data){=p->prior;while(!=front&&->data>m){->ne某t->data=->data;=->prior;某++;y++;//用于计移动次数的计数器}->ne某t->data=m;y++;}p=p->ne 某t;}cout<<"插入排序的比较次数:"<<某<<""<<"移动次数"<<y<<endl;print();}2)冒泡排序:voidclit::bubbleort(){recover();某=0;y=0;intv;node某p=front->prior;while(p!=front){=p;//表示本次排序无序元素的范围p=front;r=front->ne某t;while(r!=){某++;if(r->data>r->ne某t->data)//相邻元素进行比较{v=r->data;//元素交换r->data=r->ne某t->data;r->ne某t->data=v;p=r;y+=3;}r=r->ne某t;}}cout<<"冒泡排序的比较次数:"<<某<<""<<"移动次数"<<y<<endl;print();}3)一趟快速排序:node某clit::partion(node某p,node某q){intpivot=p->data;//选取基准元素while(p!=q){while((p!=q)&&(q->data>=pivot))//右侧扫描,查找小于轴值的元素{(某m)++;q=q->prior;}p->data=q->data;(某n)++;while((p!=q)&&(p->data<=pivot))//左侧扫描,查找大于轴值的元素{(某m)++;p=p->ne某t;}q->data=p->data;(某n)++;}p->data=pivot;returnp;//返回轴值所在的位置}快速排序:voidclit::qort(node某p,node某q){recover();if(p!=q){node某pivotloc=partion(p,q);if(pivotloc!=p)qort(p,pivotloc->prior);if(pivotloc!=q)qort(pivotloc->ne某t,q);}}4)简单选择排序:voidclit::ort(){recover();某=0;y=0;while(p!=front->prior){=p;//假设所指元素是最小的r=->ne某t;while(r!=front)//查找最小值的位置{某++;if(r->data<->data)=r;r=r->ne某t;}if(!=p)//若第一个就是最小元素,则不用交换{intm=p->data;p->data=->data;->data=m;y+=3;}p=p->ne某t;}cout<<"简单选择排序的比较次数:"<<某<<""<<"移动次数"<<y<<endl;print();} 3程序运行结果各种排序算法的比较次数和移动次数满足它们时间复杂度的最好、最坏和平均情况,它们的性能如下:4.总结问题及解决:对于计算快速排序中的移动次数和比较次数,由于它是递归,所以要通过改变计数同时要保持下去,后来想到可以在函数参数中加两个整型的指针,通过地址传递,直接修改这两个指针所指元素的值,也实现了计移动次数和比较次数的目的。

北邮数据结构实验报告-排序

北邮数据结构实验报告-排序北邮数据结构实验报告-排序一、实验目的本实验旨在掌握常见的排序算法,包括冒泡排序、插入排序、选择排序、快速排序、归并排序等,并通过实际编程实现对数字序列的排序。

二、实验内容1.冒泡排序冒泡排序是一种简单的排序算法,其基本思想是依次比较相邻的两个元素,并按照从小到大或从大到小的顺序交换。

具体步骤如下:- 从待排序序列的第一个元素开始,依次比较相邻的两个元素;- 如果前面的元素大于后面的元素,则交换这两个元素的位置;- 重复上述步骤,直到整个序列有序。

2.插入排序插入排序是一种简单且直观的排序算法,其基本思想是将待排序序列分为已排序和未排序两部分,每次从未排序部分中选择一个元素插入到已排序部分的合适位置。

具体步骤如下:- 从待排序序列中选择一个元素作为已排序部分的第一个元素;- 依次将未排序部分的元素插入到已排序部分的合适位置,使得已排序部分保持有序;- 重复上述步骤,直到整个序列有序。

3.选择排序选择排序是一种简单且直观的排序算法,其基本思想是每次选择未排序部分中的最小(或最大)元素,并将其放在已排序部分的末尾。

具体步骤如下:- 在未排序部分中选择最小(或最大)的元素;- 将选择的最小(或最大)元素与未排序部分的第一个元素交换位置;- 重复上述步骤,直到整个序列有序。

4.快速排序快速排序是一种高效的排序算法,其基本思想是通过一趟排序将待排序序列分割成两部分,其中一部分的元素都比另一部分的元素小。

具体步骤如下:- 选择一个枢轴元素(一般选择第一个元素);- 将待排序序列中小于枢轴元素的元素放在枢轴元素的左侧,大于枢轴元素的元素放在枢轴元素的右侧;- 对枢轴元素左右两侧的子序列分别进行递归快速排序;- 重复上述步骤,直到整个序列有序。

5.归并排序归并排序是一种高效的排序算法,其基本思想是将待排序序列划分成足够小的子序列,然后对这些子序列进行两两合并,最终形成有序的序列。

具体步骤如下:- 将待排序序列递归地划分成足够小的子序列;- 对每个子序列进行归并排序;- 合并相邻的子序列,直到整个序列有序。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

数据结构实验报告实验名称:实验四——链表的排序学生姓名:班级:班内序号:学号:日期:1.实验要求[内容要求]使用链表实现下面各种排序算法,并进行比较。

排序算法:1、插入排序2、冒泡排序3、快速排序4、简单选择排序5、其他要求:1、测试数据分成三类:正序、逆序、随机数据2、对于这三类数据,比较上述排序算法中关键字的比较次数和移动次数(其中关键字交换计为3次移动)。

3、对于这三类数据,比较上述排序算法中不同算法的执行时间,精确到微秒(选作)4、对2和3的结果进行分析,验证上述各种算法的时间复杂度编写测试main()函数测试线性表的正确性代码要求1、必须要有异常处理,比如删除空链表时需要抛出异常;2、保持良好的编程的风格:代码段与段之间要有空行和缩近标识符名称应该与其代表的意义一致函数名之前应该添加注释说明该函数的功能关键代码应说明其功能3、递归程序注意调用的过程,防止栈溢出2. 程序分析2.1 存储结构[内容要求]存储结构:双链表2.2 关键算法分析[内容要求]定义类:template <class T>class LinkList{public:LinkList(){front = new Node <T>;front->next=rear;front->prior=NULL;rear=newNode<T>;rear->next=NULL;rear->prior=front;}LinkList(T a[],int n);void BackLinkList(T a[]);//恢复原链表~LinkList();//析构函数void PrintList();//打印数列void InsertSort();//插入排序void BubbleSort();//冒泡排序Node <T>* Partion(Node <T> *i,Node <T> *j);//快速排序中寻找轴值的函数void Qsort(Node <T> *i,Node <T> *j);//快速排序void SelectSort();//选择排序Node<T>*front;Node<T>*rear;};成员函数包括:构造函数:单链表,打印单链表,插入排序,快速排序,冒泡排序,选择排序,析构函数公有成员:头指针和尾指针1、构造函数:LinkList<T>::LinkList(T a[],int n){front=new Node<T>;rear=new Node<T>;front->prior=NULL;front->next=rear;rear->next=NULL;rear->prior=front;Node <T>*s;for (int i=n-1;i>=0;i--){s=new Node<T>;s->data=a[i];s->next=front->next;front->next=s;s->prior=front;s->next->prior=s;}}2、析构函数LinkList<T>::~LinkList(){Node<T> *p=front->next;while(p->next!=NULL){delete p->prior;p=p->next;}delete rear;front=NULL;rear=NULL;}3、打印函数template <class T>void LinkList<T>::PrintList(){Node<T> *p=front->next;while(p->next!=NULL){cout<<p->data<<" ";p=p->next;}cout<<endl;}4、插入排序template <class T>void LinkList<T>::InsertSort(){Node<T> *p=front->next->next;Node<T> *q;T temp;while (p->next!=NULL){if (p->data<p->prior->data){temp=p->data;MoveCount++;q=p->prior;while (temp<q->data){q->next->data=q->data;q=q->prior;CompareCount++;MoveCount++;}q->next->data=temp;MoveCount++;}CompareCount++;p=p->next;}}将链表分为有序区和无序区,分别将无序区的每一个元素插入到有序区的相应位置。

每次首先都找到无序区中最小的链节,然后摘除链表,在新的位置插入。

时间复杂度:O(n^n)空间复杂度:O(n)5、冒泡排序template <class T>void LinkList<T>::BubbleSort(){Node<T> *p;Node<T> *q;T temp;Node<T> *pos=rear->prior;Node<T> *bound;while (pos!=NULL){bound=pos;pos=NULL;q=front->next;p=front->next->next;while (q!=bound&&p->next!=NULL)//后半个条件很重要,处理一个元素和2个元素的情况{if (q->data>p->data){temp=p->data;p->data=temp;p->data=q->data;q->data=temp;pos=p->prior;MoveCount+=3;}CompareCount++;q=q->next;p=p->next;}}}和数组实现是一样的,一共进行n-1趟,每一趟当前面的数据大于后面的数据,进行交换,一趟可以实现将这一趟的最大的放在最后面。

时间复杂度:O(N^2)空间复杂度O(n)6、快速排序template <class T>Node <T>* LinkList<T>::Partion(Node <T> *i,Node <T> *j){T pivot=i->data;while (i!=j){while((i!=j)&&(j->data>=pivot)){j=j->prior;CompareCount++;}i->data=j->data;MoveCount++;while((i!=j)&&(i->data<=pivot)){i=i->next;CompareCount++;}j->data=i->data;MoveCount++;}i->data=pivot;MoveCount++;return i;}template <class T>void LinkList<T>::Qsort(Node <T> *i,Node <T> *j){if (i!=j&&i->prior!=j){Node <T>* pivotloc=Partion(i,j);Qsort(i,pivotloc->prior);Qsort(pivotloc->next,j);}}每一次将第一个作为轴值,交换一次使比他大的放在左面,比他小的放在右面。

接着递归将轴值左面的链表和右面的链表分别做相同操作直至只有一个链结为止。

时间复杂度:O(nlog n)空间复杂度:调用栈空间O(log2n)7、选择排序template <class T>void LinkList<T>::SelectSort(){Node<T> *p=front->next;Node<T> *q=p->next;Node<T> * index;T temp;while (p->next->next!=NULL){index=p;while (q->next!=NULL){if (q->data<index->data){index=q;}q=q->next;CompareCount++;}if (index!=p){temp=p->data;p->data=index->data;index->data=temp;MoveCount+=3;}p=p->next;q=p->next;}}每一轮都是找到最小的数第i趟交换,交换n趟。

是冒泡排序的优化了交换次数。

时间复杂度:O(n^2)空间复杂度:O(n)2.3 其他使用微秒级的计数器:调用<windows.h>库函数//计时的函数void Timer(mem_fun ptr,LinkList<int> &A,int a[],mem_fun2 ptr2=NULL,mem_fun3 ptr3=NULL){QueryPerformanceFrequency(&litmp);dfFreq = (double)litmp.QuadPart;// 获得计数器的时钟频率(QuadPart是8字节整形数)QueryPerformanceCounter(&litmp);QPart1 = litmp.QuadPart;// 获得初始值if (ptr2!=NULL)for (double i=0;i<10000;i++)(A.*ptr2)(a);else if(ptr3!=NULL)for (double i=0;i<10000;i++){A.BackLinkList(a);(A.*ptr3)(A.front->next,A.rear->prior);}elsefor (double i=0;i<10000;i++)//由于使用QueryPerformanceFrequency(&litmp)和QueryPerformanceCounter(&litmp)计时只精确到毫秒,因此循环10000次,忽略判断时间{A.BackLinkList(a);(A.*ptr)();}QueryPerformanceCounter(&litmp);QPart2 = litmp.QuadPart;//获得终止值dfMinus = (double)(QPart2-QPart1);dfTim=100*dfMinus/dfFreq-dfBackTim;// 获得对应的时间值,单位为微秒if(ptr2!=NULL)return;cout<<setiosflags(ios::left);cout<<"Compare:"<<setw(8)<<CompareCount/10000<<setw(8)<<"Move:"<<setw(8)<<MoveCount/10000<<setw(8)<<"Time:"<<setw(8)<<dfTim<<"us"<<endl;cout<<"排序结果:";A.PrintList();cout<<endl;MoveCount=0;CompareCount=0;}3. 程序运行结果4. 总结1.通过与数组排序比较,链表的排序所花时间更长,因为增加了指针的移动;2.递归调用的排序算法时间较长,因为涉及到函数调用进栈出栈的问题。

相关文档
最新文档