今天给大家开始介绍前端方面的数据结构,刚把vue源码过完就开始数据结构,可见它的地位有多重要。有人说我一前端又不是后端学这个数据结构干嘛,好吧,只能说你还没有这个意识,一是面试很多大厂就会考察,我面试别人也会出一些简单算法题来做,以此考察逻辑能力以及js基础能力。二是当你写逻辑方面代码时候,明明可以一层for循环搞定,非要三层for循环,这里就凸显巧用数据结构的好处了。闲话不多说,直接上来二分搜索。
一 二分搜索
所谓二分查找,就是在有序表中,每次都让被查找数据与当前表的中间结点进行比较,根据比较结果“舍弃”掉以中间结点划分的某一半子表。
总结出来它的基本逻辑: 优先和数组的中间元素比较,如果等于中间元素,则直接返回。如果不等于则取半继续查找。
适用场景:假设现在有一个数组,数组中的数据按照某个关键字排好了序,现在我们希望判断某个数据是否已存在于数组中,怎么样做才更快?
总结出来它的适应场景: 数组 有序
基本二分查找有 非递归版本 和 递归版本
由上的方法我们可以总结出二分查找的几个特点:
1 每次我们都将表的大小减半,也就是除以二 ;
2 最坏情况下我们要一直“除以2”直到表只剩下一个元素;
3 二分查找花费的时间关键点就是比较了多少次,而比较的次数在最坏情况下就是表的大小n不断除以2直至n为1的次数。这样以来我们很快就能得出二分查找的时间复杂度:O(log2N) ;
那如果我们想要表的大小能够动态的变化,并且数据具有层级用什么来表示呢?没错,二叉树。
在树结构中,每一个结点只有一个前件,称为父结点,没有前件的结点只有一个,称为树的根结点,简称树的根(root)。每一个结点可以有多个后件,称为该结点的子结点。没有后件的结点称为叶子结点。一个结点所拥有的子结点的个数称为该结点的度,所有结点中最大的度称为树的度。树的最大层次称为树的深度。
同时,我们还可以看到一些基本的树的特点:
每个节点的键值大于左孩子,每个节点的键值大于右孩子。以左右孩子为根的子树仍然为二分搜索树。
二叉树是一种特殊的树,它的子节点个数不超过两个,且分别称为该结点的左子树(left subtree)与右子树(right subtree),二叉树常被用作二叉查找树和二叉堆或是二叉排序树(BST)。
二 二叉树的插入
那么现在我们就用javascript来时实现一个简单的二叉搜索树。
首先我们创建一个Node类,用于存放树的节点。首先要添加新的节点,首先需要创建一个Node对象,将数据传入该对象。 其次要检查当前的BST树是否有根节点,如果没有,那么表示是一棵新数,该节点就为该树的根节点,那么插入这个过程就结束了;否则,就要继续进行下一步了。 如果待插入节点不是根节点,那么就必须对BST进行遍历,找到合适的位置。该过程类似遍历链表,用一个变量存储当前节点,一层一层遍历BST,算法如下:
- 设值当前节点为根节点
- 如果待插入节点保存的数据小于当前节点,则新节点为原节点的左节点,反之,执行第4步
- 如果当前节点的左节点为null,就将新节点放到这个位置,退出循环;反之,继续执行下一次循环
- 设置新节点为原节点的右节点
- 如果当前节点的右节点为null,就将新节点放到这个位置,退出循环;反之,继续执行下一次循环
这样,就能保证每次添加的新节点能够放到正确的位置上.
三 二插树的查找
查找通常分为三种情况 查找最小值 查找最大值 查找定值
1 查找定值:
如果找到就返回该值,未找到就返回null;
2 查找最小值
3 查找最大值
三 二叉树 的循环遍历
循环遍历分为 前序遍历 中序遍历 后序遍历
我们首先构造一个树
1 前序遍历
2 中序遍历
3 后序遍历
4 广度优先遍历
四 二叉树 删除节点
删除节点的思路大致如下:
首先判断当前节点是否包含待删除的数据,如果包含,则删除该节点;如果不包含,则比较当前节点上的数据和待删除树的的大小关系。如果待删除的数据小于当前节点的数据,则移至当前节点的左子节点继续比较;如果大于,则移至当前节点的右子节点继续比较。 如果待删除节点是叶子节点(没有子节点),那么只需要将从父节点指向它的链接指向变为null; 如果待删除节点含有一个子节点,那么原本指向它的节点需要做调整,使其指向它的子节点; 最后,如果待删除节点包含两个子节点,可以选择查找待删除节点左子树上的最大值或者查找其右子树上的最小值,这里我们选择后一种。
至此,我们基本操作方法已经分析完了,快来动手实践下吧。