二叉树递归应用
此文档主要是用来记录二叉树的一些递归操作.
结构
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;
}
后续视进度可能有改进.