给定一棵二叉树的先序遍历序列和中序遍历序列,要求计算该二叉树的高度。
输入首先给出正整数N(≤50),为树中结点总数。下面两行先后给出先序和中序遍历序列,均是长度为N的不包含重复英文字母(区别大小写)的字符串。
输出为一个整数,即该二叉树的高度。
9
ABDFGHIEC
FDHGIBEAC
5
#include
#include
#include
int n;
char pre[60],in[60];
struct TNode{
int Data;
struct TNode* Left;
struct TNode* Right;
};//二叉树的结构体
typedef struct TNode* Tree;
Tree restoreTree(char pre[],char in[],int n){//还原二叉树的函数
int i;
char lpre[60],rpre[60];
char lin[60],rin[60];
int n1 = 0,n2 = 0;//n1记录前序遍历序列的左子树长度n2则记录前序遍历序列的右子树长度
int m1 = 0,m2 = 0;//m1记录中序遍历序列的左子树长度m2记录中序遍历序列右子树长度
if(n==0){//如果长度为零说明这可子树建完了返回NULL
return NULL;
}
Tree T = (Tree)malloc(sizeof(struct TNode));
if(T==NULL){
return NULL;//若内存满了,返回NULL;
}
T->Data = pre[0];//每一次,一定是前序遍历的第一个作为根节点,然后再去建左右子树
//下面是关键,通过根节点把中序遍历分出左右子树,然后再根据这个分好的长度,再把前序遍历分成相同长度,依次确定根节点,递归实现
//分中序遍历序列
for(i = 0; i < n; i++){
if(i<=n1&&in[i]!=pre[0]){//中序遍历被根节点分开的左子树的点
lin[n1] = in[i];
n1++;
}
else if(in[i]!=pre[0]){//右子树的点,注意是else if,因为这个时候i是大于n1的
rin[n2] = in[i];
n2++;
}
}
//分前序遍历序列,注意!这里从1开始循环,因为0号元素作为根
for(i = 1; i < n; i++){
if(i<(n1+1)){
lpre[m1] = pre[i];
m1++;
}
else{
rpre[m2] = pre[i];
m2++;
}
}
T->Left = restoreTree(lpre,lin,n1);
T->Right = restoreTree(rpre,rin,n2);
return T;//最后一定要return这颗树,要不然怎么算高。。。
}
int getHight(Tree BST){//得到树的高度,已知左右树高,树高为max(左树高,右树高)+1;
int lh,rh;
if(BST==NULL){
return 0;
}
else {
lh = getHight(BST->Left);
rh = getHight(BST->Right);
return (lh>rh?lh:rh)+1;
}
}
int main(){
scanf("%d",&n);
scanf("%s",pre);
scanf("%s",in);//输入
Tree BST = NULL;
BST = restoreTree(pre,in,n);//建树
int hight;
hight = getHight(BST);//求高
printf("%d\n",hight);//输出
return 0;
}
本题要求根据给定的一棵二叉树的后序遍历和中序遍历结果,输出该树的先序遍历结果。
第一行给出正整数N(≤30),是树中结点的个数。随后两行,每行给出N个整数,分别对应后序遍历和中序遍历结果,数字间以空格分隔。题目保证输入正确对应一棵二叉树。
在一行中输出Preorder:
以及该树的先序遍历结果。数字间有1个空格,行末不得有多余空格。
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
Preorder: 4 1 3 2 6 5 7
#include
using namespace std;
int in[31],post[31];
typedef struct BiTNode{
int data;
struct BiTNode *lchild;
struct BiTNode *rchild;
}BiTNode,*BiTree;
BiTree Build(int *in,int *post,int n)
{//第一个参数是中序序列的起始位置,第二个参数是后序序列的起始位置,n是长度
if(n <= 0)//如果长度小于等于0,直接返回即可
return NULL;
int *p = in;//定义一个指向in的指针
while(p){//找到根节点在中序中的位置
if(*p == *(post + n - 1))
break;
p++;
}
BiTree T = new BiTNode;
T->data = *p;
int len = p - in;
T->lchild = Build(in,post,len);
T->rchild = Build(p + 1,post + len,n - len - 1);
return T;
}
void PreOrder(BiTree T){
if(T){
printf(" %d",T->data);
PreOrder(T->lchild);
PreOrder(T->rchild);
}
return;
}
int main(){
int n;
BiTree T;//只需要定义,不需要赋值->[BiTree T = new BiTNode;]
scanf("%d",&n);
for(int i = 0;i < n;i++)
scanf("%d",&post[i]);
for(int i = 0;i < n;i++)
scanf("%d",&in[i]);
T = Build(in,post,n);
printf("Preorder:");
PreOrder(T);
return 0;
}
呵呵。大家都知道五服以内不得通婚,即两个人最近的共同祖先如果在五代以内(即本人、父母、祖父母、曾祖父母、高祖父母)则不可通婚。本题就请你帮助一对有情人判断一下,他们究竟是否可以成婚?
输入第一行给出一个正整数N
(2 ≤ N
≤104),随后N
行,每行按以下格式给出一个人的信息:
本人ID 性别 父亲ID 母亲ID
其中ID
是5位数字,每人不同;性别M
代表男性、F
代表女性。如果某人的父亲或母亲已经不可考,则相应的ID
位置上标记为-1
。
接下来给出一个正整数K
,随后K
行,每行给出一对有情人的ID
,其间以空格分隔。
注意:题目保证两个人是同辈,每人只有一个性别,并且血缘关系网中没有乱伦或隔辈成婚的情况。
对每一对有情人,判断他们的关系是否可以通婚:如果两人是同性,输出Never Mind
;如果是异性并且关系出了五服,输出Yes
;如果异性关系未出五服,输出No
。
24
00001 M 01111 -1
00002 F 02222 03333
00003 M 02222 03333
00004 F 04444 03333
00005 M 04444 05555
00006 F 04444 05555
00007 F 06666 07777
00008 M 06666 07777
00009 M 00001 00002
00010 M 00003 00006
00011 F 00005 00007
00012 F 00008 08888
00013 F 00009 00011
00014 M 00010 09999
00015 M 00010 09999
00016 M 10000 00012
00017 F -1 00012
00018 F 11000 00013
00019 F 11100 00018
00020 F 00015 11110
00021 M 11100 00020
00022 M 00016 -1
00023 M 10012 00017
00024 M 00022 10013
9
00021 00024
00019 00024
00011 00012
00022 00018
00001 00004
00013 00016
00017 00015
00019 00021
00010 00011
Never Mind
Yes
Never Mind
No
Yes
No
Yes
No
No
#include
#include
using namespace std;
typedef struct Node{
char sex;
int fId;
int mId;
}Node;
Node p[100001];
int flag,visited[100001];
void f(int a,int sum){
if(sum > 5 || a == -1 || a == 0)//如果代数大于5代,或者a==-1,说明都不在人世,
//或者a==0说明没有被赋值,直接返回
return;
visited[a]++;//记录被访问的次数
if(visited[a] >= 2)//如果五代以内的同一个人被访问超过2次,说明在五代之内有共同的祖先
flag = 0;
f(p[a].fId,sum + 1);//递归调用,a的父亲,代数+1
f(p[a].mId,sum + 1);//递归调用,a的母亲,代数+1
return;
}
int main(){
int n,selfId,fId,mId,k,a,b;
char c;
scanf("%d",&n);
for(int i = 0;i < n;i++){
scanf("%d %c%d%d",&selfId,&c,&fId,&mId);
p[selfId].sex = c;//记录自己的性别
p[selfId].fId = fId;//记录父亲的Id
p[selfId].mId = mId;
p[fId].sex = 'M';//记录自己父亲的性别,否则,可能会漏掉
p[mId].sex = 'F';//记录自己母亲的性别,否则,可能会漏掉
}
scanf("%d",&k);
while(k--){
flag = 1;//标记变量,默认为1
memset(visited,0,sizeof(visited));//每循环一次,必须进行一次初始化
scanf("%d%d",&a,&b);
if(p[a].sex == p[b].sex){
printf("Never Mind\n");
continue;
}
f(a,1);//以a为起点,代数为一代,进行寻找
f(b,1);//以a为起点,代数为一代,进行寻找
if(flag)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
对于给定的二叉树,本题要求你按从上到下、从左到右的顺序输出其所有叶节点。
首先第一行给出一个正整数 N(≤10),为树中结点总数。树中的结点从 0 到 N−1 编号。随后 N 行,每行给出一个对应结点左右孩子的编号。如果某个孩子不存在,则在对应位置给出 “-”。编号间以 1 个空格分隔。
在一行中按规定顺序输出叶节点的编号。编号间以 1 个空格分隔,行首尾不得有多余空格。
8
1 -
- -
0 -
2 7
- -
- -
5 -
4 6
4 1 5
#include
#include
using namespace std;
struct fun{
char l,r;
};
fun s[100];
vector<int>ve[100];
void funs(int t,int cur)
{
if(s[t].l=='-'&&s[t].r=='-')
{
ve[cur].push_back(t);//cur++了
return ;
}
if(s[t].l!='-')
funs(s[t].l-'0',cur+1);
if(s[t].r!='-')
funs(s[t].r-'0',cur+1);
}
int main()
{
int root[100]={0};
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
cin>>s[i].l>>s[i].r;
root[s[i].l-'0']=1;
root[s[i].r-'0']=1;
}
int r;
for(int i=0;i<n;i++)
{
if(root[i]==0)//
{
r=i;
break;
}
}
funs(r,1);
int flag=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<ve[i].size();j++)
{
if(flag==0)
flag=1;
else
cout<<" ";
cout<<ve[i][j];
}
}
}
根据输入构造二叉树,输出该二叉树的先序序列。二叉树共有N个节点,节点编号是1到N。约定1号节点是根节点。
第一行输入整数N。 接下来有N行,依次给出1到N节点的左孩子和右孩子。对于这N行中的每一行,有两个整数。第i(i=1, 2, …, N)行中,第一个整数指出左孩子的编号,第二个整数指出右孩子的编号。如果整数值为0,表示没有左孩子或右孩子。
输出一行,内容是二叉树的先序序列。节点编号之间用空格隔开,行末有1个空格。
6
2 5
3 4
0 0
0 0
0 6
0 0
1 2 3 4 5 6
#include
using namespace std;
struct Node
{
int lChild;
int rChild;
};
void Pre(Node nodes[], int root)
{
if (root == 0)
return; //结束
cout << root << " ";
Pre(nodes, nodes[root].lChild);
Pre(nodes, nodes[root].rChild);
}
int main()
{
int N;
cin >> N;
Node nodes[N + 1]; //注意一下数据的类型
for (int i = 1; i <= N; i++)
cin >> nodes[i].lChild >> nodes[i].rChild;
//调用递归函数
Pre(nodes, 1);
}
给定一段文字,如果我们统计出字母出现的频率,是可以根据哈夫曼算法给出一套编码,使得用此编码压缩原文可以得到最短的编码总长。然而哈夫曼编码并不是唯一的。例如对字符串"aaaxuaxz",容易得到字母 ‘a’、‘x’、‘u’、‘z’ 的出现频率对应为 4、2、1、1。我们可以设计编码 {‘a’=0, ‘x’=10, ‘u’=110, ‘z’=111},也可以用另一套 {‘a’=1, ‘x’=01, ‘u’=001, ‘z’=000},还可以用 {‘a’=0, ‘x’=11, ‘u’=100, ‘z’=101},三套编码都可以把原文压缩到 14 个字节。但是 {‘a’=0, ‘x’=01, ‘u’=011, ‘z’=001} 就不是哈夫曼编码,因为用这套编码压缩得到 00001011001001 后,解码的结果不唯一,“aaaxuaxz” 和 “aazuaxax” 都可以对应解码的结果。本题就请你判断任一套编码是否哈夫曼编码。
首先第一行给出一个正整数 N(2≤N≤63),随后第二行给出 N 个不重复的字符及其出现频率,格式如下:
c[1] f[1] c[2] f[2] ... c[N] f[N]
其中c[i]
是集合{‘0’ - ‘9’, ‘a’ - ‘z’, ‘A’ - ‘Z’, ‘_’}中的字符;f[i]
是c[i]
的出现频率,为不超过 1000 的整数。再下一行给出一个正整数 M(≤1000),随后是 M 套待检的编码。每套编码占 N 行,格式为:
c[i] code[i]
其中c[i]
是第i
个字符;code[i]
是不超过63个’0’和’1’的非空字符串。
对每套待检编码,如果是正确的哈夫曼编码,就在一行中输出"Yes",否则输出"No"。
注意:最优编码并不一定通过哈夫曼算法得到。任何能压缩到最优长度的前缀编码都应被判为正确。
7
A 1 B 1 C 1 D 3 E 3 F 6 G 6
4
A 00000
B 00001
C 0001
D 001
E 01
F 10
G 11
A 01010
B 01011
C 0100
D 011
E 10
F 11
G 00
A 000
B 001
C 010
D 011
E 100
F 101
G 110
A 00000
B 00001
C 0001
D 001
E 00
F 10
G 11
Yes
Yes
No
No
#include
#include
#include
#include
using namespace std;
//代表小顶堆的优先队列
priority_queue<int ,vector<int>,greater<int> > q;
int main(void){
int n;
char s[66];
int p[66];
scanf("%d",&n);
for(int i=0;i<n;i++){
getchar();
scanf("%c%d",&s[i],&p[i]);
q.push(p[i]);
}
int ans=0;
//ans即为哈弗曼树带权路径长度和,也就是所对应的哈夫曼编码的长度
while(q.size()>1){
int x=q.top();
q.pop();
int y=q.top();
q.pop();
q.push(x+y);
ans+=x+y;
}
int m;
scanf("%d",&m);
for(int i=0;i<m;i++){
char ss[66][66];
int sum=0;
for(int j=0;j<n;j++){
getchar();
char c;
scanf("%c %s",&c,ss[j]);
sum+=strlen(ss[j])*p[j];
}
if(sum!=ans)printf("No\n");
else{
int flag=0;
for(int j=0;j<n;j++){
int x=strlen(ss[j]);
for(int l=0;l<n;l++){
if(j!=l){
if(strstr(ss[l],ss[j])==&ss[l][0]){
//查找字符串,如果找到了并且是前缀,就标记为No了
flag=1;
break;
}
}
}
if(flag==1)break;
}
if(flag==1)printf("No\n");
else printf("Yes\n");
}
}
return 0;
}