高级数据结构---B树、红黑树 python实现

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-12t-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)

运行样例:
在这里插入图片描述
在这里插入图片描述

原创文章 30 获赞 13 访问量 5319

猜你喜欢

转载自blog.csdn.net/Wang_Runlin/article/details/105757320