最近学习了python数据结构,做一些必要的笔记,一来是对自己学习的知识的巩固,二来对有同样问题的人有参考作用
一 树
1、基本概念
树是由结点或顶点和边组成的(可能是非线性的)且不存在着任何环的一种数据结构。没有结点的树称为空(null或empty)树。一棵非空的树包括一个根结点,还(很可能)有多个附加结点,所有结点构成一个多级分层结构。
树是由n个节点组成的集合:
-
如果n=0,那么这是一颗空树
-
如果n>0,那么存在一个节点作为树的根节点,其他节点可以分成m个集合,每个集合本身又是一棵树
2、特点
-
根节点
-
叶子节点
-
树的深度
-
树的度
-
父节点
-
孩子节点
二 二叉树
1、定义
二叉树的每个结点至多只有二棵子树(不存在度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。二叉树的第i层至多有2i-1个结点;深度为k的二叉树至多有2k-1个结点;对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1。
2、分类
(1)满二叉树
定义:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点。也可以这样理解,除叶子结点外的所有结点均有两个子结点。节点数达到最大值,所有叶子结点必须在同一层上。
性质:
-
一颗树深度为h,最大层数为k,深度与最大层数相同,k=h;
-
叶子数为2h;
-
第k层的结点数是:2k-1;
-
总结点数是:2k-1,且总节点数一定是奇数
(2)完全二叉树
定义:若设二叉树的深度为h,除第 h 层外,其它各层 (1~(h-1)层) 的结点数都达到最大个数,第h层所有的结点都连续集中在最左边,这就是完全二叉树。
注:完全二叉树是效率很高的数据结构,堆是一种完全二叉树或者近似完全二叉树,所以效率极高,像十分常用的排序算法、Dijkstra算法、Prim算法等都要用堆才能优化,二叉排序树的效率也要借助平衡性来提高,而平衡性基于完全二叉树。
3、性质
二叉树的性质:
-
在非空二叉树中,第i层的结点总数不超过2i-1, i>=1;
-
深度为h的二叉树最多有2h-1个结点(h>=1),最少有h个结点;
-
对于任意一棵二叉树,如果其叶结点数为N0,而度数为2的结点总数为N2,则N0=N2+1;
-
具有n个结点的完全二叉树的深度为log2(n+1);
-
有N个结点的完全二叉树各结点如果用顺序方式存储,则结点之间有如下关系:
-
若I为结点编号则 如果I>1,则其父结点的编号为I/2;
-
如果2I<=N,则其左儿子(即左子树的根结点)的编号为2I;若2I>N,则无左儿子;
-
如果2I+1<=N,则其右儿子的结点编号为2I+1;若2I+1>N,则无右儿子。
-
-
给定N个节点,能构成h(N)种不同的二叉树,其中h(N)为卡特兰数的第N项,h(n)=C(2*n, n)/(n+1)。
-
设有i个枝点,I为所有枝点的道路长度总和,J为叶的道路长度总和J=I+2i。
4、二叉树的遍历
构造树:
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
(1)前序遍历
不同的遍历方法主要是根节点的访问顺序不同。
def pre_order(root):
if root:
print(root.data,end=",")
pre_order(root.lchild)
pre_order(root.rchild)
(2)中序遍历
def in_order(root):
if root:
in_order(root.lchild)
print(root.data,end=",")
in_order(root.rchild)
(3)后序遍历
def post_order(root):
if root:
post_order(root.lchild)
post_order(root.rchild)
print(root.data, end=',')
(4)层次遍历
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)
特别地:我们们要能够根据前序、中序、后序遍历的结果的其中两种,推断出树的结构。
三 二叉搜索树
1、定义
二叉搜索树是一颗二叉树且满足性质:设x是二叉树的一个节点。如果y是x左子树的一个节点,那么y.key <= x.key;如果y是x的右子树的一个节点,那么y.key >= x.key。
2、二叉搜索树的操作
(1)查询
二叉查找树的性质:对二叉查找树进行中序遍历,即可得到有序的数列。
(2)插入
二叉查找树的插入过程如下:
-
若当前的二叉查找树为空,则插入的元素为根节点;
-
若插入的元素值小于根节点值,则将元素插入到左子树中;
-
若插入的元素值不小于根节点值,则将元素插入到右子树中。
(3)删除
二叉查找树的删除,分三种情况进行处理:
- p为叶子节点,直接删除该节点,再修改其父节点的指针(注意分是根节点和不是根节点),如图a;
- p为单支节点(即只有左子树或右子树)。让p的子树与p的父亲节点相连,删除p即可(注意分是根节点和不是根节点),如图b;
- p的左子树和右子树均不空。找到p的后继y,因为y一定没有左子树,所以可以删除y,并让y的父亲节点成为y的右子树的父亲节点,并用y的值代替p的值;或者方法二是找到p的前驱x,x一定没有右子树,所以可以删除x,并让x的父亲节点成为y的左子树的父亲节点。如图c:
(4)代码实现
class BiTreeNode:
def __init__(self,data):
self.data = data
self.lchild = None
self.rchild = None
self.parent = None
class BST:
def __init__(self,li=None):
self.root = None
if li:
for val in li:
self.insert_no_rec(val)
def insert(self,node,val):
if not node:
node = BiTreeNode(val)
elif val < node.data:
node.lchild = self.insert(node.lchild,val)
node.lchild.parent = node
elif val > node.data:
node.rchild = self.insert(node.rchild,val)
node.rchild.parent = node
return node
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)
p.lchild.parent = p
return
elif val > p.data:
if p.rchild:
p = p.rchild
else:
p.rchild = BiTreeNode(val)
p.rchild.parent = p
return
else:
return
def query(self,node,val):
if not node:
return None
if node.data < val:
return self.query(node.rchild,val)
elif node.data > val:
return self.query(node.lchild,val)
else:
return node
def query_no_rec(self,val):
p = self.root
while p:
if p.data < val:
p = p.rchild
elif p.data > val:
p = p.lchild
else:
return p
else:
return None
def in_order(self, root):
if root:
self.in_order(root.lchild)
print(root.data, end=',')
self.in_order(root.rchild)
def __remove_node_1(self,node):
# 情况一, node是叶子节点
if not node.parent:
self.root = None
if node == node.parent.lchild: # node 是它父亲的左孩子
node.parent.lchild = None
else: # 右孩子
node.parent.rchild = None
def __remove_node_21(self,node):
# 情况2.1: node只有一个左孩子
if not node.parent: # 根节点
node.lchild.parent = None
self.root = node.lchild
elif node == node.parent.lchild:
node.parent.lchild = node.lchild
node.lchild.parent = node.parent
else:
node.parent.rchild = node.lchild
node.lchild.parent = node.parent
def __remove_node_22(self,node):
# 情况2.2: node只有一个右孩子
if not node.parent:
node.rchild.parent = None
self.root = node.rchild
if node == node.parent.lchild:
node.parent.lchild = node.rchild
node.rchild.parent = node.parent
else:
node.parent.rchild = node.rchild
node.rchild.parent = node.parent
def delete(self,val):
if self.root:
node = self.query_no_rec(val)
if not node:
return False
else:
if not node.lchild and not node.rchild: # 叶子节点
self.__remove_node_1(node)
elif not node.rchild: # 只有一个左孩子
self.__remove_node_21(node)
elif not node.lchild: # 只有一个右孩子
self.__remove_node_22(node)
else: # 既有左孩子也有右孩子
min_node = node.rchild
while min_node.lchild:
min_node = min_node.lchild
node.data = min_node.data
# 删除 min_node 节点
if min_node.rchild:
self.__remove_node_22(min_node)
else:
self.__remove_node_1(min_node)
tree = BST([1,4,2,5,3,8,6,9,7])
tree.in_order(tree.root)
print()
print(tree.query_no_rec(12))
print()
tree.delete(4)
tree.in_order(tree.root)
四 总结
如有错误恳请指正,如有侵权请联系我删除
参考文章: 数据结构中各种树