树的线索化

        遍历二叉树是以一定的规则(顺序)将二叉树中结点排列成一个线性排列,结点在这个排列中有唯一一个前趋和唯一一个后继(第一个结点没有前驱,最后一个结点没有后继)。在有n个结点的二叉树中必有n+1个空的链域,不加以利用的话有些浪费,如果我们用它们存放结点在遍历中的前驱和后继信息,也就是对它们线索化,线索化之后的树再对其进行遍历时,可以提升遍历效率。

       像上面所说,二叉树的分支要么指向它的孩子,要么指向它在遍历中的前驱/后继,为了加以区分,需要给二叉树的结点增加一个flag来指示分支是指向它的孩子还是它在遍历中的前驱/后继。

        中序遍历的线索化:

        中序遍历二叉树,设置prev指向前一个访问的结点,curr指向当前访问的结点,若prev结点没有右孩子,则设置它的righttag为1,并让rightchild为curr,表示prev结点的后继为curr,若curr结点没有左孩子,则设置它的lefttag为1,并让leftchild为prev,表示curr结点的前驱为prev。

       中序线索化二叉树的遍历:

       1)找到子树遍历中的第一个结点(树的最左下结点),访问它

       2)访问当前结点的righttag,若它指示rightchild是它的后继,当前结点更新为它的后继,访问它,重复2)直到当前结点的righttag指示rightchild是它的右孩子,则当前结点更新为它的右孩子,转到1

class Node:
    leftchld = None
    rightchld = None
    lefttag = 0
    righttag = 0
    def __init__(self, val = "null"):
        self.val = val
    def __str__(self):
        return self.val

class InorderThreadedTree:
    def __init__(self, root):
        self.root = Node("X")
        self.root.leftchld = root
        self.root.righttag = 1
        self.threading()

    def _traverse(self, root):
        if not root:
            return
        yield from self._traverse(root.leftchld)
        yield root
        yield from self._traverse(root.rightchld)

    def threading(self):
        prev = self.root
        _iter = self._traverse(self.root.leftchld)
        curr = next(_iter)
        curr.leftchld = prev
        curr.lefttag = 1
        #print("%s prev %s" % (curr, prev))
        prev = curr
        for curr in _iter:
            if not prev.rightchld:
                prev.rightchld = curr
                prev.righttag = 1
                #print("%s next %s" % (prev, curr))
            if not curr.leftchld:
                curr.leftchld = prev
                curr.lefttag = 1
                #print("%s prev %s" % (curr, prev))
            prev = curr
        curr.rightchld = self.root
        curr.righttag = 1
        #print("%s next %s" % (curr, self.root))
        self.root.rightchld = curr
        self.root.righttag = 1
        #print("%s next %s" % (self.root, curr))
        

    def traverse(self):
        root = self.root
        curr = root.leftchld
        while curr is not root:
            while not curr.lefttag:
                curr = curr.leftchld
            yield curr
            while curr.righttag and curr.rightchld is not root:
                curr = curr.rightchld
                yield curr
            curr = curr.rightchld

    def reverse(self):
        root = self.root
        curr = root.rightchld
        yield curr
        while True:
            while curr.lefttag and curr.leftchld is not root:
                curr = curr.leftchld
                yield curr
            curr = curr.leftchld
            if curr is root:
                break
            while not curr.righttag:
                curr = curr.rightchld
            yield curr

def create_tree(treestr):
    cursor = 0
    def getval():
        nonlocal cursor
        start = cursor
        while cursor < len(treestr):
            if treestr[cursor] in ('(', ')', ','):
                break
            cursor += 1
        return treestr[start:cursor].strip()
    def create():
        nonlocal cursor
        val = getval()
        print(val)
        if not val:
            return None
        root = Node(val)
        #one node tree
        if cursor >= len(treestr):
            return root
        #leaf node
        if treestr[cursor] in (',', ')'):
            return root

        if treestr[cursor] == '(':
            cursor += 1
            root.leftchld = create()
        if treestr[cursor] == ',':
            cursor += 1
            root.rightchld = create()
        if treestr[cursor] == ')':
            cursor += 1
        return root

    return create()


root = create_tree("A(B(C(,D),E),F(,G))")
#print(root)
tree = InorderThreadedTree(root)
print(" ".join([str(i) for i in tree.traverse()]))
print(" ".join([str(i) for i in tree.reverse()]))

         前序/后序遍历的线索化及其线索化之后的遍历,也有类似的逻辑,这里不再赘述。

        感觉树的线索化没有什么价值,一旦树的结构发生变化,就要对树重新进行线索化,还有我们完全可以副设一个list记录它的遍历序列,不是更方面更高效?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__空无一人__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值