数据结构第三次实验+第二题链表排序

合集下载

数据结构排序实验报告

数据结构排序实验报告

数据结构排序实验报告数据结构排序实验报告引言:数据结构是计算机科学中的重要概念之一,它涉及到数据的组织、存储和操作方式。

排序是数据结构中的基本操作之一,它可以将一组无序的数据按照特定的规则进行排列,从而方便后续的查找和处理。

本实验旨在通过对不同排序算法的实验比较,探讨它们的性能差异和适用场景。

一、实验目的本实验的主要目的是通过实际操作,深入理解不同排序算法的原理和实现方式,并通过对比它们的性能差异,选取合适的排序算法用于不同场景中。

二、实验环境和工具实验环境:Windows 10 操作系统开发工具:Visual Studio 2019编程语言:C++三、实验过程1. 实验准备在开始实验之前,我们需要先准备一组待排序的数据。

为了保证实验的公正性,我们选择了一组包含10000个随机整数的数据集。

这些数据将被用于对比各种排序算法的性能。

2. 实验步骤我们选择了常见的五种排序算法进行实验比较,分别是冒泡排序、选择排序、插入排序、快速排序和归并排序。

- 冒泡排序:该算法通过不断比较相邻元素的大小,将较大的元素逐渐“冒泡”到数组的末尾。

实现时,我们使用了双重循环来遍历整个数组,并通过交换元素的方式进行排序。

- 选择排序:该算法通过不断选择数组中的最小元素,并将其放置在已排序部分的末尾。

实现时,我们使用了双重循环来遍历整个数组,并通过交换元素的方式进行排序。

- 插入排序:该算法将数组分为已排序和未排序两部分,然后逐个将未排序部分的元素插入到已排序部分的合适位置。

实现时,我们使用了循环和条件判断来找到插入位置,并通过移动元素的方式进行排序。

- 快速排序:该算法通过选取一个基准元素,将数组分为两个子数组,并对子数组进行递归排序。

实现时,我们使用了递归和分治的思想,将数组不断划分为更小的子数组进行排序。

- 归并排序:该算法通过将数组递归地划分为更小的子数组,并将子数组进行合并排序。

实现时,我们使用了递归和分治的思想,将数组不断划分为更小的子数组进行排序,然后再将子数组合并起来。

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

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

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

以下排序算法的正确性都可以在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,我们选取第⼀个节点作为枢纽元,然后把⼩于枢纽的节点放到⼀个链中,把不⼩于枢纽的及节点放到另⼀个链中,最后把两条链以及枢纽连接成⼀条链。

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

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

数据结构实验报告实验名称:________链表排序___________ 学生姓名:_____________________班级:________________班内序号:_________________________ 学号:________________日期:_______________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、实验目的∙熟练掌握线性表的链式存储结构定义及基本操作∙理解循环链表和双链表的特点和基本运算2、实验内容:建立单链表,完成链表(带表头结点)的基本操作:建立链表、插入、删除、查找、输出、求前驱、求后继、两个有序链表的合并操作。

其他基本操作还有销毁链表、将链表置为空表、求链表的长度、获取某位置结点的内容、搜索结点。

1.问题描述:利用线性表的链式存储结构,设计一组输入数据(假定为一组整数),能够对单链表进行如下操作:∙初始化一个带表头结点的空链表;∙创建一个单链表是从无到有地建立起一个链表,即一个一个地输入各结点数据,并建立起前后相互链接的关系。

又分为逆位序(插在表头)输入n 个元素的值和正位序(插在表尾)输入n 个元素的值;∙插入结点可以根据给定位置进行插入(位置插入),也可以根据结点的值插入到已知的链表中(值插入),且保持结点的数据按原来的递增次序排列,形成有序链表。

∙删除结点可以根据给定位置进行删除(位置删除),也可以把链表中查找结点的值为搜索对象的结点全部删除(值删除);∙输出单链表的内容是将链表中各结点的数据依次显示,直到链表尾结点;∙求前驱结点是根据给定结点的值,在单链表中搜索其当前结点的后继结点值为给定的值,将当前结点返回;∙求后继结点是根据给定结点的值,在单链表中搜索其当前结点的值为给定的值,将后继结点返回;∙两个有序链表的合并是分别将两个单链表的结点依次插入到第3 个单链表中,继续保持结点有序;编写主程序,实现对各不同的算法调用。

其它的操作算法描述略。

2.实现要求:对链表的各项操作一定要编写成为C(C++)语言函数,组合成模块化的形式,还要针对每个算法的实现从时间复杂度和空间复杂度上进行评价。

