一.题目理解
1)叶(子)节点 / 终端结点 / 树叶:是度为 0 的结点。(带叶字或终端!)
分支结点:度不为0的结点。
区:结点、根节点
2)层序遍历:从上到下、从左到右的顺序。(先进先出)
a)借数组当队列!!
b)层序遍历的结果存在数组ans[]中
法1:数组存储的是从根节点开始,左孩子,右孩子,左孩子的(左孩子,右孩子),右孩子的(左孩子,右孩子)…
1>找到根节点,存入数组ans[0]。
找根节点way:利用输入为左右孩子序号,所以根节点不会出现在输入中(因为根节点不是任何结点的子节点)
2>利用for循环,从根节点开始,左孩子,右孩子,左孩子的(左孩子,右孩子),右孩子的(左孩子,右孩子)…
注意:tree的下标是ans[i]
【理解:从根节点ans[0]开始的左孩子ans[1]、右孩子ans[2],然后左孩子ans[1]的(左孩子ans[3],右孩子ans[4])...】
int ans[15] = {};//借数组当队列,队列ans[i]是层序遍历的存储结果
for(int i = 0;i < n;i++)
{
if(checked[i] == 0)
{
ans[0] = i; //找到根节点,存入数组ans[0]
break;
}
}
int k = 1; //注意一下,k是从 1 开始的(因为根节点存进了ans[0])
for(int i = 0;i < n;i++) //层序遍历存储:从根节点开始,左孩子,右孩子,左孩子的(左孩子,右孩子),右孩子的(左孩子,右孩子)…
{
if(tree[ans[i]].left != -1)ans[k++] = tree[ans[i]].left; //tree的下标是ans[i]
//理解:从根节点ans[0]开始的左孩子ans[1]、右孩子ans[2],然后左孩子ans[1]的(左孩子ans[3],右孩子ans[4])...
if(tree[ans[i]].right != -1)ans[k++] = tree[ans[i]].right;
}
法2:创建了一个二叉树,再层序输出(同数据结构书P115)
(有出队、左右孩子入队)
二.题目输入(不是先中后序遍历)
输入左右孩子序号的:使用结构体数组进行存储
【数组的下标就是数据域(即父节点),因此只需要保存每个结点的左右孩子】
三.小知识点
1)不确定输入的是字符还是数字:定义为char型
2)将char型的数字转化为int型数字:直接 减 ‘0’
原因:
四.代码
法1:
#include <iostream>
#include <cstdio>
using namespace std;
struct Node
{
// int data;
int left;
int right;
};
int main()
{
int n;
cin >> n;
getchar(); //千万千万注意这个getchar(),否则程序会直接崩溃
Node tree[15]; //因为这个数组的下标就是data,所以我不需要额外的data域
int checked[15] = {}; //检查根节点的(因为根节点不是任何结点的子节点,所以根节点不会出现在输入中)
for(int i = 0;i < n;i++)
{
char l,r;
scanf("%c %c",&l,&r);//输入用char
getchar();
if(l == '-')tree[i].left = -1;
else
{
tree[i].left = (l - '0');
checked[l - '0'] = 1;
}
if(r == '-')tree[i].right = -1;
else
{
tree[i].right = (r - '0');
checked[r - '0'] = 1;
}
}
int ans[15] = {};//借数组当队列,队列ans[i]是层序遍历的存储结果
for(int i = 0;i < n;i++)
{
if(checked[i] == 0)
{
ans[0] = i; //找到根节点,存入数组ans[0]
break;
}
}
int k = 1; //注意一下,k是从 1 开始的(因为根节点存进了ans[0])
for(int i = 0;i < n;i++) //层序遍历存储:从根节点开始,左孩子,右孩子,左孩子的(左孩子,右孩子),右孩子的(左孩子,右孩子)…
{
if(tree[ans[i]].left != -1)ans[k++] = tree[ans[i]].left; //tree的下标是ans[i]
//理解:从根节点ans[0]开始的左孩子ans[1]、右孩子ans[2],然后左孩子ans[1]的(左孩子ans[3],右孩子ans[4])...
if(tree[ans[i]].right != -1)ans[k++] = tree[ans[i]].right;
}
int flag = 0;
for(int i = 0;i < n;i++)
{
if(tree[ans[i]].left == -1 && tree[ans[i]].right == -1)//tree的下标是ans[i],因为ans[i]是层序遍历的存储结果
{
if(flag)cout << " ";
flag = 1;
cout << ans[i];
}
}
return 0;
}
法2:
#include<stdio.h>
#include<stdlib.h>
typedef struct Node *node;
struct Node {//储存输入数据,并找到父节点
int on;
int left;
int right;
};
typedef struct Snode *Tree;
struct Snode{//树
int data;
Tree Left;
Tree Right;
};
int flag=1;//判断输出时第一个字母不带空格
Tree buidTree(int rot,node nod[]);
void myprint(Tree t);
int main(){
int n,j=0,num[14]={0};
node tr[14];
char ch;
scanf("%d",&n);
scanf("%c",&ch);//清除回车
char str[5];
//输入数据,没有孩子的默认为1
for(int i=0;i<n;i++){
node t=(node)malloc(sizeof(struct Node));
gets(str);
if(str[0]!='-'){t->left=(int)(str[0]-'0');num[t->left]++;}
else t->left=-1;
if(str[2]!='-'){t->right=str[2]-'0';num[t->right]++;}
else t->right=-1;
t->on=i;//记住父节点值
tr[i]=t;
}
//找根结点
for(j;j<n;j++)
if(num[j]==0)
break;
Tree T=buidTree(j,tr);
myprint(T);
}
//层序输出
void myprint(Tree t){
int first=0;
Tree tep;
Tree dd[12];
int top=0,dom=0;//
dd[top]=t;//借数组当队列用
top++;
while(dom<top){
tep=dd[dom];//出队
dom++;
if(!tep->Left&&!tep->Right){
first++;
if(first==flag)printf("%d",tep->data);
else printf(" %d",tep->data);
}
if(tep->Left){ dd[top]=tep->Left;top++;}//左右孩子入队
if(tep->Right) {dd[top]=tep->Right;top++;}
}
}
Tree buidTree(int rot,node nod[]){
node t= nod[rot];
Tree tr=(Tree)malloc(sizeof(struct Snode));
tr->data=t->on;
if(t->left!=-1){
tr->Left=buidTree(t->left,nod);
}else tr->Left=NULL;
if(t->right!=-1){
tr->Right=buidTree(t->right,nod);
}else tr->Right=NULL;
return tr;
}