数据结构第十周笔记——排序(下2)(慕课浙大版本--XiaoYu)

简介: 表排序和基数排序,还有他们之间的对比

10.2 表排序

10.2.1 算法概述

什么时候会用到表排序:

  1. 待排元素不是一个简单的整数,而是一个庞大的结构(比如说是一本书)
  2. 表排序在实际上是不需要移动原始数据的,移动的是指向他们位置的指针

间接排序:

  1. 不移动元素本身,只移动指针
  2. 定义一个指针数组作为"表"(table)
    网络异常,图片无法展示
    |

  3. 交换的只是table的整数(指针),得到
    网络异常,图片无法展示
    |

10.2.2 物理排序

N个数字的排列由若干个独立的环组成,意思如下:

网络异常,图片无法展示
|
table值的3跳到1再跳到5最后跳到0形成一个环。而环与环之间是独立互不交集(不相干)的

如何判断一个环的结束?每访问一个空位i后,就令table[i]=i。当发现table[i]==i时,环就结束了。

复杂度分析

  1. 最好情况:初始即有序
  2. 物理排序过程的最坏情况是:有N/2个环,每个环包含2个元素。需要3N/2次元素移动
  3. T = O(mN),m是每个A元素的复制时间

10.3 基数排序

仅仅基于比较进行的排序所有的这些算法他的最坏时间复杂度下界是O(NlogN),也就是说不管有多快我们总能制造出一个最坏的情况让他用最快的算法跑他也只能跑到NlogN。

这个时候除了比较之外有没有更快的排序呢?有,那就是基数排序

10.3.1 桶排序

基数排序是桶排序的升级版

网络异常,图片无法展示
|

count是数组,这个数组的每一个元素都是一个指针,一开始被初始化为空链表的头指针,所以一开始有101个空链表(对应了101个空的桶 )

假设一个学生考88分:先找到88这个桶,然后把学生信息插到这个链表的表头里

网络异常,图片无法展示
|

伪码描述

voidBucket_Sort(ElementTypeA[],intN)

{

   count[]初始化;

   while(读入一个学生成绩grade)

       将该生插入count[grade]链表;

   for( i=0;i<M;i++){

       if( count[i] )//桶不为空

           输出整个count[i]链表;

   }

}

桶排序算法的时间复杂度T(M, N)是多少?  T(N,M) =O(M+N)

   当M非常小的时候(例如4w个学生只有101个不同成绩值,那这个时候其实就相当于一种线性的算法)

10.3.2 基数排序

如果M>>N的话怎么办?

网络异常,图片无法展示
|

值是0-999之间,最多一共就三位数。我们在考虑三位数的时候每一位数只有十种可能。

基数就是这个进制的基数,二进制的基数就是2,八进制基数就是8,所以十进制的基数自然就是10

输入序列:64,8,216,512,27,729,0,1,343,125

   "次位优先"(LeastSignificantDigit)=>简称LSD算法

   //什么是次位优先?假设目前手里是216,这个时候6 个位数是最次位,2 百位数是主位(有一种算法是主位优先)

   //比较先从个位数开始

第一步:建立十个桶

网络异常,图片无法展示
|

第二步:根据个位数把他们放入相应的桶里面

网络异常,图片无法展示
|

第三步:根据十位数放入相应的桶里面:

网络异常,图片无法展示
|

最后一步:根据百位数放入相应的桶里面:

网络异常,图片无法展示
|

设元素个数为N,整数进制为B,LSD的趟数为P,则最坏时间复杂度是:T=O(P(N+B))

次位优先LSD算法

对于给定范围在0-999之间的10个关键字{64,8,216,512,27,729,0,1,343,125}

① 先为最次位关键字建立桶(10个),将关键字按最次位分别放到10个桶中

② 然后将①中得到的序列按十位放到相应的桶里

③ 做一次收集,扫描每一个桶,收集到一个链表中串起来

④ 将③中得到的序列按最主位放到桶中

⑤ 最后做一次收集,这样就得到一个有序的序列了

10.3.3 多关键字的排序

基数排序不仅仅用于处理整数的基数,还可以用于处理有多关键字的排序

网络异常,图片无法展示
|

采用"主位优先"(MostSignificantDigit)排序:为花色建4个桶

   在每个桶内分别排序,最后合并结果

   =>其实我们还是需要在每个桶内调用相应的排序算法来解决,但是总体的时间复杂度会比我们把它完整的看成一个待排数组来排稍微好一点