∙“初始化算法”的操作结果:构造一个空的线性表L,产生头结点,并使L 指向此头结点;∙“建立链表算法”初始条件:空链存在;操作结果:选择逆位序或正位序的方法,建立一个单链表,并且返回完成的结果;∙“链表(位置)插入算法”初始条件:已知单链表L 存在;操作结果:在带头结点的单链线性表L 中第i 个位置之前插入元素e;∙“链表(位置)删除算法”初始条件:已知单链表L 存在;操作结果:在带头结点的单链线性表L 中,删除第i 个元素,并由e 返回其值;∙“输出算法”初始条件:链表L 已存在;操作结果:依次输出链表的各个结点的值;∙“求前驱算法”初始条件: 线性表L 已存在;操作结果: 若cur_e 是L 的数据元素,且不是第一个,则用pre_e 返回它的前驱;∙“求后继算法”初始条件: 线性表L 已存在;操作结果: 若cur_e 是L 的数据元素,且不是最后一个,则用next_e 返回它的后继;∙“两个有序链表的合并算法”初始条件: 线性表单链线性表La 和Lb 的元素按值非递减排列;操作结果:归并La 和Lb 得到新的单链表。

数据结构实验三——二叉树基本操作及运算实验报告

数据结构实验三——二叉树基本操作及运算实验报告

《数据结构与数据库》实验报告实验题目二叉树的基本操作及运算一、需要分析问题描述:实现二叉树(包括二叉排序树)的建立,并实现先序、中序、后序和按层次遍历,计算叶子结点数、树的深度、树的宽度,求树的非空子孙结点个数、度为2的结点数目、度为2的结点数目,以及二叉树常用运算。

问题分析:二叉树树型结构是一类重要的非线性数据结构,对它的熟练掌握是学习数据结构的基本要求。

由于二叉树的定义本身就是一种递归定义,所以二叉树的一些基本操作也可采用递归调用的方法。

处理本问题,我觉得应该:1、建立二叉树;2、通过递归方法来遍历(先序、中序和后序)二叉树;3、通过队列应用来实现对二叉树的层次遍历;4、借用递归方法对二叉树进行一些基本操作,如:求叶子数、树的深度宽度等;5、运用广义表对二叉树进行广义表形式的打印。

算法规定:输入形式:为了方便操作,规定二叉树的元素类型都为字符型,允许各种字符类型的输入,没有元素的结点以空格输入表示,并且本实验是以先序顺序输入的。

输出形式:通过先序、中序和后序遍历的方法对树的各字符型元素进行遍历打印,再以广义表形式进行打印。

对二叉树的一些运算结果以整型输出。

程序功能:实现对二叉树的先序、中序和后序遍历,层次遍历。

计算叶子结点数、树的深度、树的宽度,求树的非空子孙结点个数、度为2的结点数目、度为2的结点数目。

对二叉树的某个元素进行查找,对二叉树的某个结点进行删除。

测试数据:输入一:ABC□□DE□G□□F□□□(以□表示空格),查找5,删除E预测结果:先序遍历ABCDEGF中序遍历CBEGDFA后序遍历CGEFDBA层次遍历ABCDEFG广义表打印A(B(C,D(E(,G),F)))叶子数3 深度5 宽度2 非空子孙数6 度为2的数目2 度为1的数目2查找5,成功,查找的元素为E删除E后,以广义表形式打印A(B(C,D(,F)))输入二:ABD□□EH□□□CF□G□□□(以□表示空格),查找10,删除B预测结果:先序遍历ABDEHCFG中序遍历DBHEAGFC后序遍历DHEBGFCA层次遍历ABCDEFHG广义表打印A(B(D,E(H)),C(F(,G)))叶子数3 深度4 宽度3 非空子孙数7 度为2的数目2 度为1的数目3查找10,失败。

数据结构实验报告排序

数据结构实验报告排序

数据结构实验报告排序数据结构实验报告:排序引言:排序是计算机科学中常见的算法问题之一,它的目标是将一组无序的数据按照特定的规则进行排列,以便于后续的查找、统计和分析。

在本次实验中,我们将学习和实现几种常见的排序算法,并对它们的性能进行比较和分析。

一、冒泡排序冒泡排序是最简单的排序算法之一,它通过不断交换相邻的元素,将较大(或较小)的元素逐渐“冒泡”到数组的一端。

具体实现时,我们可以使用两层循环来比较和交换元素,直到整个数组有序。

二、插入排序插入排序的思想是将数组分为两个部分:已排序部分和未排序部分。

每次从未排序部分中取出一个元素,插入到已排序部分的适当位置,以保持已排序部分的有序性。

插入排序的实现可以使用一层循环和适当的元素交换。

三、选择排序选择排序每次从未排序部分中选择最小(或最大)的元素,与未排序部分的第一个元素进行交换。

通过不断选择最小(或最大)的元素,将其放置到已排序部分的末尾,从而逐渐形成有序序列。

