数据结构与算法之美
supreme_1
这个作者很懒,什么都没留下…
展开
-
17.跳表
17.跳表:为什么Redis一定要用跳表来实现有序集合?markdown文件已上传至github因为二分查找底层依赖的是数组随机访问的特性,所以只能用数组来实现。如果数据存储在链表中,我们只需要对链表稍加改造,就可以支持类似“二分”的查找算法。我们把改造之后的数据结构叫做跳表(Skip list)。跳表:是一种各方面性能都比较优秀的动态数据结构,可以支持快速地插入、删除、查找操作,写起来也不复杂,甚至可以替代红黑树(Red-black tree)。1.如何理解“跳表”?单链表中即使存储的数据有序,原创 2020-08-11 17:30:09 · 375 阅读 · 0 评论 -
16.二分查找(下):二分查找的变体
16.二分查找(下):如何快速定位IP对应的省份地址?markdown文件已上传至github打开百度,在搜索框里随便输一个 IP 地址,就会看到它的归属地。它是通过维护一个很大的 IP 地址库来实现的。地址库中包括 IP 地址范围和归属地的对应关系。当我们想要查询 $202.102.133.13 这个IP地址的归属地时,我们就在地址库中搜索,发现这个IP地址落在这个 IP 地址的归属地时,我们就在地址库中搜索,发现这个 IP 地址落在这个IP地址的归属地时,我们就在地址库中搜索,发现这个IP地址落原创 2020-08-11 00:31:50 · 243 阅读 · 0 评论 -
15.二分查找(上)
15.二分查找(上):如何用最省内存的方式实现快速查找功能?markdown文件已上传至github假设我们有 1000 万个整数数据,每个数据占 8 个字节,如何设计数据结构和算法,快速判断某个整数是否出现在这 1000 万数据中? 我们希望这个功能不要占用太多的内存空间,最多不要超过 100MB,你会怎么做呢?1.二分查找二分查找针对的是一个有序的数据集合,查找思想有点类似分治思想。每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为 0。二分原创 2020-08-10 15:32:44 · 556 阅读 · 0 评论 -
14.排序优化
14.排序优化:如何实现一个通用的、高性能的排序函数?markdown文件已上传至github1.如何选择合适的排序算法线性排序算法的时间复杂度比较低,使用场景比较特殊,所以实现通用的排序算法不能选择线性排序算法。对小规模数据可以选择时间复杂度为O(n2)O(n^2)O(n2)的算法,对大规模数据进行排序选择O(nlogn)O(nlogn)O(nlogn)的排序算法。所以为了兼顾任意规模数据的排序一般都会首选时间复杂度为O(nlogn)O(nlogn)O(nlogn)的算法来实现排序函数。时间复原创 2020-08-10 10:58:41 · 205 阅读 · 0 评论 -
13.线性排序
13.线性排序:如何根据年龄给100万用户数据排序?markdown文件已上传至github桶排序、计数排序、基数排序的时间复杂度都为O(n),所以称为线性排序。之所以能做到线性的时间复杂度,主要原因是这三个算法都不是基于比较的排序算法,都不涉及元素之间的比较操作。思考:如何根据年龄给100万用户排序?归并、快排能够解决这个问题,最快时间复杂度也是O(nlogn),有没有更快的排序方法呢?1.桶排序核心思想是将要排序的数据分到几个有序的桶里,每个桶里的数据再单独进行排序。桶内排完序之后,再把每原创 2020-08-09 23:27:39 · 222 阅读 · 0 评论 -
12.排序(下)
12.排序(下):如何用快排思想在O(n)内查找第K大元素?markdown文件已上传至github冒泡排序、选择排序、插入排序的时间复杂度都是O(n^2),适合小规模数据的排序。这一节介绍两种时间复杂度为O(nlogn)O(nlogn)O(nlogn)的排序算法,归并排序和快速排序。这两种排序算法适合大规模的数据排序,更常用,它们都用了分治的思想,可以借鉴这个思想来解决排序的问题,比如:如何在O(n)O(n)O(n)的时间复杂度内查找一个无序数组中第K大元素?1.归并排序的原理核心思想:先把数组从原创 2020-08-06 11:42:49 · 177 阅读 · 0 评论 -
11.排序(上)
11.排序(上):为什么插入排序比冒泡排序更受欢迎?markdown文件已上传至github按照时间复杂度将排序分三节课来讲。带着问题去学习,是最有效的学习方法。所以,先给出一个思考题:插入排序和冒泡排序的时间复杂度相同,都是O(n2)O(n^2)O(n2),在实际的软件开发里,为什么我们更倾向于使用插入排序,而不是冒泡排序?1.如何分析一个排序算法?从以下几个方面入手:1.1 排序算法的执行效率。对于排序算法的执行效率,我们一般从这几个方面来衡量:1.1.1 最好情况、最坏情况、平均情原创 2020-08-02 17:00:49 · 242 阅读 · 0 评论 -
10.如何写递归代码
10.递归:如何用三行代码找到“最终推荐人”?markdown文件已上传至github推荐注册佣金这个功能大家应该都不陌生吧。用户A推荐用户B来注册,B推荐C注册。这里,用户B和用户C的最终“推荐人”都为用户A,用户A没有最终“最终推荐人”。可以用数据库来记录这种推荐关系。在数据库表中,我们可以记录两行数据,actor_id表示用户ID,referrer_id表示推荐人ID。**给定一个用户ID,如何查找这个用户的“最终推荐人”?解决这个问题,可以用递归。1.如何理解递归?周末带着女朋友去看原创 2020-07-31 14:41:38 · 3484 阅读 · 0 评论 -
09.队列
09.队列:队列在线程池等有限资源池中的应用markdown文件已上传至githubCPU资源是有限的,任务的处理速度与线程个数并不是线性正相关的。过多的线程反而会导致CPU频繁切换,处理性能下降。所以线程池的大小一般都是综合考虑要处理任务的特点和硬件环境,来事先设置的。当我们向固定大小的线程池中请求一个线程时,如果线程池中没有空闲资源了,这时候线程池如何处理这个请求?是拒绝请求还是排队请求?各种处理策略又是怎么实现的?这个问题就要用带队列。1.如何理解“队列”?可以想象成排队买票,先来的先买,原创 2020-07-30 00:50:48 · 151 阅读 · 0 评论 -
08.栈
08.栈:如何实现浏览器的前进和后退功能?markdown文件已上传至github浏览器的前进后退功能:当你访问完一系列页面a-b-c,点击浏览器的后退按钮,就可以查看之前浏览过的页面b和a.当你后退到a页面,点击前进按钮,就可以重新查看页面b和c。但是,如果你后退到页面b,点击了新页面d后,就无法再通过前进、后退功能查看页面c了。那么如何实现这个功能呢?这就要用到”栈“这种数据结构了。1.如何理解“栈”?可以把栈比喻成一叠盘子,放盘子的时候从下往上放,取盘子的时候从上往下取。特点:先进后出,后原创 2020-07-29 21:39:52 · 808 阅读 · 0 评论 -
07.链表(下)
07.链表(下):如何轻松写出正确的链表代码?markdown文件已上传至github1.理解指针或引用的含义有些语言有“指针”的概念,如C语言;有些语言没有指针的概念,取而代之的是’'引用“,如Java、Python;不管是“指针”还是“引用”,它们的意思都是一样的,都是存储所指对象的内存地址。将某个遍历赋值给指针,实际上就是将这个变量的地址复制给指针。指针中存储了这个变量的内存地址,通过指针就能找到这个变量。p–>next =q,指p结点中的next指针存储了q结点的内存地址。p–原创 2020-07-26 14:56:43 · 173 阅读 · 0 评论 -
06.链表(上)
06.链表(上)markdown文件已上传至github缓存是一种提高数据读取性能的技术,在硬件设计、软件开发中都有着非常广泛的应用,比较常见的有CPU缓存、数据库缓存、浏览器缓存等等。当缓存被用满时哪些数据应该被清理出去,哪些数据应该被保留,是由缓存淘汰策略来决定的,常见策略有三种:先进先出策略FIFO(First In,First Out)、最少使用策略LFU(Least Frequently Used)、最近最少使用策略LRU(Least Recently Used)。1.五花八门的链表结构原创 2020-07-25 23:58:41 · 182 阅读 · 0 评论 -
05.数组是什么
05.数组:为什么很多很多编程语言中数组都从0开始编号?markdown文件已上传至github1.什么是数组数组(Array)是一种线性表数据结构,它用一组连续的内存空间,来存储一组具有相同类型的数据。2.理解数组理解以下几个关键词,就能彻底掌握数组的概念了。2.1 线性表**线性表(Linear List)????*线性表就是数据排成像一条线一样的结构。每个线性表上的数据最多只有前和后两个方向。除了数组,链表、队列、栈等也是线性结构。与之相对立的概念是非线性表,比如二叉树、堆、图等。在非原创 2020-07-25 00:11:23 · 232 阅读 · 0 评论