五.二叉树——习题解

一.递归

1带返回值

  1. 求高度
  2. 求父结点
  3. 计算分支结点数
  4. 判断二叉树是否相似
  5. 求先序第k个结点的值

1.求高度——递归返回型,返回一个int值。

int Depth(BiTree T) {
	if (T==NULL)
		return 0;
	else 
		return Depth(T->lchild) > Depth(T->rchild) ? Depth(T->lchild)+1 : Depth(T->rchild)+1;
	//return T == NULL ? 0 : Depth(T->lchild) > Depth(T->rchild) ? Depth(T->lchild) + 1 : Depth(T->rchild) + 1;
}

2.求任意结点的父结点——递归返回型,返回一个结点。

//找父结点
BSTNode* father(BSTree T, BSTNode* p) {
	if (T == NULL)
		return NULL;
	if (T->lchild == p || T->rchild == p)
		return T;
	else
		return father(T->lchild, p) ? father(T->lchild, p) : (father(T->rchild, p) ? father(T->rchild, p) : NULL);
}

3.计算分支结点数——递归返回型,返回一个int值。

/*Q8 计算一个二叉树所有双分支结点数*/
int Q8(BiTree T) {
	if (T == NULL)
		return 0;
	else if (T->lchild && T->rchild)    
		return Q8(T->lchild) + Q8(T->rchild) + 1;
	else
		return Q8(T->lchild) + Q8(T->rchild);
}

4.判断二叉树是否相似——递归返回型,返回一个bool值。

/*Q17 判断二叉树是否相似*/
bool Q17(BiTree T1, BiTree T2) {
	if (T1 != NULL && T2 != NULL)		//返回小的(0),若都相同,返回1
		return Q17(T1->lchild, T2->lchild) && Q17(T1->rchild, T2->rchild); //直接返回两值想与!我用三目返回小的
	else if (T1 == NULL && T2 == NULL)
		return 1;
	else
		return 0;
}

5.求先序第k个结点的值——递归返回型,返回一个char值。

/*Q10 求先序遍历序列中第k个结点的值*/
char ch;	//带返回值的递归一般return 函数;但是这里需要判断,所以用了赋值
char Q10_(BiTree T, int k) {
		if (T == NULL)
			return '#';
		if (j == k)
			return T->data;
		j++;
		ch=Q10_(T->lchild, k);     //这里如果递归中找到,则return T->data会return到ch中,我们需要输出ch,若左边没找到也就是ch='#',继续找右边
		if (ch != '#')
			return ch;
		ch=Q10_(T->rchild, k);
			return ch;
}



2.带参数deep

  1. 计算二叉树的带权路径长度
  2. 中缀表达式输出

1.计算二叉树的带权路径长度——全局变量,带层参数

/*Q19 真题——计算二叉树的带权路径长度(即所有叶结点的带权路径长度之和)*/
int sum = 0;
void PreQ19(Q19Tree T,int level) {     //将level作为参数传入
	if (T) {						   //level初始值为0
		if (T->lchild == 0 && T->rchild == 0)    //叶子结点,直接计算权值
			sum += T->weight * level;
		else {
			PreQ19(T->lchild, level + 1);
			PreQ19(T->rchild, level + 1);
		}
	}
}

2.中缀表达式输出——带层参递归,中序遍历

/*Q20 真题——中缀表达式输出*/
//除了第一层外,都是(左子树,根,右子树),加一个depth做参数
void BtreeToExp(BTree* T, int deep) {	//deep初始值为1
	if (T == NULL)
		return;
	else if (T->left == NULL && T->right == NULL)  //叶子直接输出
		cout << T->data[0];
	else {
		if (deep > 1)
			cout << "(";
		BtreeToExp(T->left, deep + 1);     //左子
		cout << T->data[0];                   //输出根
		BtreeToExp(T->right, deep + 1);    //右子
		if (deep > 1)
			cout << ")";
	}
}



3.三种遍历变体

  1. 交换所有左右子树
  2. 删除子树
  3. pre转化成post(满二叉树)

1.交换所有左右子树——先序遍历型。

/*Q9 交换所有结点的左右子树*/
void Q9(BiTree& T) {
	if (T) {
		BiNode* p = T->lchild;
		T->lchild = T->rchild;
		T->rchild = p;
		Q9(T->lchild);
		Q9(T->rchild);
	}
}

2.删除子树——后序+先序遍历型。

/*Q11 删除二叉树中以值为x的结点为根的子树,并释放空间*/
//初想法,利用后序遍历写一个删除函数,利用先序遍历找到相应的根然后删除并释放空间
void PostDelete(BiTree& T) {
	if (T) {
		PostDelete(T->lchild);
		PostDelete(T->rchild);
		delete(T);        //从下向上删除
		T = NULL;
	}
}
void Q11(BiTree &T, char x) {    //自上而下找值
	if (T) {
		if (T->data == x)
			PostDelete(T);
		else {
			Q11(T->lchild, x);
			Q11(T->rchild, x);
		}
	}
}

3.pre转化成post(满二叉树)——序列转化型。

/*Q15 已知满二叉树的先序序列pre,求其后序序列*/
//递归处理,每次将根移到后面,然后左右子树递归
void Q15(char* pre,int L,int R) {
	if((R - L + 1) % 2 != 0) {			//为奇数,说明有根
		int temp = pre[L];
		for (int i = L; i < R; i++)       //每次将根移到最后面,其他元素前移一位
			pre[i] = pre[i + 1];
		pre[R] = temp;						//因为第一位移到最后,所以(L+R)/2此时是右子树第一位
		Q15(pre, L, (L + R) / 2 - 1);			//递归处理左边一半
		Q15(pre, (L + R) / 2, R - 1);			//递归处理右边一半
	}
}
void Q15_(char* pre, int l1, int h1, char* post, int l2, int h2) {
	int half;
	if (h1 >= l1) {
		post[h2] = pre[l1];
		half = (h1 - l1) / 2;
		Q15_(pre, l1 + 1, l1 + half, post, l2, l2 + half - 1);    
		Q15_(pre, l1 + half + 1, h1, post, l2 + half, h2 - 1);
	}
}

4.叶操作

叶子操作型——前、中、后序遍历均可实现。

1.rchild 串联所有叶子

/*Q16 将二叉树的叶结点从左到右串成单链表,用lchild来链接,头为head*/
//前中后均可,此处用中序
BiNode* head , * p = NULL;    //p用来向后遍历叶子
void Q16(BiTree T) {
	if (T) {
		Q16(T->lchild);
		if (T->lchild == NULL && T->rchild == NULL) {
			if (p == NULL) {	//第一个叶子
				head = T;
				p = T;
			}
			else {
				p->rchild = T;
				p = p->rchild;
			}
		}
		Q16(T->rchild);
	}
}

2.二叉树带权路径长度
见前面

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值