吴军的硅谷来信-数据结构

558 阅读6分钟

几何结构

美杜莎之筏

image.png

image.png

有时候我们看那些好的作品,总觉得好,但有说不出是哪里好。 其实牛b的画家在绘图之前,都会把内容抽象成对应的几何图图形。如上图整个构图是有两个三角形,让画面保存了平衡。

那么当我们撸代码的时候,看到需求原型的时候,也应该先把内容抽象成某种结构,再从结构上搭建代码。

这种结构就叫做:“数据结构”

《数据结构+算法=程序》pascal作者出版,可见数据结构的重要性

线性表

相当于几何图形中的直线,是最基本的数据结构,是有序的,如学生档案。

数组

  • 定义:编了号的固定大小单元。
  • 优化:可以直接索引到具体的行,如arr = ['a','b','c','d'],找到d只需要 arr[3]直接索引访问
  • 缺点:数据插入非常麻烦,会导致这个数据重新调整。

链表

  • 链表的每一个节点只关心下一个节点内容。所以插入数据非常方便,如:a->b,b->c,c->d, 这时候如果插入e到b后面,只需要把b->指向e,e->指向c,就完成插入。
  • 缺点:不能直接找到某一个元素,如想找到d,必须从a开始一个个往下找。

二叉树

在我们生活中到底是具体的数值重要,还是相对大小重要?

  • 在生活中钱数值越大,当然越重要,但是在比赛中第一名永远是相对于其他对手,所以相对重要。
  • 在计算机里是相对是最重要的。

因为计算机经常要做的就是:判断真假,比较大小,排序,挑选最大值。

image.png

  1. 先来的占据根部,以及靠近根节点较高位置,后来的相对靠下(同一方向子节点都必须补齐,才能继续往下发展子节点)
  2. 每个分支都和根比较大小,小的放左边,大的放右边。

例子

[3,5,-2,0,6]

image.png

最终只需要把二叉树上的内容,从左边往右依次取出即可。

在网站中,目录结构也是树形结构,如果我们找到一个网站后,要下载他所有内容,只需要通过二叉树来进行算法遍历。

锦标赛排序算法

image.png

高盛面试题:

假定有二十五名短跑选手比赛竞争金银铜牌,赛场上有五条赛道,因此一次可以有五个人同时比赛。比赛并不计时,只看相应的名次。假如选手的发挥是稳定的,也就是说如果约翰比张三跑得快,张三比凯利跑得快,那么约翰一定比凯利跑得快。最少需要几组比赛才能决出前三名?

对应成表格如下: image.png

需要注意:输给a1的a2不一定都输给其他组的第一名的情况

方案1

  1. 找到第一名很容易,只需要a-e组各比一次共5次,比出的结果(a1,b1,c1,d1,e1)再比一次就能找到NO.1,共6次
  2. 找第二名,则需要把输给a的b1,c1,d1,e1和a2比较。 共1次
  3. 如果b1才是第一,则把剩下的 b2,c1,d1,e1,a2。共1次 最终是8次能找出前三名

方案2

  1. 找到第一名很容易,只需要a-e组各比一次共5次,比出的结果(a1,b1,c1,d1,e1)再比一次就能找到NO.1,共6次
  2. 把有可能参加2-3名的名单才列入比赛
  • (1) 由于第6次找到No.1的时候,已经确定,d1,e1是排在第4,5名所有重新比较可以把他们忽略。
  • (2) 剩下有可能做第二名的是 输给a1的a2,b1,c1(当然三个里面,除了赢得,剩下的可能是第三名)
  • (3) 剩下有可能做第三名的是 输给a2后面的a3,b1后面的b2

image.png

这样只需要把a2,a3,b1,b2,c1一起比较一次,就能得出前三名, 第六次。

总结:

  1. 比较的时候,要善用已经生成的信息,前6次比赛已经列出前3名的候选。
  2. 要少做一些无用工,由于d1,e1已经是是确定不在候选,所以后面的比较不应该把d1,e1也放进去比较。

谷歌面试题:

如何设计一个地图功能,找到离当前最近的加油站?

  1. 确定信息: 首先我们假定汽车是通过gps定位,加油站的信息也是通过gps已经收集好的。由于汽车是移动的,所以算法需要足够的快才支持快速的响应。

  2. 距离计算。使用动态规划,找出单个搜索的最佳路径。

  3. 所有路线进行排序,然后推荐给用户最优的几个方案: 比如深圳附近有100的加油站,每一个加油站都有对应的方案,要找到最近,则需要对所有加油站的路线进行排序,取最前面,则每次排序的量级会很大。这里关键在于用户只关心前几名,不关系后面的内容。可以使用“堆排序”,优化排序。

  4. 全局优化:比如A用户在Z的位置找加油站的需求,跟B用户在Z位置找加油站的需求是一样的。所以每次查询后,都应该把推荐的信息记录存储下来,下次再次发起一样的请求,可以直接返回已经记录号的信息。

大数据思维:不能像过去那样,只把事情看成彼此独立事件,分开处理,而是把所有数据集中起来,全局优化

如何找中值问题

假如有一个巨大的数组(你可以理解成一串数字),如何用最有效的方法找到它的中值?

  • 中值不是平均值。比如1,4,9,100,0 中值是4,其实就是中间位置的值。当然如果总长度是偶数,则有两个中值。
  • “巨大”是指数据量很大的数据。
  • “最有效”,要找最好办法

如有:[1,-5,3,7,1000,2,-10]

方案1 排序

  • 直接顺序排序后是
  • [-10,-5,1,2,3,7,1000]
  • 然后取中间的值是 2

方案2

利用堆排序可以只排到中间大就ok,节省一半空间。

方案2 划分

在数组里先随机取出一个值,然后与左右值比较,大于小于各分两边。如果左边等于右边则找到,如果一边大一边小,则取大的一边。再大的一边继续往下找,知道某一个值左边有没有值,或者右边没有值证明是中值。 比如:

  • (1) 取出随机数1,分成两个数组,小于1 [-5,-10] A数组, 大于1[3,7,2,1000]B数组,这时候中值肯定在B数组里面,不在A数组-5,-10和1
  • (2) 在数组B [3,7,1000,2]里面再取出随机数7,则小于7 [1,-5,3,2,-10]C数组, 大于7[1000]D数组。 那么中值肯定在C数组,不在7和1000.
  • (3)那么有效数组就可以排除掉[-5,-10,1]和[7,1000],就只剩下[3,2],再套入3 发现还不是中间,再套入2,发现刚好在中间。 则2为中值