数据结构------树(未更新完...)

1.树的定义

树是一种数据结构,比如目录结构
树是一种可以递归定义的数据结构
树由n各节点组成的集合:(1)如果n=0,那么这是一棵空树;(2)如果n>0,那存在1个节点作为树的根节点,其他节点可以分为m个集合,每个集合本身又是一棵树.

2.一些树的术语

(1)节点
(2)根节点:没有入边的节点
(3)父节点
(4)子节点
(5)兄弟节点
(6)子树
(7)叶子节点:没有子节点的节点
(8)树的高度(深度)
(9)树的度
实现文件系统:

class Node:
    def __init__(self,name,type='dir'):
        self.name = name
        self.type = type
        self.children = []
        self.parent = None

    def __str__(self):
        return self.name

class FileSystemTree():
    def __init__(self):
        self.root = Node('/')
        self.now = self.root

    def mkdir(self, name):
        if name[-1] != '/':
            name+='/'
        node = Node(name)
        self.now.children.append(node)
        node.parent = self.now

    def ls(self):
        return self.now.children

    def cd(self, name):
        if name[-1] != '/':
            name += '/'
        if name == '../':
            self.now = self.now.parent
            return
        for child in self.now.children:
            if child.name == name:
                self.now = child
                return
        raise ValueError('invaild dir')
    

二叉树

二叉树

二叉树是一个比较特殊的树,其每个节点的子节点不超过2;

实现二叉树

二叉树的链式存储:将二叉树的节点定义为一个对象,节点之间通过类似链表的链接方式来连接.

节点定义:

class BtreeNode():
    def __init__(self, data):
        self.data = data
        self.lchild = None
        self.rchild = None

创建二叉树

在这里插入图片描述

a = BtreeNode('A')
b = BtreeNode('B')
c = BtreeNode('C')
d = BtreeNode('D')
e = BtreeNode('E')
f = BtreeNode('F')
g = BtreeNode('G')

e.lchild = a
e.rchild = g
a.rchild = c
c.lchild = b
c.rchild = d
g.rchild = f

二叉树的遍历

(1)前序遍历:根在前EACBDGF
(2)中序遍历:根在中间ABCDEGF
(3)后续遍历:根在后BDCAFGE
(4)层次遍历:从根开始逐层从左到右遍历EAGCFBD
代码实现:

root = e

# 前序遍历
def pre_order(root):
    if root:
        print(root.data, end='')
        pre_order(root.lchild)
        pre_order(root.rchild)
pre_order(root)


def in_order(root):
    if root:
        in_order(root.lchild)
        print(root.data, end='')
        in_order(root.rchild)
in_order(root)


def post_order(root):
    if root:
        post_order(root.lchild)
        post_order(root.rchild)
        print(root.data, end='')


from collections import deque
def level_order(root):
    queue = deque()
    queue.append(root)
    while len(queue):
        node = queue.popleft()
        print(node.data,end='')
        if node.lchild:
            queue.append(node.lchild)
        if node.rchild:
            queue.append(node.rchild)

二叉堆实现优先级

二叉搜索树

二叉搜索树是一棵二叉树,且满足性质: 设x是二叉树的一个节点.如果y是x的左子树的一个节点,那么y.key<=x.key; 如果y是x的右子树的一个节点,那么y.key>=x.key.
即对于每个节点都满足左孩子小于父节点,右孩子大于父节点.

二叉搜索树的插入

class BtreeNode():
    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_2(val)
              
    def insert(self, node, val):
        if not node:
            node = BtreeNode(val)
        elif val<node.data:
            node.lchid = 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_2(self, val):
        p = self.root
        if not p:
            self.root = BtreeNode(val)
            return
        while True:
            if val < p.data:
                if p.lchild:
                    p = p.lchild
                else:
                    p.lchild = BtreeNode(val)
                    p.lchild.parent = p
                    return
            elif val > p.data:
                if p.rchild:
                    p = p.rchild
                else:
                    p.rchild = BtreeNode(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.lchild, val)
        elif node.data>val:
            return self.query(node.rchild, val)
        else:
            return node
    def query_2(self, val):
        p = self.root
        while p:
            if p.data>val:
                p = p.lchild
            elif p.data < val:
                p = p.rchild
            else:
                return p
        return None

二插搜索树的删除

删除某个节点,必须要先找到该节点,再进行删除;则分为以下三种情况
(1)删除叶子节点:直接删除

