原文链接: https://gobea.cn/blog/detail/p6aeO26N.html, 转载请注明出处!
二叉树的种类
满二叉树
如上图所示,满二叉树的性质如下:
- 除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树。
- 第k层上的节点数为: 2^(k-1)
- 一个层数为k的满二叉树的总结点数为: (2^k) - 1
完全二叉树
如上图所示,满二叉树的性质如下:
- 在满二叉树的基础上,最底层从右往左删去若干节点,得到的都是完全二叉树
- 最低层可以不满,但最底层的节点都必须集中在最左边,也就是说次底层的节点一定会有左子节点,但可能没有右子节点
如果对一棵有n个结点的完全二叉树的结点按层序编号, 则对任一结点i (1≤i≤n):
- 如果i=1, 则结点i是二叉树的根, 无双亲;如果i>1, 则i节点的父节点是i/2(取整,不四舍五入)
- 如果2i>n, 则结点i无左孩子, 否则其左孩子是结点2i;
- 如果2i+1>n, 则结点i无右孩子, 否则其右孩子是结点2i+1
平衡二叉树
- 树的左右子树的高度差不超过1的数
- 空树也是平衡二叉树的一种
二叉搜索树
- 二叉搜索树的特点:对于树中的每个节点,它的左子树中所有关键字值小于父节点关键字值,而它的右子树中所有关键字值大于父节点的关键字值。
- 根据这个性质,对一个二叉树进行中序遍历,如果是单调递增的,则可以说明这个树是二叉搜索树。
- 二叉搜索树可以用栈结构来实现,并不一定要用递归
b树
https://www.cnblogs.com/mayjors/p/11144874.html
b树是一种多路平衡查找树,每一个节点最多包含m个子节点,m被成为b树的阶,m的大小取决于磁盘页的大小,b树主要用于文件系统以及部分数据库索引,例如mongodb
- 最多有m个子节点,最少有m/2个子节点,m是b树的阶
- 每个节点有多个key,key数量比子节点少1(除叶子节点)
- 所有叶子节点都在同一层,并且是有序的
b树和二叉树的区别
- b树一个节点可以有多个子节点,而二叉树只能有两个
- mysql使用
b+树
是因为可以减少io次数,二叉树最坏情况下io次数等于树的高度 - b树是矮胖,二叉树是高瘦
- 如果一个页包含更多key,查询效率可能更快
b+树
b+树是b树的变种,具体如下:
- 每个节点的key数量等于子节点数量,每个key不保存数据,只保存索引,所有数据存储在子节点上
- 所有叶子节点包含了全部的key
- 在最底层,每一个叶子节点指向下一个叶子节点的指针,形成了一个有序链表
b树和b+树的区别
- b+树节点不包含数据,所有可以拥有更多的key,所以更加矮胖,io次数更少
- b+树一定会查找到叶子节点,查询性能稳定
- 支持范围查询
二叉树的遍历
前序遍历
先序遍历就是先访问根节点,在访问左节点,最后访问右节点
中序遍历
中序遍历就是先访问左节点,再访问根节点,最后访问右节点
后序遍历
后序遍历就是先访问左节点,再访问右节点,最后访问根节点
二叉树遍历代码
package main
import "fmt"
// 二叉树的数据结构
type TreeNode struct {
Data int
Left *TreeNode
Right *TreeNode
}
// 二叉树的实现
type Tree struct {
root *TreeNode
}
// 添加数据
func (self *Tree) Add(data int) {
var queue []*TreeNode
newNode := &TreeNode{Data:data}
if self.root == nil {
self.root = newNode
}else {
queue = append(queue, self.root)
for len(queue) != 0 {
cur := queue[0]
queue = append(queue[:0], queue[0+1:]...)
// 往右树添加
if data > cur.Data {
if cur.Right == nil {
cur.Right = newNode
} else {
queue = append(queue, cur.Right)
}
// 往左数添加
} else {
if cur.Left == nil {
cur.Left = newNode
} else {
queue = append(queue, cur.Left)
}
}
}
}
}
// 前序遍历 根 ---> 左 --->右
func (self *Tree )preorderTraverse(node *TreeNode) {
if node == nil {
return
} else {
fmt.Print(node.Data, " ")
self.preorderTraverse(node.Left)
self.preorderTraverse(node.Right)
}
}
// 中序遍历 左 ---> 根 --->右
func (self *Tree) inorderTraverse(node *TreeNode) {
if node == nil {
return
} else {
self.inorderTraverse(node.Left)
fmt.Print(node.Data, " ")
self.inorderTraverse(node.Right)
}
}
// 后序遍历 左 ----> 右 ---> 根
func (self *Tree) postTraverse(node *TreeNode) {
if node == nil {
return
} else {
self.postTraverse(node.Left)
self.postTraverse(node.Right)
fmt.Print(node.Data, " ")
}
}
func main() {
tree := &Tree{}
tree.Add(50)
tree.Add(45)
tree.Add(40)
tree.Add(48)
tree.Add(51)
tree.Add(61)
tree.Add(71)
fmt.Println("前序遍历")
tree.preorderTraverse(tree.root)
fmt.Println("")
fmt.Println("中序遍历")
tree.inorderTraverse(tree.root)
fmt.Println("")
fmt.Println("后续遍历")
tree.postTraverse(tree.root)
}
以上代码来源于: https://blog.csdn.net/lucky404/article/details/92440857
参考
- https://gobea.cn/blog/detail/p6aeO26N.html
- https://www.cnblogs.com/mayjors/p/11144874.html
- https://blog.csdn.net/lucky404/article/details/92440857
说明: 以上图片来源于网络
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。