算法基础之二叉树理论


1.树基础

官方定义:树是n(n>=0)个结点的有限集。在任意一棵非空树中:

  • 有且仅有一个特定的被称为根(Root)的结点
  • 当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2,…,Tm,其中每一个集合本身又是一棵树,并且称为根的子树(SubTree)

解释:
树是一种以层次化方式组织和存放数据的特定数据结构。树有两个主要特征:

  • 每个项都有多个子节点
  • 除了叫做根的特殊的项,所有其他的项都只有一个父节点

在这里插入图片描述
在这里插入图片描述
结点分类:

  • 结点的度(Degree):结点拥有的子树数称为结点的度。度为0的结点称为叶子(Leaf)或终端结点。度不为0的结点称为非终端结点或分支结点
  • 树的度:是树内各结点的度的最大值

结点间关系:

  • 孩子和双亲:结点的子树的根称为该结点的孩子(Child),相应地,该结点称为孩子的双亲(Parent)
  • 兄弟:同一个双亲的结点的孩子之间互称兄弟

结点的层次(Level):是从根结点开始计算起,根为第一层,根的孩子为第二层,依次类推。树中结点的最大层次称为树的深度(Depth)或高度

如果将树中结点的各子树看成从左至右是有次序的(即不能互换),则称该树为有序树,否则称为无序树

森林:由m(m>=0)棵互不相交的树组成的集合

2.二叉树基础

官方定义:二叉树是n个结点的有限集合,该集合或者为空集,或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成

解释: 二叉树(Binary Tree)是一种特殊的树型结构,它的特点是每个结点至多有两棵子树,且二叉树的子树有左右之分,其次序不能任意颠倒

在这里插入图片描述
思考:只有三个结点的树有多少种形态?
在这里插入图片描述
特殊的二叉树:

  • 满二叉树:

在这里插入图片描述

  • 完全二叉树:

    对一棵具有n个结点的二叉树按层序编号,如果编号为i的结点与同样深度的满二叉树中编号结点为 i的结点在二叉树中位置完全相同,则这棵二叉树成为完全二叉树
    其特点为:

    • 叶子结点只能出现在最下两层
    • 最下层的叶子一定集中在左部连续位置
    • 倒数二层,若有叶子结点,一定都在右部连续位置
    • 如果结点度为1,则该结点只有左孩子,即不存在只有右子树的情况
    • 同样结点数的二叉树,完全二叉树的深度最小

在这里插入图片描述
二叉树性质:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
二叉树的存储方式:

  • 链式存储:

在这里插入图片描述

  • 顺序存储:

在这里插入图片描述

3.二叉树基本操作

class Node(object):
    def __init__(self, item):
        self.item = item
        self.left = None #左结点指针
        self.right = None #右结点指针

    def __str__(self): #方便打印
        return str(self.item)
    
class Tree(object):
    def __init__(self):
        # 根节点定义为 root 永不删除,做为哨兵使用。
        self.root = Node('root')

3.1插入结点

插入一个元素(逐层向下插入):
在这里插入图片描述

 def add(self, item):
        node = Node(item)
        if self.root is None: #边界条件
            self.root = node
        else:
            q = [self.root] #队列:先进先出

            while True:
                pop_node = q.pop(0)
                if pop_node.left is None:
                    pop_node.left = node
                    return
                elif pop_node.right is None:
                    pop_node.right = node
                    return
                else: 
                    q.append(pop_node.left)
                    q.append(pop_node.right)

3.2二叉树遍历

二叉树的遍历,指的是如何按某种搜索路径巡防树中的每个结点,使得每个结点均被访问一次,而且仅被访问一次。
⼆叉树主要有两种遍历⽅式:

  • 深度优先遍历:先往深⾛,遇到叶⼦节点再往回⾛。
  • ⼴度优先遍历:⼀层⼀层的去遍历。

3.2.1 深度优先遍历

  • 前序遍历:根-左-右
    操作定义为:若二叉树为空,为空操作;否则(1)访问根节点;(2)先序遍历左子树;(3)先序遍历右子树。

在这里插入图片描述

 def preorder(self, root):  # 先序遍历
        if root is None:
            return []
        result = [root.item]
        left_item = self.preorder(root.left)  #递归调用
        right_item = self.preorder(root.right)
        return result + left_item + right_item #根结点 左子树结点 右子树结点
  • 中序遍历:左-根-右
    操作定义为:若二叉树为空,为空操作;否则(1)中序遍历左子树;(2)访问根结点;(3)中序遍历右子树。