四、快速排序快速排序是一种分治的排序算法,它通过选择一个基准元素,将数组划分为两个子数组,其中一个子数组的所有元素都小于等于基准元素,另一个子数组的所有元素都大于基准元素。

然后对两个子数组分别递归地进行快速排序,最终将整个数组排序。

五、归并排序归并排序也是一种分治的排序算法,它将数组划分为多个子数组,对每个子数组进行排序,然后再将排好序的子数组合并成一个有序的数组。

归并排序的实现可以使用递归或迭代的方式。

六、性能比较与分析在本次实验中,我们对以上几种排序算法进行了实现,并通过对不同规模的随机数组进行排序,比较了它们的性能。

我们使用了计算排序时间的方式,并记录了每种算法在不同规模下的运行时间。

通过对比实验结果,我们可以得出以下结论:1. 冒泡排序和插入排序在处理小规模数据时表现较好,但在处理大规模数据时性能较差,因为它们的时间复杂度为O(n^2)。

2. 选择排序的时间复杂度也为O(n^2),与冒泡排序和插入排序相似,但相对而言,选择排序的性能稍好一些。

c++数据结构实验链表排序

c++数据结构实验链表排序

1.实验要求i.实验目的:通过编程,学习、实现、对比各种排序算法,掌握各种排序算法的优劣,以及各种算法使用的情况。

理解算法的主要思想及流程。

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

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

