在了解二叉树以前,首先咱们得有树的概念。java
树是一种数据结构又可称为树状图,如文档的目录、HTML的文档树都是树结构,它是由n(n>=1)个有限节点组成一个具备层次关系的集合。把它叫作“树”是由于它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具备如下的特色:node
有关树的一些相关术语:算法
树的种类有:无序树、有序树、二叉树、霍夫曼树。其中最重要应用最多的就是二叉树,下面咱们来学习有关二叉树的知识。数据库
二叉树的定义为度不超过2的树,即每一个节点最多有两个叉(两个分支)。上面那个例图其实就是一颗二叉树。数据结构
二叉树有两个特殊的形态:满二叉树和彻底二叉树app
满二叉树ide
一个二叉树,若是除了叶子节点外每个层的结点数都达到最大值,则这个二叉树就是满二叉树。post
彻底二叉树学习
叶节点只能出如今最下层和次下层,而且最下面一层的结点都集中在该层最左边的若干位置的二叉树为彻底二叉树。即右边的最下层和次下层能够适当缺一个右子数spa
彻底二叉树是效率很高的数据结构
二叉树的遍历
二叉树的链式存储:将二叉树的节点定义为一个对象,节点之间经过相似链表的连接方式来链接。
二叉树结点的定义
#二叉树结点的定义 class BiTreeNode: def __init__(self, data): self.data = data self.lchild = None self.rchild = None
二叉树的遍历分为四种——前序遍历、中序遍历、后序遍历和层级遍历
设树结构为:
四种遍历方法的代码实现:
from collections import deque #结点的定义 class BiTreeNode: def __init__(self, data): self.data = data self.lchild = None self.rchild = None #二叉树结点 a = BiTreeNode('A') b = BiTreeNode('B') c = BiTreeNode('C') d = BiTreeNode('D') e = BiTreeNode('E') f = BiTreeNode('F') g = BiTreeNode('G') #结点之间的关系 e.lchild = a e.rchild = g a.rchild = c c.lchild = b c.rchild = d g.rchild = f root = e #前序遍历:先打印根,再递归左孩子,后递归右孩子 def pre_order(root): if root: print(root.data, end='') pre_order(root.lchild) pre_order(root.rchild) #中序遍历:以根为中心,左边打印左子树,右边打印右子树(注意,每一个子树也有相应的根和子树) #(ACBD) E (GF)-->(A(CBD)) E (GF)-->(A (B C D)) E (G F) def in_order(root): if root: in_order(root.lchild) print(root.data, end='') in_order(root.rchild) #后序遍历:先递归左子树,再递归右子数,后打印根(注意,每一个子树也有相应的根和子树) # (ABCD)(GF)E-->((BCD)A)(GF)E-->(BDCA)(FG)E def post_order(root): if root: post_order(root.lchild) post_order(root.rchild) print(root.data, end='') #层次遍历:一层一层来,同一层的从左到右输出 def level_order(root): queue = deque() queue.append(root) while len(queue) > 0: node = queue.popleft() print(node.data,end='') if node.lchild: queue.append(node.lchild) if node.rchild: queue.append(node.rchild) pre_order(root)#EACBDGF print("") in_order(root)#ABCDEGF print("") post_order(root)#BDCAFGE print("") level_order(root)#EAGCFBD
二叉搜索树
二叉搜索树(Binary Search Tree),它或者是一棵空树,或者是具备下列性质的二叉树: 若它的左子树不空,则左子树上全部结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上全部结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉搜索树。
二叉搜索树一个很好玩的网址,集成了增删改的功能:https://visualgo.net/en/bst
二叉搜索树的中序遍历获得的是原来列表按升序排序的列表
由列表生成二叉搜索树、经过二叉搜索树查询值和删除值的示例代码:
#结点定义 class BiTreeNode: def __init__(self, data): self.data = data self.lchild = None self.rchild = None #创建二叉搜索树(循环列表,插入值) class BST: def __init__(self, li=None): self.root = None if li: self.root = self.insert(self.root, li[0])#列表的第一个元素是根 for val in li[1:]: self.insert(self.root, val) #生成二叉搜索树递归版本 def insert(self, root, val): if root is None: root = BiTreeNode(val) elif val < root.data:#插入的值小于root,要放到左子树中(递归查询插入的位置) root.lchild = self.insert(root.lchild, val) else:#插入的值大于root,要放到右子树中(递归查询插入的位置) root.rchild = self.insert(root.rchild, val) return root #生成二叉搜索树不递归的版本 def insert_no_rec(self, val): p = self.root if not p: self.root = BiTreeNode(val) return while True: if val < p.data: if p.lchild: p = p.lchild else: p.lchild = BiTreeNode(val) break else: if p.rchild: p = p.rchild else: p.rchild = BiTreeNode(val) break #查询递归版本 def query(self, root, val): if not root: return False if root.data == val: return True elif root.data > val: return self.query(root.lchild, val) else: return self.query(root.rchild, val) #查询非递归版本 def query_no_rec(self, val): p = self.root while p: if p.data == val: return True elif p.data > val: p = p.lchild else: p = p.rchild return False #中序遍历,获得的是升序的列表 def in_order(self, root): if root: self.in_order(root.lchild) print(root.data, end=',') self.in_order(root.rchild) tree = BST() for i in [1,5,9,8,7,6,4,3,2]: tree.insert_no_rec(i) tree.in_order(tree.root) #print(tree.query_no_rec(12))
二叉搜索树的应用——AVL树、B树、B+树
AVL树
AVL树:AVL树是一棵自平衡的二叉搜索树。
AVL树具备如下性质: 根的左右子树的高度之差的绝对值不能超过1 根的左右子树都是平衡二叉树
AVL的实现方式:旋转
B树
B树是一棵自平衡的多路搜索树。经常使用于数据库的索引。
在B-树中查找给定关键字的方法是,首先把根结点取来,在根结点所包含的关键字K1,…,Kn查找给定的关键字(可用顺序查找或二分查找法),若找到等于给定值的关键字,则查找成功;不然,必定能够肯定要查找的关键字在Ki与Ki+1之间,Pi为指向子树根节点的指针,此时取指针Pi所指的结点继续查找,直至找到,或指针Pi为空时查找失败。
B+ 树
B+树的查找
1
2
3
4
5
6
7
8
9
10
|
Function: search (k)
return
tree_search (k, root); Function: tree_search (k, node)
if
node is a leaf then
return
node;
switch
k
do
case
k < k_0
return
tree_search(k, p_0);
case
k_i ≤ k < k_{i+
1
}
return
tree_search(k, p_{i+
1
});
case
k_d ≤ k
return
tree_search(k, p_{d+
1
});
//伪代码假设没有重复值
|
B+树的插入
B+树的删除