二叉树递归应用

二叉树递归应用

此文档主要是用来记录二叉树的一些递归操作.

结构

typedef struct node { // 二叉树节点结构
    char data;
    struct node *lchild;
    struct node *rchild;
} *Bitree;

建树

Bitree CreateBitree() {
    char ch;
    cin >> ch; // 此处不拘泥小节
    Bitree T;
    T = new node;
    if (ch == '#') T = NULL;
        //注意:二叉树的输入需要严格遵守以#结尾的规则,并且输入顺序按照前序遍历的方式
    else {
        T->data = ch; // 构建此节点
        T->lchild = CreateBitree(); // 构建左子树
        T->rchild = CreateBitree(); // 构建右子树
    }
    return T;
}
// 输入样例 AB#C##DE##FG#H##I##

求叶子节点个数

// 数叶子节点数目
int countLeaf(Bitree T) {
    if (!T)
        return 0;
    if (!T->lchild && !T->rchild) { // 对于叶子节点,其向上返回1(一个叶子)
        return 1;
    } else {
        int cnt = 0;   // 非叶子节点的向上返回其左右子树叶子节点的和
        cnt += countLeaf(T->lchild);
        cnt += countLeaf(T->rchild);
        return cnt;
    }
}

求二叉树深度

// 求二叉树深度
int countDeep(Bitree T) {
    if (!T)
        return 0;
    return max(countDeep(T->lchild), countDeep(T->rchild)) + 1;// 对于非空子树,其深度是左右子树最大深度+1
}

删除指定元素及其子树

// 删除T为根节点的子树,包括T
void realDel(Bitree T) {
    if (!T)
        return;
    realDel(T->lchild);
    realDel(T->rchild);
    free(T);
}

// 从T中删除 以“值为x的节点”作为根节点的子树
Bitree myDel(Bitree T, char x) {
    if (!T)
        return NULL;
    if (T->data == x) {// 找到目标节点,直接删除它与其左右子树
        realDel(T);
        return NULL;
    } else {// 此节点不是需删除的节点,向左右子树递归删除
        T->lchild = myDel(T->lchild, x); // 注意此处,保证置空
        T->rchild = myDel(T->rchild, x);
        return T;
    }
}

求先序序列中第k个位置的节点的值

// 自己写得不太完善,参考了课本的写法,即将函数的范围值设为布尔类型,用以判断是否找到了元素,再通过参数x来接收返回值(如果成功找到的话)
// 寻找先序遍历中第k个元素
int findPreK(Bitree T, int *cur, int k, char *x) {// 树,已处理节点个数,目标节点数,接收节点值的变量
    if (!T)
        return false;
    if (*cur >= k) {
        return false;
    }
    (*cur)++; // 一开始有困惑,后来发现cur计数器加一的操作是和对本节点的访问绑定的,也就是如果不访问本节点,就不能算作"处理了一个节点",更不能加一了
    if (*cur == k) {
        *x = T->data;
        return true;
    }
    if (!findPreK(T->lchild, cur, k, x)) {
        return findPreK(T->rchild, cur, k, x);
    }
    return true;
}

然后顺手把中序和后序写了一下


int findOrdK(Bitree T, int *cur, int k, char *x) { // 中序(记不清怎么命名了,稍后再改吧)
    if (!T)
        return false;
    if (*cur >= k)
        return false;
    if (findOrdK(T->lchild, cur, k, x))// 左
        return true;
    (*cur)++;   // 中
    if (*cur == k) {
        *x = T->data;
        return true;
    }
    return findOrdK(T->rchild, cur, k, x); // 右
}

int findAftK(Bitree T, int *cur, int k, char *x) { // 后序
    if (!T)
        return false;
    if (*cur >= k)
        return false;
    if (findAftK(T->lchild, cur, k, x))	// 左
        return true;
    if (findAftK(T->rchild, cur, k, x)) // 右
        return true;
    (*cur)++;// 中
    if (*cur == k) {
        *x = T->data;
        return true;
    }
    return false;
}

根据前缀表达式建树

// 这里要注意..乘法不要写'x',而要写'*',否则会误判
int isOpNum(char n) {
    return n >= 'a' && n <= 'z';
}

// 前缀表达式建树
Bitree CreateBitree() {
    cin >> ch;
    Bitree T;
    T = new node;
    T->lchild = NULL;
    T->rchild = NULL;
    T->data = ch;
    if (!isOpNum(ch)) {// 是操作符
        T->lchild = CreateBitree();
        T->rchild = CreateBitree();
    }
    return T;
}

中缀表达式建树

// 这个难度实在太大,教材和ppt上都未详细解答,这个程序虽不能解决括号问题,但是却能给出初步答案,而且也给我启示:中缀表达式难以在线解决(或许换成后缀表达式可以?)
//中缀表达式建树过程  - 递归过程
Bitree InTree(char s[], int i, int j)  //s - 表达式字符串、i - 字符串起始位置、j - 字符串最后一个字符的位置
{
    //动态生成的树节点
    Bitree p;
    int k, flag = 0, pos;

    //如果i == j,则说明字符串只有一个字符,即为叶子节点、则创建只有一个根节点的二叉树并返回
    if (i == j) {
        p = new node;
        p->data = s[i];
        p->lchild = NULL;
        p->rchild = NULL;
        return p;
    }
    //以下是 i != j的情况
    //从左往右找最后一个+或-,先找+或-为了体现先乘除后加减的原则
    for (k = i; k <= j; k++) {
        if (s[k] == '+' || s[k] == '-') {
            flag = 1;
            pos = k;
        }
    }
    //若没有+或-,则寻找字符串中最后一个*或/
    if (flag == 0) {
        for (k = 0; k <= j; k++) {
            if (s[k] == '*' || s[k] == '/') {
                flag = 1;
                pos = k;
            }
        }
    }
    //若flag不等于0,则以pos为界将字符串分为左右两部分,分别对应表达式二叉树的左、右子树
    //同样以最后的运算符为根,将串分为两部分
    //创建一个根节点、将找到的运算符放入
    if (flag != 0) {
        p = new node;
        p->data = s[pos];
        p->lchild = InTree(s, i, pos - 1);      //递归调用自身进入其左子树建树过程
        p->rchild = InTree(s, pos + 1, j);     //递归调用自身进入其右子树建树过程
        return p;
    } else
        return NULL;
}

后续视进度可能有改进.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值