简介: 有哪些常见的数据结构?基本操作是什么?常见的排序算法是如何实现的?各有什么优缺点?本文简要分享算法根底、常见的数据结构以及排序算法,给同学们带来一堂数据结构和算法的基础课。
一 前言
1 为什么要学习算法和数据结构?
- 解决特定问题。
- 深度优化程序性能的根底。
- 学习一种思维:如何把事实问题转化为计算机语言示意。
2 业务开发要把握到水平?
- 理解常见数据结构和算法,沟通没有阻碍。
- 活学活用:遇到问题时晓得要用什么数据结构和算法去优化。
二 数据结构根底
1 什么是数据结构?
数据结构是数据的组织、治理和存储格局,其应用目标是为了高效的拜访和批改数据。
数据结构是算法的基石。如果把算法比喻成漂亮灵动的舞者,那么数据结构就是舞者脚下广大而松软的舞台。
2 物理构造和逻辑构造的区别?
物理构造就像人的血肉和骨骼,看得见,摸得着,实实在在,如数组、链表。
逻辑构造就像人的思维和精力,它们看不见、摸不着,如队列、栈、树、图。
3 线性存储构造和非线性存储构造的区别?
- 线性:元素之间的关系是一对一的,如栈、队列。
- 非线性:每个元素可能连贯 0 或多个元素,如树、图。
三 算法根底
1 什么是算法?
- 数学:算法是用于解决某一类问题的公式和思维。
- 计算机:一系列程序指令,用于解决特定的运算和逻辑问题。
2 如何掂量算法好坏?
- 工夫复杂度:运行工夫长短。
- 空间复杂度:占用内存大小。
3 怎么计算工夫复杂度?
大 O 表示法(渐进工夫复杂度):把程序的绝对执行工夫函数 T(n)简化为一个数量级,这个数量级能够是 n、n^2、logN 等。
推导工夫复杂度的几个准则:
- 如果运行工夫是常数量级,则用常数 1 示意。
- 只保留工夫函数中的最高阶项。
- 如果最高阶项存在,则省去最高项后面的系数。
工夫复杂度比照:O(1) > O(logn) > O(n) > O(nlogn) > O(n^2)。
不同工夫复杂度算法运行次数比照:
4 怎么计算空间复杂度?
常量空间 O(1):存储空间大小固定,和输出规模没有间接的关系。
线性空间 O(n):调配的空间是一个线性的汇合,并且汇合大小和输出规模 n 成正比。
二维空间 O(n^2):调配的空间是一个二维数组汇合,并且汇合的长度和宽度都与输出规模 n 成正比。
递归空间 O(logn):递归是一个比拟非凡的场景。尽管递归代码中并没有显式的申明变量或汇合,然而计算机在执行程序时,会专门调配一块内存空间,用来存储“办法调用栈”。执行递归操作所须要的内存空间和递归的深度成正比。
5 如何定义算法稳定性?
稳固:如果 a 本来在 b 后面,而 a =b,排序之后 a 依然在 b 的后面。
不稳固:如果 a 本来在 b 的后面,而 a =b,排序之后 a 可能会呈现在 b 的前面。
6 有哪些常见算法?
首先要明确:特定算法解决特定问题。
- 字符串:暴力匹配、BM、KMP、Trie 等。
- 查找:二分查找、遍历查找等。
- 排序:冒泡排序、快排、计数排序、堆排序等。
- 搜寻:TFIDF、PageRank 等。
- 聚类分析:冀望最大化、k-meanings、k- 数位等。
- 深度学习:深度信念网络、深度卷积神经网络、生成式反抗等。
- 异样检测:k 最近邻、部分异样因子等。
- ……
其中,字符串、查找、排序算法是最根底的算法。
四 常见数据结构
1 数组
1)什么是数组?
数据是无限个雷同类型的变量所组成的有序汇合。数组中的每一个变量被称为元素。
2)数组的基本操作?
读取 O(1)、更新 O(1)、插入 O(n)、删除 O(n)、扩容 O(n)。
2 链表
1)什么是链表?
链表是一种在物理上非间断、非程序的数据结构,由若干个节点组成。
单向链表的每一个节点又蕴含两局部,一部分是存放数据的变量 data,另一部分是指向下一个节点的指针 next。
2)链表的基本操作?
读取 O(n)、更新 O(1)、插入 O(1)、删除 O(1)。
3)链表 VS 数组
数组:适宜多读、插入删除少的场景。
链表:实用于插入删除多、读少的场景。
3 栈
1)什么是栈?
栈是一种线性逻辑数据结构,栈的元素只能后进先出。最早进入的元素寄存的地位叫做栈底,最初进入的元素寄存的地位叫栈顶。
一个比喻,栈是一个一端关闭一端的凋谢的中空管子,队列是两端凋谢的中空管子。
2)如何实现栈?
数组实现:
链表实现:
3)栈的基本操作
入栈 O(1)、出栈 O(1)。
4)栈的利用?
- 回溯历史,比方办法调用栈。
- 页面面包屑导航。
4 队列
1)什么是队列?
一种线性逻辑数据结构,队列的元素只能后进后出。队列的进口端叫做队头,队列的入口端叫做队尾。
2)如何实现队列?
数组实现:
链表实现:
3)队列的基本操作?
入队 O(1)、出队 O(1)。
4)队列的利用
- 音讯队列
- 多线程的期待队列
- 网络爬虫的待爬 URL 队列
5 哈希表
1)什么是哈希表?
一种逻辑数据结构,提供了键(key)和值(value)的映射关系。
2)哈希表的基本操作?
写入:O(1)、读取:O(1)、扩容 O(n)。
3)什么是哈希函数?
哈希表实质上是一个数组,只是数组只能依据下标,像 a[0] a[1] a[2] a[3] 这样来拜访,而哈希表的 key 则是以字符串类型为主的。
通过哈希函数,咱们能够把字符串或其余类型的 key,转化成数组的下标 index。
如给出一个长度为 8 的数组,则:
当 key=001121 时,
index = HashCode ("001121") % Array.length = 7
当 key=this 时,
index = HashCode ("this") % Array.length = 6
4)什么是哈希抵触?
不同的 key 通过哈希函数取得的下标有可能是雷同的,例如 002936 这个 key 对应的数组下标是 2,002947 对应的数组下标也是 2,这种状况就是哈希抵触。
5)如何解决哈希抵触?
凋谢寻址法:例子 Threadlocal。
链表法:例子 Hashmap。
6 树
1)什么是树?
树(tree)是 n(n≥0)个节点的无限集。
当 n = 0 时,称为空树。在任意一个非空树中,有如下特点:
- 有且仅有一个特定的称为根的节点。
- 当 n >1 时,其余节点可分为 m(m>0)个互不相交的无限集,每一个汇合自身又是一个树,并称为根的子树。
2)树的遍历?
(1)深度优先
前序:根节点、左子树、右子树。
中序:左子树、根节点、右子树。
后序:左子树、右子树、根节点。
实现形式:递归或栈。
(2)广度优先
层序:一层一层遍历。
实现形式:队列。
7 二叉树
1)什么是二叉树?
二叉树(binary tree)是树的一种非凡模式。二叉,顾名思义,这种树的每个节点最多有 2 个孩子节点。留神,这里是最多有 2 个,也可能只有 1 个,或者没有孩子节点。
2)什么是满二叉树?
一个二叉树的所有非叶子节点都存在左右孩子,并且所有叶子节点都在同一层级上,那么这个树就是满二叉树。
3)什么是齐全二叉树?
对一个有 n 个节点的二叉树,按层级程序编号,则所有节点的编号为从 1 到 n。如果这个树所有节点和同样深度的满二叉树的编号为从 1 到 n 的节点地位雷同,则这个二叉树为齐全二叉树。
8 二叉查找树
1)什么是二叉查找树?
二叉查找树在二叉树的根底上减少了以下几个条件:
- 如果左子树不为空,则左子树上所有节点的值均小于根节点的值。
- 如果右子树不为空,则右子树上所有节点的值均大于根节点的值。
- 左、右子树也都是二叉查找树。
2)二叉查找树的作用?
- 查找 ==》二分查找。
- 排序 ==》中序遍历。
3)二叉树的实现形式?
- 链表。
- 数组:对于稠密二叉树来说,数组表示法是十分节约空间的。
9 二叉堆
1)什么是二叉堆?
二叉堆是一种非凡的齐全二叉树,它分为两个类型:最大堆和最小堆。
- 最大堆的任何一个父节点的值,都大于或等于它左、右孩子节点的值。
- 最小堆的任何一个父节点的值,都小于或等于它左、右孩子节点的值。
2)二叉堆的基本操作?
(1)插入:插入最末,节点上浮。
(2)删除:删除头节点,尾节点放到头部,再下沉。
(3)构建二叉堆:二叉树 ==》二叉堆,所有非叶子节点顺次下沉。
3)二叉堆的实现形式?
数组:
五 常见排序算法
1 十大经典排序算法
2 冒泡排序
1)算法形容
冒泡排序是一种简略的排序算法。它反复地走访过要排序的数列,一次比拟两个元素,如果它们的程序谬误就把它们替换过去。走访数列的工作是反复地进行直到没有再须要替换,也就是说该数列曾经排序实现。这个算法的名字由来是因为越小的元素会经由替换缓缓“浮”到数列的顶端。
2)实现步骤
- 比拟相邻的元素。如果第一个比第二个大,就替换它们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最初一对,这样在最初的元素应该会是最大的数。
- 针对所有的元素反复以上的步骤,除了最初一个。
- 反复步骤 1~3,直到排序实现。
3)优缺点
- 长处:实现和了解简略。
- 毛病:工夫复杂度是 O(n^2),排序元素多时效率比拟低。
4)适用范围
数据曾经根本有序,且数据量较小的场景。
5)场景优化
(1)曾经有序了还再持续冒泡问题
- 本轮排序中,元素没有替换,则 isSorted 为 true,间接跳出大循环,防止后续无意义的反复。
(2)局部曾经有序了,下一轮的时候但还是会被遍历
- 记录有序和无序数据的边界,有序的局部在下一轮就不必遍历了。
(3)只有一个元素不对,但须要走完全部轮排序
- 鸡尾酒排序:元素的比拟和替换是双向的,就像摇摆鸡尾酒一样。
3 归并排序
1)算法形容
归并排序是建设在归并操作上的一种无效的排序算法。该算法是采纳分治法的一个十分典型的利用。递归的把以后序列宰割成两半(宰割),在放弃元素程序的同时将上一步失去的子序列集成到一起(归并),最终造成一个有序数列。
2)实现步骤
图源:https://www.cnblogs.com/chengxiao/p/6194356.html
- 把长度为 n 的输出序列分成两个长度为 n / 2 的子序列。
- 对这两个子序列别离采纳归并排序。
- 将两个排序好的子序列合并成一个最终的排序序列。
3)优缺点
长处:
- 性能好且稳固,工夫复杂度为 O(nlogn)。
- 稳固排序,实用场景更多。
毛病:
- 非原地排序,空间复杂度高。
4)适用范围
大数据量且冀望要求排序稳固的场景。
4 疾速排序
1)算法形容
疾速排序应用分治法策略来把一个序列分为较小和较大的 2 个子序列,而后递归地排序两个子序列,以达到整个数列最终有序。
2)实现步骤
- 从数列中挑出一个元素,称为“基准值”(pivot)。
- 从新排序数列,所有元素比基准值小的摆放在基准后面,所有元素比基准值大的摆在基准的前面(雷同的数能够到任一边)。在这个分区退出之后,该基准就处于数列的两头地位。这个称为分区(partition)操作。
- 递归地对【小于基准值元素的子数列】和【大于基准值元素的子数列】进行排序。
3)优缺点
长处:
- 性能较好,工夫复杂度最好为 O(nlogn),大多数场景性能都靠近最优。
- 原地排序,工夫复杂度优于归并排序。
毛病:
- 局部场景,排序性能最差为 O(n^2)。
- 不稳固排序。
4)适用范围
大数据量且不要求排序稳固的场景。
5)场景优化
(1)每次的基准元素都选中最大或最小元素
- 随机抉择基准元素,而不是抉择第一个元素。
- 三数取中法,随机抉择三个数,取两头数为基准元素。
(2)数列含有大量反复数据
- 大于、小于、等于基准值。
(3)快排的性能优化
- 双轴快排:2 个基准数,例子:Arrays.sort()。
5 堆排序
1)算法形容
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。沉积是一个近似齐全二叉树的构造,并同时满足沉积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
2)实现步骤
- 将初始待排序关键字序列 (R1,R2….Rn) 构建成最大堆,此堆为初始的无序区。
- 将堆顶元素 R[1]与最初一个元素 R[n]替换,此时失去新的无序区 (R1,R2,……Rn-1) 和新的有序区(Rn), 且满足 R[1,2…n-1]<=R[n]。
- 因为替换后新的堆顶 R[1]可能违反堆的性质,因而须要对以后无序区 (R1,R2,……Rn-1) 调整为新堆,而后再次将 R[1]与无序区最初一个元素替换,失去新的无序区 (R1,R2….Rn-2) 和新的有序区(Rn-1,Rn)。一直反复此过程直到有序区的元素个数为 n -1,则整个排序过程实现。
3)优缺点
长处:
- 性能较好,工夫复杂度为 O(nlogn)。
- 工夫复杂度比较稳定。
- 辅助空间复杂度为 O(1)。
毛病:
- 数据变动的状况下,堆的保护老本较高。
4)适用范围
数据量大且数据呈流式输出的场景。
5)为什么理论状况快排比堆排快?
堆排序的过程可知,建设最大堆后,会将堆顶的元素和最初一个元素对调,而后让那最初一个元素从顶上往下沉到失当的地位,因为底部的元素肯定是比拟小的,下沉的过程中会进行大量的近乎有效的比拟。所以堆排尽管和快排一样复杂度都是 O(NlogN),但堆排复杂度的常系数更大。
6 计数排序
1)算法形容
计数排序不是基于比拟的排序算法,其外围在于将输出的数据值转化为键存储在额定开拓的数组空间中。作为一种线性工夫复杂度的排序,计数排序要求输出的数据必须是有确定范畴的整数。
2)实现步骤
- 找出待排序的数组中最大元素。
- 构建一个数组 C,长度为最大元素值 +1。
- 遍历无序的随机数列,每一个整数依照其值对号入座,对应数组下标的值加 1。
- 遍历数组 C,输入数组元素的下标值,元素的值是几就输入几次。
3)优缺点
长处:
- 性能完爆比拟排序,工夫复杂度为 O(n+k),k 为数列最大值。
- 稳固排序。
毛病:
- 适用范围比拟狭隘。
4)适用范围
数列元素是整数,当 k 不是很大且序列比拟集中时实用。
5)场景优化
(1)数字不是从 0 开始,会存在空间节约的问题
- 数列的最小值作为偏移量,以数列最大值 - 最小值 + 1 作为统计数组的长度。
7 桶排序
1)算法形容
桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的要害就在于这个映射函数的确定。实现原理:假如输出数据遵从均匀分布,将数据分到无限数量的桶里,每个桶再别离排序(有可能再应用别的排序算法或是以递归形式持续应用桶排序进行排序)。
2)实现步骤
- 创立桶,区间跨度 =(最大值 - 最小值)/(桶的数量 -1)。
- 遍历数列,对号入座。
- 每个桶内进行排序,可抉择快排等。
- 遍历所有的桶,输入所有元素。
3)优缺点
长处:
- 最优工夫复杂度为 O(n),完爆比拟排序算法。
毛病:
- 适用范围比拟狭隘。
- 工夫复杂度不稳固。
4)适用范围
数据遵从均匀分布的场景。
8 性能比照
随机生成区间 0 ~ K 之间的序列,共计 N 个数字,利用各种算法进行排序,记录排序所需工夫。
参考内容及图源
[1]《漫画算法:小灰的算法之旅》
[2]《算法(第 4 版)》
[3]《算法图解》
[4]《剑指 Offer》
[5]十大经典排序算法(动图演示)
https://www.cnblogs.com/onepixel/p/7674659.html
[6]维基百科
https://zh.wikipedia.org/wiki/Wikipedia:%E9%A6%96%E9%A1%B5