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

合集下载

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

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

数据结构实验报告实验名称:实验四——排序学生: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、插入排序2、冒泡排序3、快速排序4、简单选择排序5、其他一.程序分析1.存储结构:双向链表2.关键算法分析:a)插入排序:⒈从有序数列和无序数列{a2,a3,…,an}开始进行排序;⒉处理第i个元素时(i=2,3,…,n),数列{a1,a2,…,ai-1}是已有序的,而数列{ai,ai+1,…,an}是无序的。

用ai与ai-1,a i-2,…,a1进行比较,找出合适的位置将ai插入;⒊重复第二步,共进行n-i次插入处理,数列全部有序。

b)冒泡排序:1.比较相邻的元素。

如果第一个比第二个大,就交换他们两个。

2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。

在这一点,最后的元素应该会是最大的数。

3.针对所有的元素重复以上的步骤,除了最后一个。

4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

c)快速排序:一趟快速排序的算法是:1.设置两个变量i、j,排序开始的时候:i=0,j=N-1;2.以第一个数组元素作为关键数据,赋值给key,即key=A[0];3.从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]互换;4.从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;5.重复第3、4步,直到i=j;(3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。

找到符合条件的值,进行交换的时候i,j指针位置不变。

另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。

d)简单选择排序:设所排序序列的记录个数为n。

i取1,2,…,n-1,从所有n-i+1个记录(Ri,Ri+1,…,Rn)中找出排序码最小的记录,与第i个记录交换。

北邮数据结构实验报告

北邮数据结构实验报告

北邮数据结构实验报告北邮数据结构实验报告一、引言数据结构是计算机科学中的重要基础知识,对于计算机程序的设计和性能优化起着至关重要的作用。

本报告旨在总结北邮数据结构实验的相关内容,包括实验目的、实验设计、实验过程和实验结果等。

二、实验目的本次实验旨在通过实践操作,加深对数据结构的理解和应用能力。

具体目的如下:1. 掌握线性表、栈和队列等基本数据结构的实现方法;2. 熟悉二叉树、图等非线性数据结构的构建和遍历算法;3. 学会使用递归和非递归算法解决实际问题;4. 培养编程实践能力和团队合作意识。

三、实验设计本次实验包括以下几个部分:1. 线性表实验:设计一个线性表类,实现线性表的基本操作,如插入、删除和查找等。

通过实验,了解线性表的顺序存储和链式存储结构的特点和应用场景。

2. 栈和队列实验:设计栈和队列类,实现栈和队列的基本操作,如入栈、出栈、入队和出队等。

通过实验,掌握栈和队列的应用,如括号匹配、迷宫求解等。

3. 二叉树实验:设计二叉树类,实现二叉树的创建、遍历和查找等操作。

通过实验,熟悉二叉树的前序、中序和后序遍历算法,并了解二叉树的应用,如表达式求值等。

4. 图实验:设计图类,实现图的创建、遍历和最短路径等操作。

通过实验,掌握图的邻接矩阵和邻接表表示方法,并了解图的深度优先搜索和广度优先搜索算法。

四、实验过程1. 线性表实验:根据实验要求,首先选择线性表的存储结构,然后设计线性表类,实现插入、删除和查找等基本操作。

在实验过程中,遇到了一些问题,如边界条件的处理和内存管理等,通过团队合作,最终解决了这些问题。

2. 栈和队列实验:根据实验要求,设计栈和队列类,实现入栈、出栈、入队和出队等基本操作。

在实验过程中,我们发现了栈和队列在实际应用中的重要性,如括号匹配和迷宫求解等,通过实验加深了对栈和队列的理解。

3. 二叉树实验:根据实验要求,设计二叉树类,实现二叉树的创建、遍历和查找等操作。

在实验过程中,我们发现了二叉树在表达式求值和排序等方面的应用,通过实验加深了对二叉树的理解。

链表基数排序

链表基数排序

链表基数排序链表是一种常用的数据结构,可以用来存储和操作数据。

而基数排序是一种排序算法,通过将数据按照位数进行排序,从而达到排序的目的。

本文将介绍链表基数排序的原理和实现过程。

一、基数排序简介基数排序是一种非比较型的排序算法,其基本思想是将待排序的数据按照权重进行分组,依次对每一位进行排序,直到所有的位都排序完成。

基数排序的时间复杂度为O(d*(n+r)),其中d是数字的位数,n是数据的个数,r是基数的大小。

链表基数排序是基于链表的数据结构进行排序的一种方法。

其主要思想是通过将待排序的数据放入链表中,然后按照权重进行分组,并依次对每一位进行排序,直到所有的位都排序完成。

具体的实现过程如下:1. 创建一个链表数组,用于存储待排序的数据。

数组的大小等于基数的大小。

2. 将待排序的数据按照个位数的大小,放入对应的链表中。

3. 依次取出链表中的数据,按照十位数的大小,放入对应的链表中。

4. 依次重复上述步骤,直到所有的位都排序完成。

5. 最后将链表中的数据按照顺序取出,即可得到排序后的结果。

三、链表基数排序的实现下面以一个示例来说明链表基数排序的实现过程。

假设有以下一组数据:85,65,45,95,35,75,551. 创建一个链表数组,大小为10,用于存储待排序的数据。

2. 将待排序的数据按照个位数的大小,放入对应的链表中,得到如下结果:链表0:无数据链表1:无数据链表2:无数据链表3:35链表4:45链表5:55,65,75,85,95链表6:无数据链表7:无数据链表8:无数据链表9:无数据3. 依次取出链表中的数据,按照十位数的大小,放入对应的链表中,得到如下结果:链表0:无数据链表1:无数据链表2:35,45,55链表3:无数据链表4:65,75链表5:85,95链表6:无数据链表7:无数据链表8:无数据链表9:无数据4. 依次重复上述步骤,直到所有的位都排序完成。

