期末自救|腾讯大神教你攻克数据结构与算法,附算法总结
Posted 小蓝鲸的深海代码
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了期末自救|腾讯大神教你攻克数据结构与算法,附算法总结相关的知识,希望对你有一定的参考价值。
全文共5039个字,预计阅读时长13分钟
不知不觉已经来到8102的最后一天
不知道8102对大家来说是怎样的一年
真的不考虑和代码君一起
用充实的学习为8102画下句号嘛~
为了给大家期末复习护航
我们邀请到了一位腾讯项目研发经理
并且他是土生土长的蓝鲸人哦~
代码君在此给大家奉上
腾讯程序员谈 数据结构与算法学习
&爱丽丝的算法总结
人物简介
D琛
南京人,在宁17年后北上读书
现就职于腾讯,职务项目研发经理
代码君:Hello,琛。几乎所有高校都进入了考试月,数据结构与算法基础作为一门并不简单的甚至让很多人都头痛的核心课程,小蓝鲸 非常有幸邀请到您,土生土长的南京程序员大佬,琛可以和我们蓝鲸的学弟学妹说一说数据结构与算法嘛 嘿嘿
琛:小蓝鲸真的太客气了。我从小就是理科生语言表达不是我的专长,第一次被采访,我其实是有一些心理压力的哈哈 。不说客套话了 ,咱们开始吧。
代码君:好! 我们在学习这门课程之前就知道这是门核心课程, 相当的重要。 您能从实际工作的角度讲一讲数据结构与算法 吗?
琛:在编程实践中,数据结构和算法是随处可见。如果有人说在工作中没用到数据结构和算法,那真的是个误会。并非让你去实现一个链表才叫使用了链表。这可能与大学里教条的教学模式有关,一味地讲这些数据结构是怎么编程实现的,一味地讲这些算法是怎么证明的,却忽视了学习这些的主要目的是为了在编程实践中去应用它们优化自己的程序,而不是去重造轮子再发明一次(当然也有少数在算法领域继续深造作出新贡献的人,这里就排除不讲了)。见过不少对链表的基本属性都不了解的人,在程序里一味使用数组,内存能开多大就多大;也见过太多根本不知道Hash原理的人,对Hash表随意使用,造成KEY值严重重复、效率极为低下,这就失去了我们选用HASH的初衷,你说对吗?
代码君:是的。我们的选择都是要围绕我们最终的目的的。
琛:所以啊,即使不是算法密集型的程序里,哪怕是面向业务的编程工作中,能够适当地应用数据结构,选择恰当的算法,也是能极大地提高程序的开发效率、运行效率和运行稳定性的。更不要说面向业务和工作流的基础平台,本身就含有大量的数据结构与算法理论,想利用好这些平台,没有一个好的底子,那会事倍功半的。
代码君:琛可以就本科生的学习给一些意见吗?
琛:除了多学多上手练,我主要谈三点。
独立实践中举一反三
学习过程要保持独立的思想,跟着作者一起分析不代表没有自己的思路。别被作者牵着鼻子走。多去实践,看一天的书不如写一个程序。希望你能在融会贯通的基础上,举一反三,进而深入学习。
学会跳过、会找重点
看书的时候遇到自己看不懂的是很正常,说明思维水平还没有到达作者的层次,这时候可以先跳过,不要自己死磕。已有的数据结构与算法,怎么实现是末节,能理解原理、明白适用场合才是重点。
多讨论学习分享
不懂的不要自己死磕,多和别人讨论交流,也不要吝啬和别人分享自己所学。多读开源作品,看看他们是怎么熟练应用那些基本的数据结构与算法的。不必过度追求怪异算法,适用的就是最好的,简单的才是最佳的。
最后祝蓝鲸的学弟学妹 数据结构高分飘过!!!
| 查找算法
算法 |
最优复杂度 |
最差复杂度 |
平均复杂度 |
顺序查找 |
O(1) |
O(n) |
O(n) |
折半查找 |
O(1) |
O(log n) |
O(log n) |
哈希查找 |
O(1) |
O(1) |
O(1) |
根据查找表的操作方式,分为两种:
静态查找表:只做查找操作
① 查询某个特定的数据元素是否在表中
② 检索某个特定的数据元素和各种属性
动态查找表:在查找过程中同时还插入或删除元素
一、静态查找表(顺序、折半)
① 一般顺序表的查找
顺序查找
算法思想 : 顾名思义就是从数组的0坐标开始逐个查找对比.
② 有序表查找
折半查找
算法思想 : 在一个有序数组里, 先对比数组中间的数middle与要查找的数num的大小关系
- middle == num : 直接返回
- middle < num : 递归查找数组右半部分
- middle > num : 递归查找数组左半部分
二、动态查找(二叉树、哈希)
哈希查找
哈希查找需要一张哈希表, 哈希表又称为散列法, 是高效实现字典的方法. 查找速度在O(1), 这说明无论你需要查找的数据量有多大, 他都能在常数时间内找到, 快得有点违背常理吧? 嘿嘿.
哈希几个重要的概念:
· 负载因子:α =n / m (n为键的个数, m为单元格个数), 负载因子越大, 发生冲突的概率则越大
· 哈希函数:
§ 哈希函数是指你把一样东西存进去之前, 先对它的key进行一次函数转换, 然后在通过转换出来的值作为key, 把你要存的东西存在表上.
· 碰撞解决机制:
§ 再哈希法 : 使用其他的哈希函数对key再次计算, 直到没有发生冲突为止(计算量增加, 不推荐)
§ 如果两样东西通过哈希函数算出来的key相同怎么办? 东西怎么存? 这个时候就是碰撞检测机制派上用场的时候
§ 方法一:开散列法, 也称分离链法
即相当于在数组中每个格子是一个链表, 只要发生冲突就把后来的value拼接在先来的value后面, 形成一条链.
§ 方法二:闭散列法, 也称开式寻址法
可以这么说, 哈希函数设计得越好, 冲突越少, 哈希表的效率就越高.
| 查找算法中可能需要了解的名词
· 旅行商问题
§ 哈密顿回路 : 经过图中所有顶点一次仅一次的通路
· 凸包问题
§ 凸集合 : 平面上一个点集合, 任意两点为端点的线段都属于该集合
§ 凸包 : 平面上n个点, 求包含这些点的最小凸多边形
§ 极点 : 不是线段的中点
· 曼哈顿距离
§ dM (p1, p2) = |x1 - x2| + |y1-y2|
· 深度优先查找(DFS) : 用栈实现
· 广度优先查找(BFS) : 用队列实现
· 拓扑排序( 无环有向图 )
§ 深度优先查找 -> 记住顶点(出栈)的顺序, 反过来就是一个解
§ 找源, 它是一个没有输入边的顶点, 然后删除它和它出发的所有边, 重复操作直到没有源为止.
· 2-3树
§ 2节点 : 只包含1个键和2个子女
§ 3节点 : 包含2个键和3个子女
§ 高度平衡<所有叶子节点必须位于同一层>
§ 可以包含两种类型的节点
· BST树 :
§ 也称为B树
§ 二叉查找树, 随着插入和删除的操作有可能不是平衡的.
· AVL树 :
§ 平衡二叉查找树
§ 左右子树深度只差不超过1
§ 左右子树仍为平衡二叉树
· RBT红黑树:
§ 一种平衡二叉树
§ 跟AVL树类似, 通过插入和删除操作时通过特定操作保持二叉查找树的平衡, 从而有较高的查找性能.
§ 相当于弱平衡的AVL数(牺牲了一定次数的旋转操作), 若查找 > 插入/删除, 则选择AVL树; 若差不多则选择红黑树
· 哈夫曼树
§ 自由前缀变长编码
§ 叶子之间的加权路径长度达到最小
§ 哈夫曼编码
| 排序算法
算法 |
最优复杂度 |
最差复杂度 |
平均复杂度 |
辅助存储 |
稳定性 |
选择排序 |
O(n²) |
O(n²) |
O(n²) |
O(1) |
不稳定 |
冒泡排序 |
O(n) |
O(n²) |
O(n²) |
O(1) |
稳定 |
插入排序 |
O(n) |
O(n²) |
O(n²) |
O(1) |
稳定 |
希尔排序 |
O(n) |
O(n²) |
O(n1.3) |
O(1) |
不稳定 |
归并排序 |
O(nlog n) |
O(nlog n) |
O(nlog n) |
O(n) |
稳定 |
快速排序 |
O(nlog n) |
O(n²) |
O(nlog n) |
O(log n) |
不稳定 |
堆排序 |
O(nlog n) |
O(nlog n) |
O(nlog n) |
O(1) |
不稳定 |
基数排序 |
O(d(r+n)) |
O(d(n+rd)) |
O(d(r+n)) |
O(rd) |
稳定 |
ps:基数排序的复杂度中, r代表关键字的基数, d代表位数, n代表关键字的个数. 也就是说,基数排序不受待排序列规模的影响。
算法复杂度 : 上表中指的是算法的时间复杂度, 一般由O(1), O(n), O(logn),O(nlogn), O(n²), ..., O(n!). 从左到右复杂度依次增大, 时间复杂度是指执行算法所需要的计算工作量。一般而言,好的性能是 O(nlogn),且坏的性能是 O(n^2)。对于一个排序理想的性能是 O(n)。而仅使用一个抽象关键比较运算的排序算法总平均上总是至少需要 O(nlogn)。
还有个概念叫空间复杂度,指的是指执行这个算法所需要的辅助存储空间。
稳定性 : 算法的稳定性体现在执行算法之前,若r[i]=r[j], 且r[i]在r[j]之前,若在排序后的序列中,r[i]仍在r[j]之的前面, 则这个算法是稳定的, 否则称为不稳定的。
选择排序
原理:每次从无序区中找出最小的元素, 跟无序区的第一个元素交换
1、设数组内存放了n个待排数字,数组下标从1开始,到n结束。
2、初始化i=1
3、从数组的第i个元素开始到第n个元素,寻找最小的元素。
4、将上一步找到的最小元素和第i位元素交换。
5、i++,直到i=n-1算法结束,否则回到第3步
冒泡排序
原理:每次对比相邻两项的元素的大小,不符合顺序则交换
插入排序
原理:每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序列中的适当位置,直到全部记录插入完成为止。
SHELL排序
实质上是一种分组插入方法, 也称为缩小增量排序. 比普通的插入排序拥有更高的性能.
算法思想 : 每一趟排序设定一个步长,每次对序列中间隔这个步长的元素子序列进 行直接插入排序
每一趟排序完之后,在下一趟的排序中,改变步长再次进行排序,直至排完
(直接插入排序在元素基本有序的情况下效率很高)
shell排序的执行时间依赖于步长序列。
好的步长序列的共同特征:
①最后一个步长必须为1;
②应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况。
有人通过大量的实验,给出了目前较好的结果:当n较大时,比较和移动的次数约在n到1.6n之间。
归并排序
原理 : 如果有一具有n个元素的序列,则可以看成是n个具有1个元素的序列,然后分别进行两两归并,形成n/2个具有2个元素的有序序列,再次进行两两归并…,最终完成整个序列的排序
以上方法由于每次进行两两归并,因此称为2路归并排序
堆排序
§ 二叉堆是完全二叉树或者是近似完全二叉树。
· 二叉堆满足二个特性:
§ 若有子结点,则该结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
§ 每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。
最大堆:每一个结点不小于孩子结点
最小堆:每一个结点不大于孩子结点
算法思想:堆排序 = 构造堆 + 交换堆末尾元素与根结点 + 删除末尾结点 + 构造堆 + 交换....依次循环, 由于根结点必定是堆中最大(最小)的元素, 所以删除出来的元素序列也必定是升序(降序)的.
堆排序的过程中,每一趟都会在堆顶产生一个当前序列最大(最小)的元素,所以它是选择排序的一种
快速排序
算法思想 : 先从数列中取出一个数作为基准数 -> 将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边 -> 再对左右区间重复第二步,直到各区间只有一个数
基数排序
基数排序的算法复杂度不会因为待排序列的规模而改变.它并非建立在“元素比较”的基础上。它的思想是“多关键字排序”。
基数排序又称为桶排序. 基数排序有3个重要概念 :
· r : 关键字的基数,指的是关键字k的取值范围, 十进制数的话, k=10
· d : 位数
· n : 关键字的个数
| 几种图论的算法
最短路径
· Dijkstra算法
§ 找一个源(起点), 之后求出离起点最近的点的距离; 然后第二近, 以此类推(允许通过其他点为中间点), 设置顶点集合S, 只要源到该顶点的距离已知就把该顶点加入到S中. 直到S包含了V中所有顶点.
§ 求有向带权图中一个"源"到所有其他各顶点的最短路径
· Floyed算法
§ 选取一个顶点作为桥梁, 考察所有顶点是否可以通过该桥梁到达其他的顶点, 如果能, (如a到c, b为桥梁)再比较Dab + Dbc< Dac ? 如果成立, 则更新最短距离
§ 求每个顶点到各个顶点的最短路径
最小生成树(都利用了MST性质)
· Prim算法
§ 首先找出S = {你选取的一个顶点}, 然后添加另一顶点(该顶点∈(V-S)且它们两顶点之间的边的权重最小, 直到S = V.
§ 求无向带权连通图的最小生成树(每次按节点递增)
· Kruskal算法
§ 第一次选出权重最小的边加入, 之后每次选择权重最小的边加入并不构成环.
§ 求无向带权连通图的最小生成树(每次按边递增)
拓扑排序算法
在有向图中选一个没有前驱的顶点并且输出
从图中删除该顶点和所有以它为尾的弧(白话就是:删除所有和它有关的边)
重复上述两步,直至所有顶点输出,或者当前图中不存在无前驱的顶点为止,后者代表我们的有向图是有环的,因此,也可以通过拓扑排序来判断一个图是否有环。
关键路径算法
祝大家新年快乐!2019每一天充实又幸福!
算法总结:Alice
责任编辑:Alice
执行编辑:凌雅娴
图片来自网络
往期回顾
未经授权 禁止转载
蓝忘的酒和鲸彩的故事,只差一个关注的你。
以上是关于期末自救|腾讯大神教你攻克数据结构与算法,附算法总结的主要内容,如果未能解决你的问题,请参考以下文章