一.递归
1带返回值
- 求高度
- 求父结点
- 计算分支结点数
- 判断二叉树是否相似
- 求先序第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.计算二叉树的带权路径长度——全局变量,带层参数
/*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.三种遍历变体
- 交换所有左右子树
- 删除子树
- 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.二叉树带权路径长度
见前面