采用"次位优先"(LeastSignificantDigit)排序:为面值建13个桶

   这个方便就不需要再排序了,直接将结果合并,然后再为花色建4个桶就ok了

   

从上面两个例子来看,我们可以看出次位优先比主位优先要聪明得多,时间复杂度也快不少

10.4 排序算法的比较

前三个是简单排序,时间复杂度都是比较差的。优点在于程序非常好写,很短且不需要额外的空间

冒泡排序跟直接插入排序因为每次都交换两个相邻的元素,虽然慢,但是稳定

简单选择排序是跳着交换的,导致它是不稳定的

希尔排序是最先打破下界的算法,d最坏情况下是2,这个还是取决于增量排序,因为这是跳着排,所以也不稳定

堆排序跟归并排序理论来说,他们的时间复杂度都是最好的为NlogN

归并排序的缺点:需要一个额外的空间。当我们要排的数据量非常大的时候,归并排序会导致我们只能排一半的数据,本来可以排下的数据因为空间的问题而排不下。但好处在于稳定

网络异常,图片无法展示
|

目录
相关文章
|
存储 机器学习/深度学习 算法
C 408—《数据结构》图、查找、排序专题考点(含解析)
408考研——《数据结构》图,查找和排序专题考点选择题汇总(含解析)。
966 29
|
存储 人工智能 算法
【C++数据结构——内排序】二路归并排序(头歌实践教学平台习题)【合集】
本关任务是实现二路归并算法,即将两个有序数组合并为一个有序数组。主要内容包括: - **任务描述**:实现二路归并算法。 - **相关知识**: - 二路归并算法的基本概念。 - 算法步骤:通过比较两个有序数组的元素,依次将较小的元素放入新数组中。 - 代码示例(以 C++ 为例)。 - 时间复杂度为 O(m+n),空间复杂度为 O(m+n)。 - **测试说明**:平台会对你编写的代码进行测试,提供输入和输出示例。 - **通关代码**:提供了完整的 C++ 实现代码。 - **测试结果**:展示代码运行后的排序结果。 开始你的任务吧,祝你成功!
416 10
|
搜索推荐 算法 数据处理
【C++数据结构——内排序】希尔排序(头歌实践教学平台习题)【合集】
本文介绍了希尔排序算法的实现及相关知识。主要内容包括: - **任务描述**:实现希尔排序算法。 - **相关知识**: - 排序算法基础概念,如稳定性。 - 插入排序的基本思想和步骤。 - 间隔序列(增量序列)的概念及其在希尔排序中的应用。 - 算法的时间复杂度和空间复杂度分析。 - 代码实现技巧,如循环嵌套和索引计算。 - **测试说明**:提供了测试输入和输出示例,帮助验证代码正确性。 - **我的通关代码**:给出了完整的C++代码实现。 - **测试结果**:展示了代码运行的测试结果。 通过这些内容,读者可以全面了解希尔排序的原理和实现方法。
295 10
|
搜索推荐 C++
【C++数据结构——内排序】快速排序(头歌实践教学平台习题)【合集】
快速排序是一种高效的排序算法,基于分治策略。它的主要思想是通过选择一个基准元素(pivot),将数组划分成两部分。一部分的元素都小于等于基准元素,另一部分的元素都大于等于基准元素。然后对这两部分分别进行排序,最终使整个数组有序。(第一行是元素个数,第二行是待排序的原始关键字数据。本关任务:实现快速排序算法。开始你的任务吧,祝你成功!
332 7
|
存储 搜索推荐 算法
【用Java学习数据结构系列】七大排序要悄咪咪的学(直接插入,希尔,归并,选择,堆排,冒泡,快排)以及计数排序(非比较排序)
【用Java学习数据结构系列】七大排序要悄咪咪的学(直接插入,希尔,归并,选择,堆排,冒泡,快排)以及计数排序(非比较排序)
209 1
|
算法 搜索推荐 Java
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
基数排序是一种稳定的排序算法,通过将数字按位数切割并分配到不同的桶中,以空间换时间的方式实现快速排序,但占用内存较大,不适合含有负数的数组。
322 0
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
|
算法
蓝桥杯宝藏排序 | 数据结构 | 快速排序 归并排序
蓝桥杯宝藏排序 | 数据结构 | 快速排序 归并排序
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
357 59
|
8月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
187 0
栈区的非法访问导致的死循环(x64)
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
673 77

热门文章

最新文章