王道p144

09.设树B是一棵采用链式结构存储的二叉树,编写一个把树B中所有结点的左右子树进行交换的函数。

  • 算法思想:采用递归算法实现交换二叉树的左右子树,首先交换b结点的左孩子的左右子树,然后交换右孩子的左右子树,最后交换b结点的左右孩子,当结点为空时递归结束(后序遍历思想)。
void swap(BiTree b) {
	if(b) {
		swap(b->lchild);
		swap(b->rchild);
		temp=b->lchild;
		b->lchild=b->rchild;
		b->rchild=temp;
	}
}

10.求先序遍历序列中第k个结点的值。

  • 算法思想:设置一个全局变量i(初值为1)来表示先序遍历时,当前访问的第几个结点。先序遍历二叉树,当二叉树为空时,返回#;当k==i时,返回b->data;当k不为i时,递归地依次在左、右子树查找。
int i=1;
ElemType preNode(BiTree b,int k) {
	if(b==NULL)
		return	'#';
	if(i==k)
		return b->data;
	i++;
	ch=preNode(b->lchild,k);
	if(ch!='#')
		return ch;
	ch=preNode(b->rchild,k);
	return ch;
}

11.对于树中每个元素值为x的结点,删除以它为根的子树,并释放相应的空间。

  • 算法思想:删除值为x的结点,意味着将其父结点的左(右)子女指针置空,用层次遍历易找到其父结点。要删除每个元素值为x的结点,因此需要遍历整棵树。而想要释放相应的空间,首先需要删除其左右子树,再释放值为x的根结点的空间,可采用后序遍历。
  • 后序遍历,删除结点的左右子树。
  • 层次遍历,查找x的父结点,释放空间。
  • 遍历整棵树,找到所有元素值为x的结点·。
void deleteXTree(BiTree &b) {
	if(b) {
		deleteXTree(b->lchild);
		deleteXTree(b->rchild);
		free(b);
	}
}
void search(BiTree b,ElemType x) {
	BiTree Q[];
	if(b) {
		if(b->data==x) {
			deleteXTree(b);
			exit(0);
		}
		InitQueue(Q);
		EnQueue(Q,b);
		while(!IsEmpty(Q)) {
			DeQueue(Q,p);
			if(p->lchild) {
				if(p->lchild->data==x) {
					deleteXTree(p->lchild);
				} else
					EnQueue(Q,p->lchild);
			} else
				EnQueue(Q,p->rchild);
		}
	}
}

12.在二叉树中查找值为x的结点,打印值为x的结点的所有祖先

  • 采用非递归后序遍历(先出栈再访问),最后访问根结点,访问到x的结点时,栈中所有元素均为该结点的祖先,依次打印即可。
    在这里插入图片描述
typedef struct {
	BiTree t;
	int tag;
} stack;
void search(BiTree bt,ElemType x) {
	stack s[];
	top=0;
	while(bt!=NULL||top>0) {
		//结点入栈 (根,左孩子 )
		while(bt!=NULL&&bt->data!=x) {
			s[++top].t=bt;
			s[top].tag=0;
			bt=bt->lchild;
		}
		if(bt!=NULL&&bt->data==x) {
			printf("所查结点的所有祖先结点的值为:\n");
			for(i=1; i<=top; i++)
				printf("%d",s[i].t->data);
			exit(1);
		}
		while(top!=0&&s[top].tag=1)
			top--;
		if(top!=0) {
			s[top].tag=1;
			bt=s[top].t->rchild;
		}
	}
}

13.设一棵二叉树的结点结构为(LLINK,INFO,RLINK),ROOT为指向该二叉树根结点的指针,p和q分别指向该二叉树中任意两个结点的指针,编写算法ANCESTOR(ROOT,p,q,r),找到p和q的最近公共祖先结点r。

14.求非空二叉树的宽度。

  • 采用层次遍历求出所有结点的层次,并将所有结点和对应的层次放在一个队列中。然后通过扫描队列求出各层的结点数,最大的层结点数即为二叉树的宽度。
