数据结构——二叉树

2019-01-05

1 树的基本术语

节点的度:节点拥有子树的数目
叶子:度为零的节点
分枝结点:度不为零的节点
树的度:树中节点的最大的度
层次:根节点的层次为1,其余节点的层次等于该节点的双亲节点的层次加1
树的高度:树中节点的最大层次

2 二叉树的性质

性质1:二叉树第$i$层的节点数目最多为$2^n (n=i-1,i>=1)$
性质2:深度为$k$的二叉树至多有$2^k-1(k>=1)$个节点
性质3:包含$n$个节点的二叉树的高度至少为$log_2(n+1)$
性质4:在任意一棵二叉树中,若叶子节点的个数为$n_0$,度为2的节点的个数为$n_2$,那么$n_0=n_2+1$
性质5:如果T2是由有序树T转换而来的二叉树,那么T中结点的前序就是T2中结点的前序,T中结点的后序就是T2中结点的中序。

3 满二叉树

定义:高度为$h$,并且节点数是$2^h-1$,则称为满二叉树。
满二叉树

4 完全二叉树

定义:一棵二叉树中,只有最下面两层结点的度可以小于2,并且最下一层的叶结点集中在靠左的若干位置上。这样的二叉树称为完全二叉树。
特点:叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。显然,一棵满二叉树必定是一棵完全二叉树,而完全二叉树未必是满二叉树。
完全二叉树

5 二叉查找树

定义:又称为二叉搜索树,设$x$为二叉查找树的一个节点,$x$节点的值为$x.val$。如果$y$$x$的左子树中的一个节点,则$y.val<=x.val$;如果$y$$x$的右子树中的一个节点,则$y.val>=x.val$
二叉查找树
特点

  • 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 任意节点的左、右子树也分别为二叉查找树;
  • 没有键值相等的节点。

6 二叉树的实现(Python)

用Python实现二叉树可以通过两种方式,分别是使用List实现和使用类实现。

6.1 使用List实现

# 实现二叉树(用 list 实现)
# -*- coding: utf-8 -*-
# 初始化
def BinaryTree(data):
    return [data,[],[]]

def insertLeft(tree, data):
    leftSubTree = tree.pop(1)
    if leftSubTree: # 判断当前这个树的左子树是否为空
        tree.insert(1, [data, leftSubTree, []]) # 不为空,将数插入,并将原左子树作为该数的左子树
    else:
        tree.insert(1, [data, [], []])
    return tree

def insertRight(tree, data):
    rightSubTree = tree.pop(2)
    if rightSubTree:
        tree.insert(2, [data, [], rightSubTree])
    else:
        tree.insert(2, [data, [], []])
    return tree

def getLeftChild(tree):
    return tree[1]

def getRightChild(tree):
    return tree[2]

if __name__ == '__main__':
    tree = BinaryTree('a')
    print(tree)
    insertLeft(tree, 'b')
    print(tree)
    insertRight(tree, 'c')
    print(tree)
    insertLeft(tree, 'd')
    print(tree)
    insertLeft(getLeftChild(getLeftChild(tree)), 'f')
    print(tree)

# 输出
['a', [], []]
['a', ['b', [], []], []]
['a', ['b', [], []], ['c', [], []]]
['a', ['d', ['b', [], []], []], ['c', [], []]]
['a', ['d', ['b', ['f', [], []], []], []], ['c', [], []]]

使用类实现

## 6.2 实现二叉树(用类实现)
# -*- coding: utf-8 -*-
class BinaryTree(object):
    def __init__(self, data):
        self.__key = data
        self.__leftChild = None
        self.__rightChild = None

    def getKey(self):
        return self.__key

    def getLeft(self):
        return self.__leftChild

    def setLeft(self, tree):
        self.__leftChild = tree

    def getRight(self):
        return self.__rightChild

    def setRight(self, tree):
        self.__rightChild = tree

    def insertLeft(self, data):
        if self.__leftChild == None:
            # self.__leftChild = BinaryTree(data)
            self.setLeft(BinaryTree(data))
        else:
            t = BinaryTree(data)
            t.setLeft(self.getLeft())
            self.setLeft(t)
            # t.__leftChild = self.__leftChild
            # self.__leftChild = t

    def insertRight(self, data):
        if self.__rightChild == None:
            self.setRight(BinaryTree(data))
            # self.__rightChild = BinaryTree(data)
        else:
            t = BinaryTree(data)
            self.setRight(self.getRight())
            self.setRight(t)
            # t.__rightChild = self.__rightChild
            # self.__rightChild = t

    # 树的先序遍历
    def preorder(self, nodelist = None):
        if nodelist is None:
            nodelist = []
        if self:
            nodelist.append(self.getKey())
            if self.getLeft():
                self.getLeft().preorder(nodelist)
            if self.getRight():
                self.getRight().preorder(nodelist)
        return nodelist

    # 中序遍历,使用递归,返回list
    def inorder(self, nodelist = None):
        if nodelist is None:
            nodelist = []
        if self:
            if self.getLeft():
                self.getLeft().inorder(nodelist)
            nodelist.append(self.getKey())
            if self.getRight():
                self.getRight().inorder(nodelist)
        return nodelist

    # 中序遍历,使用递归,直接输出
    def inorder1(self):
        if self:
            if self.getLeft():
                self.getLeft().inorder1()
            print(self.getKey())
            if self.getRight():
                self.getRight().inorder1()

    # 后序遍历
    def postorder(self, nodelist = None):
        if nodelist is None:
            nodelist = []
        if self:
            if self.getLeft():
                self.getLeft().postorder(nodelist)
            if self.getRight():
                self.getRight().postorder(nodelist)
            nodelist.append(self.getKey())
        return nodelist

if __name__ == '__main__':
    tree = BinaryTree('a')
    tree.insertLeft('b')
    tree.insertRight('c')
    tree.getLeft().insertRight('d')
    node = tree.preorder()
    print(node)
    node1 = tree.inorder1()
    print(node1)
    node2 = tree.postorder()
    print(node2) 
    
# 输出
['a', 'b', 'd', 'c']
b
d
a
c
None
['d', 'b', 'c', 'a']