调整construct()函数

问题描述

class Node:
    def __init__(self,data,left=None,right=None):
        self.data = data
        self.left = left
        self.right = right
 
def construct(start,end,preorder,pIndex,dict):
 
    # base case
    if start > end:
        return None,pIndex
 
    root = Node(preorder[pIndex])
    pIndex = pIndex + 1
 
    index = dict[root.data]
 
    root.left,pIndex = construct(start,index - 1,dict)
 
    root.right,pIndex = construct(index + 1,dict)
 
    return root,pIndex     

def constructTree(inorder,preorder):
 
    dict = {}
    for i,e in enumerate(inorder):
        dict[e] = i
 
    pIndex = 0
 
    return construct(0,len(inorder) - 1,dict)[0]
 
 
if __name__ == '__main__':
 
 
    inorder = [4,2,1,7,5,8,3,6]
    preorder = [1,4,6]
 
    root = constructTree(inorder,preorder)
 
    print("The inorder traversal is ",end='')
    inorderTraversal(root)
 
    preorderTraversal(root)

这段代码构造了一个带有前序和中序遍历的树。如何修改代码以使其适用于 inorder-postorder 和 preorder-postorder?我想我只需要以类似的方式修改 construct() 并创建 constructPreOrderInorderTree()constructPreOrderpostorderTree()

编辑

假设我有 inorder=[3,10,9,6,2]postorder = [3,5]construct() 会为 inorder-preorder 这样做,但它不适用于该示例。所以我需要一个可以同时使用 inorder-postorder 和 preorder-postorder函数版本。

解决方法

变化:

  • 使用像 lookup 这样的变量名以避免掩盖现有的类型名称(例如 dict
  • 从右到左
    • 从头开始
    • 一路递减 pIndex
    • 从相反方向更新 pIndex
def construct_post(start,end,postorder,pIndex,lookup):
    # base case
    if start > end or pIndex < 0:
        return None,pIndex
 
    root = Node(postorder[pIndex])
    
    # go from the right to the left instead
    pIndex = pIndex - 1

    index = lookup[root.data]

    # update pIndex going in the opposite direction
    root.right,pIndex = construct_post(index + 1,lookup)
    root.left,pIndex = construct_post(start,index - 1,lookup)

    return root,pIndex


def constructTree_post(inorder,postorder):
    lookup = {e: i for i,e in enumerate(inorder)}
    pIndex = len(postorder) - 1

    # start from the end
    return construct_post(0,len(inorder) - 1,lookup)[0]

结果树:

          1
       /     \
     2        3
   /        /   \
  4        5     6
          / \
         7   8

,

我什至没有阅读 Geeks-for-Geeks 页面,就决定实现我自己的构造函数算法(前序-后序、前序-中序、中序-后序)。

我所有的算法都是 O(N^2) 复杂度。

除了构造函数(construct_preorder_postorder()construct_preorder_inorder()construct_inorder_postorder())我还实现了遍历函数(traverse_preorder()traverse_inorder()traverse_postorder()),控制台树打印函数(print_tree())和节点相等比较函数(__eq__())。

Try it online!

class Node:
    def __init__(self,data,left = None,right = None):
        self.data = data
        self.left = left
        self.right = right
    def __eq__(self,other):
        return (self.data == other.data and self.left == other.left and
            self.right == other.right)
        
def traverse_inorder(node):
    return ([] if node is None else
        traverse_inorder(node.left) + [node.data] + traverse_inorder(node.right))
        
def traverse_preorder(node):
    return ([] if node is None else
        [node.data] + traverse_preorder(node.left) + traverse_preorder(node.right))
        
def traverse_postorder(node):
    return ([] if node is None else
        traverse_postorder(node.left) + traverse_postorder(node.right) + [node.data])
        
def construct_preorder_postorder(pre,post):
    assert sorted(pre) == sorted(post) and len(pre) == len(set(pre)),(pre,post)
    if len(pre) == 0:
        return None
    if len(pre) == 1:
        return Node(pre[0])
    root,l = pre[0],pre[1]
    for i,e in enumerate(post):
        if e == l:
            ls = i + 1
            rs = len(post) - 1 - ls
            break
    return Node(root,None if ls == 0 else construct_preorder_postorder(pre[1:1 + ls],post[:ls]),None if rs == 0 else construct_preorder_postorder(pre[-rs:],post[-1 - rs:-1]))
        
def construct_preorder_inorder(pre,ino):
    assert sorted(pre) == sorted(ino) and len(pre) == len(set(pre)),ino)
    if len(pre) == 0:
        return None
    if len(pre) == 1:
        return Node(pre[0])
    root,e in enumerate(ino):
        if e == root:
            ls = i
            rs = len(ino) - 1 - ls
            break
    return Node(root,None if ls == 0 else construct_preorder_inorder(pre[1:1 + ls],ino[:ls]),None if rs == 0 else construct_preorder_inorder(pre[-rs:],ino[-rs:]))
        
def construct_inorder_postorder(ino,post):
    assert sorted(ino) == sorted(post) and len(ino) == len(set(ino)),(ino,post)
    if len(post) == 0:
        return None
    if len(post) == 1:
        return Node(post[0])
    root,r = post[-1],post[-2]
    for i,None if ls == 0 else construct_inorder_postorder(ino[:ls],None if rs == 0 else construct_inorder_postorder(ino[-rs:],post[-1 - rs:-1]))
    
def print_tree(node):
    def inner(node,*,upref = '',cpref = '',dpref = ''):
        if node is None:
            return
        inner(node.right,upref = dpref + '  |',cpref = dpref + '  /',dpref = dpref + '   ')
        print(cpref + '--' + str(node.data))
        inner(node.left,upref = upref + '   ',cpref = upref + '  \\',dpref = upref + '  |')
    inner(node)
        
if __name__ == '__main__':
    node = Node(1,Node(2,Node(4)),Node(3,Node(5,Node(7),Node(8)),Node(6)))
    print_tree(node)
    preorder,inorder,postorder = (
        traverse_preorder(node),traverse_inorder(node),traverse_postorder(node))
    preorder_cons,inorder_cons,postorder_cons = (
        construct_preorder_postorder(preorder,postorder),construct_preorder_inorder(preorder,inorder),construct_inorder_postorder(inorder,)
    assert preorder_cons == inorder_cons == postorder_cons

输出:

     /--6
  /--3
  |  |  /--8
  |  \--5
  |     \--7
--1
  \--2
     \--4