常用基础数据结构
优秀的算法取决于用哪种数据结构,因此我们这里大概回顾一下编程语言中最基础的数据结构,并分享一点自己的心得体会,学习算法与数据结构,与其说是通过学习实用技巧来解决问题,不如说是在遇到问题时,我们的一个思考思路与思想。
General view
- 数据与字符串
- 链表
- 栈
- 队列与双端队列
- 树🌲
Array && String
数组和字符串是最基本的数据结构,数组中的每个元素都有一个对应的下标,同样的,我们在构建一个数组时要提前指定长度,为其分配一段连续的存储空间。 常用于元素个数确定而很少添加删除的场景。
关键词:定长,下标,查找
优点:
- 构建非常简单
- 能在 O(1) 的时间里根据数组的下标(index)查询某个元素
缺点:
- 构建时必须分配一段连续的空间
- 查询某个元素是否存在时需要遍历整个数组,耗费 O(n) 的时间(其中,n 是元素的个数)
- 删除和添加某个元素时,同样需要耗费 O(n) 的时间
例题:
常见的题目有反转字符串,leetcode242
LinkedList
单链表:链表中的每个元素实际上是一个单独的对象,而所有对象都通过每个元素中的引用字段链接在一起。双链表:与单链表不同的是,双链表的每个结点中都含有两个引用字段。常用于元素个数不确定,频繁添加删除。
关键词:非定长,指针(引用),添加删除
优点:
- 链表能灵活地分配内存空间;
- 能在 O(1) 时间内删除或者添加元素,前提是该元素的前一个元素已知,当然也取决于是单链表还是双链表,在双链表中,如果已知该元素的后一个元素,同样可以在 O(1) 时间内删除或者添加该元素。
缺点:
- 不像数组能通过下标迅速读取元素,每次都要从链表头开始一个一个读取;
- 查询第 k 个元素需要 O(k) 时间。
例题:
常用的解法如 快慢指针,构建虚假链表头,例题如leetcode 24,25
Stack
栈常用于后进先出的应用场景。即只能向栈顶压入元素,从栈顶弹出元素,常常使用一个单链表来实现,链头指针指向栈顶元素。 常用于在解决某个问题的时候,只要求关心**最近一次**的操作,并且在操作完成了之后,需要向前**查找到更前一次**的操作。
关键词:后入先出 ,最近操作
例题:
leetcode20,739
Queue && Dequeue
队列常用于先进先出,即顺序的应用场景。即我们只能在队尾添加元素,从队头删除元素。当我们需要按照一定的顺序来处理数据,而该数据的数据量在不断地变化的时候,则需要队列来帮助解题。在算法面试题当中,广度优先搜索(Breadth-First Search)是运用队列最多的地方。
双端队列允许在队列两端进行添加于删除操作。
关键词:先入先出,顺序处理,数据量变化
例题:
Leetcode239
Tree
树的结构十分直观,而树的很多概念定义都有一个相同的特点:递归,也就是说,一棵树要满足某种性质,往往要求每个节点都必须满足。例如,在定义一棵二叉搜索树时,每个节点也都必须是一棵二叉搜索树。在面试中常考的树的形状有:普通二叉树、平衡二叉树、完全二叉树、二叉搜索树、四叉树(Quadtree)、多叉树(N-ary Tree)。树的以下三种遍历方式一定要熟练掌握,掌握后才能真正理解🌲数据结构的思想。
前序遍历
方法:先访问根节点,然后访问左子树,最后访问右子树。在访问左、右子树的时候,同样,先访问子树的根节点,再访问子树根节点的左子树和右子树,这是一个不断递归的过程。
常用于树的搜索以及创建新树。
中序遍历
方法:先访问左子树,然后访问根节点,最后访问右子树,在访问左、右子树的时候,同样,先访问子树的左边,再访问子树的根节点,最后再访问子树的右边。
最常见的是二叉搜素树,由于二叉搜索树的性质就是左孩子小于根节点,根节点小于右孩子,对二叉搜索树进行中序遍历的时候,被访问到的节点大小是按顺序进行的。
后序遍历
先访问左子树,然后访问右子树,最后访问根节点。
在对某个节点进行分析的时候,需要来自左子树和右子树的信息。收集信息的操作是从树的底部不断地往上进行,好比你在修剪一棵树的叶子,修剪的方法是从外面不断地往根部将叶子一片片地修剪掉。
关键词:递归
例题:
leetcode230
Review
在我看来,大部分的复杂数据结构都由上述基本数据结构实现,底层基础决定了上层建筑,并且各个数据结构特点鲜明,我们应多练多思考,这样才能理解相应数据结构的构建思想,找到其中的通性与规律,这样一来,融汇贯通,能帮助我们解决很多问题。