二叉树的类实现

二叉树的结点类

二叉树由一组结点组成,结点通过链接引用其子结点,没有子结点时用 None N o n e 值,空二叉树用 None N o n e 表示。

class BinTNode:
    def __init__(self, dat, left=None, right=None):
        self.data = dat
        self.left = left
        self.right = right

这个结点类接受三个参数,分别为其结点数据和左右子结点,两个参数都用默认值时构造出的为叶结点。
下面语句构造了一个包含三个结点的二叉树:

t1 = BinTNode(1, BinTNode(2), BinTNode(3))

基于BinTNode类构造的二叉树具有递归的结构,所以很容易采用递归的方式处理,下面两个函数定义展示了处理这种二叉树的典型技术:

#统计树中结点个数
def count_BinTNodes(t):
    if t is None:
        return 0
    else:
        return 1 + count_BinTNodes(t.left) + count_BinTNodes(t.right)

#假设结点中保存数值,求二叉树中所有数值的和
def sum_BinTNodes(t):
    if t is None:
        return 0
    else:
        return t.data + sum_BinTNodes(t.left) + sum_BinTNodes(t.right)

可以看出,递归定义的二叉树操作具有统一的模式:
- 描述对空树的处理,应直接给出结果。
- 描述非空树情况的处理:
1.如何处理根节点。
2.通过递归调用分别处理左,右子树。
3.基于上述三个部分处理的结果,得到对整个树的处理结果。


遍历算法
递归定义的遍历函数

采用递归方式实现的是按深度优先方式遍历二叉树。

def preorder(t, proc):
    if t is None:
        return
    proc(t.data)
    preorder(t.left)
    preorder(t.right)

为了能看到二叉树的具体情况,现在定义一个以易读形式输出二叉树的函数,这里采用带括号的前缀形式输出,为显示空子树输出一个符号“^”。

from __future__ import print_function  #python2的print不支持end=,所以import print_function

def print_BinTNodes(t):
    if t is None:
        print ('^', end='')
        return
    print ('(' + str(t.data), end='')
    print_BinTNodes(t.left)
    print_BinTNodes(t.right)
    print (')', end='')


t = BinTNode(1, BinTNode(2, BinTNode(5)), BinTNode(3))
print_BinTNodes(t)
#输出:
(1(2(5^^)^)(3^^))
宽度优先遍历

要实现宽度优先遍历二叉树,需要一个队列,下面的定义使用了之前的SQueue类:

from SQueue import *

def levelorder(t, proc):
    qu = SQueue()
    qu.enqueue(t)
    while not qu.is_empty():
        n = qu.dequeue()    #从队列中取出一个处理
        if n is None:       #如果取出的结点为空,不做任何处理,返回循环
            continue
        qu.enqueue(n.left)   #把取出结点的左/右结点入队
        qu.enqueue(n.right)
        proc(n.data)         #处理当前节点,完成后循环队列的下一个目标
非递归的先根序遍历函数

这里需要一个栈来保存未处理的子树,基本想法为:
- 由于采用先根序,遇到结点就可以访问,下一步应该沿着树的左枝下行。
- 但结点的右分支还没有访问,因此需要记录,将右子结点入栈。
- 遇到空树时回溯,取出栈里保存的一个右分支,再重复上述步骤
上述三个条件包含两个循环:1.访问该结点,把右结点入栈,再访问左结点,直到左结点为空,停止循环,转入第二步;2.从栈中取出一个,继续第一步,每次访问一个左结点都说明它的兄弟结点和父节点已经访问过,如果不能顺着该结点继续访问,就应该再从栈中取出一个,知道最后取来的结点为空或者栈中没有结点。

def preorder_nonrec(t, proc):
    s = SStack()
    while t is not None or not s.is_empty():
        while t is not None:
            proc(t.data)
            s.push(t.right)
            t = t.left
        t = s.pop()
通过生成器函数遍历
def preorder_elements(t):
    s = LStack()
    while t is not None or not s.is_empty():
        while t is not None:
            yield t.data
            s.push(t.right)
            t = t.left
        t = s.pop()

print('**************************')
for i in preorder_elements(t):
    print(i)
二叉树类

基于结点构造的二叉树具有递归结构,可以很方便处理,但也有不足:用None表示空树,但None的类型并不是BinTNode,而且不是一种很好的数据封装类型。下面定义一个二叉树类,它接受前面的BinTNode作为结点链接成树形结构:

class BinTree:
    def __init__(self):
        self._root = None

    def is_empty(self):
        return self._root is None

    def root(self):
        return self._root

    def leftchild(self):
        if self._root is None:
            raise ValueError("The Tree is empty!")
        return self._root.left

    def rightchild(self):
        if self._root is None:
            raise ValueError("The Tree is empty!")
        return self._root.right

    def set_root(self, rootnode):
        self._root = rootnode

    def set_left(self, leftchild):
        self._root.left = leftchild

    def set_right(self, rightchild):
        self._root.right = rightchild

#定义一个元素迭代器
    def preorder_elements(self):
        t, s = self._root, SStack()
        while t is not None or not s.is_empty():
            while t is not None:
                s.push(t.right)
                yield t.data
                t = t.left
            t = s.pop()

和链接表一样,无法通过一个二叉树结点找到它的父结点,可以为结点类添加一个链接指向它的父结点。


在old-style class中,任意instance的type都是’instance’。所以绝对不能用type来判断其类型。
另外这个问题又与Python的思想有关,正常情况下不应该编写代码检查类型的,而应该直接假设被操作的instance具有你希望的属性,否则抛出异常。即使需要检查类型,也应该用isinstance来判断,这样你期望类型的subclass也能正常被处理(比如,一个函数需要处理Message类型,那么它应该也能处理Message的子类型MyMessage,所以应该使用isinstance(arg,Message)这样来判断而不是type(arg) == Message来判断)。

>>> from collections import Iterator
>>> class A(object):
...  def __iter__(self):
...   pass
...  def next(self):
...   pass
... 
>>> isinstance(A(), Iterator)
True

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值