(2)删除只有一个孩子的节点
当只有一个孩子时,我们把孩子和该节点的父母相连
(3)删除有两个孩子的节点
当有两个孩子时,我们把这个节点删掉,必须找到一个节点来填补这个节点的位置,我们取这个节点右子树的最小节点,(右子树的左子树一直找到最后一个左叶子节点,这时这个节点最多有一个右孩子)
如图,当要删除节点C时,找到其右子树的最小节点,从其右子树的左孩子一直找到左边最后一个左孩子就为最小的节点,并且这个孩子最多只有一个右孩子,或者是一个叶子节点.
在这里插入图片描述

    def _del_1(self,node):
        # 删除的是叶子节点
        if not node.parent:
            self.root = None
        if node == node.parent.lchild:
            node.parent.lchild = None
        else:
            node.parent.rchild = None

    def _del_2(self, node):
        # 删除的node只有一个左孩子
        if not node.parent:
            # 根节点
            self.root = node.lchild
            node.lchild.parent = None
        elif node == node.parent.lchild:
            node.parent.lchild = node.lchild
            node.lchild.parent = node.parent
        elif node == node.parent.rchild:
            node.parent.rchild = node.lchild
            node.lchild.parent = node.parent

    def _del_3(self, node):
        # 删除的node只有一个右孩子的情况
        if not node.parent:
            # 根节点
            self.root = node.rchild
            node.rchild.parent = None
        elif node == node.parent.lchild:
            node.parent.lchild = node.rchild
            node.rchild.parent = node.parent
        elif node == node.parent.rchild:
            node.parent.rchild = node.rchild
            node.rchild.parent = node.parent

    def delete(self, val):
        if self.root:
            node = self.query_2(val)
            if not node:
                return False
            elif not node.lchild and not node.rchild:
                # 删除叶子节点
                self._del_1(node)
            elif not node.rchild:
                self._del_2(node)
            elif not node.lchild:
                self._del_3(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._del_3(min_node)
                else:
                    self._del_1(min_node)

搜索二叉树的效率

搜索二叉树平均情况下进行搜索的时间复杂度为O(lgn)
最坏抢矿下二叉树十分偏斜:
在这里插入图片描述
解决方法:
(1)随机插入
(2)AVL平衡二叉树.

AVL平衡二叉树

AVL树是一棵自平衡二叉树搜索树.
AVL树具有以下性质:
(1)根的左右子树的高度之差的绝对值不能超过1;
(2)根的左右子树都是平衡二叉树

AVL树–插入与旋转

插入一个节点可能会破坏AVL树的平衡,可以通过旋转操作来进行修正.
插入一个节点后,只有从插入节点到根节点的路径上的节点的平衡可能被改变.我们需要找出第一个破坏了平衡条件的节点,称之为k.k的两颗子树的高度差2.
不平衡的出现可能有4种情况.
(1)不平衡是由于对k的左孩子的左子树插入导致的: 右旋
(2)不平衡是由于对k的右孩子的右子树插入导致的: 左旋
(3)不平衡是由于对k的右孩子的左子树插入导致的: 右旋-左旋
(4)不平衡是由于对k的左孩子的右子树插入导致的: 左旋-右旋

class AVLNode:
    def __init__(self, data):
        self.data = data
        self.lchild = None
        self.rchild = None
        self.parent = None
        self.bf = 0
from .BST import BST      
class AVLTree(BST):
    def __init__(self, li=None):
        BST.__init__(self,li)
    
    # 左旋    
    def rotate_left(self,p,c):
        s2 = c.lchild
        p.rchild = s2
        if s2:
            s2.parent = p
        c.lchild = p
        p.parent = c
        
        p.bf = 0
        c.bf = 0
        return c
        
    # 右旋
    def rotate_right(self,p,c):
        s2 = c.rchild
        p.rchild = s2
        if s2:
            s2.parent = p
        c.rchild = p
        p.parent = c
        p.bf = 0
        c.bf = 0
        return c
    # 右旋-左旋
    def right_left(self,p,c):
        g = c.lchild
        s2 = g.lchild
        s3 = g.rchild
        c.lchild = s3
        if s3:
            s3.parent = c
        g.rchild = c
        c.parent = g
        
        p.rchild = s2
        if s2:
            s2.parent = p
        g.lchild = p
        p.parent = g
        
        # 跟新bf
        if g.bf>0:  #g.bf = 1
            p.bf = -1
            c.bf = 0
        elif g.bf < 0:
            p.bf = 0
            c.bf = 1
        else:
            p.bf = 0
            c.bf = 0
        g.bf = 0
        return g
            
    # 左旋-右旋
    def rotate_left_right(self,p,c):
        g = c.rchild
        s2 = g.lchild
        s3 = g.rchild
        p.lchild = s3
        if s3:
            s3.parent = p
        g.rchild = p
        p.parent = g

        c.rchild = s2
        if s2:
            s2.parent = c
        g.lchild = c
        c.parent = g

        # 跟新bf
        if g.bf > 0:  # g.bf = 1
            p.bf = 0
            c.bf = -1
        elif g.bf < 0:
            p.bf = 1
            c.bf = 0
        else:
            p.bf = 0
            c.bf = 0
        g.bf = 0    
        return g
    
    def insert_item(self,val):
        p = self.root
        if not p:
            self.root = AVLNode(val)
            return
        while True:
            if p.data>val:
                if p.lchild:
                    p = p.lchild
                else:
                    p.lchild = AVLNode(val)
                    p.lchild.parent = p
                    node = p.lchild
                    break
            elif p.data<val:
                if p.rchild:
                    p = p.rchild
                else:
                    p.rchild = AVLNode(val)
                    p.rchild.parent = p
                    node = p.rchild
                    break
            else:
                return 
        # 更新bf
        while node.parent:
            if node.parent.lchild == node: # 传递从左子树来,左边更沉
                # 更新node_parent的bf-1
                if node.parent.bf<0: # -1,会变为-1
                    # 做旋转
                    # 看node哪边更沉
                    g = node.parent.parent
                    if node.bf>0:
                        n = self.rotate_left_right(node.parent, node)
                    else:
                        n = self.rotate_right(node.parent,node)
                elif node.parent.bf>0:
                    node.parent.bf = 0
                    break
                else:
                    node.parent.bf=-1
                    node = node.parent
                    continue
            else:
                # 右子树更沉同理
                pass
            
            # 链接旋转后的子树
            n.parent = g
            if g:
                if node.parent == g.lchild:
                    g.lchild = n
                else:
                    g.rchild = n
                break
            else:
                self.root=n
                break
      

二叉搜索树扩展应用–B树

B-Tree是一棵自平衡的多路搜索树.常用语数据库的索引.

红黑树

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值