数据结构及算法学习(一)

感谢可视化算法学习网站
https://visualgo.net/zh
虽然这个网站支持切到中文,但是里边讲解的内容都是用英语的!

排序算法

排序问题有各种有趣的算法解决方案,体现了许多计算机科学的想法:

  • 比较与非比较的策略,
  • 迭代与递归实现,
  • 分歧和征服范式(这个或这个),
  • 最佳/最差/平均时间复杂度分析,
  • 随机算法等

当数组被排序时,涉及其内容的许多问题变得容易(或更容易),例如

  • 搜索数组中的特定值v - 二进制搜索,
  • 在(静态)数组中找到最小/最大/第k个最小/最大值,
  • 测试唯一性和删除重复,
  • 计算特定值v在阵列中出现多少时间,
  • 在两个排序的数组A和B之间设置交集/联合,
  • 寻找目标对x和y使得x + y等于目标z等。

前六个算法是基于比较的排序算法,而最后两个算法不是。中间三种算法是递归排序算法,其余算法通常迭代实现。
为了节省屏幕空间,我们将算法名称缩写为三个字符:
基于比较的排序算法:

  1. BUB - 冒泡排序,
  2. SEL - 选择排序,
  3. INS - 插入排序,
  4. MER - Merge Sort(递归实现),
  5. QUI - 快速排序(递归执行),
  6. RQ - 随机快速排序(递归实现)。

不基于比较的排序算法:

  1. COU - 计数排序,
  2. RAD - 基数排序。

冒泡排序

逻辑

给定一个N个元素的数组,冒泡排序将:
比较一对相邻项目(a,b),
如果项目出现故障,交换对(在本例中为> b),
重复步骤1和2,直到我们到达数组的最后(最后一对,(N - 2)项和(N -1)项使用基于0的索引)
到目前为止,最大的项目将在最后的位置。
然后我们将N减少1,并重复步骤1,直到我们有N = 1。
(一个框,可以把框内的两个数按大小排序,框先框住最左边的两个数,排序,然后右移一位,排序,继续…)
(这样循环一次,最大的便移动到最右端了,然后去掉最右端,再来)

时间复杂度

ON2
(标准)气泡排序中有两个嵌套循环。

外部循环运行正好N次迭代。
但内循环越来越短:
当i = 0,(N -1)迭代(比较和可能的交换)时,
当i = 1,(N -2)迭代时,
…,
当i =(N -2),1次迭代时,
当i =(N -1),0迭代。
因此,迭代的总数 =N1+N2+...+1+0=NN12
总时间 =cNN1/2=ON2

选择排序

逻辑

给定N个项目的数组,L = 0,选择排序将:
在[ L … N -1] 的范围内找到最小项目X的位置,
交换X与第L项,
将下限L增加1并重复步骤1,直到L = N -2。
(找麦子,找最小的,比手上小的就记住位置及大小,一路找到最后,将那个位置与当前位置的交换,走到下一位,再次执行)

时间复杂度

ON2
类似与冒泡排序
外循环N次
内循环越来越短
因此,迭代的总数 =N1+N2+...+1+0=NN12
总时间 =cNN1/2=ON2

插入排序

逻辑

(对前两个数进行排序)
(检测第三个数,向左比较,如果比自己大,将那个数右移一位,继续向左比较,直到比自己小(或者没有数(到头了)),在该位置插入)
(检测第四个数…)

时间复杂度

外部循环执行N次,这很清楚。
但内循环的执行次数取决于输入:
在最佳情况下,阵列已经被排序,并且(a [j]> X)总是为假
所以不需要数据移位,并且内循环在O(1)中运行,
在最坏情况下,阵列是反向排序的,(a [j]> X)总是为真
插入总是出现在数组的前面,内部循环在O(N)中运行。
因此,
最佳情况时间为 ON×1=ON
最坏情况时间为 ON×N=ON2

合并排序

逻辑

给定一组N个项目,合并排序将:
将每对单个元素(默认情况下,排序)合并到2个元素的排序数组中,
将2个元素的每对排序的数组合并为4个元素的排序数组,
重复该过程…,
最后一步:合并2个N / 2元素的排序数组(为了简单的讨论,我们假设N是偶数),以获得一个完整排序的N个元素的数组。
这只是一般的想法,我们需要更多的细节,然后才能讨论合并排序的真实形式。
(排序第一第二个数,排序第三第四个数,排序一二三四)
(排序第五第六个数,排序第七第八个数,排序五六七八,排序一二三四五六七八)
(排序第九第十个数,to be continued)

时间复杂度

ON 合并

给定大小为N 1和N 2的两个排序的数组A和B,我们可以在O(N)个时间内将它们有效地合并成一个大小为N = N 1 + N 2的较大组合排序的数组。
这是通过简单地比较两个阵列的前端并在任何时候取两个中较小的一个来实现的。但是,我们将需要额外的数组来正确地进行合并。

