数据结构
栈
特点:后进先出,先进后出
队列
特点:先进先出,后进后出
数组
特点:查询快,增删慢
- 查询速度快:查询数据通过地址值和索引定位,查询任意数据耗时相同。(元素在内存中是连续存储的)
- 删除效率低:要将原始数据删除,同时后面每个数据前移。
- 添加效率较低:添加位置后的每个数据后移,再添加元素。
链表
链表由一个个的结点组成,链表中的结点是独立的对象,在内存中是不连续的。每个结点包括数据和地址两部分:前面是数据,后面是下一个结点的地址。
特点:查询慢,增删快
单向链表
查找时从头到尾,并且一个结点只有数据和后一结点的地址。
双向链表
查找时先分析,要查找的离头近还是离尾近,再进行查找。此时一个结点包含数据,前一结点地址和后一节点地址。
树
树由许多的节点组成,最上层的节点被称为根,最下层的节点被称为叶。
此外,上下层结点间又分为父节点和子节点的关系,一个父节点可以拥有两个子节点:左子结点和右子节点。
在一个节点中,包含:
- 父节点地址
- 值
- 左子节点地址
- 右子节点地址
根没有父节点地址,叶没有子节点地址。
二叉树
定义:任意节点的度<=2的树
- 度:每个节点的子节点数量
- 树高:树的总层数
二叉查找树
定义:二叉查找树,又称二叉排序树或者二叉搜索树
特点:
- 每一个节点上最多有两个子节点
- 任意节点左子树上的值都小于当前节点
- 任意节点右子树上的值都大于当前节点
添加规则:小的存左边,大的存右边,一样的不存。
查找规则:逐一比较,比根小的查左边,比根大的查右边。
遍历方式:
-
前序遍历:当前节点,左子节点,右子节点
-
中序遍历:左子节点,当前节点,右子节点
-
后序遍历:左子节点,右子节点,当前节点
-
层序遍历:一层一层去遍历
弊端:若添加的节点一个比一个大,最后会形成链表而非树。
平衡二叉树
规则:任意节点左右子树高度差不超过1
注意,这里的“任意”指的是这个数中的任意,而非有关联的任意,也就是说根也需要算入其中。
平衡二叉树旋转机制
这个机制是用来保证平衡二叉树的规则能够正常成立的。
- 规则1:左旋
- 规则2:右旋
- 触发时机:当添加一个节点之后,该树不再是一颗平衡二叉树。
左旋
核心:
确定支点:从添加的节点开始,不断地往父节点找不平衡的节点。
- 支点没有左子结点:
- 以不平衡的点为支点
- 把支点左旋降级,变成左子结点
- 晋升原来的右子节点
通俗一点理解可以是,一个正级干部犯了错,破坏了平衡,就得被降级,然后他之前的下一级干部上来顶替他的位置。
- 支点有左子结点:
- 以不平衡的点作为支点
- 将根节点的右侧往左拉
- 原先的右子节点变成新的父节点,并把多余的左子结点出让,给已经降级的根节点当右子节点。
右旋
核心与左旋一致。
- 支点没有右子节点:
- 以不平衡的点为支点
- 把支点右旋降级,变成右子结点
- 晋升原来的左子节点
- 支点有右子节点:
- 以不平衡的点作为支点
- 将根节点的左侧往右拉
- 原先的左子节点变成新的父节点,并把多余的右子结点出让,给已经降级的根节点当左子节点。
需要旋转的四种情况
- 左左:当根节点左子树的左子树有节点插入,导致不平衡
一次右旋。
- 左右:当根节点左子树的右子树有节点插入,导致不平衡
在这里我们需要将左右转换成左左,再去进行右旋才能平衡。
- 右右:当根节点右子树的右子树有节点插入,导致不平衡
一次左旋。
- 右左:当根节点右子树的左子树有节点插入,导致不平衡
先将右左转换成右右,也就是进行一次局部右旋,再去进行左旋。
红黑树
基本概念
- 红黑树是一种自平衡的二叉查找树,是计算机科学中用到的一种数据结构。
- 它是一种特殊的二叉查找树,红黑树的每一个节点上都有存储位表示节点的颜色。
- 每一个节点可以是红或者黑,红黑树不是高度平衡的,它的平衡是通过“红黑规则”进行实现的。
- 红黑树增删改查的性能都很好。
红黑规则
- 每一个节点是红色或者黑色的
- 根节点必须是黑色
- 如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个都是黑色的。
- 如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
- 对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点。
添加规则
默认颜色:添加节点默认是红色的(效率高)
解释:若添加三个节点(包括根节点),默认是黑色时,我们需要把另外两个非根节点调整为红色,也就是2次;但默认是红色时,我们只需要把根节点调整为黑色,也就是1次。
根:直接变为黑色
非根:
情况一:父节点为黑色
不做任何操作。
情况二:父节点为红色
- 叔叔红色
- 将“父”设为黑色,将“叔叔”设为黑色
- 将“祖父”设为“红色”
- 如果祖父为根,再将根变为黑色
- 如果祖父非根,将祖父设置为当前节点再进行其他判断
- 叔叔黑色,当前节点是父的右孩子
- 把父作为当前节点并左旋,再进行判断
- 叔叔黑色,当前节点是父的左孩子
- 将“父”设为“黑色”
- 将“祖父”设为“红色”
- 以祖父为支点进行右旋