B树
一棵 2t (t>=2)阶(此处阶数表示每个节点最大的孩子数量)B树是一棵平衡的 2t 路搜索树。它或者是空树,或者是满足下列性质的树:
1、根节点至少有两个子女;
2、每个非根节点所包含的关键字个数j满足:t-1<=j<=2t-1;
3、每个节点都包含了目前节点内key数量+1个孩子指针,叶子节点除外;
4、节点孩子树中的key与当前节点中key的值存在大小关系;
5、所有的叶子节点都位于同一层,其深度为树高。
t=2时的B树也被称为2-3-4树
节点拆分要求当且仅当节点内关键字数量等于(注意是等于)2t-1,拆分时需注意插入新节点后不再检查本节点和父节点是否需要拆分,插入下一个节点时再检查所经过节点是否需要拆分。
第一行输入一个正整数t,表示要构造2t阶B树;第二行输入一个正整数n,表示分别将1,2,…,n作为关键词按照顺序构造对应的B树。
例如,若输入
“2
9”,
构造的B树如下图所示:
class Node():
"""B树节点"""
def __init__(self):
self.keys = [] #存储元素
self.children = [] #存储孩子节点
self.is_leaf = False
class B_tree():
"""B树"""
def __init__(self, t=2):
self.treeroot = Node()
self.treeroot.is_leaf = True
self.t = t #每棵树的t(节点大小从t-1到2t-1)
def search(self, node, num):
"""查找元素"""
i = 0
while i <= len(node.keys) and num > node.keys[i]:
i += 1
if i <= len(node.keys) and num == node.keys[i]:
return node, i
elif node.leaf:
return None, None
else:
return self.search(node.children[i], num)
def split_child(self, node, i):
"""拆分孩子"""
newnode_left = Node()
newnode_right = Node()
#把元素拆分
newnode_left.keys = node.children[i].keys[0:int((2 * self.t - 1) / 2)]
newnode_right.keys = node.children[i].keys[int((2 * self.t - 1) / 2) + 1:2 * self.t - 1]
#保留树叶性质
newnode_left.is_leaf = node.children[i].is_leaf
newnode_right.is_leaf = node.children[i].is_leaf
#把子节点拆分
if not node.children[i].is_leaf:
newnode_left.children = node.children[i].children[0:self.t]
newnode_right.children = node.children[i].children[self.t:2 * self.t]
#把中间结点上提
node.keys.insert(i, node.children[i].keys[int((2 * self.t - 1) / 2)])
node.children.insert(i, newnode_left)
node.children.insert(i + 1, newnode_right)
#删掉一个多余节点
node.children.pop(-1)
def B_tree_insert_non_full(self, node, k):
"""插入元素(非满状态下)"""
i = len(node.keys) - 1
if node.is_leaf:
while i >= 1 and k < node.keys[i]:
i -= 1
node.keys.insert(i + 1, k)
else:
while i >= 1 and k < node.keys[i]:
i -= 1
i += 1
if len(node.children[i].keys) == 2 * self.t - 1:
self.split_child(node, i)
if k > node.keys[i]:
i += 1
self.B_tree_insert_non_full(node.children[i], k)
def B_tree_insert(self, k):
"""B树插入"""
curnode = self.treeroot
if len(curnode.keys) == 2 * self.t - 1:
newnode = Node()
self.treeroot = newnode
newnode.children.append(curnode)
self.split_child(newnode, 0)
self.B_tree_insert_non_full(newnode, k)
else:
self.B_tree_insert_non_full(curnode, k)
def output_left(tree):
"""输出函数"""
print(tree.keys[0], end=" ")
if not tree.children:
return
output_left(tree.children[0])
def output_right(tree):
"""输出函数"""
print(tree.keys[-1], end=" ")
if not tree.children:
return
output_right(tree.children[-1])
t = int(input(""))
x = int(input(""))
lt = []
for i in range(1, x + 1):
lt.append(i)
tree = B_tree(t)
for i in range(0, len(lt)):
tree.B_tree_insert(lt[i])
output_left(tree.treeroot)
print("")
output_right(tree.treeroot)
输出:
红黑树
构造一颗红黑树(没有合法性判断),并输出该树的前序遍历。
红黑树的特征:
特征一:节点要么是红色,要么是黑色;
特征二:根节点是黑色的;
特征三:每个叶节点(nil或空节点)是黑色的;
特征四:每个红色节点的两个子节点都是黑色的(相连的两个节点不能都是红色的);
特征五:从任一个节点到其每个叶子节点的所有路径都是包含相同数量的黑色节点。
输入:纯数字组合,数据与数据间以空格分开,数据末尾没有空格。
输出共有两行,第一行该红黑树的前序遍历结果,不需换行,每个数据间留一个空格;第二行输出对应节点的颜色,红色代表0,黑色代表1,不需换行,每个数据间留一个空格。
# 颜色常量
RED = 0
BLACK = 1
def preorder_tree_walk(node):
if node:
print (node.value, end = ' ')
preorder_tree_walk(node.left)
preorder_tree_walk(node.right)
def preorder_tree_walk1(node):
if node:
print (node.color, end = ' ')
preorder_tree_walk1(node.left)
preorder_tree_walk1(node.right)
class RedBlackTreeNode(object):
def __init__(self, value):
self.value = value
self.left = None
self.right = None
self.p = None
self.color = RED
class RedBlackTree(object):
def __init__(self):
self.root = None
def insert(self, node):
# 找到最接近的节点
temp_root = self.root
temp_node = None
while temp_root:
temp_node = temp_root
if node.value == temp_node.value:
return False
elif node.value > temp_node.value:
temp_root = temp_root.right
else:
temp_root = temp_root.left
# 在相应位置插入节点
if not temp_node:
self.root = node
node.color = BLACK
elif node.value < temp_node.value:
temp_node.left = node
node.p = temp_node
else:
temp_node.right = node
node.p = temp_node
# 调整树
self.insert_fixup(node)
def insert_fixup(self, node):
if node.value == self.root.value:
return
# 为什么是这个终止条件?
# 因为如果不是这个终止条件那就不需要调整
while node.p and node.p.color == RED:
# 只要进入循环则必有祖父节点 否则父节点为根节点 根节点颜色为黑色 不会进入循环
if node.p == node.p.p.left:
node_uncle = node.p.p.right
# 1. 没有叔叔节点 若此节点为父节点的右子 则先左旋再右旋 否则直接右旋
# 2. 有叔叔节点 叔叔节点颜色为黑色
# 3. 有叔叔节点 叔叔节点颜色为红色 父节点颜色置黑 叔叔节点颜色置黑 祖父节点颜色置红 continue
# 注: 1 2 情况可以合为一起讨论 父节点为祖父节点右子情况相同 只需要改指针指向即可
if node_uncle and node_uncle.color == RED:
node.p.color = BLACK
node_uncle.color = BLACK
node.p.p.color = RED
node = node.p.p
continue
elif node == node.p.right:
left_rotate(self, node.p)
node = node.left
node.p.color = BLACK
node.p.p.color = RED
right_rotate(self, node.p.p)
return
elif node.p == node.p.p.right:
node_uncle = node.p.p.left
if node_uncle and node_uncle.color == RED:
node.p.color = BLACK
node_uncle.color = BLACK
node.p.p.color = RED
node = node.p.p
continue
elif node == node.p.left:
right_rotate(self, node)
node = node.right
node.p.color = BLACK
node.p.p.color = RED
left_rotate(self, node.p.p)
return
# 最后记得把根节点的颜色改为黑色 保证红黑树特性
self.root.color = BLACK
def left_rotate(tree, node):
if not node.right:
return False
node_right = node.right
node_right.p = node.p
if not node.p:
tree.root = node_right
elif node == node.p.left:
node.p.left = node_right
else:
node.p.right = node_right
if node_right.left:
node_right.left.p = node
node.right = node_right.left
node.p = node_right
node_right.left = node
def right_rotate(tree, node):
if not node.left:
return False
node_left = node.left
node_left.p = node.p
if not node.p:
tree.root = node_left
elif node == node.p.left:
node.p.left = node_left
elif node == node.p.right:
node.p.right = node_left
if node_left.right:
node_left.right.p = node
node.left = node_left.right
node.p = node_left
node_left.right = node
n = list(map(int,input().split()))
RBT = RedBlackTree()
for i in range(len(n)):
RBT.insert(RedBlackTreeNode(n[i]))
preorder_tree_walk(RBT.root)
print()
preorder_tree_walk1(RBT.root)
运行样例: