「上层建筑」与「结构基础」~不被迷惑

数据结构的存储方式

数据结构的存储方式只有两种:数组(顺序存储)和链表(链式存储).

我们分析问题,一定要有递归的思想,自顶向下,从抽象到具体.散列表、栈、队列、堆、树、图等这些都属于「上层建筑」,而数组和链表才是「结构基础」.因为那些多样化的数据结构,究其源头,都是在链表或者数组上的特殊操作,API 不同而已

底层存储无非数组或者链表,二者的优缺点如下:
数组由于是紧凑连续存储,可以随机访问,通过索引快速找到对应元素,而且相对节约存储空间.但正因为连续存储,内存空间必须一次性分配够,所以说数组如果要扩容,需要重新分配一块更大的空间,再把数据全部复制过去,时间复杂度 O(N);而且你如果想在数组中间进行插入和删除,每次必须搬移后面的所有数据以保持连续,时间复杂度 O(N).更适合查询操作.
链表因为元素不连续,而是靠指针指向下一个元素的位置,所以不存在数组的扩容问题;如果知道某一元素的前驱和后驱,操作指针即可删除该元素或者插入新元素,时间复杂度 O(1).但是正因为存储空间不连续,你无法根据一个索引算出对应元素的地址,所以不能随机访问;而且由于每个元素必须存储指向前后元素位置的指针,会消耗相对更多的储存空间.更适合增加和删除操作.

数据结构的基本操作

对于任何数据结构,其基本操作无非遍历 + 访问,再具体一点就是:增删查改。数据结构种类很多,但它们存在的目的都是在不同的应用场景,尽可能高效地增删查改,这就是数据结构的使命

如何遍历 + 访问?我们仍然从最高层来看,各种数据结构的遍历 + 访问无非两种形式:线性的和非线性的。
线性就是 for/while 迭代为代表,非线性就是递归为代表。

线性遍历是一个框架,非线性遍历是一个框架,非线性遍历的结构,遍历框架都是一致的.所谓框架,就是套路.不管增删查改,这些代码都是永远无法脱离的结构,你可以把这个结构作为大纲,根据具体问题在框架上添加代码就行了

算法刷题指南

首先要明确的是,数据结构是工具,算法是通过合适的工具解决特定问题的方法.也就是说,学习算法之前,最起码得了解那些常用的数据结构,了解它们的特性和缺陷.

从框架上看问题,就是像我们这样基于框架进行抽取和扩展,既可以在看别人解法时快速理解核心逻辑,也有助于找到我们自己写解法时的思路方向.当然,如果细节出错,你得不到正确的答案,但是只要有框架,你再错也错不到哪去,因为你的方向是对的.但是,你要是心中没有框架,那么你根本无法解题,给了你答案,你也不会发现这就是个树的遍历问题.这种思维是很重要的

动态规划详解中总结的找状态转移方程的几步流程,有时候按照流程写出解法,说实话我自己都不知道为啥是对的,反正它就是对了.这就是框架的力量,能够保证你在快睡着的时候,依然能写出正确的程序,就算你啥都不会,都能比别人高一个级别.

刷算法题建议从「树」分类开始刷,结合框架思维,把这几十道题刷完,对于树结构的理解应该就到位了。这时候去看回溯、动规、分治等算法专题,对思路的理解可能会更加深刻一些。为什么要先刷二叉树呢,因为二叉树是最容易培养框架思维的,而且大部分算法技巧,本质上都是树的遍历问题.不要小看这几行破代码,几乎所有二叉树的题目都是一套这个框架就出来了.
void traverse(TreeNode root) {
// 前序遍历
traverse(root.left)
// 中序遍历
traverse(root.right)
// 后序遍历
}

Hard 难度的题目不过如此,而且还这么有规律可循,只要把框架写出来,然后往相应的位置加东西就行了,这不就是思路吗.对于一个理解二叉树的人来说,刷一道二叉树的题目花不了多长时间.那么如果你对刷题无从下手或者有畏惧心理,不妨从二叉树下手,前10道也许有点难受,结合框架再做20道,也许你就有点自己的理解了,刷完整个专题,再去做什么回溯动规分治专题,你就会发现只要涉及递归的问题,都是树的问题.其实很多动态规划问题就是在遍历一棵树,你如果对树的遍历操作烂熟于心,起码知道怎么把思路转化成代码,也知道如何提取别人解法的核心思路.
总结:
数据结构的基本存储方式就是链式和顺序两种,基本操作就是增删查改,遍历方式无非迭代和递归。

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页