数据结构与算法之美
扮猪吃老虎2号
这个作者很懒,什么都没留下…
展开
-
1.时间复杂度和空间复杂度
一、 时间复杂度 时间复杂度是总运算次数表达式中受n的变化影响最大的那一项(不含系数),它并不是用于来真实代表算法的执行时间的,它是用来表示表示算法的执⾏时间与数据规模(n)之间的增⻓关系。 1、计算方法 一般情况下,代码的执⾏时间T(n)与每⾏代码的执⾏次数n成正⽐,因此,算法的时间复杂度记T(n)=O(f(n)) T(n)表示代码执⾏的时间; n表示数据规模的⼤⼩; f...原创 2019-04-24 10:56:28 · 192 阅读 · 0 评论 -
11. 跳表 为什么Redis一定要用跳表来实现有序集合
一、什么是跳表? 为一个值有序的链表建立多级索引,比如每2个节点提取一个节点到上一级,我们把抽出来的那一级叫做索引或索引层。如下图所示,其中down表示down指针,指向下一级节点。以此类推,对于节点数为n的链表,大约可以建立log2n-1级索引。像这种为链表建立多级索引的数据结构就称为跳表。 二、跳表的时间复杂度? 1.计算跳表的高度 如果链表有n个节点,每2个节点抽取抽出一个节点作为上...原创 2019-08-27 11:45:42 · 575 阅读 · 0 评论 -
13. 散列表(中):如何打造一个工业级水平的散列表
面试题目:如何设计一个工业级的散列函数? 思路: 何为一个工业级的散列表?工业级的散列表应该具有哪些特性?结合学过的知识,我觉的应该有这样的要求: 1.支持快速的查询、插入、删除操作; 2.内存占用合理,不能浪费过多空间; 3.性能稳定,在极端情况下,散列表的性能也不会退化到无法接受的情况。 方案: 如何设计这样一个散列表呢?根据前面讲到的知识,我会从3个方面来考虑设计思路: 1.设计一个合适的...原创 2019-08-27 16:12:49 · 196 阅读 · 0 评论 -
12. 散列表(上):Word文档中的单词拼写检查功能是如何实现的
一、散列表的由来? 1.散列表来源于数组,它借助散列函数对数组这种数据结构进行扩展,利用的是数组支持按照下标随机访问元素的特性。 2.需要存储在散列表中的数据我们称为键,将键转化为数组下标的方法称为散列函数,散列函数的计算结果称为散列值。 3.将数据存储在散列值对应的数组下标位置。 二、如何设计散列函数? 总结3点设计散列函数的基本要求 1.散列函数计算得到的散列值是一个非负整数。 2.若key1...原创 2019-08-27 15:13:29 · 163 阅读 · 0 评论 -
14. 散列表(下):为什么散列表和链表经常会一起使用
1.为什么散列表和链表经常放在一起使用? 2.散列表和链表如何组合起来使用? 一、为什么散列表和链表经常放在一起使用? 1.散列表的优点:支持高效的数据插入、删除和查找操作 2.散列表的缺点:不支持快速顺序遍历散列表中的数据 3.如何按照顺序快速遍历散列表的数据?只能将数据转移到数组,然后排序,最后再遍历数据。 4.我们知道散列表是动态的数据结构,需要频繁的插入和删除数据,那么每次顺序遍历之前都需...原创 2019-08-27 18:21:53 · 133 阅读 · 0 评论 -
15. 哈希算法(上):如何防止数据库中的用户信息被脱库
1.如何防止数据库中的用户信息被脱库? 2.你会如何存储用户密码这么重要的数据吗?仅仅 MD5 加密一下存储就够了吗? 3.在实际开发中,我们应该如何用哈希算法解决问题? 一、什么是哈希算法? 1.定义 将任意长度的二进制值串映射成固定长度的二进制值串,这个映射的规则就是哈希算法,而通过原始数据映射之后得到的二进制值串就是哈希值。 2.如何设计一个优秀的哈希算法? ①单向哈希: 从哈希值不能反向推...原创 2019-08-27 18:44:12 · 288 阅读 · 0 评论 -
16. 哈希算法(下):哈希算法在分布式系统中的应用
1.负载均衡 1.1.需求 如何实现一个会话粘滞(session sticky)的负载均衡算法?也就是说,在一次会话中的所有请求都路由到同一个服务器上。 1.2.解决方案 通过哈希算法对客户端IP或会话ID计算哈希值,将取得的哈希值与服务器列表的大小进行取模运算,最终得到的值就是应该被路由到的服务器编号。这样,就可以把同一个IP过来的请求都路由到同一个后端服务器上。 2.数据分片 2.1.如何统...原创 2019-08-27 18:46:45 · 158 阅读 · 0 评论 -
17. 二叉树(上):二叉树及其三种遍历方法
一、树 叶子节点:没有子节点的节点 节点的高度:节点到叶子节点的最长路径所包含的边数 节点的深度:根节点到节点的路径所包含的边数 节点的层数:节点的深度+1(根节点的层数是1) 树的高度:等于根节点的高度 二、二叉树 1.概念 ①什么是二叉树? 每个节点最多只有2个子节点的树,这两个节点分别是左子节点和右子节点。 ②什么是满二叉树? 有一种二叉树,除了叶子节点外,每个节点都有左右两个子节点,...原创 2019-04-16 09:53:05 · 446 阅读 · 0 评论 -
18. 二叉树(下):二叉查找树与散列表的优缺点
二叉查找树(Binary Search Tree) 二叉查找树是二叉树中最常用的一种类型,也叫二叉搜索树。顾名思义,二叉查找树是为了实现快速查找而生的。不过,它不仅仅支持快速查找一个数据,还支持快速插入、删除一个数据。它是怎么做到这些的呢? 这些都依赖于二叉查找树的特殊结构。二叉查找树要求,在树中的任意一个节点,其左子树中的每个节点的值,都要小于这个节点的值,而右子树节点的值都大于这个节点的值...原创 2019-08-28 16:09:25 · 3242 阅读 · 0 评论 -
10. 二分查找(下) 二分查找的四种变形问题
一、四种常见的二分查找变形问题 1.查找第一个值等于给定值的元素 //查找a里面第一个等于value的元素的位置 public static int bsearch2(int[] a, int n, int value) { int low = 0; int high = n - 1; while (low <= high)...原创 2019-08-27 11:35:10 · 169 阅读 · 0 评论 -
10. 二分查找(上) 如何用最省内存的方式实现快速查找功能
一、什么是二分查找? 二分查找针对的是一个有序的数据集合,每次通过跟区间中间的元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间缩小为0。 二、时间复杂度分析? 1.时间复杂度 假设数据大小是n,每次查找后数据都会缩小为原来的一半,最坏的情况下,直到查找区间被缩小为空,才停止。所以,每次查找的数据大小是:n,n/2,n/4,…,n/(2^k),…,这是一个等比数列。当n/(2...原创 2019-08-27 11:30:55 · 108 阅读 · 0 评论 -
7. 递归:如何用三行代码找到“最终推荐人”
一、什么是递归? 1.递归是一种非常高效、简洁的编码技巧,一种应用非常广泛的算法,比如DFS深度优先搜索、前中后序二叉树遍历等都是使用递归。 2.方法或函数调用自身的方式称为递归调用,调用称为递,返回称为归。 3.基本上,所有的递归问题都可以用递推公式来表示,比如 f(n) = f(n-1) + 1; f(n) = f(n-1) + f(n-2); f(n)=n*f(n-1); 二、为什么使用递归...原创 2019-08-02 15:44:17 · 148 阅读 · 0 评论 -
2. 数组:为什么很多编程语⾔中数组都从0开始编号
数组(Array) 是⼀种线性表数据结构。 它⽤⼀组连续的内存空间, 来存储⼀组具有相同类型的数据。线性表(Linear List):线性表就是数据排成像⼀条线⼀样的结构。 每个线性表上的数据最多只有前和后两个⽅向。 其实除了数组, 链表、 队列、 栈等也是线性表结构。⾮线性表, ⽐如⼆叉树、 堆、 图等。 之所以叫⾮线性, 是因为, 在⾮线性表中, 数据之间并不是简单的前后关系。连续的内存空间和...原创 2019-07-30 19:53:46 · 132 阅读 · 0 评论 -
3. 链表(上) : 如何实现LRU缓存淘汰算法
链表底层的存储结构: 一、什么是链表? 1.和数组一样,链表也是一种线性表。 2.从内存结构来看,链表的内存结构是不连续的内存空间,是将一组零散的内存块串联起来,从而进行数据存储的数据结构。 3.链表中的每一个内存块被称为节点Node。节点除了存储数据外,还需记录链上下一个节点的地址,即后继指针next。二、为什么使用链表?即链表的特点 1.插入、删除数据效率高O(1)级别(只需更改指针指向...原创 2019-07-30 20:36:09 · 105 阅读 · 0 评论 -
4. 链表(下):如何优雅的写出链表代码?6大学习技巧
一、理解指针或引用的含义 1.含义:将某个变量(对象)赋值给指针(引用),实际上就是就是将这个变量(对象)的地址赋值给指针(引用)。 2.示例: p—>next = q; 表示p节点的后继指针存储了q节点的内存地址。 p—>next = p—>next—>next; 表示p节点的后继指针存储了p节点的下下个节点的内存地址。 二、警惕指针丢失和内存泄漏(单链表) 1.插入节点...原创 2019-07-31 10:02:24 · 95 阅读 · 0 评论 -
5. 栈:如何实现浏览器的前进和后退功能
一、什么是栈? 1.后进者先出,先进者后出,这就是典型的“栈”结构。 2.从栈的操作特性来看,是一种“操作受限”的线性表,只允许在端插入和删除数据。 二、为什么需要栈? 1.栈是一种操作受限的数据结构,其操作特性用数组和链表均可实现。 2.但,任何数据结构都是对特定应用场景的抽象,数组和链表虽然使用起来更加灵活,但却暴露了几乎所有的操作,难免会引发错误操作的风险。 3.所以,当某个数据集合只涉及在...原创 2019-08-01 10:13:15 · 159 阅读 · 0 评论 -
6. 队列:队列在线程池等有限资源池中的应用
一、什么是队列? 1.先进者先出,这就是典型的“队列”结构。 2.支持两个操作:入队enqueue(),放一个数据到队尾;出队dequeue(),从队头取一个元素。 3.所以,和栈一样,队列也是一种操作受限的线性表。 二、如何实现队列? 1.队列API public interface Queue<T> { public void enqueue(T item); //入队 publi...原创 2019-08-02 10:35:18 · 83 阅读 · 0 评论 -
8. 排序(上):为什么插入排序比冒泡排序更受欢迎
一、几种经典排序算法及其时间复杂度级别 二、如何分析一个排序算法? 1.学习排序算法的思路?明确原理、掌握实现以及分析性能。 2.如何分析排序算法性能?从执行效率、内存消耗以及稳定性3个方面分析排序算法的性能。 3.执行效率:从以下3个方面来衡量 1)最好情况、最坏情况、平均情况时间复杂度 2)时间复杂度的系数、常数、低阶:排序的数据量比较小时考虑 3)比较次数和交换(或移动)次数 4.内存消耗:...原创 2019-08-06 19:20:20 · 221 阅读 · 0 评论 -
9.排序(上) 如何用快排思想在O(n)内查找第K大元素
高快省的排序算法 有没有既不浪费空间又可以快一点的排序算法呢?那就是“快速排序”啦!光听这个名字是不是就觉得很高端呢。 假设我们现在对“6 1 2 7 9 3 4 5 10 8”这个10个数进行排序。首先在这个序列中随便找一个数作为基准数(不要被这个名词吓到了,就是一个用来参照的数,待会你就知道它用来做啥的了)。为了方便,就让第一个数6作为基准数吧。接下来,需要将这个序列中所有比基准数大的数放...原创 2019-08-27 11:18:24 · 217 阅读 · 0 评论 -
19. 红黑树(上):为什么工程中都用红黑树这种二叉树
我们依次讲了树、二叉树、二叉查找树。二叉查找树是最常用的一种二叉树,它支持快速插入、删除、查找操作,各个操作的时间复杂度跟树的高度成正比,理想情况下,时间复杂度是O(logn)。 不过,二叉查找树在频繁的动态更新过程中,可能会出现树的高度远大于log2n的情况,从而导致各个操作的效率下降。极端情况下,二叉树会退化为链表,时间复杂度会退化到O(n)。我上一节说了,要解决这个复杂度退化的问题,我们需...原创 2019-08-29 11:48:17 · 142 阅读 · 0 评论