本文主要是介绍树的括号表示法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1.括号表示法构造一棵树
下面的代码都使用下面的图测试:
这颗树的前序遍历是
- [A,B,D,G,C,E,F,H]
为了程序的完整性,我想先构建一颗上述树,知识匮乏的我只能使用括号表示法构造:
- “A(B(,D(G,)),C(E,F(H,)))”
1.用一个类表示树的节点
class Node
{
public:int val;vector<Node*> children; //每个Node节点包含一个children数组,数组元素是Node*类型,表示指向其它的节点//三个构造函数Node() {} Node(int _val) {val = _val;}Node(int _val, vector<Node*> _children) {val = _val;children = _children;}
};
2.使用括号表示法构建树
void CreateTree(Node *&root,string &s)
{stack<Node*>tree;Node* p = NULL;int i =0;char ch = s[0];while (i < s.length()){switch (ch){case '(':tree.push(p);break;case ')':tree.pop();break;case ',':break;default:p = new Node();p->val = ch;if (root == NULL) //没有加入根节点{root = p;}else{tree.top()->children.push_back(p);}}ch = s[++i];}
}
我觉得这个代码逻辑非常清晰,我想尝试一下用递归的方式完成上述代码。在此之前,我先介绍一下我现在对于构建二叉树的理解,我感觉这个难度不亚于用非递归写出树的前中后序遍历😋
个人见解:
对于S字符串分析,S=A(B(,D(G,)),C(E,F(H,)))。从头开始遍历,想要通过S字符串构建一颗树。
想要将问题给解决,必须找到字符串内在的联系并且将其具体化。发现,所有的括号都是配对出现的,且’(‘其配对的是最近的’)’。每次当遇到’(‘的时候,可以把新的问题具体成”构建一棵小树“(发现和最开始的问题是一个内在逻辑)。然后小树挂在大树身上
解释一下:
最开始的问题是构建A(B(,D(G,)),C(E,F(H,))) 这棵树。
遍历到B后面的’(‘的时候,问题变成构建B(,D(G,)),C(E,F(H,))这棵树,然后B挂在A身上
遍历到D后面的’(‘的时候,问题变成构建D(G,)这颗树。然后D挂在B身上
发现了实际上就是解决无数个这样的小问题最后解决大问题,而进入小问题的接口就是遇到’('。所以只需要能解决最简单的A(B,C)这个问题,那么后面无限的衍生都是一个道理。
问题即抽象为:
A ( B , C , D , E . . . . ) A(B,C,D,E....) A(B,C,D,E....)
即将每个子树都‘挂’在A后面即可
Node* CreateTree1(int i,int len) //表示创建一颗树(从下标i(根节点)开始,后面跟着长度为len的子树)即用s[i]~s[i+len]构造树
{if (s[i] == ',')return NULL; //树的根应该是一个字母Node* p = new Node();p->val = s[i];if (len == 0)return p;//接下来要把该根节点的所有子树都挂在它身上//要创建若干颗树//子树都是由字符串s构造的int start = i + 2; //子树开始位置int length = 0; //子树(除去根节点)长度(从根节点后面第一个左括号到匹配完所有对应的右括号为止)比如A(B(C,D),E),这里面B(C,D)就是一个子树,子树长度在这里指根节点后面跟着的长度+1,即(C,D)的长度为5,B(C,D)的长度是6while (start <= i+len)// 子树的区间[i+2,i+len],s[i+2]是子树的根节点{if (s[start] < 'A'|| s[start]>'Z') //保证s[start]是个字母(树的根节点){start++;continue; }length = Find_BabyTree(start); //找子树长度p->children.push_back(CreateTree1(start, length)); //子树挂到根节点后面start = start + length + 2; //下一个子树的起点}return p;
}
我的测试数据A(B(,D(G,)),C(E,F(H,)))
输出是正确的,就是博客开头的树
放完整代码
#include<iostream>
#include<vector>
#include<cstring>
#include<new>
#include<stack>using namespace std;class Node
{
public:int val;vector<Node*> children; //每个Node节点包含一个children数组,数组元素是Node*类型,表示指向其它的节点//三个构造函数Node() {}Node(int _val){val = _val;}Node(int _val, vector<Node*> _children){val = _val;children = _children;}
};string s;void CreateTree(Node*& root, string& s) //括号表示法构建树,非递归法
{stack<Node*>tree;Node* p = NULL;int i = 0;char ch = s[0];while (i < s.length()){switch (ch){case '(':tree.push(p);break;case ')':tree.pop();break;case ',':break;default:p = new Node();p->val = ch;if (root == NULL) //没有加入根节点{root = p;}else{tree.top()->children.push_back(p);}}ch = s[++i];}}void preOrdered(Node* root) //前序遍历,非递归法
{if (root == NULL)return;cout << char(root->val) << " ";for (int i = 0; i < root->children.size(); i++)preOrdered(root->children[i]);return;
}int Find_BabyTree(int start) //数以s[start]为根节点的子树长度
{//根据括号规律,一个'('匹配一个')',当'('的次数等于')'的次数时表示当前这颗树构造完了//左括号+1,右括号-1if (s[start + 1] !='(')return 0; //该树只有一个根节点,子树长度为0int kuohao = 0;int i = 1;for (i; i + start < s.length(); i++){if (s[start+i] == '(')kuohao++;if (s[start+i] == ')')kuohao--;if (kuohao == 0)break;}return i;
}Node* CreateTree1(int i,int len) //表示创建一颗树(从下标i(根节点)开始,后面跟着长度为len的子树)即用s[i]~s[i+len]构造树
{if (s[i] == ',')return NULL; //树的根应该是一个字母个Node* p = new Node();p->val = s[i];if (len == 0)return p;//接下来要把该根节点的所有子树都挂在它身上//要创建若干颗树//子树都是由字符串s构造的int start = i + 2; //子树开始位置int length = 0; //子树长度(从根节点后面第一个左括号到匹配完所有对应的右括号为止)比如A(B(C,D),E),这里面B(C,D)就是一个子树,子树长度在这里指根节点后面跟着的长度,即(B,C)的长度为5while (start <= i+len)// 子树的区间[i+2,i+len],s[i+2]是子树的根节点{if (s[start] < 'A'|| s[start]>'Z') //保证s[start]是个字母(树的根节点){start++;continue; }length = Find_BabyTree(start); //找子树长度p->children.push_back(CreateTree1(start, length)); //子树挂到根节点后面start = start + length + 2; //下一个子树的起点}return p;
}int main()
{Node* root = NULL; //根节点s = "A(B(,D(G,)),C(E,F(H,)))"; //使用括号表示法构建树//CreateTree(root, s); //建树root = CreateTree1(0,s.length()-1);//然后用前序遍历输出树看是否正确preOrdered(root); //前序遍历return 0;
}
强迫症使然,找到思考大致的题目:leetcode
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution
{
public:TreeNode* CreateTree(string s) //表示当前根节点是s[i],当前的树的长度是len(包括i){if(!s.size())return NULL;TreeNode*root=new TreeNode();int flag=1;int i=0;if(s[i]=='-') //特殊判断负数{flag=-flag;i++;}//要将截至到最近的'('的所有字符提取出来转换为数字(有可能不是一个字符)int st=i;int n=s.size();while(i<n&&s[i]!='(')i++;root->val=flag*stoi(s.substr(st,i));if(i==n)return root; //只有数字没有括号的情况,可以提前退出//处理子树int kuohao=1; //此时i指向左括号,左括号数量加1int ls=i+1;i++;for(;i<n&&kuohao!=0;i++){if(s[i]=='(')kuohao++;if(s[i]==')')kuohao--;}//此时k指向左子树结束的后一个字符root->left=str2tree(s.substr(ls,i-ls-1));//看是否有右子树if(i<n){root->right=str2tree(s.substr(i+1,n-i-2)); //有点难算,先画个图}return root;}TreeNode* str2tree(string s) {//分解问题,找到规律://遇到字符则新建节点(当成一颗新树)//将当前字符为根节点的左右子树挂到根节点后面(左右子树)TreeNode *root=NULL;root=CreateTree(s);return root;}
};
这篇关于树的括号表示法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!