树(2021.7.11晚)

考研 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(")");
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值