树
1.定义
有且只有一个根结点,若干个互不相交(没有交集)的子树;
除了根结点,每个结点有且只有一个父结点;
N个结点的树有N-1条边(每个结点都有往上的一条边除了根结点);
2.存储
孩子兄弟表示法
A、每个结点都有一个指向其第一个孩子的指针
B、每个结点都有一个指向其第一个右兄弟的指针
二叉树
1.性质
1)第i层最多 2^ i-1 个结点;
2)深度为 k 的二叉树上至多含 2^k-1 个结点(k≥1);
3) 对任何一棵二叉树,若它含有n0 个叶子结点、n2 个度为 2 的结点,则必存在关系式:n0 = n2+1;
二叉树上结点总数 n = n0 + n1 + n2;
二叉树上分支总数 b = n1 + 2n2;
b = n-1;
4)完全二叉树的特性:
A、同样结点数的二叉树,完全二叉树的深度最小;
B、完全二叉树的叶子结点仅出现在最下边两层,并且最底层的叶子结点一定出现在左边,倒数第二层的叶子结点一定出现在右边;
C、完全二叉树中度为1的结点只有左孩子;
5) 完全二叉树:
A.非根结点的父结点是小超过i/2的最大整数;
B.若 2i>n,则该结点无左孩子, 否则,编号为 2i 的结点为其左孩子结点;
C.若 2i+1>n,则该结点无右孩子结点, 否则,编号为2i+1 的结点为其右孩子结点;
2.存储结构
1)顺序存储:完全二叉树从上往下,从左往右放入一维数组中;非完全把不存在的结点空出;(完全二叉树)
2)链式存储:
3.遍历
从左往右:(访问根结点、遍历左子树、遍历右子树)先序(根),中序,后序;
1.先序递归
先访问根结点;先序遍历左子树;先序遍历右子树;
void prev(struct node *t)
{
if(t)
{
printf("%d",t->data);
prev(t->lchild);
prev(t->rchild);
}
}
非递归
从根结点开始访问入栈,
2.层次遍历
4.建立
1.已知二叉树先序遍历输入的字符序列,空结点用,表示;
int i=0;
char s[100];
struct node* creat ( )
{
struct node *t;
if(s[i]==',')
{
i++;
t=NULL;
}
else
{
t=(struct node*)malloc(sizeof(struct node));
t->data=s[i];
i++;
t->lchild=creat();
t->rchild=creat();
}
return t;
}
2.两种遍历序列确定二叉树
必须有中序
A. 已知先序和中序
struct node *creat(char a[], char b[], int n)
{
struct node *t;
int i;
if(n==0) t=NULL;
else
{
t=(struct node*)malloc(sizeof(struct node));
for(i=0; i<n; i++)
{
if(b[i]==a[0]) break;
}
t->lchild=creat(a+1,b,i); //i个左子树
t->rchild=creat(a+1+i,b+i+1,n-1-i); //先序 +根+左子树;中序 +根+左子树;总个数 n-1;
}
return t;;
}
B.已知后序和中序
struct node *creat(char a[] , char b[] , int n)
{
struct node *t;
int i;
if(n==0) t=NULL;
else
{
t=(struct node*)malloc(sizeof(struct node));
t->data=b[n-1]; //b后序
for(i=0; i<n; i++)
{
if(b[i]==b[n-1]) break; //a中序
}
t->lchild=creat(a,b,i);
t->rchild=creat(a+1+i,b+i,n-1-i); //中序 +根+左子树;后序 +左子树;
}
return t;
}
5.应用
1.求二叉树深度
int depth(struct node *t)
{
if(t==NULL) return 0;
else
{
int left=depth(t->lchild);
int right=depth(t->rchild);
if(left<right) return right+1;
else return left+1;
}
}