思路:有一个括号表示的一串序列,假设为A(B,C(Q,E),D),我们发现出现(则表示下面一些元素为(前面一个元素的子女,直到出现),所以们在出现时,就要把之后的元素与他的父亲相连,这里用孩子数组法,也就是父亲节点保存了所有孩子的下标,每次遇到(,就要保存他前一个元素,可以把它压入栈中,然后之后遇到的字母都为该栈顶的子女,直到遇到右括号,用栈的好处就是当括号里还有括号,考虑到就进原则,括号内的元素肯定是最近(前一个元素的子女,栈的思想为先进后出,这样就先考虑后进那个元素的子女,从而实现建树过程,也可以说这是根据前序遍历的思想做的。
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 11111
#define m 3
using namespace std;
typedef struct
{
char data;
int child[m];
}node;
typedef struct
{
node treelist[maxn];
int len;
}Tree;
/*--------------自定义堆栈-----------------*/
typedef struct
{
int st[maxn];
int top;
}Stack;
void Init(Stack &s){s.top=0;}
void Push(Stack &s,int i){s.st[s.top++]=i;}
void Pop(Stack &s){s.top--;}
int Empty(Stack &s){return s.top==0?1:0;}
/*-----------------------------------------*/
void convert(char s[],Tree *t)
{
int i=0,j=0;
int len= strlen(s);
Stack st;
Init(st);
for(int k=0;k<m;k++) t->treelist[j].child[k]=-1;
t->treelist[j].data=s[i];
j++,i++;
do
{
if(s[i]=='(') Push(st,j-1);//若遇到(,则说明括号内的都为前一个元素的儿子,就把前一个元素的标号压入栈,这里要注意 压入的是是刚建好树的下标
else if(s[i]==')') Pop(st);//遇到)则说明栈顶元素的子女已经都连接完,就把该元素弹出
else if(s[i]>='a'&&s[i]<='z'||s[i]>='1'&&s[i]<<'9'||s[i]>='A'&&s[i]<='Z')//如果是数字,字母,就加入树中
{
t->treelist[j].data=s[i];//扫到一个元素加入树
for(int k=0;k<m;k++) t->treelist[j].child[k]=-1;//见该节点的儿子全部初始化为-1
int l=st.st[st.top-1];//找到栈顶元素,也就是他的父亲节点
int k=0;
while(t->treelist[l].child[k]!=-1) k++;//找到父亲节点存放儿子下标的空位
t->treelist[l].child[k]=j; //下标存入父亲节点
j++;//对应树的下标要加一
}
i++;//源串的下标加一
//cout<<"s["<<i<<"] "<<s[i]<<endl;
}while(!Empty(st)&&i<len);//栈为空说明已经连接完成
t->len=j;
}
void Print(Tree &t)
{
for(int i=0;i<t.len;i++)
{
cout<<t.treelist[i].data<<' ';
for(int j=0;j<m;j++)
cout<<t.treelist[i].child[j]<<' ';
cout<<endl;
}
}
void preorder(Tree &t,int n)//前序遍历
{
if(n==t.len) return ;
cout<<t.treelist[n].data;
for(int i=0;i<m;i++)
if(t.treelist[n].child[i]!=-1) preorder(t,t.treelist[n].child[i]);
}
int main()
{
char s[maxn];
Tree t;
while(cin.getline(s,maxn))
{
convert(s,&t);
Print(t);
preorder(t,0);
}
return 0;
}