Time Limit: 1 Sec Memory Limit: 4 MB
Description
计算输入有序树的深度和有序树转化为二叉树之后树的深度。
Input
输入包含多组数据。每组数据第一行为一个整数n(2<=n<=30000)代表节点的数量,接下来n-1行,两个整数a、b代表a是b的父亲结点。
Output
输出当前树的深度和转化成二叉树之后的深度。
Sample Input
5
1 5
1 3
5 2
1 4
Sample Output
3 4
算法一 : 二叉链表
用孩子-兄弟表示法表示有序树和二叉树,这也就意味着直接用二叉树的形式表示有序树,只不过每个节点的两个指针不是左右孩子的指针,而是一个指向第一个孩子、另一个指向下一个兄弟。
有序树转二叉树在遍历的时候,操作不一样。
在形式上有序树存成了二叉树的样子,看的角度不同,就是有序树与二叉树的区别。
遍历一个存成二叉树形式的有序树的算法:
int depth_Tree(CSTree t)
{
if(t==NULL)
return 0;
int firstchild_depth = depth_Tree(t->firstchild);
int nextsibling_depth = depth_Tree(t->nextsibling);
return (firstchild_depth+1 > nextsibling_depth ? firstchild_depth+1 : nextsibling_depth);
}
完整程序: (OJ系统判断 TimeLimit Exceed)
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
typedef int ElemType;
typedef int Status;
///孩子-兄弟表示法
typedef struct CSNode
{
ElemType data;
struct CSNode *firstchild,*nextsibling;
} CSNode,*CSTree;
///初始化树
int Init_CSTree(CSTree &t)
{
t=NULL;
//static int maxn = 0;
return 0;
}
//查找数据元素
CSNode *Traverse(CSTree t,int x)
{
//查找数据元素x是否在二叉树root中
//查找到则返回该节点指针,未查找到则返回空指针
CSNode *f=NULL;
if(t!=NULL)
{
if(t->data==x)
{
f=t;
}
else
{
f=Traverse(t->firstchild,x);//在左子树中找
if(f==NULL)
{
f=Traverse(t->nextsibling,x);
}
}
}
return f;//返回查找标志
}
int Create_CSTree(CSTree &t,int a,int b)
{
if(t==NULL)
{
///t = (CSNode*)malloc(sizeof(CSNode));
t=new CSNode;
t->data = a;
t->firstchild = new CSNode;
t->nextsibling=NULL;
t->firstchild->data = b;
t->firstchild->firstchild=NULL;
t->firstchild->nextsibling=NULL;
}
else
{
/// 查找 新输入的 a 是否在已存在的二叉链表中也有与a相等的
///节点 有的话 在其firstchild的节点上添加兄弟节点
CSNode *p;
p = Traverse(t,a); ///传值没问题
if(p==NULL)
{
return -1;
//printf("input wrong!\n");
}
if(p->firstchild != NULL)
{
CSNode *q;
q = p->firstchild;
for(int i = 0; ; i++)
{
if(q->nextsibling==NULL)
{
break;
}
else
{
q = q->nextsibling;
}
}
q->nextsibling = new CSNode;
q->nextsibling->data = b;
q->nextsibling->firstchild=NULL;
q->nextsibling->nextsibling=NULL;
}
else
{
p->firstchild = new CSNode;
p->firstchild->data = b;
p->firstchild->firstchild = NULL;
p->firstchild->nextsibling = NULL;
}
}
return 0;
}
int Judge(CSTree t) ///求二叉链表中节点个数
{
if(t==NULL)
return 0;
int firstchild_num = Judge(t->firstchild);
int nextsubling_num = Judge(t->nextsibling);
int ret = firstchild_num + nextsubling_num +1;
return ret;
}
int depth_Tree(CSTree t)
{
if(t==NULL)
return 0;
int firstchild_depth = depth_Tree(t->firstchild);
int nextsibling_depth = depth_Tree(t->nextsibling);
return (firstchild_depth+1 > nextsibling_depth ? firstchild_depth+1 : nextsibling_depth);
}
int depth_BiTree(CSTree t)
{
if(t==NULL)
return 0;
int firstBiTree_depth = depth_BiTree(t->firstchild);
int siblingBiTree_depth = depth_BiTree(t->nextsibling);
if(firstBiTree_depth>siblingBiTree_depth)
return firstBiTree_depth+1;
else
return siblingBiTree_depth+1;
}
void freeTree(CSTree &root)
{
maxn = 0;
if (root!=NULL)
{
if (root->firstchild)
{
freeTree(root->firstchild);
root->firstchild= NULL;
}
if (root->nextsibling)
{
freeTree(root->nextsibling);
root->nextsibling = NULL;
}
if (root!=NULL)
{
free(root);
root=NULL;
}
}
//return 0;
}
int main()
{
int n,flag = 1;
while(scanf("%d",&n)!=EOF)
{
CSTree T;
Init_CSTree(T);
int c[2][n-1];
for(int op =0; op<n-1 ; op++) ///创建树
{
int x,y;
scanf("%d %d",&c[0][op],&c[1][op]);
//Create_CSTree(T,x,y);
}
for(int w=0; w<n-1; w++)
{
int wr = c[0][w];
int wt = c[1][w];
Create_CSTree(T,wr,wt);
}
///再来一个对firstchild 进行计数的函数 (即 这棵树有几层 就是有序树的深度)
///然后把这个孩子-兄第表示的树 看成二叉树 求深度即可
int a,b;
a = depth_Tree(T);
b = depth_BiTree(T);
printf("%d %d\n",a,b);
freeTree(T);
}
return 0;
}
算法二 : 结构体数组 结构体数组的指针
以空间换时间,访问数组而不是遍历二叉树。
定义一个结构体,结构体中存有指向第一个孩子的指针和指向下一个兄弟的指针,以及是否存在的标记。
定义一个结构体数组用来存储这些结构体,而下标就表示输入的父亲孩子节点的数值。
其实如果用指针来指向结构体数组的其他元素的话,也可以看成二叉链表的形式(如上图右边的形式),只不过对其进行操作时是数组形式,更加简单方便。
#include<stdio.h>
#include<stdlib.h>
using namespace std;
typedef struct ArTree
{
struct ArTree *firstchild;//,*lastsibling;
struct ArTree *nextsibling;
int exist_status;
ArTree()///mo ren gou zao han shu
{
firstchild =NULL;///结构体成员指针需要初始化
//lastsibling = NULL;
nextsibling=NULL;
exist_status=0;
}
} ArTree;
int Create_ArTree(struct ArTree *Ar,int a,int b,int &n)/// 检测根结点是否发生变化
{
if((Ar+a)->exist_status == 1 && (Ar+a)->firstchild==NULL)
{
(Ar+a)->firstchild = (Ar+b);
(Ar+b)->exist_status = 1;
}
else if((Ar+a)->exist_status == 1 && (Ar+a)->firstchild!=NULL)
{
ArTree *qq=NULL;
qq = (Ar+a)->firstchild;
while((qq->nextsibling)!=NULL)
{
qq = qq->nextsibling;
}
qq->nextsibling = (Ar+b);
(Ar+b)->exist_status = 1;
///free(qq);
}
else if((Ar+b)->exist_status == 1)
{
(Ar+a)->firstchild = (Ar+b);
(Ar+a)->exist_status = 1;
n = a;
Ar = Ar+a;
}
}
///求深度
int depth_ArTree_Order(ArTree *Ar)
{
if(Ar==NULL)
return 0;
int firstchild_depth = depth_ArTree_Order(Ar->firstchild);
int nextsibling_depth = depth_ArTree_Order(Ar->nextsibling);
return (firstchild_depth+1 > nextsibling_depth ? firstchild_depth+1 : nextsibling_depth);
}
int depth_ArTree(ArTree *Ar)
{
if(Ar==NULL)
return 0;
int fir = depth_ArTree(Ar->firstchild);
int nex = depth_ArTree(Ar->nextsibling);
if(fir>nex)
return fir+1;
else
return nex+1;
}
int main()
{
int input_num;
while(scanf("%d",&input_num)!=EOF)
{
struct ArTree Ar[30010],*p;//,*pro;
p = Ar;
int flag = 0;
int n = 1;
for(int i = 0; i<input_num-1; i++)
{
int a,b;
scanf("%d %d",&a,&b);
if(flag==0)
{
(p+a)->firstchild = p+b;
n=a;
(p+a)->exist_status = 1;
(p+b)->exist_status = 1;
flag=1;
//printf("p+a = %p (p+a)->firstchild = %p p+b = %p\n",p+a,(p+a)->firstchild ,p+b);
}
else if(flag!=0)
{
Create_ArTree(p,a,b,n);
}
}
printf("%d %d\n",depth_ArTree_Order(p+n),depth_ArTree(p+n));
}
}
算法二如果使用 free(q) 会出现 RunTime Error,报错结果为:
Runtime Error:[ERROR] A Not allowed system call: runid:1508674
callid:146 *** glibc detected *** ./Main: free(): invalid pointer:
0xbfaaa550 *** Runtime Error:[ERROR] A Not allowed system call:
runid:1508674 callid:146 *** glibc detected *** ./Main: free():
invalid pointer: 0xbf9d4514 ***
算法三 : 二叉链表存储、结构体数组访问
核心:建立二叉链表与结构体数组间的联系
步骤:
1. 建立结构体和二叉树,并进行结构体数组和树的初始化;
2. 输入第一对节点,建立二叉链表,同时对相应的数组元素进行操作,令根结点的firstchild指向其在二叉链表中的孩子节点,而lastsibling则指向自己(也就是根结点);
3. 接下来的输入按照以下步骤:
判断输入的a是否在二叉链表里且a是否有孩子,如果没有的话,利用数组取得其地址,对其地址所在的节点加孩子,并且对相应的数组元素进行操作;
如果有孩子的话,利用数组找到其孩子的最后一个兄弟,在最后一个兄弟后再加一个兄弟,并且对其原来的最后一个兄弟和现在的最后一个兄弟所在的数组元素进行操作;
结构体数组与二叉链表之间的关系
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
typedef int ElemType;
typedef int Status;
///孩子-兄弟表示法
typedef struct CSNode
{
ElemType data;
struct CSNode *firstchild,*nextsibling;
} CSNode,*CSTree;
///中间件
typedef struct ArTree
{
CSNode *firstchild_Ar,*lastsibling;
//struct ArTree *nextsibling;
int exist_status;
ArTree()///默认构造函数
{
firstchild_Ar =NULL;///结构体成员指针需要初始化
lastsibling = NULL;
//nextsibling=NULL;
exist_status=0;
}
} ArTree;
///初始化树
int Init_CSTree(CSTree &t)
{
t=NULL;
//static int maxn = 0;
return 0;
}
int Create_ArTree_BiTree(CSTree &T,struct ArTree *Ar,int a,int b)
{
if(T==NULL)
{
///create artree
T = new CSNode;
T->data = a;
T->nextsibling=NULL;
T->firstchild = new CSNode;
T->firstchild->data =b;
T->firstchild->firstchild = NULL;
T->firstchild->nextsibling=NULL;
///中间件
(Ar+a)->firstchild_Ar = T->firstchild;
//n=a;
(Ar+a)->lastsibling=T;
(Ar+b)->lastsibling = T->firstchild;
(Ar+a)->exist_status = 1;
(Ar+b)->exist_status = 1;
}
else
{
///判断输入的a 是否已经在二叉链表里了
if((Ar+a)->exist_status==1 && (Ar+a)->firstchild_Ar == NULL)
{
if((Ar+a)->lastsibling->data == a)
{
CSNode *lq;
lq= (Ar+a)->lastsibling;///zi shen
lq->firstchild= new CSNode;
lq->firstchild->data = b;
lq->firstchild->firstchild=NULL;
lq->firstchild->nextsibling=NULL;
(Ar+a)->firstchild_Ar=lq->firstchild;
(Ar+b)->lastsibling=lq->firstchild;
(Ar+b)->exist_status =1;
}
else if((Ar+a)->lastsibling->data != a)
{
CSNode *haha;
haha = (Ar+a)->lastsibling;
int y;
y = haha->data;
(Ar+y)->lastsibling->firstchild=new CSNode;
(Ar+y)->lastsibling->firstchild->data=b;
(Ar+y)->lastsibling->firstchild->firstchild=NULL;
(Ar+y)->lastsibling->firstchild->nextsibling=NULL;
(Ar+a)->firstchild_Ar=(Ar+y)->lastsibling->firstchild;
(Ar+b)->lastsibling=(Ar+y)->lastsibling->firstchild;
(Ar+b)->exist_status=1;
}
}
else if((Ar+a)->exist_status ==1 && (Ar+a)->firstchild_Ar != NULL)
{
//CSNode *lq;
int n;
n = (Ar+a)->firstchild_Ar->data;
if((Ar+n)->lastsibling == (Ar+a)->firstchild_Ar)
{
CSNode *qll;
qll=new CSNode;
qll->data=b;
qll->firstchild=NULL;
qll->nextsibling=NULL;
(Ar+n)->lastsibling->nextsibling=qll;
(Ar+n)->lastsibling=qll;
(Ar+b)->lastsibling= (Ar+a)->firstchild_Ar;///指回去
(Ar+b)->exist_status=1;
}
else
{
CSNode *qll;
qll = (Ar+n)->lastsibling;
qll->nextsibling=new CSNode;
qll->nextsibling->data=b;
qll->nextsibling->firstchild=NULL;
qll->nextsibling->nextsibling=NULL;
(Ar+n)->lastsibling=qll->nextsibling;
int m;
m=qll->data;
(Ar+m)->lastsibling=qll;
(Ar+b)->lastsibling=(Ar+a)->firstchild_Ar;
(Ar+b)->exist_status=1;
}
}
}
return 0;
}
///求深度
void freeTree(CSTree &root)
{
if (root!=NULL)
{
if (root->firstchild)
{
freeTree(root->firstchild);
root->firstchild= NULL;
}
if (root->nextsibling)
{
freeTree(root->nextsibling);
root->nextsibling = NULL;
}
if (root!=NULL)
{
free(root);
root=NULL;
}
}
}
void InOrder(CSTree T)
{
if(T)
{
InOrder(T->firstchild);
printf("%d ",T->data);
InOrder(T->nextsibling);
}
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
///first create bitree
CSTree T;
Init_CSTree(T);
struct ArTree Ar[31000];//,*p;
//p=Ar;
///input data
for(int i =0; i<n-1; i++)
{
int a,b;
scanf("%d %d",&a,&b);
Create_ArTree_BiTree(T,Ar,a,b);
//InOrder(T);
//printf("\n");
}
printf("%d %d\n",depth_Tree(T),depth_BiTree(T));
//freeTree(T);
}
return 0;
}
还有一个现象:
如果静态变量没有初始化,但在函数中出现了,codeblocks不会运行。
如上。