Divide and Conquer(简称D&C)(分治算法)

合并排序是一个分治排序算法。
分治算法递归地把一个大问题分解为多个类型相同的子问题,直到这些子问题足够的简单能被直接解决.最后把这些子问题的解结合起来就能得到原始问题的解.
分解步骤很简单:将当前数组划分成两半(如果N是偶数则完全相等,如果N是奇数,则一边稍大一个元素),然后递归地对这两半进行排序。
治理步骤是最有效的工作:使用前面讨论的合并例程合并两个(排序)的一半以形成排序的数组。

时间复杂度计算

在合并排序中,大部分工作是在治理/合并步骤中完成的,因为分解步骤并不真正做任何事情(视为O(1))。

这里写图片描述
Level 1: 2^0=1 calls to merge() with N/2^1 items each, O(2^0 x 2 x N/2^1) = O(N)
Level 2: 2^1=2 calls to merge() with N/2^2 items each, O(2^1 x 2 x N/2^2) = O(N)
Level 3: 2^2=4 calls to merge() with N/2^3 items each, O(2^2 x 2 x N/2^3) = O(N)

Level (log N): 2^(log N-1) (or N/2) calls to merge() with N/2^log N (or 1) item each, O(N)

存在logN级,并且在每个级别中,我们执行O(N)工作,因此总时间复杂度为O(N log N)。我们稍后会看到这是一个最优(基于比较的)排序算法,即我们不能比这更好。

稍稍有些难以理解。

快速排序

逻辑

分解步骤:选择项目p(称为枢纽)
然后将[i..j]的项目分为三部分:a [i..m-1],a [m]和[m + 1 ..j]。
a [i..m-1](可能为空)包含小于p的项目。
a [m]是枢轴p,即索引m是数组a的排序顺序中p的正确位置。a [m + 1..j](可能为空)包含大于或等于p的项目。然后,递归地分类这两个部分。
治理步骤:不要惊讶…我们什么都不做:哦!
(选择第一个数,将其它所有的数同它进行比较,比它小的放到前一个序列,比它大的放到后边的序列(这样这个数的位置就确定了))
(这样我们有了一个位置已经确定的数以及两个序列,在对那两个序列进行同样的步骤(递归))

时间复杂度

我们将通过首先讨论其最重要的子例程O(N)分区来剖析此快速排序算法。

为了分割一个[i..j],我们首先选择一个[i]作为枢轴点p。
其余项目(即[i + 1..j])分为3个区域:
S1 = a [i + 1..m]其中项目为< p,
S2 = 一个[M + 1..k-1] ,其中项目≥ p,和
未知= a [k..j],其中项目尚未分配给S1或S2。
最初,S1和S2两个区域都是空的,即除了指定枢轴p之外的所有项目都在未知区域。
然后,对于未知区域中的每个项目a [k],我们将a [k]与p进行比较,并确定两种情况之一:
如果一个[K] ≥ p,把一个[K]为S2,或
否则,将[k]设为S1。
最后,我们交换一个[i]和[m]将枢轴p右移到S1和S2的中间。
这里写图片描述
这里写图片描述
只有一个循环遍历(ji)次。由于j可以和N -1 一样大,我可以低至0,所以分区的时间复杂度为O(N)。
在这种最糟糕的情况输入情况下,会发生什么:
这里写图片描述
当分区总是将阵列分成两个相等的两半,如合并排序时,出现快速排序的最佳情况。

当这种情况发生时,递归的深度只有日志n。

当每个级别采用O(N)比较时,时间复杂度为O(N log N)。

随机快速排序

逻辑

不选第一个数,随便选个位置的数

时间复杂度

ONlogN)

计数排序

如果存在输入数组的某些假设,我们可以实现更快的排序算法 - 即在O(N)中,因此我们可以避免比较项目以确定排序顺序。

逻辑

假设:如果要排序的项目是小范围的整数,我们可以计算每个整数的出现频率(在该小范围内),并循环通过该小范围以排序顺序输出项目。
尝试计数对上面的示例数组进行排序,其中所有整数都在[1..9]内,因此我们只需要计算整数1出现多少次,出现多少次整数2,出现多少次整数9,然后循环1到9。
(假设序列中的数都在1到9中,只要统计下个数,就能进行排序了)

时间复杂度

时间复杂度是O(N)来计算频率,O(k)其中k是输入整数的范围,在这个例子中为9-1 + 1 = 9。计数排序的时间复杂度是O(N + k),如果k是(非常)小,则为O(N)。

基数排序

逻辑

把每一个项目进行排序为字符串ð数字(我们垫整数有小于ð位数字加上零如果必要的话)。

