最近面试里常被问到二叉树相关的题,这类题又往往绕不开二叉树的输入。吃亏了几次后还是决定记录一下。
要构建一颗确定的二叉树,需要给出二叉树的前序+中序/后序+中序的数组,这样可以参考力扣上的两道题:
105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode) (leetcode-cn.com)
106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode) (leetcode-cn.com)
但具体实现思路实在复杂,而且还要求程序员每次构建一棵树前需要自己先得到相应的前序、中序、后序序列。为此,我考虑到从层序遍历的序列入手。以下图为例,由层序遍历的序列nums得到相应的一颗二叉树。其中,节点0对应序列中下标为0,其左孩子节点1对应下标为1(2*0+1),其右孩子节点2对应小标为2(2*0+2);节点1对应序列中的下标为1,其左孩子节点3对应下标为3(2*1+1),其右孩子节点4对应下标为4(2*1+2)... 由数学归纳法可得,层序遍历序列中下标(i)的节点对应的左孩子节点下标为(2*i+1),对应的右孩子节点为(2*i+2)。基于此性质,结合哈希表防止节点的重复构建,代码如下:
1 struct TNode{ 2 int m_val; 3 TNode* left; 4 TNode* right; 5 }; 6 //采用哈希表记录已构建的节点 7 unordered_map<int, TNode*> m; 8 int main() 9 { 10 vector<int> nums = {0, 1, 2, 3, 4, null, null, null ,null, null, null}; 11 int n = nums.size(); 12 for(int i = 0; i < (n-1)/2; ++i) //父节点的下标不超过(n-1)/2 13 { 14 TNode* root; 15 if(m.find(i) == m.end()) 16 { 17 root = new TNode(nums[i]); 18 m.insert({i, root}); 19 } 20 else 21 root = m[i]; 22 23 TNode *LNode; 24 int left_index = 2 * i + 1; 25 if(num[left_index] != NULL) //需要先判断左孩子是否存在 26 { 27 if(m.find(left_index) == m.end()) //如果(2*i+1)对应节点未被创建,则创建后放入哈希表中 28 { 29 LNode = new TNode(nums[left_index]); 30 m.insert({2*i+1, LNode}); 31 } 32 else 33 LNode = m[left_index]; //如果(2*i+1)对应节点已被创建,则根据下标为key直接获取对应节点 34 root->left = LNode; 35 } 36 else 37 root->left = nullptr; 38 39 TNode *RNode; 40 int right_index = 2 * i + 2; 41 if(num[right_index] != NULL) //需要先判断右孩子是否存在 42 { 43 if(m.find(right_index) == m.end()) 44 { 45 RNode = new TNode(nums[right_index]); 46 m.insert({2*i+2, RNode}); 47 } 48 else 49 RNode = m[right_index]; 50 root->right = RNode; 51 } 52 else 53 root->right = nullptr; 54 } 55 return m[0]; //哈希表中下标0所对应的节点为根节点 56 }