typedef struct {
	BiTree data[MaxSize];
	int level[MaxSize];
	int front,rear;
} Qu;
int BTWidth(BiTree b) {
	BiTree p;//出队结点
	//k层次,max最多结点个数 ,i扫描队中所有元素,n统计第k层 结点个数
	int k,max,i,n;
	//队列为空
	Qu.front=Qu.rear=-1;
	//根结点入队
	Qu.data[++Qu.rear]=b;
	Qu.level[Qu.rear]=1;
	while(Qu.front<Qu.rear) {
		//出队
		Qu.front++;
		p=Qu.data[Qu.front];
		k=Qu.level[Qu.front];
		//左孩子入队
		if(p->lchild!=NULL) {
			Qu.data[++Qu.rear]=p->lchild;
			Qu.level[Qu.rear]=k+1;
		}
		//右孩子入队
		if(p->rchild!=NULL) {
			Qu.data[++Qu.rear]=p->rchild;
			Qu.level[Qu.rear]=k+1;
		}
	}
	k=1;max=0;i=0;
	while(i<=Qu.rear) {
		n=0;
		while(i<=Qu.rear&&Qu.level[i]==k) {
			n++;
			i++;
		}
		//更新层数
		k=Qu.level[i];
		if(n>max)
			max=n;
	}
	return max;
}
  • 按照层次遍历的思路,我们将根结点入队,然后出队,temp表示二叉树每层的结点个数,每次出队一个元素temp++,然后把根节点的左右孩子入队,判断front指针是否大于last(每层结点最后元素的位置),即判断这一层的元素是否全部出队(全部出队则front与上一次的rear相等,即大于last(rear-1)),如果全部出队则更新last,max(最大宽度)和temp,最后递归所有元素然后返回最大宽度max。
int WidthBiTree(BiTree T) {
	if(!T)	return 0;//空树
	Queue Q;
	//temp为树每层的结点个数 ,last为一层中最后一个结点在队列的位置
	int temp=0,last=0,max=0;
	InitQueue(Q);
	EnQueue(Q,T);
	while(Q.front <= last) { //每出队一个元素front+1
		DeQueue(Q, T);
		temp++;
		if (e->lchild != NULL)//每次入队rear+1
			EnQueue(Q, T->lchild);
		if (e->rchild != NULL)
			EnQueue(Q, T->rchild);
		//判断这一层的元素是否全部出队
		if (Q.front > last) {
			last = Q.rear-1;
			max = max > temp ? max : temp;
			temp = 0;
		}
	}
	return max;
}

15.一棵满二叉树,已知先序序列为pre,求其后序序列post。

  • 相对于满二叉树而言,任意一个结点的左右子树均含有相等的结点数。同时,先序序列的第一个结点作为后序序列的最后一个结点。
void PreToPost (ElemType pre[],int l1,int h1,ElemType post[],int l2,int 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+1+half,h1,post,l2+half,h2-1);
	}
}

16.设计一个算法将二叉树的叶结点按从左到右的顺序连成一个单链表,表头指针为head。二叉树按二叉链表的方式存储,链接时用叶结点的右指针域来存放单链表的指针。

  • 采用中序递归遍历的思想。设置前驱结点指针pre,初始为空。第一个叶结点由指针head指向,遍历到叶结点时,将前驱的rchild指针指向它,最后一个叶结点的rchild为空。
  • 算法的时间复杂度为O(n),空间复杂度为O(n)。
LinkedList head,pre=NULL;
LinkedList InOrder(BiTree b) {
	if(b) {
		InOrder(b->lchild);
		if(b->lchild==NULL&&b->rchild==NULL) {
			if(pre==NULL) {
				head=b;
				pre=b;
			} else {
				pre->rchild=b;
				pre=b;
			}
		}
		InOrder(b->rchild);
		pre->rchild=NULL;
	}
	return head;
}

18.写出在中序线索二叉树里查找指定结点在后序的前驱结点的算法。

  • 在后序序列中,若结点p有右子女,则右子女是其前驱,若无有子女而有左子女,则左子女是其前驱。若结点p左右子女均无,设其中序左线索指向某祖先结点f(p是f右子树中按中序遍历的第一个结点),若f有左子女,则左子女是其前驱;若f无左子女,则顺其前驱找双亲的双亲,一直找到双亲有左子女(这时左子女是其前驱)。若p是中序遍历的第一个结点,则结点p在中序和后序下均无前驱。
BiThrTree InPostPre(BiThrTree t,BiThrTree p) {
	BiThrTree q;
	//结点p有右子女,则右子女是其前驱
	if(p->rtag==0)
		q=p->rchild;
	//有左子女,则左子女是其前驱
	else if(p->ltag==0)
		q=p->lchild;
	//p是中序遍历的第一个结点,则结点p在中序和后序下均无前驱
	else if(p->lchild==NULL)
		q=NULL;
	else {
		while(p->ltag==1&&p->lchild!=NULL)
			q=p->lchild;
		if(p->ltag==0)
			q=p->lchild;
		else
			q=NULL;
	}
	return q;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

上岸啦小王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值