这里只需进行一次操作,即按照百位数的大小进行排序,得到最终的结果:链表0:35,45,55,65,75,85,95链表1:无数据链表2:无数据链表3:无数据链表4:无数据链表5:无数据链表6:无数据链表7:无数据链表8:无数据链表9:无数据最终的排序结果为:35,45,55,65,75,85,95四、总结链表基数排序是一种通过链表数据结构实现的排序算法,其主要思想是将待排序的数据按照位数进行分组,并依次对每一位进行排序,直到所有的位都排序完成。

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

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

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

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

排序算法如下: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、测试条件:按题目要求分别输入同组数据的正序、逆序、随机序列进行测试。

北邮数据结构实验题目

北邮数据结构实验题目

实验一线性表1 实验目的通过选择下面四个题目之一进行实现,掌握如下内容:熟悉C++语言的基本编程方法,掌握集成编译环境的调试方法学习指针、模板类、异常处理的使用掌握线性表的操作的实现方法学习使用线性表解决实际问题的能力2 实验内容2.1题目1根据线性表的抽象数据类型的定义,选择下面任一种链式结构实现线性表,并完成线性表的基本功能。

线性表存储结构(五选一):1、带头结点的单链表2、不带头结点的单链表3、循环链表4、双链表5、静态链表线性表的基本功能:1、构造:使用头插法、尾插法两种方法2、插入:要求建立的链表按照关键字从小到大有序3、删除4、查找5、获取链表长度6、销毁7、其他:可自行定义编写测试main()函数测试线性表的正确性。

2.2题目2利用线性表实现一个通讯录管理,通信录的数据格式如下:struct DataType{int ID; //编号char name[10]; //姓名char ch; //性别char phone[13]; //电话char addr[31]; //地址};要求:实现通讯录的建立、增加、删除、修改、查询等功能能够实现简单的菜单交互,即可以根据用户输入的命令,选择不同的操作。

能够保存每次更新的数据(选作)能够进行通讯录分类,比如班级类、好友类、黑名单等等(选作)编写测试main()函数测试线性表的正确性2.3题目3利用线性表实现一个一元多项式Polynomialf(x) = a+ a1x + a2x2 + a3x3+ … + a n x n提示:Polynomial的结点结构如下:struct term{float coef; //系数int expn; //指数};可以使用链表实现,也可以使用顺序表实现。

要求:能够实现一元多项式的输入和输出能够进行一元多项式相加能够进行一元多项式相减能够计算一元多项式在x处的值能够计算一元多项式的导数(选作)能够进行一元多项式相乘(选作)编写测试main()函数测试线性表的正确性2.4题目4利用循环链表实现约瑟夫问题的求解。

链表排序算法总结

链表排序算法总结

这个星期做数据结构课设,涉及到两个基于链表的排序算法,分别是基于链表的选择排序算法和归并排序算法。

写出来跟大家一起分享一下,希望对数据结构初学朋友有所帮助,高手就直接忽视它吧。

话不多说,下面就看代码吧。

[c-sharp]view plaincopy1.node *sorted(node *sub_root)2.{3.if (sub_root->next)4. {5. node * second_half = NULL;6. node * first_half = sub_root;7. node * temp = sub_root->next->next;8.while (temp)9. {10. first_half = first_half->next;11. temp = temp->next;12.if(temp)13. temp = temp->next;14. }15. second_half = first_half->next;16. first_half->next = NULL;17. node * lChild = sorted(sub_root);18. node * rChild = sorted(second_half);19.if (lChild->data < rChild->data)20. {21. sub_root = temp = lChild;22. lChild = lChild->next;23. }24.else25. {26. sub_root = temp = rChild;27. rChild = rChild->next;28. }29.while (lChild&&rChild)30. {31.if (lChild->data < rChild->data )32. {33. temp->next = lChild;34. temp = temp->next;35. lChild = lChild->next;36. }37.else38. {39. temp->next = rChild;40. temp = temp->next;41. rChild = rChild->next;42. }43. }44.if (lChild)45. temp->next = lChild;46.else47. temp->next = rChild;48. }49.return sub_root;50.51.}上面贴出来的就是归并排序的算法,刚开始写的时候,由于考虑不够周到,出现许多错误,经过调式之后,才能运行成功。

链表的排序---链表插入排序

链表的排序---链表插入排序

链表的排序---链表插⼊排序链表的插⼊排序Insertion Sort List1)基本思想:在要排序的⼀组数中,假设前⾯(n-1)[n>=2] 个数已经是排好顺序的,现在要把第n个数插到前⾯的有序数中,使得这n个数也是排好顺序的。

⽽对有链表,没有办法随机读取。

所以插⼊排序,对每⼀个节点来说,只能从头节点开始,慢慢的向后开始⽐较,如果找到位置则将节点插⼊序列中。

代码如下,leetcode accept./*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/class Solution {public:ListNode* insertionSortList(ListNode* head) {if(head ==NULL|| head->next ==NULL)return head;ListNode * dummy = new ListNode(-1);dummy->next = head;ListNode * pre = head ;ListNode * cur = head->next ; // 从第⼆个节点开始while(cur){if(pre->val > cur->val) // 这⾥假设从头节点到 pre 节点之间是排好序的{ListNode *tmp = dummy;while(tmp->next->val<cur->val)tmp= tmp->next;pre->next = cur->next; // 将pre 与cur 后⾯的节点连接cur->next = tmp->next; // cur 插⼊适当的位置tmp->next = cur;}elsepre = pre->next ;cur = pre->next;}return dummy->next;}};。

  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.递归调用的排序算法时间较长,因为涉及到函数调用进栈出栈的问题。

相关文档
最新文档