前序、中序确定一棵二叉树
事实上,中序 + 另一种遍历,都可以唯一确定一棵二叉树。学堂在线上也提到过相关知识点。
关于这个代码怎么构思呢?
首先,是存储树节点的数据结,我留了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 。