3、对于这三类数据,比较上述排序算法中不同算法的执行时间,精确到微秒(选作)4、对2与3的结果进行分析,验证上述各种算法的时间复杂度编写测试main()函数测试线性表的正确性iii.代码要求:1、必须要有异常处理,比如删除空链表时需要抛出异常;2、保持良好的编程的风格:代码段与段之间要有空行与缩近标识符名称应该与其代表的意义一致函数名之前应该添加注释说明该函数的功能关键代码应说明其功能3、递归程序注意调用的过程,防止栈溢出2、程序分析通过排序算法将单链表中的数据进行由小至大(正向排序)2、1 存储结构单链表存储数据:struct node{ ……int data;node*next;};单链表定义如下:class LinkList{private:node * front;public:LinkList(int a[], int n); //构造~LinkList();void insert(node*p, node*s); //插入void turn(node*p, node*s); //交换数据void print(); //输出void InsertSort(); //插入排序void BubbleSort(); //pos冒泡void QSort(); //快速排序void SelectSort(); //简单选择排序node* Get(int i); //查找位置为i的结点void sift(int k, int m); //一趟堆排序void LinkList::QSZ(node * b, node *e); //快速排序的递归主体void heapsort(int n); //堆排序算法};2.2关键算法分析:1、直接插入排序:首先将待排序数据建立一个带头结点的单链表。

数据结构实验报告之链表顺序表的操作

数据结构实验报告之链表顺序表的操作

数据结构实验报告之链表顺序表的操作1、编写程序实现顺序表的各种基本运算:初始化、插⼊、删除、取表元素、求表长、输出表、销毁、判断是否为空表、查找元素。

在此基础上设计⼀个主程序完成如下功能:(1)初始化顺序表L;(2)依次在表尾插⼊a,b,c,d,e五个元素;(3)输出顺序表L;(4)输出顺序表L的长度;(5)判断顺序表L是否为空;(6)输出顺序表L的第4个元素;(7)输出元素c的位置;(8)在第3个位置上插⼊元素f,之后输出顺序表L;(9)删除L的第2个元素,之后输出顺序表L;(10)销毁顺序表L。

2、编写程序实现单链表的各种基本运算:初始化、插⼊、删除、取表元素、求表长、输出表、销毁、判断是否为空表、查找元素。

在此基础上设计⼀个主程序完成如下功能:(1)初始化单链表L;(2)依次在表尾插⼊a,b,c,d,e五个元素;(3)输出单链表L;(4)输出单链表L的长度;(5)判断单链表L是否为空;(6)输出单链表L的第4个元素;(7)输出元素c的位置;(8)在第3个位置上插⼊元素f,之后输出单链表L;(9)删除L的第2个元素,之后输出单链表L;(10)销毁单链表L。

1顺序表2 #include<stdio.h>3 #include<malloc.h>4 #include<stdlib.h>56#define TRUE 17#define FALSE 08#define OK 19#define ERROR 010#define INFEASIBLE -111#define OVERFLOW -212 typedef int Status;13 typedef char ElemType;1415#define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量16#define LISTINCREMENT 10 //线性表存储空间的分配增量17 typedef struct {18 ElemType *elem; //存储空间基地址19int length; //当前长度20int listsize; //当前分配的存储容量21 } SqList;2223 Status InitList_Sq(SqList &L) { //算法2.324 L.elem = (ElemType *)malloc(LIST_INIT_SIZE * sizeof(ElemType));25if (!L.elem) exit(OVERFLOW); //存储分配失败26 L.length = 0; //空表长度为027 L.listsize = LIST_INIT_SIZE; //初始存储容量28return OK;29 }//InitList_Sq3031 Status ListInsert_Sq(SqList &L, int i, ElemType e) { //算法2.432 ElemType *newbase, *p, *q;33if (i<1 || i>L.length + 1) return ERROR; //i值不合法34if (L.length >= L.listsize)35 { //当前存储空间已满,增加分配36 newbase = (ElemType*)realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(ElemType));37if (!newbase) exit(OVERFLOW); //存储分配失败38 L.elem = newbase; //新基址39 L.listsize += LISTINCREMENT; //增加存储容量40 }41 q = &(L.elem[i - 1]); //q为插⼊位置42for (p = &(L.elem[L.length - 1]); p >= q; --p) *(p + 1) = *p; //元素右移43 *q = e; //插⼊e44 ++L.length; //表长增145return OK;46 }4748void DispSqList(SqList L)49 {50int i;51for (i = 0; i < L.length; i++)52 printf("%c ", L.elem[i]);53 }5455 Status ListDelete(SqList &L, int i, ElemType &e)56 {57 ElemType *p,*q;58if ((i < 1) || (i > L.length)) return ERROR;59 p = &(L.elem[i - 1]);60 e = *p;61 q = L.elem + L.length - 1;62for (++p; p <= q; ++p)63 *(p - 1) = *p;64 --L.length;65return OK;66 } //ListDelete_Sq6768 Status GetElem(SqList L, int i, ElemType &e)69 {70if (L.length == 0 || i<1 || i>L.length)71return ERROR;72 e = L.elem[i - 1];73return OK;74 }7576int ListLength(SqList L)77 {78return(L.length);79 }8081 Status DestroyList(SqList &L)82 {83 free(L.elem);84 L.length = 0;85return OK;86 }8788 Status ListEmpty(SqList L)89 {90return(L.length == 0);91 }9293int LocateElem(SqList L, ElemType e)94 {95int i = 0;96while (i < L.length && L.elem[i] != e) i++;97if (i >= L.length) return0;98else return i + 1;99 }100101void main()102 {103 SqList h;104 ElemType e;105 InitList_Sq(h);106 ListInsert_Sq(h, h.length + 1, 'a');107 ListInsert_Sq(h, h.length + 1, 'b');108 ListInsert_Sq(h, h.length + 1, 'c');109 ListInsert_Sq(h, h.length + 1, 'd');110 ListInsert_Sq(h, h.length + 1, 'e');111 DispSqList(h);112 printf("%d\n\n",ListLength(h));113 ListEmpty(h);114if (ListEmpty(h))116 printf("Empty\n\n");117 }118else119 {120 printf("Not empty\n\n");121 }122 GetElem(h, 4, e);123 printf("%c\n", e);124 printf("%d\n",LocateElem(h, 'c'));125 ListInsert_Sq(h,3,' f');126 DispSqList(h);127 ListDelete(h, 2, e);128 DispSqList(h);129 DestroyList(h);130 }131132133134135136单链表137138139140 #include<stdio.h>141 #include<malloc.h>142 #include<stdlib.h>143144#define TRUE 1145#define FALSE 0146#define OK 1147#define ERROR 0148#define INFEASIBLE -1149#define OVERFLOW -2150 typedef int Status;151152 typedef char ElemType;153154155 typedef struct LNode {156 ElemType data;157int length;158struct LNode *next;159 }LNode, *LinkList;160161162 Status InitList_L(LinkList &L) {163 L = (LinkList)malloc(sizeof(LNode));164 L->next = NULL;165return OK;166 }167168 Status ListInsert_L(LinkList L, int i, ElemType e) { 169 LinkList p = L,s;170int j = 0;171while (p && j < i - 1)172 {173 p = p->next;174 ++j;175 }176if (!p || j > i - 1)177 {178return ERROR;179 }180else181 {182 s = (LinkList)malloc(sizeof(LNode));183 s->data = e;184 s->next = p->next;185 p->next = s;186return OK;187 }188 }189190void DispList_L(LinkList L)191 {192 LinkList p = L->next;193while (p != NULL)194 {195 printf("%c\n", p->data);196 p = p->next;197 }198200201void DestoryList(LinkList &L)202 {203 LinkList p = L, q = p->next;204while (q != NULL)205 {206 free(p);207 p = q;208 q = p->next;209 }210 free(p);211 }212213 Status ListLength_L(LinkList L) {214 LinkList p = L; int n = 0;215while (p->next != NULL)216 {217 n++;218 p = p->next;219 }220return (n);221 }222223 Status ListDelete(LinkList L, int i, ElemType &e){ 224int j;225 LinkList p, q;226 p = L;227 j = 1;228while (p->next && j < i)229 {230 p = p->next;231 ++j;232 }233if (!(p->next) || j > i)234 {235return ERROR;236 }237 q = p->next;238 p->next = q->next;239 e = q->data;240 free(q);241return OK;242 }243244 Status ListEmpty_L(LinkList L)245 {246return(L->length == 0);247 }248249 Status GetElem(LinkList L, int i, ElemType &e) 250 {251int j;252 LinkList p;253 p = L->next;254 j = 1;255while (p&&j<i)256 {257 p = p->next;258 ++j;259 }260if (!p || j > i)261 {262return ERROR;263 }264 e = p->data;265return OK;266 }267268 Status LocateElem(LinkList L, int e)269 {270 LinkList p = L;271int n=0;272//p->length = 0;273while (p != NULL)274 {275if(p->data != e)276 {277 p = p->next;278 n++;279 }280else281 {282break;283 }284 }285if(p != NULL)286 {287return n;288 }289else290 {291return ERROR;292 }293 }294295void main()296 {297 LinkList h;298 ElemType e;299 InitList_L(h);300 ListInsert_L(h, 1, 'a');301 ListInsert_L(h, 2, 'b');302 ListInsert_L(h, 3, 'c');303 ListInsert_L(h, 4, 'd');304 ListInsert_L(h, 5, 'e');305 DispList_L(h);306 printf("%d\n", ListLength_L(h)); 307if (ListEmpty_L(h))308 {309 printf("Empty\n\n");310 }311else312 {313 printf("Not empty\n\n");314 }315 GetElem(h, 4, e);316 printf("%c\n", e);317 printf("%d\n", LocateElem(h, 'c')); 318 ListInsert_L(h, 3, 'f');319 DispList_L(h);320 ListDelete(h, 2, e);321 DispList_L(h);322 DestoryList(h);323 }。

链表基数排序

链表基数排序

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

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

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

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

基数排序的时间复杂度为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四、总结链表基数排序是一种通过链表数据结构实现的排序算法,其主要思想是将待排序的数据按照位数进行分组,并依次对每一位进行排序,直到所有的位都排序完成。

数据结构链表的基本操作(附答案)

数据结构链表的基本操作(附答案)
typedef struct Polynode
{int coef;
int exp;
struct Polynode *next;
}Polynode,*Polylist;
Polylist PolyCreate()
{Polynode *head;
Polynode *rear, *s;
int c,e;
head=(Polynode*)malloc(sizeof(Polynode));
{
Polynode *p, *q, *pre, *temp;
int sum;
p=polya->next; /*令p和q分别指向polya和polyb多项式链表中的第一个结点*/
scanf("%d,%d",&c,&e);
}
rear->next=NULL;/*将表的最后一个结点的next置NULL,以示表结束*/
return head;}
Polylist PolyAdd(Polylist polya, Polylist polyb)
/*此函数用于将两个多项式相加,然后将和多项式存放在多项式polya中,并将多项式ployb删除*/
q=q->next; //___________________;
free(temp);
}
else
{
temp=p;
p=p->next;
free(temp);
/*若系数和为零,则删除结点p与q,并将指针指向下一个结点*/
temp=q;
q=q->next; //___________________________
else if(head->exp==0)

(链表)链表的排序问题

(链表)链表的排序问题

(链表)链表的排序问题题⽬⼀:对链表进⾏排序。

⽅法⼀:利⽤数组进⾏排序。

效率⽐较低。

代码/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/class Solution {public:ListNode *sortList(ListNode *head) {vector<int> res;ListNode *temp = head;int length = 0;while (temp){res.push_back(temp->val);temp = temp->next, length++;}sort(res.begin(), res.end());temp = head;int i =0;while (temp && i<length){temp->val = res[i];temp = temp->next;i++;}return head;}}; ⽅法⼆:对链表进⾏插⼊排序 分析:这⾥其实和插⼊排序数组类似,但是数组是在原数组的基础上⾯进⾏插⼊排序的,但是对于链表来说⽐较复杂,所以新建链表进⾏插⼊排序。

插⼊排序顾名思义就是⼀个⼀个的将数字插⼊进⾏,插⼊的过程中与链表的所有数字进⾏⽐较,找到合适的位置进⾏插⼊,所以我们设置两个指针,pre指向新链表的头部,cur指向当前链表的当前节点,之后⽐较两个指针的值,依次插⼊即可 代码:/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/class Solution {public:ListNode *sortList(ListNode *head) {if(head == NULL || head->next == NULL) return head;ListNode* dummyhead = new ListNode(0);ListNode* pre = dummyhead;ListNode* cur = head;while(cur != NULL){ListNode* next = cur->next; //维护链表的下⼀个结点pre = dummyhead; //重置pre为新链表头开始//在当前排好的新链表中找到第⼀个⼤于cur->val的结点while(pre->next != NULL && pre->next->val <= cur->val){pre = pre->next;}//当前pre的next结点的值⼤于cur的值,将cur插⼊到pre后cur->next = pre->next;pre->next = cur;cur = next; //cur指向原链表的下⼀个节点}return dummyhead->next;}};。

c数据结构实验链表排序

c数据结构实验链表排序

1.实验要求i.实验目的:通过编程,学习、实现、对比各种排序算法,掌握各种排序算法的优劣,以及各种算法使用的情况。

理解算法的主要思想及流程。

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

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

3、对于这三类数据,比较上述排序算法中不同算法的执行时间,精确到微秒(选作)4、对2和3的结果进行分析,验证上述各种算法的时间复杂度编写测试main()函数测试线性表的正确性iii.代码要求:1、必须要有异常处理,比如删除空链表时需要抛出异常;2、保持良好的编程的风格:代码段与段之间要有空行和缩近标识符名称应该与其代表的意义一致函数名之前应该添加注释说明该函数的功能关键代码应说明其功能3、递归程序注意调用的过程,防止栈溢出2. 程序分析通过排序算法将单链表中的数据进行由小至大(正向排序)2.1 存储结构单链表存储数据:struct node……{int data;node*next;};单链表定义如下:class LinkList{private:node * front;public:LinkList(int a[], int n); //构造~LinkList();void insert(node*p, node*s); //插入void turn(node*p, node*s); //交换数据void print(); //输出void InsertSort(); //插入排序void BubbleSort(); //pos冒泡void QSort(); //快速排序void SelectSort(); //简单选择排序node* Get(int i); //查找位置为i的结点void sift(int k, int m); //一趟堆排序void LinkList::QSZ(node * b, node *e); //快速排序的递归主体void heapsort(int n); //堆排序算法};2.2关键算法分析:1.直接插入排序:首先将待排序数据建立一个带头结点的单链表。

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

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

北邮数据结构实验--链表排序链表排序数据结构实验报告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.总结问题及解决:对于计算快速排序中的移动次数和比较次数,由于它是递归,所以要通过改变计数同时要保持下去,后来想到可以在函数参数中加两个整型的指针,通过地址传递,直接修改这两个指针所指元素的值,也实现了计移动次数和比较次数的目的。

排序算法---链表排序

排序算法---链表排序

排序算法---链表排序前⾔ 链表排序思想和数组排序类似,区别就是数组遍历容易,数据交换也容易;链表(单项链表)只能⼀个⽅向遍历,不能逆序遍历(也可以先反转在遍历),且不能随机访问,所以排序⽐较⿇烦,同时链表的数据交换也很⿇烦,如果交换两个节点,需要共涉及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 }。

链表排序——精选推荐

链表排序——精选推荐

链表排序以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)函数将三个链表拼接起来。

链表排序--SortList

链表排序--SortList

链表排序--SortListSort ListSort a linked list in O(n log n) time using constant space complexity.题⽬:链表的排序。

要求:时间复杂度O(nlogn),空间复杂度O(1)。

解题思路:由于题⽬对时间复杂度和空间复杂度要求⽐较⾼,所以查看了各种解法,最好的解法就是归并排序,由于链表在归并操作时并不需要像数组的归并操作那样分配⼀个临时数组空间,所以这样就是常数空间复杂度了,当然这⾥不考虑递归所产⽣的系统调⽤的栈。

这⾥涉及到⼀个链表常⽤的操作,即快慢指针的技巧。

设置slow和fast指针,开始它们都指向表头,fast每次⾛两步,slow每次⾛⼀步,fast到链表尾部时,slow正好到中间,这样就将链表截为两段。

1# Definition for singly-linked list.2# class ListNode:3# def __init__(self, x):4# self.val = x5# self.next = None67class Solution:8# @param {ListNode} head9# @return {ListNode}10def merge(self,head1,head2):11if head1==None: return head212if head2==None: return head113 dummy=ListNode(0)14 p=dummy15while head1 and head2:16if head1.val<head2.val:17 p.next=head118 head1=head1.next19 p=p.next20else:21 p.next=head222 head2=head2.next23 p=p.next24if head1==None:25 p.next=head226if head2==None:27 p.next=head128return dummy.next29def sortList(self, head):30if head==None or head.next==None: return head #别忘记31 slow=fast=head32while fast.next and fast.next.next:33 slow=slow.next34 fast=fast.next.next35 head1=head #快慢指针将链表截为两段36 head2=slow.next37 slow.next=None38 head1=self.sortList(head1) #递归调⽤,直到2个或1个结点为⽌进⾏merge返回39 head2=self.sortList(head2)40 head=self.merge(head1,head2)41return head。

链表的排序——精选推荐

链表的排序——精选推荐

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

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

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

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

另⼀种排序要求是倒序。

当然,我们可以修改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++) {// 相邻⽐较,前者⼩则互换值。

《链表排序法》

《链表排序法》

《链表排序法》
哎呀,说起链表排序法,这可让我想起了之前在学校里的一段有趣经历。

那时候,我们计算机课上正在学习链表排序法,老师在讲台上讲得眉飞色舞,我在下面却是听得云里雾里。

这玩意儿可真不简单呐!
下课后,我和几个小伙伴凑在一起,准备好好研究研究这个链表排序法。

“这到底是个啥呀?我咋一点都没听懂。

”我一脸愁容地说。

同桌小明也跟着附和:“就是就是,感觉比做数学题还难。


学习委员小李倒是信心满满:“别着急,咱们一起好好琢磨琢磨。


于是,我们几个就开始在纸上写写画画。

我一会儿挠挠头,一会儿咬咬笔杆,心里那个着急呀。

“哎呀,我好像有点思路了。

”小李突然叫起来。

我们赶紧凑过去,“快说说,快说说。


小李指着纸上的图,开始给我们讲解。

可我听着听着,又迷糊了。

“等等,这里我没明白。

”我着急地打断他。

大家你一言我一语,争论得热火朝天。

经过好一番折腾,我们总算是对链表排序法有了那么一点点的理解。

现在回想起来,那段和小伙伴们一起钻研链表排序法的时光,还真是有趣又难忘。

原来学习也可以这么热闹,这么欢乐。

总之,链表排序法虽然难,但因为有了小伙伴们的陪伴和努力,也变得没那么可怕啦!。

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

数据结构实验报告实验名称:实验三——排序学生姓名:XXX班级:xxxxxxxxxxx班内序号:学号:日期:2018年6月3日1.实验要求实验目的:通过选择下面两个题目之一,学习、实现、对比各种排序算法,掌握各种排序算法的优劣,以及各种算法使用的情况。

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

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

3、对于这三类数据,比较上述排序算法中不同算法的执行时间,精确到微秒(选作)4、对2和3的结果进行分析,验证上述各种算法的时间复杂度编写测试main()函数测试线性表的正确性。

2. 程序分析2.1 存储结构单链表,储存每个元素值同时,储存该元素的直接后继元素位置信息。

即数据域(data),指针域(next)。

struct Node{int data;struct Node *next;};2.2 关键算法分析链表的建立:Linklist::Linklist (int a[],int n){front = new Node;Node *r = front ;for(int i=0;i<n;i++) //尾插法初始化链表{Node *s = new Node;s->data = a[i];r->next = s;r=s;}r->next = NULL;}尾插法创建链表:①堆中建立新节点②将a[i]写入新节点data域③新节点加入链表r->next=s.④修改尾指针r=s.简单选择排序:void Linklist ::Link_Selectsort (int n){Node *p=front->next ;int a=0,b=0; //a记载比较次数,b记载移动次数while(p!=NULL){Node *s =p; //s指向最小节点Node *q=p->next ;while(q!=NULL){if(q->data<s->data) s=q;a++;q=q->next ;}if(p!=s){int t=p->data ;p->data =s->data ;s->data =t; //交换节点值b=b+3;}p=p->next ;}Print(n,a,b);}建立p节点记载有序区最后节点的下一个节点,s节点则记载无序区的最小节点,q节点用于遍历链表无序区,找出最小值。

每次循环中q都找到无序最小节点,用s指向该节点,后p和s节点值交换。

时间复杂度为O(n^2)直接插入排序:void Linklist ::Link_Insertsort(int n){Node *p=front;Node *q=front->next ; //q为无序区第一个节点的前驱int a=0,b=0; //a记录比较次数,b记录移动次数while(p->next !=NULL){p=front; //初始化p为有序区的第一个前驱while(q->next !=NULL&&p!=q){a++;if (p->next ->data>q->next ->data ) //比较,交换节点顺序 { Node *s=q->next ;q->next =s->next ; //摘除s 节点 s->next =p->next ; //插到p 节点之后 p->next =s; b=b+3;break ;}p=p->next ;}if (p==q) q=q->next ; //若本躺排序无节点交换,则q 点下移p=q; //当q 到链尾时,用于结束循环}Print(n,a,b);}① 指针p 指向有序区的待比较节点前驱(初始化时即front 节点)②指针q 指向无序区第一个元素的前驱Ⅰ:若无序区的第一个节点值较大,则p 下移,直到p=q 为止Ⅱ:若无序区第一个元素节点值较小,则用指针s 指向该节点,然后摘除s 节点,插入到p 节点后继位置,即本趟循环结束。

时间复杂程度平均为O(n^2),最好为O(n),最坏为O(n^2).…………③冒泡排序:void Linklist ::Link_Bubblesort (int n)Node *p,*r;p=front->next ;r=NULL; //尾指针int a=0,b=0; //a记载比较次数,b记载交换次数while(p!=NULL&&r!=front->next ){p=front->next ; //初始化p到链表头部while(p->next !=r){if(p->data >p->next ->data ) //相邻反序,则交换data域{int t=p->data ;p->data =p->next ->data ;p->next ->data =t;b=b+3;}p=p->next ;a++;}r=p; //尾指针前移}Print(n,a,b);}①每趟排序,指针p指向无序区的待比较的节点,初始化时p指向无序区的第一个节点。

②指针r指向有序区的第一个节点,初始化,r=NULL。

③从p指针开始,前后两个节点的元素值比较,若反序则交换元素的data,否则p下移,直到计较到r为止,本趟排序完成。

④一趟排序后,将尾指针前移一位,即r=p,直到r为第一个元素排序结束。

时间复杂程度平均为O(n^2),最好为O(n),最坏为O(n^2).快速排序:void Linklist ::swap (Node *a,Node *b){int t=a->data ;a->data =b->data ;b->data =t;}Node *Linklist ::partion (Node *start,Node *end,int b[]) //求中间结点{if(start==end||start->next ==end)return start;Node *p=start,*q=start,*refer=start; //取第一个元素为基准元素,refer为轴值while(q!=end) //从start开始向后进行一次遍历,因为单链表无法从左右向中间遍历{if(q->data <refer->data ){p=p->next ;swap(p,q);b[1]=b[1]+3;}q=q->next ;b[0]++;}swap(p,refer);b[1]=b[1]+3;return p;}void Linklist ::quick_sort (Node* start,Node *end,int b[]) //递归,与课本不同,每次递归的第一节点即为轴值{if(start==end||start->next ==end)return;Node *pivotloc=partion (start,end,b);quick_sort (start,pivotloc ,b); //左分区快速排序quick_sort (pivotloc ->next ,end,b); //右分区快速排序}void Linklist ::Link_Quicksort (int n){if((front->next ==NULL)||(front->next ->next==NULL)){if(front->next ->next ==NULL&&front->next !=NULL) Print(n,0,0);return;}int b[2]={0}; //用于记载数据,b[0]记载比较次数,b[1]记载移动次数Node *start =front->next ;Node *end=NULL;quick_sort (start,end,b);int a=b[0], c=b[1];Print(n,a,c);}传入的开始节点,与结束节点中,默认第一个元素为轴值,再把元素一一与轴值比较,比轴值小的放前面,比轴值大的放后面。

不断递归下去排序,当传进去的头尾节点一样时,表明排序已经完成。

注意,由于局部变量的原因,整形变量不能在递归中,因此我用一个数组b 来记录比较次数、移动次数。

时间复杂程度平均为O(nlog2n),,最好情况也同此,最坏情况为O(n^2)。

2.3 其他一、编写一个公共的打印函数,在比较函数中调用,就不用考虑把记载比较次数、交换次数的整形变量如何传递出函数的问题了(当然用整形变量也能解决这一问题)。

二、要设置一个重置链表顺序的函数,应为一次排序后,链表已经变得有序,影响后面排序的结果。

所以调用一个排序函数时,先用一次重置函数。

void Linklist ::Reset (int a[],int n){Node *p = front ;for(int i=0;i<n;i++) //重新把数组a赋值进入链表{p=p->next ;p->data =a[i];}}三、用switch写主函数,让程序有一点人机交互能力。

3. 程序运行结果流程图:结果:4. 总结这次实验,我选的是第二题,比第一题还是复杂一点点。

不过还好,参考书里给了我三种排序的代码,虽然理解起来比用数组麻烦了一点。

但我还是很乐意一试的。

通过编程,不仅对这四种排序有了更深入的了解,而且还能复习一下单链表的使用,还是一举两得的。

不过,很遗憾我没有做选作部分,也就是计算排序函数所用时间。

虽然上网查了方法,比较简单的是使用clock()函数,但是这是毫秒级别的计算,我的数组手动输入,太小了,无法达到毫秒级别,不能计算出来。

用同学给我了建议,那就是用随机数生成大量数据,挺好的,不过上千个数字打印出来也是问题,我作罢了。

倒数第二次实验了,我还是比较满意。

希望最后一次也能如此!。

相关文档
最新文档