考研 ing
努力努力再努力
**
第五章 树
1.基础知识
线索二叉树
typedef struct ThreadNode{
ElemType data;
struct ThreadNode *lchild,*rchild;
int ltag,rtag;
}ThreadNode,*ThreadTree;
中序线索二叉树构造(不带头结点)
void InThread(ThreadTree &p,ThreadTree &pre){
if(p!=NULL){
InThread(p->lchild,pre);
if(p->lchild==NULL)
p->lchild=pre,p->ltag=1;
if(pre!=NULL&&pre->rchild==NULL)
pre->rchild=p,pre->rtag=1;
pre=p;
InThread(p->rchild,pre);
}
}
void CreateInThread(ThreadTree T){
ThreadTree pre=NULL;
if(T!=NULL){
InThread(T,pre);
pre->rchild=NULL;
pre->rtag=1;
}
}
中序遍历(3种)
1.递归
void Inorder(BiTree T){
if(T!=NULL){
Inorder(T->lchild);
visit(T);
Inorder(T->rchild);
}
}
2.非递归:用栈
void Inorder(BiTree T){
InitStack(S); p=T;
while(p||!StackEmpty(S)){
if(p)
Push(S,p), p=p->lchild;
else{
Pop(S,p), visit(p);
p=p->rchild;
}
}
}
3.非递归:用线索链表
void Inorder(BiTree T){
p=T;
while(p!=NULL){
while(p->ltag==0) p=p->lchild;
visit(p);
while(p->rtag==1&&p->rchild!=NULL)
p=p->rchild, visit(p);
p=p->rchild;
}
}
2.寻找二叉树两结点最近邻祖先
ElemType comancestor(SqTree T,int i,int j){
if(T[i]!='#'&&T[j]!='#'){ //两结点存在
while(i!=j){
if(i>j) i=i/2;
else j=j/2;
}
return T[i];
}
}
3.后序遍历(非递归)
void postorder(BiTree T){
p=T;
InitStack(S);
r=NULL;
while(p||!IsEmpty(S)){
if(p)
Push(S,p), p=p->lchild;
else{
GetTop(S,p);
if(p->rchild&&p->rchild!=r)
p=p->rchild;
else{
Pop(S,p);
visit(p->data);
r=p;
p=NULL;
}
}
}
}
4.层次遍历的逆
//思想:先层次遍历入栈再输出即可得其逆
void InvertLevel(BiTree T){
InitStack(S);
InitQueue(Q);
EnQueue(Q,T);
while(!IsEmpty(Q)){
DeQueue(Q,p);
Push(S,p);
if(p->lchild) EnQueue(Q,p->lchild);
if(p->rchild) EnQueue(Q,p->rchild);
}
while(!IsEmpty(S)){
Pop(S,p);
visit(p);
}
}
5.二叉树的深度
1.非递归:利用层次遍历
int depth(BiTree T){
if(!T)
return 0;
int front=-1,rear=-1;
int last=0,level=0;
BiTree Q[Maxsize];
Q[++rear]=T;
BiTree=p;
while(front<rear){
p=Q[++front];
if(p->lchild) Q[++rear]=p->lchild;
if(p->rchild) Q[++rear]=p->rchild;
if(front==last)
level++,last=rear;
}
return level;
}
2.递归
int depth(BiTree T){
if(!T)
return 0;
ldep=depth(T->lchild);
rdep=depth(T->rchild);
if(ldep>rdep)
return ldep+1;
else
return rdep+1;
}
6.知中序和先序遍历建立二叉链表
BiTree create(ElemType A[],ElemType B[],int l1,int h1,int l2,int h2){
//开始时l1=l2=1,h1=h2=n
//先序遍历第一个和最后一个结点下标为l1和h1
//中序遍历第一个和最后一个结点下标为l2和h2
root=(BiNode *)malloc(sizeof(BiNode));
root->data=A[l1];
for(i=l2;B[i]!=root->data;i++);
llen=i-l2;
rlen=h2-i;
if(llen)
create(A,B,l1+1,l1+llen,l2,l2+llen-1);
else
root->lchild=NULL;
if(rlen)
create(A,B,h1-rlen+1,h1,h2-rlen+1,h2);
else
root->rchild=NULL;
return root;
}
7.判断一棵二叉树是否为完全二叉树
bool Iscomplete(BiTree T){
if(!T)
return 1; //空树是完全二叉树
EnQueue(Q,T);
while(!isEmpty(Q)){
DeQueue(Q,p);
if(p)
EnQueue(Q,p->lchild),EnQueue(Q,p->rchild);
else{
while(!isEmpty(Q)){
DeQueue(Q,p);
if(p) return 0;
}
}
}
return 1;
}
8.计算二叉树双分支结点个数
int DNode(BiTree T){
if(!T)
return 0;
else if(T->rchild&&T->lchild)
return DNode(T->lchild)+DNode(T->rchild)+1;
else if(T->rchild||T->lchild)
return DNode(T->lchild)+DNode(T->rchild);
}
9.交换左右子树
void swap(BiTree T){
if(b){
swap(T->lchild);
swap(T->rchild);
temp=T->lchild;
T->lchild=T->rchild;
T->rchild=temp;
}
}
10.求前序遍历第k个结点值
int i=1;
ElemType PreNode(BiTree T,int k){
if(!T)
return '#';
if(i==k)
return T->data;
i++;
ch=PreNode(T-lchild,k);
if(ch!='#')
return ch;
ch=PreNode(T->rchild,k);
return ch;
}
11.删除值为x的结点和以该节点为根结点的树
//思想:找到值为x的结点,删除该节点左子树和右子树
删除操作
void DeleteX(BiTree &T){
if(T){
DeleteX(T->lchild);
DeleteX(T->rchild);
free(T);
}
}
主函数
void Search(BiTree T,ElemType x){
if(T){
if(T->data==x){
DeleteX(T);
exit(0);
}
BiTree Q[]; //层次遍历队列寻找x
EnQueue(Q,T);
while(!isEmpty(Q)){
DeQueue(Q,p);
if(p->lchild){
if(p->lchild->data==x)
DeleteX(p->lchild), p->lchild=NULL;
else
EnQueue(Q,p->lchild);
}
if(p->rchild){
if(p->rchild->data==x)
DeleteX(p->rchild), p->rchild=NULL;
else
EnQueue(Q,p->rchild);
}
}
}
12.输出值为x的结点的所有祖先
typedef struct{
BiTree T;
int tag; //tag=0,左子树已访问;tag=1,右子树已访问
}stack;
void shuchu(BiTree T,ElemType x){
p=T;
stack s[];
top=0;
while(p||top>0){
while(p&&p->data!=x){
s[++top].T=p;
s[top].tag=0;
p=p->lchild;
}
if(p->data==x){
for(i=1;i<=top;i++)
visit(s[i].T->data);
exit(1);
}
while(top>0&&s[top].tag==1)
top--;
if(top>0){
s[top].tag=1;
p=s[top].T->rchild;
}
}
}
13.任意两结点最近邻公共祖先
思想:后序遍历栈中所剩元素皆为结点祖先,不失一般性,假设p在q的左边。即先遍历到p,然后遍历到q。
typedef struct{
BiTree t;
int tag;
}stack;
BiTree ancestor(BiTree root,BiTNode *p,BiTNode *q){
stack s[],sl[];
top=0,bt=root;
while(top>0||bt){
while(bt){
s[++top].t=bt;
s[top].tag=0; //访问左孩子为0,访问右孩子为1
bt=bt->lchild;
}
while(top>0&&s[top].tag==1){
if(s[top].t==p){
for(i=1;i<=top;i++)
sl[i]=s[i];
topl=top;
}
if(s[top].t==q)
for(i=top;i>0;i--){
for(j=topl;j>0;j--)
if(s[i].t==sl[j].t)
return s[i].t;
}
top--;
}
if(top>0){
s[top].tag=1;
bt=s[top].t->rchild;
}
}
return NULL;
}
14.二叉树宽度
思想:层次遍历,标记层数,最后数每层结点个数。
typedef struct{
BiTree data[maxsize];
int level[maxsize];
int front,rear;
}qu;
int BTwidth(BiTree b){
BiTree p;
int k,max,i,n;
qu.front=qu.rear=-1;
qu.rear++;
qu.data[qu.rear]=b;
qu.data[qu.rear]=1;
while(qu.front<qu.rear){
qu.front++;
p=qu.data[qu.front];
k=qu.level[qu.front];
if(p->lchild){
qu.rear++;
qu.data[qu.rear]=p->lchild;
qu.level[qu.rear]=k+1;
}
if(p->rchild){
qu.rear++;
qu.data[qu.rear]=p->rchild;
qu.level[qu.rear]=k+1;
}
}
max=0,i=0;
k=1;
while(i<=q.rear){
n=0;
while(i<=q.rear&&qu.level[i]==k)
n++,i++;
k=qu.level[i];
if(n>max)
max=n;
}
return max;
}
15.满二叉树已知先序求后序
思想:一般二叉树只知先序和后序无法确定树。
但对于满二叉树,任一结点的左右子树包含结点数相等,故先序的第一个为后序的最后一个,先序的左右子树分别利用递归方法求得最终结果。
void pretopost(ElemType pre[],int l1,int h1,ElemType post[],int l2,int h2){
//l1,h1,l2,h2分别为先序和后序得第一和最后一个结点
int half;
if(h1>=l1){
post[h2]=pre[l1];
half=(h1-l1)/2;
pretopost(pre,l1+1,l1+half,post,l2,l2+half-1);
pretopost(pre,l1+half+1,h1,post,l2+half,h2-1);
}
}
16.将叶结点从左到右连接
思想:中序遍历
LinkList head,pre=NULL; //定义全局变量,可以连续记忆
LinkList InOrder(BiTree bt){
if(bt){
InOrder(bt->lchild);
if(!bt->lchild&&!bt->rchild){
if(!pre){
head=bt;
pre=bt;
}
else{
pre->rchild=bt;
pre=bt;
}
}
InOrder(bt->rchild);
pre->rchild=NULL;
}
return head;
}
17.判断两棵树是否相似
int similar(BiTree t1,BiTree t2){
int lefts,rights;
if(t1==NULL&&t2==NULL)
return 1;
else if(t1==NULL||t2==NULL)
return 0;
else{
lefts=similar(t1->lchild,t2->lchild);
rights=similar(t1->rchild,t2->rchild);
return lefts&&rights;
}
}
18.中序线索二叉树查找结点在后序遍历中的前驱
BiThrTree Inpostpre(BiThrTree t,BiThrTree p){
BiThrTree q;
if(p->rtag==0)
q=p->rchild;
else if(q->ltag==0)
q=p->lchild;
else if(q->lchild==NULL)
q=NULL;
else{
while(p->ltag==1&&p->lchild!=NULL)
p=p->lchild;
if(p->ltag==0)
q=p->lchild;
else
q=NULL;
}
return q;
}
19.带权路径长度之和
typedef struct BiTNode{
int weight;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
思路一:先序遍历到叶结点,wpl=权值*路径长度
int WPL(BiTree root){
return wpl_preorder(root,0);
}
int wpl_preorder(BiTree bt,int deep){
static int wpl=0;
//定义静态变量存储wpl,程序执行前创建,执行期间一直存在
if(bt->lchild==NULL&&bt->rchild==NULL)
wpl+=deep*bt->weight;
if(bt->lchild!=NULL)
wpl_preorder(bt->lchild,deep+1);
if(bt->rchild!=NULL)
wpl_preorder(bt->rchild,deep+1);
return wpl;
}
思路二:层次遍历,记录层数,到达叶结点,累计wpl
#define maxsize 100
int wpl_levelorder(BiTree root){
BiTree q[maxsize];
int end1,end2;
end1=end2=0;
int wpl=0,deep=0;
BiTree lastnode,newlastnode;
lastnode=root,newlastnode=NULL;
q[end2++]=root;
while(end1!=end2){
BiTree t=q[end1++];
if(t->lchild==NULL&&t->rchild==NULL)
wpl+=deep*t->weight;
if(t->lchild!=NULL){
q[end2++]=t->lchild;
newlastnode=t->lchild;
}
if(t->rchild!=NULL){
q[end2++]=t->rchild;
newlastnode=t->rchild;
}
if(t=lastnode){
lastnode=newlastnode;
deep+=1;
}
}
return wpl;
}
20.将二叉树转换为中缀表达式
void BtoE(BTree *root){
BtoExp(root,1);
}
void BtoExp(BTree *root,int deep){
if(root==NULL)
return;
else if(root->left==NULL&&root->right==NULL)
printf("%s",root->date);
else{
if(deep>1) printf("(");
BtoExp(root->left,deep+1);
printf("%s",root->data);
BtoExp(root->right,deep+1);
if(deep>1) printf(")");
}
}