对于最高有效位(最右边)的数字(最左边),我们通过N个项目,并将它们根据活动数字放入10个队列(每个数字[0..9]一个),这就像一个修改的计数排序这个保持稳定性。然后我们再重新连接组,以便后续的迭代。
(将序列中的每一个数的最后一位按从0到9进行排列)
这里写图片描述
(然后逐项扔出(先进先出))
这里写图片描述
(将序列中的每一个数的倒数第二位按从0到9进行排列)
这里写图片描述
(然后逐项扔出(先进先出))
这里写图片描述
(依此类推,直到最高位)

时间复杂度

注意,我们只执行O(d×(N + k))次迭代。d为最大数字位数,k为数量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
算法数据结构它们分别涵盖了以下主要内容: 数据结构(Data Structures): 逻辑结构:描述数据元素之间的逻辑关系,如线性结构(如数组、链表)、树形结构(如二叉树、堆、B树)、图结构(有向图、无向图等)以及集合和队列等抽象数据类型。 存储结构(物理结构):描述数据在计算机中如何具体存储。例如,数组的连续存储,链表的动态分配节点,树和图的邻接矩阵或邻接表表示等。 基本操作:针对每种数据结构,定义了一系列基本的操作,包括但不限于插入、删除、查找、更新、遍历等,并分析这些操作的时间复杂度和空间复杂度。 算法算法设计:研究如何将解决问题的步骤形式化为一系列指令,使得计算机可以执行以求解问题。 算法特性:包括输入、输出、有穷性、确定性和可行性。即一个有效的算法必须能在有限步骤内结束,并且对于给定的输入产生唯一的确定输出。 算法分类:排序算法(如冒泡排序、快速排序、归并排序),查找算法(如顺序查找、二分查找、哈希查找),图论算法(如Dijkstra最短路径算法、Floyd-Warshall算法、Prim最小生成树算法),动态规划,贪心算法,回溯法,分支限界法等。 算法分析:通过数学方法分析算法的时间复杂度(运行时间随数据规模增长的速度)和空间复杂度(所需内存大小)来评估其效率。 学习算法数据结构不仅有助于理解程序的内部工作原理,更能帮助开发人员编写出高效、稳定和易于维护的软件系统。
算法数据结构它们分别涵盖了以下主要内容: 数据结构(Data Structures): 逻辑结构:描述数据元素之间的逻辑关系,如线性结构(如数组、链表)、树形结构(如二叉树、堆、B树)、图结构(有向图、无向图等)以及集合和队列等抽象数据类型。 存储结构(物理结构):描述数据在计算机中如何具体存储。例如,数组的连续存储,链表的动态分配节点,树和图的邻接矩阵或邻接表表示等。 基本操作:针对每种数据结构,定义了一系列基本的操作,包括但不限于插入、删除、查找、更新、遍历等,并分析这些操作的时间复杂度和空间复杂度。 算法算法设计:研究如何将解决问题的步骤形式化为一系列指令,使得计算机可以执行以求解问题。 算法特性:包括输入、输出、有穷性、确定性和可行性。即一个有效的算法必须能在有限步骤内结束,并且对于给定的输入产生唯一的确定输出。 算法分类:排序算法(如冒泡排序、快速排序、归并排序),查找算法(如顺序查找、二分查找、哈希查找),图论算法(如Dijkstra最短路径算法、Floyd-Warshall算法、Prim最小生成树算法),动态规划,贪心算法,回溯法,分支限界法等。 算法分析:通过数学方法分析算法的时间复杂度(运行时间随数据规模增长的速度)和空间复杂度(所需内存大小)来评估其效率。 学习算法数据结构不仅有助于理解程序的内部工作原理,更能帮助开发人员编写出高效、稳定和易于维护的软件系统。
逻辑结构:描述数据元素之间的逻辑关系,如线性结构(如数组、链表)、树形结构(如二叉树、堆、B树)、图结构(有向图、无向图等)以及集合和队列等抽象数据类型。 存储结构(物理结构):描述数据在计算机中如何具体存储。例如,数组的连续存储,链表的动态分配节点,树和图的邻接矩阵或邻接表表示等。 基本操作:针对每种数据结构,定义了一系列基本的操作,包括但不限于插入、删除、查找、更新、遍历等,并分析这些操作的时间复杂度和空间复杂度。 算法算法设计:研究如何将解决问题的步骤形式化为一系列指令,使得计算机可以执行以求解问题。 算法特性:包括输入、输出、有穷性、确定性和可行性。即一个有效的算法必须能在有限步骤内结束,并且对于给定的输入产生唯一的确定输出。 算法分类:排序算法(如冒泡排序、快速排序、归并排序),查找算法(如顺序查找、二分查找、哈希查找),图论算法(如Dijkstra最短路径算法、Floyd-Warshall算法、Prim最小生成树算法),动态规划,贪心算法,回溯法,分支限界法等。 算法分析:通过数学方法分析算法的时间复杂度(运行时间随数据规模增长的速度)和空间复杂度(所需内存大小)来评估其效率。 学习算法数据结构不仅有助于理解程序的内部工作原理,更能帮助开发人员编写出高效、稳定和易于维护的软件系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值