在这里插入图片描述

def inorder(self, root):  # 中序序遍历
        if root is None:
            return []
        result = [root.item]
        left_item = self.inorder(root.left)
        right_item = self.inorder(root.right)
        return left_item + result + right_item #左 根 右
  • 后序遍历:左-右-根
    操作定义为:若二叉树为空,为空操作;否则(1)后序遍历左子树;(2)后序遍历右子树;(3)访问根结点。

在这里插入图片描述

def postorder(self, root):  # 后序遍历
        if root is None:
            return []
        result = [root.item]
        left_item = self.postorder(root.left)
        right_item = self.postorder(root.right)
        return left_item + right_item + result #左 右 根

总结:
在这里插入图片描述

3.2.2 广度优先遍历

  • 层序遍历:
    操作定义为:若二叉树为空,为空操作;否则从上到下、从左到右按层次进行访问。

在这里插入图片描述

def traverse(self):  # 层次遍历
        if self.root is None:
            return None
        q = [self.root]
        res = [self.root.item]
        while q != []:
            pop_node = q.pop(0)
            if pop_node.left is not None:
                q.append(pop_node.left)
                res.append(pop_node.left.item)

            if pop_node.right is not None:
                q.append(pop_node.right)
                res.append(pop_node.right.item)
        return res

测试一下:

if __name__ == '__main__':
    t = Tree()
    for i in range(10): #10个结点
        t.add(i)
    print('层序遍历:', t.traverse())
    print('先序遍历:', t.preorder(t.root))
    print('中序遍历:', t.inorder(t.root))
    print('后序遍历:', t.postorder(t.root))

层序遍历: ['root', 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
先序遍历: ['root', 0, 2, 6, 7, 3, 8, 9, 1, 4, 5]
中序遍历: [6, 2, 7, 0, 8, 3, 9, 'root', 4, 1, 5]
后序遍历: [6, 7, 2, 8, 9, 3, 0, 4, 5, 1, 'root']

总的程序如下:

#二叉树操作

class Node(object):
    def __init__(self, item):
        self.item = item
        self.left = None #左结点指针
        self.right = None #右结点指针

    def __str__(self): #方便打印
        return str(self.item)
    
class Tree(object):
    def __init__(self):
        # 根节点定义为 root 永不删除,做为哨兵使用。
        self.root = Node('root')

    def add(self, item):
        node = Node(item)
        if self.root is None: #边界条件
            self.root = node
        else:
            q = [self.root] #队列:先进先出

            while True:
                pop_node = q.pop(0)
                if pop_node.left is None:
                    pop_node.left = node
                    return
                elif pop_node.right is None:
                    pop_node.right = node
                    return
                else: 
                    q.append(pop_node.left)
                    q.append(pop_node.right)

    

    def traverse(self):  # 层次遍历
        if self.root is None:
            return None
        q = [self.root]
        res = [self.root.item]
        while q != []:
            pop_node = q.pop(0)
            if pop_node.left is not None:
                q.append(pop_node.left)
                res.append(pop_node.left.item)

            if pop_node.right is not None:
                q.append(pop_node.right)
                res.append(pop_node.right.item)
        return res

    def preorder(self, root):  # 先序遍历
        if root is None:
            return []
        result = [root.item]
        left_item = self.preorder(root.left)  #递归调用
        right_item = self.preorder(root.right)
        return result + left_item + right_item #根结点 左子树结点 右子树结点

    def inorder(self, root):  # 中序序遍历
        if root is None:
            return []
        result = [root.item]
        left_item = self.inorder(root.left)
        right_item = self.inorder(root.right)
        return left_item + result + right_item #左 根 右

    def postorder(self, root):  # 后序遍历
        if root is None:
            return []
        result = [root.item]
        left_item = self.postorder(root.left)
        right_item = self.postorder(root.right)
        return left_item + right_item + result #左 右 根
    
if __name__ == '__main__':
    t = Tree()
    for i in range(10): #10个结点
        t.add(i)
    print('层序遍历:', t.traverse())
    print('先序遍历:', t.preorder(t.root))
    print('中序遍历:', t.inorder(t.root))
    print('后序遍历:', t.postorder(t.root))

推导遍历结果
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值