前序、中序确定一棵二叉树

事实上,中序 + 另一种遍历,都可以唯一确定一棵二叉树。学堂在线上也提到过相关知识点。

 

关于这个代码怎么构思呢?

 

首先,是存储树节点的数据结,我留了5个SLOTS:

val, lc, rc, parent, ind 分别代表,值、左孩子、右孩子、家长、编号。

其中,家长这个SLOT没用到。

 

'''-------------------------------------------------------------------------------------------------------------------------------------
LeetCode
中序+前序 确定树结构
输入 preorder, inorder
输出 构造二叉树,返回 层次遍历顺序

leetcode 地址;
https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/?envType=study-plan-v2&envId=top-interview-150

----------------------------------------------------------------------------------------------------------------------------------------'''

import numpy as np
import pandas as pd
import ctypes  # 返回 id()

 

数据结构

class TreeNode(object):
    def __init__(self, val=-1, p_lc=-1, p_rc=-1, p_parent=-1, ind=-1):
            # -- 孩子家长,均用 id()
        self.val=val
        self.p_lc=p_lc
        self.p_rc=p_rc       
        self.p_parent=p_parent
        self.ind=ind

 

其次,基本思想。递归,每传一层函数,就三分向量。

向量为空,返回。

 

由于 Python 未知 & 或者 * 怎么表示,一开始用 id() 不起作用。因为定义函数,无论你是否传入入口地址,函数内部申请的空间一定会释放。

 

解决方法也简单,就是自己再映射一层地址,说穿了就编个号。我直接用的 list.append()。直接 append 进向量,不返回具体值。

 

然后,就动手干活吧!

 

def generate_subtree(vec_in, root_subtree_in, pre_in, mid_in):
    tmp_node = root_subtree_in
    
    if (len(pre_in)==0 or len(mid_in)==0):
            # 遍历子集为判断标准
        tmp_id=tmp_node.p_parent
        tmp = vec_in[tmp_id]
        return 
    
    tmp_root = pre_in[0]
    len_left=0
    len_right=0
    has_met_root=0
    ind_root=-1

      # -- 找到 ind_root
    for i in range(len(mid_in)):
        if(mid_in[i]==tmp_root):
            has_met_root=1
            ind_root=i
            break

        if (has_met_root==0):
            len_left = len_left+1
        elif (has_met_root==1 and i>ind_root):
            len_right=len_right+1

      # -- 输出左右子树
    lc_pre = pre_in[1:len_left+1]
    rc_pre = pre_in[len_left+1:]
    
    len_left_1=len(lc_pre)
    len_right_1=len(rc_pre)
    len_all=len(mid_in)    
    lc_mid = mid_in[:len_left_1]
    rc_mid = mid_in[len_all-len_right_1:]
    
    print("This round root: ", mid_in[ind_root])
    tmp_node.val=mid_in[ind_root]
    
    # -- 叶子在主函数安装
    tmp_vec_len = len(vec_in)
    tmp_node_1=TreeNode(); tmp_node_1.val=-1; tmp_node_1.ind=tmp_vec_len; tmp_node_1.p_parent=tmp_vec_len-1
    tmp_node.p_lc=tmp_node_1.ind
    vec_in.append(tmp_node_1)
    
    tmp_node_2=TreeNode(); tmp_node_2.val=-1; tmp_node_2.ind=tmp_vec_len+1; tmp_node_2.p_parent=tmp_vec_len-1
    tmp_node.p_rc=tmp_node_2.ind
    vec_in.append(tmp_node_2)
    
    generate_subtree(vec_in, tmp_node_1, lc_pre, lc_mid)
    generate_subtree(vec_in, tmp_node_2, rc_pre, rc_mid) 
    return 

 

这段代码主要采用递归。每个节点的叶子在函数最后生成,如果遍历序列还有值,则渲染节点,否则返回空节点。

 

获得一个含有节点的向量之后,还要一段层次遍历的代码。至少 leetCode 上这样要求的。

 

def output_bst(node_vec):    
      # -- 层次遍历
        
    output_trav = []
    q_header=0; q_tail=0; q=[]
    cnt=0
    while( ( (q_header==0 and q_tail==0) or q_header!=q_tail ) and cnt<100):
        # print("Header and Tail: ", q_header, q_tail)
        if (q_tail==0):
            tmp_node = node_vec[q_tail]
        else:
            tmp_node = q[q_header]
            q_header = q_header+1
            
        if (tmp_node.val > -1):
            print("Traverse - ", len(output_trav),"th: ", tmp_node.val)
            output_trav.append( tmp_node )
        
        if (tmp_node.p_lc>-1):
            q.append( node_vec[tmp_node.p_lc] )
            q_tail=q_tail+1
            
        if (tmp_node.p_rc>-1):
            q.append( node_vec[tmp_node.p_rc] )
            q_tail=q_tail+1 
        
        cnt=cnt+1       
    return output_trav

 

调用函数

# -- 调用函数 -- 

tree_root = TreeNode(); tree_root.val=-1; tree_root.ind=0
node_vec = [TreeNode() for i in range(1)]
node_vec[0] = tree_root

pre_order = [5, 3, 4, 9, 39, 7, 1, 2, 21, 15]
in_order  = [4, 3, 9, 39, 5, 1, 7, 21, 2, 15]

print("\n --------- GENERATE TREE -------- \n")
generate_subtree(node_vec, tree_root, pre_order, in_order)

print("\n --------- TRAVERSE -------- \n")
node_trav = output_bst(node_vec)

print("\n --------- ILLUSTRATION -------- \n")
from IPython.display import Image
Image("https://userspace1.oss-cn-beijing.aliyuncs.com/article/news_20231026_10_1.png",width=500,height=500)

 

查看结果。输出构造树过程,明显看出是递归的结果,拿来和层次遍历比较。

 

最后展示树的图形表示。

欢迎关注 ShoelessCai.com 。

 

posted on 2023-10-26 20:06  Mira_2019  阅读(62)  评论(0编辑  收藏  举报