数据结构与算法:树与二叉树python实现

最近复习一遍数据结构与算法,做一些笔记,大家可以一起复习。

一、树的一些容易混淆的定义:

结点层:根结点的层定义为1;根的孩子为第二层结点,依此类推;

树的深度(或高度):树中最大的结点层;

满二叉树:这个定义国内和国外有较大的区别:

国内教程定义:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。如图1:

图1 

国外(国际)定义:a binary tree T is full if each node is either a leaf or possesses exactly two childnodes.

大意为:如果一棵二叉树的结点要么是叶子结点,要么它有两个子结点,这样的树就是满二叉树。(一棵满二叉树的每一个结点要么是叶子结点,要么它有两个子结点,但是反过来不成立,因为完全二叉树也满足这个要求,但不是满二叉树),如图2:

å¾ä¸

图2 

满二叉树的任意节点,要么度为0,要么度为2.换个说法即要么为叶子结点,要么同时具有左右孩子。霍夫曼树是符合这种定义的,满足国际上定义的满二叉树,但是不满足国内的定义。

完全二叉树:若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树

完美二叉树(可能国外才有):当所有的叶子节点都在同一层就是完美二叉树,毫无间隙填充了 h 层。对应国内满二叉树。

二、树数据结构python实现

我们将定义一个具有根值属性的类,以及左和右子树, 这个表示更接近于面向对象的编程范例。

属性:根、左右子树

方法:设置根、左右子树,获取根和左右子树

#定义二叉树类
class BinaryTree(object):
    def __init__(self, root, left = None, right = None):
        self.root = root
        self.left = left
        self.right = right
    
    def getRoot(self):
        return self.root
    def setRoot(self, root):
        self.root = root
    
    def getLeft(self):
        return self.left
    def getRight(self):
        return self.right
    
    #向树中添加左子树
    def insertLeft(self, newNode):
        if self.left == None:
            self.left = BinaryTree(newNode)
        else:                #左子树具有节点,放到下一层
            t = BinaryTree(newNode)
            t.left = self.left
            self.left = t    
    #向树中添加右子树
    def insertRight(self, newNode):
        if self.right == None:
            self.right = BinaryTree(newNode)
        else:
            t = BinaryTree(newNode)
            t.right = self.right
            self.right = t

三、二叉树的遍历

不知道你有没有发现,二叉树其实是一种递归结构,因为单独拿出来一个 subtree 子树出来,其实它还是一棵树。那遍历它就很方便啦,我们可以直接用递归的方式来遍历它。但是当处理顺序不同的时候,树又分为三种遍历方式:

  • 先(根)序遍历: 先处理根,之后是左子树,然后是右子树
  • 中(根)序遍历: 先处理左子树,之后是根,最后是右子树
  • 后(根)序遍历: 先处理左子树,之后是右子树,最后是根

设置在类中的方法:

#遍历树
    def preorder(self):
        print(self.root)
        if self.left:
            self.left.preorder()
        if self.right:
            self.right.preorder()

外部函数的方法:

#前序遍历树的外部函数
def preorder(tree):
    if tree:
        print(tree.getRoot())
        preorder(tree.getLeft())
        preorder(tree.getRight())
#后序遍历树的外部函数
def postorder(tree):
    if tree:
        postorder(tree.getLeft())
        postorder(tree.getRight())
        print(tree.getRoot())
#中序遍历树的外部函数
def midorder(tree):
    if tree:
        midorder(tree.getLeft())
        print(tree.getRoot())
        midorder(tree.getRight())

以上哪种方式实现前序最好? 答案是在这种情况下,实现前序作为外部函数可能更好。原因是你很少只是想遍历树。在大多数情况下,将要使用其中一个基本的遍历模式来完成其他任务。 事实上,我们将在下面的例子中看到后序遍历模式与我们前面编写的用于计算分析树的代码非常接近。 因此,我们用外部函数实现其余的遍历。

补充:给点节点的前序序列和中序序列,可确定一棵二叉树。不同形态的二叉树的数目恰好是前序序列均为12...n的二叉树所能得到的中序序列的数目。这个数目为\frac{1}{n+1}C_{2n}^{n},含有n个节点的不相似的二叉树的数目\frac{1}{n+1}C_{2n}^{n},二者相同。

github代码:https://github.com/makang101/python-data-structure

参考:

problem-solving-with-algorithms-and-data-structure-using-python 中文版

数据结构(C语言版)严蔚敏

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值