树 超基础二叉树知识

编写一个程序,实现二叉树的基本运算,具体要求如下:

  1. 括号表示法读入数据
  2. 括号表示法输出该树
  3. 输入一个结点的值,输出该结点的左,右孩子的值(要能测试错误数据)
  4. 输出该二叉树的高度
  5. 输出该二叉树结点的个数
  6. 输出该二叉树双分支结点的个数
  7. 输出该二叉树单分支结点的个数
  8. 输出该二叉树叶子结点的个数
  9. 输出该二叉树的宽度(宽度为每层结点数的最大值)
  10. 任意给定该二叉树的两个结点,输出它们的最近的公共祖先
  11. 销毁该二叉树

运行结果:



-1.变量定义

#include <bits/stdc++.h>
using namespace std;
const int MaxSize = 50;

typedef char ElementType; //typedef用来给数据类型char起别名(ElementType)
typedef struct bitnode
{
    ElementType data;
    struct bitnode *left, *right;
} bitnode, *bitree; //bitree为指向bitnode这种自定义数据的指针

0. 括号表示法读入数据

//----------------------------------------------------
//根据嵌套括号表示法的字符串生成链式存储的二叉树
void CreateTree(bitree &b, char str[]){
    char ch;
    bitree stack[MaxSize], p;   //stack[MaxSize]为指针数组,其每一个元素都为指向bitnode这种结构的指针,p为临时指针
    int top = -1, k = 0, j = 0; //top为栈顶指针、k决定谁是左、右孩子、j为str指针

    while ((ch = str[j++]) != '\0'){
        switch (ch)
        {
        case '(':
            top++;
            stack[top] = p; //根结点入栈
            k = 1;          //1为左孩子
            break;
        case ',':
            k = 2; //2为右孩子
            break;
        case ')':
            top--; //根结点出栈
            break;
        default:
            p = (bitree)malloc(sizeof(bitnode));
            p->data = ch;
            p->left = p->right = NULL;

            switch (k)
            {
            case 1:
                stack[top]->left = p; //根结点的左孩子
                break;
            case 2:
                stack[top]->right = p; //根结点的右孩子
                break;
            default:   // k 初始化为0
                b = p; //树为空时
                break;
            }
        }
    }
}

1. 括号表示法输出该树

//----------------------------------------------------
// 1,括号表示法输出该树。
void PrinTree(bitree b){
    if (b){
        cout << b->data; //访问根结点
        if (b->left != NULL || b->right != NULL){
            cout << "("; // 先输出左括号
            PrinTree(b->left); //递归处理左子树
            if (b->right != NULL) //不判断直接输出会导致输出结果不符
                cout << ",";
            PrinTree(b->right); //递归处理右子树
            cout << ")"; //输出右括号
        }
    }
}

2. 输入一个结点的值,输出该结点的左,右孩子的值

//----------------------------------------------------
// 2,输入一个结点的值,输出该结点的左,右孩子的值。(要能测试错误数据)
bool getValue(bitree b, ElementType value){
    if (b == NULL)//找不到就false
        return false;
    if (b->data == value){//找到输出
        if (b->left)
            cout << "左孩子结点:" << b->left->data;
        else
            cout << " 无左孩子结点";
        if (b->right)
            cout << " 右孩子结点:" << b->right->data;
        else
            cout << " 无右孩子结点";
        cout << "\n";
        return true;//标记找到了
    }
    //如果找到了就不用再递归了。而且继续递归会导致最后可能return false
    if(getValue(b->left, value))return true;
    if(getValue(b->right, value))return true;
}

3. 输出该二叉树的高度

//----------------------------------------------------
//3,输出该二叉树的高度。
int getDeep(bitree b){
    if(b==NULL)return 0;
    return max(getDeep(b->left),getDeep(b->right))+1;//左子树右子树哪边深
}

4. 输出该二叉树结点的个数

//----------------------------------------------------
// 4,输出该二叉树结点的个数。
int getNums(bitree b){
    if(b==NULL)return 0;
    return getNums(b->left)+getNums(b->right)+1;//左子树+右子树+1
}

5. 输出该二叉树双分支结点的个数

//----------------------------------------------------
// 5,输出该二叉树双分支结点的个数。
int get2BranchNums(bitree b){
    if (b == NULL||(b->left==NULL&&b->right==NULL))//由于是双分支结点,左右儿子均不能为NULL
        return 0;
    if(b->left&&b->right)//是双分支结点
        return 1+get2BranchNums(b->left)+get2BranchNums(b->right);//继续递归
    return get2BranchNums(b->left)+get2BranchNums(b->right);//递归
}

6. 输出该二叉树单分支结点的个数

//----------------------------------------------------
// 6,输出该二叉树单分支结点的个数。
int get1BranchNums(bitree b){
    if (b == NULL||(b->left==NULL&&b->right==NULL))//题目要求是单分治结点
        return 0;
    if((b->left||b->right)&&!(b->left&&b->right))//找到了
        return 1+get1BranchNums(b->left)+get1BranchNums(b->right);
    return get1BranchNums(b->left)+get1BranchNums(b->right);
}

7. 输出该二叉树叶子结点的个数

//----------------------------------------------------
// 7,输出该二叉树叶子结点的个数。
int getLeafNodes(bitree b){
    if(b==NULL)return 0;
    if(b->right==NULL&&b->left==NULL)return 1;//叶子节点没有孩子
    return getLeafNodes(b->left)+getLeafNodes(b->right);//左子树叶子结点个数+右子树叶子节点个数
}

8. 输出该二叉树的宽度(宽度为每层结点数的最大值)

//----------------------------------------------------
// 8,输出该二叉树的宽度。(宽度为每层结点数的最大值)
int getWidth(bitree b){//需要用队列
    int tmpWidth=0,maxWidth=1;
    if(b==NULL)return 0;
    queue<bitnode*> q;
    q.push(b);//入队
    while(q.size()){
        tmpWidth = q.size();
        //若每一层的宽度大于maxWidth,则重新赋值
        maxWidth = max(tmpWidth,maxWidth);//更新maxWidth
        //注意这里循环的次数是width,出队的仅仅是每一层的元素
        for (int i = 0; i < tmpWidth; i++) {
            bitnode *nodeTemp = q.front();
            q.pop();
            //左右子树不为空则入队
            if (nodeTemp->left != NULL) {
                q.push(nodeTemp->left);
            }
            if(nodeTemp->right != NULL) {
                q.push(nodeTemp->right);
            }
        }
    }
    return maxWidth;//返回求得的最大宽度
}

9. 任意给定该二叉树的两个结点,输出它们的最近的公共祖先

//----------------------------------------------------
// 9,任意给定该二叉树的两个结点,输出它们的最近的公共祖先。
bitnode* findLCA(bitree root, ElementType n1, ElementType n2){
    if (root == NULL) return NULL;
    // 此处默认输入数据合法!!!
    if (root->data == n1 || root->data == n2)
        return root;
    //递归寻找
    bitnode* left_lca  = findLCA(root->left, n1, n2);
    bitnode* right_lca = findLCA(root->right, n1, n2);
    // 如果两个结果都非NULL ,则两个点分别在左右儿子树上
    if (left_lca && right_lca)  return root;
    // 否则检查左子树或右子树是否为最近公共祖先
    return (left_lca != NULL)? left_lca: right_lca;
}

10. 销毁该二叉树

//----------------------------------------------------
//10,销毁该二叉树
bitree FreeTree(bitree b){
    if (b != NULL){
        FreeTree(b->left);  //递归释放左子树
        FreeTree(b->right); //递归释放右子树
        free(b);  //释放根结点
        b = NULL; //释放指向根结点的指针
    }
    return b; //return NULL;
}
  1. 主函数
int main(){
    // char str[] = "A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))";
    char str[] = "A(B(D(,G),),C(E,F))";
    bitree root = NULL; //不要忘记初始化
    ElementType tmp,tmp1,tmp2;
    int t1,t2;
    CreateTree(root, str);

    cout << "字符串:" << str << "\n";
    cout << "1,括号表示法输出该树:";
    PrinTree(root);
    cout << "\n";

    cout << "2,输入一个结点的值,输出该结点的左,右孩子的值\n";
    cin >> tmp;
    if (!getValue(root, tmp))
        cout << "查找失败!\n";
    cout<<"3,输出该二叉树的高度:  ";
    cout<<getDeep(root)<<"\n";

    cout<<"4,输出该二叉树结点的个数: ";
    cout<<getNums(root)<<"\n";

    cout<<"5,输出该二叉树双分支结点的个数: ";
    cout<<get2BranchNums(root)<<"\n";

    cout<<"6,输出该二叉树单分支结点的个数: ";
    cout<<get1BranchNums(root)<<"\n";

    cout<<"7,输出该二叉树叶子结点的个数: ";
    cout<<getLeafNodes(root)<<"\n";

    cout<<"8,输出该二叉树的宽度: ";
    cout<<getWidth(root)<<"\n";

    cout<<"9,给定该二叉树的两个结点,输出它们的最近的公共祖先: \n";
    cout<<"请输入您所需要查找的两个结点:";
    cin>>tmp1>>tmp2;
    bitnode* tmpnode = findLCA(root,tmp1,tmp2);
    if(tmpnode==NULL){
        cout<<"结点: "<<tmp1<<" 和 "<<tmp2<<" 没有公共结点\n";
    }else{
        cout<<"结点: "<<tmp1<<" 和 "<<tmp2<<" 的最近公共结点为:"<<tmpnode->data<<"\n";
    }

    cout<<"10,销毁该二叉树\n";
    root = FreeTree(root);
    if (root == NULL)
        cout << "二叉树销毁成功" << "\n";

    return 0;
}

完整代码

#include <bits/stdc++.h>
using namespace std;
const int MaxSize = 50;

typedef char ElementType; //typedef用来给数据类型char起别名(ElementType)
typedef struct bitnode
{
    ElementType data;
    struct bitnode *left, *right;
} bitnode, *bitree; //bitree为指向bitnode这种自定义数据的指针

//----------------------------------------------------
//根据嵌套括号表示法的字符串生成链式存储的二叉树
void CreateTree(bitree &b, char str[]){
    char ch;
    bitree stack[MaxSize], p;   //stack[MaxSize]为指针数组,其每一个元素都为指向bitnode这种结构的指针,p为临时指针
    int top = -1, k = 0, j = 0; //top为栈顶指针、k决定谁是左、右孩子、j为str指针

    while ((ch = str[j++]) != '\0'){
        switch (ch)
        {
        case '(':
            top++;
            stack[top] = p; //根结点入栈
            k = 1;          //1为左孩子
            break;
        case ',':
            k = 2; //2为右孩子
            break;
        case ')':
            top--; //根结点出栈
            break;
        default:
            p = (bitree)malloc(sizeof(bitnode));
            p->data = ch;
            p->left = p->right = NULL;

            switch (k)
            {
            case 1:
                stack[top]->left = p; //根结点的左孩子
                break;
            case 2:
                stack[top]->right = p; //根结点的右孩子
                break;
            default:   // k 初始化为0
                b = p; //树为空时
                break;
            }
        }
    }
}

//----------------------------------------------------
// 1,括号表示法输出该树。
void PrinTree(bitree b){
    if (b){
        cout << b->data; //访问根结点
        if (b->left != NULL || b->right != NULL){
            cout << "("; // 先输出左括号
            PrinTree(b->left); //递归处理左子树
            if (b->right != NULL) //不判断直接输出会导致输出结果不符
                cout << ",";
            PrinTree(b->right); //递归处理右子树
            cout << ")"; //输出右括号
        }
    }
}

//----------------------------------------------------
// 2,输入一个结点的值,输出该结点的左,右孩子的值。(要能测试错误数据)
bool getValue(bitree b, ElementType value){
    if (b == NULL)//找不到就false
        return false;
    if (b->data == value){//找到输出
        if (b->left)
            cout << "左孩子结点:" << b->left->data;
        else
            cout << " 无左孩子结点";
        if (b->right)
            cout << " 右孩子结点:" << b->right->data;
        else
            cout << " 无右孩子结点";
        cout << "\n";
        return true;//标记找到了
    }
    //如果找到了就不用再递归了。而且继续递归会导致最后可能return false
    if(getValue(b->left, value))return true;
    if(getValue(b->right, value))return true;
}
//----------------------------------------------------
//3,输出该二叉树的高度。
int getDeep(bitree b){
    if(b==NULL)return 0;
    return max(getDeep(b->left),getDeep(b->right))+1;//左子树右子树哪边深
}
//----------------------------------------------------
// 4,输出该二叉树结点的个数。
int getNums(bitree b){
    if(b==NULL)return 0;
    return getNums(b->left)+getNums(b->right)+1;//左子树+右子树+1
}
//----------------------------------------------------
// 5,输出该二叉树双分支结点的个数。
int get2BranchNums(bitree b){
    if (b == NULL||(b->left==NULL&&b->right==NULL))//由于是双分支结点,左右儿子均不能为NULL
        return 0;
    if(b->left&&b->right)//是双分支结点
        return 1+get2BranchNums(b->left)+get2BranchNums(b->right);//继续递归
    return get2BranchNums(b->left)+get2BranchNums(b->right);//递归
}
//----------------------------------------------------
// 6,输出该二叉树单分支结点的个数。
int get1BranchNums(bitree b){
    if (b == NULL||(b->left==NULL&&b->right==NULL))//题目要求是单分治结点
        return 0;
    if((b->left||b->right)&&!(b->left&&b->right))//找到了
        return 1+get1BranchNums(b->left)+get1BranchNums(b->right);
    return get1BranchNums(b->left)+get1BranchNums(b->right);
}
//----------------------------------------------------
// 7,输出该二叉树叶子结点的个数。
int getLeafNodes(bitree b){
    if(b==NULL)return 0;
    if(b->right==NULL&&b->left==NULL)return 1;//叶子节点没有孩子
    return getLeafNodes(b->left)+getLeafNodes(b->right);//左子树叶子结点个数+右子树叶子节点个数
}
//----------------------------------------------------
// 8,输出该二叉树的宽度。(宽度为每层结点数的最大值)
int getWidth(bitree b){//需要用队列
    int tmpWidth=0,maxWidth=1;
    if(b==NULL)return 0;
    queue<bitnode*> q;
    q.push(b);//入队
    while(q.size()){
        tmpWidth = q.size();
        //若每一层的宽度大于maxWidth,则重新赋值
        maxWidth = max(tmpWidth,maxWidth);//更新maxWidth
        //注意这里循环的次数是width,出队的仅仅是每一层的元素
        for (int i = 0; i < tmpWidth; i++) {
            bitnode *nodeTemp = q.front();
            q.pop();
            //左右子树不为空则入队
            if (nodeTemp->left != NULL) {
                q.push(nodeTemp->left);
            }
            if(nodeTemp->right != NULL) {
                q.push(nodeTemp->right);
            }
        }
    }
    return maxWidth;//返回求得的最大宽度
}
//----------------------------------------------------
// 9,任意给定该二叉树的两个结点,输出它们的最近的公共祖先。
bitnode* findLCA(bitree root, ElementType n1, ElementType n2){
    if (root == NULL) return NULL;
    // 此处默认输入数据合法!!!
    if (root->data == n1 || root->data == n2)
        return root;
    //递归寻找
    bitnode* left_lca  = findLCA(root->left, n1, n2);
    bitnode* right_lca = findLCA(root->right, n1, n2);
    // 如果两个结果都非NULL ,则两个点分别在左右儿子树上
    if (left_lca && right_lca)  return root;
    // 否则检查左子树或右子树是否为最近公共祖先
    return (left_lca != NULL)? left_lca: right_lca;
}

//----------------------------------------------------
//10,销毁该二叉树
bitree FreeTree(bitree b){
    if (b != NULL){
        FreeTree(b->left);  //递归释放左子树
        FreeTree(b->right); //递归释放右子树
        free(b);  //释放根结点
        b = NULL; //释放指向根结点的指针
    }
    return b; //return NULL;
}

int main(){
    // char str[] = "A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))";
    char str[] = "A(B(D(,G),),C(E,F))";
    bitree root = NULL; //不要忘记初始化
    ElementType tmp,tmp1,tmp2;
    int t1,t2;
    CreateTree(root, str);

    cout << "字符串:" << str << "\n";
    cout << "1,括号表示法输出该树:";
    PrinTree(root);
    cout << "\n";

    cout << "2,输入一个结点的值,输出该结点的左,右孩子的值\n";
    cin >> tmp;
    if (!getValue(root, tmp))
        cout << "查找失败!\n";
    cout<<"3,输出该二叉树的高度:  ";
    cout<<getDeep(root)<<"\n";

    cout<<"4,输出该二叉树结点的个数: ";
    cout<<getNums(root)<<"\n";

    cout<<"5,输出该二叉树双分支结点的个数: ";
    cout<<get2BranchNums(root)<<"\n";

    cout<<"6,输出该二叉树单分支结点的个数: ";
    cout<<get1BranchNums(root)<<"\n";

    cout<<"7,输出该二叉树叶子结点的个数: ";
    cout<<getLeafNodes(root)<<"\n";

    cout<<"8,输出该二叉树的宽度: ";
    cout<<getWidth(root)<<"\n";

    cout<<"9,给定该二叉树的两个结点,输出它们的最近的公共祖先: \n";
    cout<<"请输入您所需要查找的两个结点:";
    cin>>tmp1>>tmp2;
    bitnode* tmpnode = findLCA(root,tmp1,tmp2);
    if(tmpnode==NULL){
        cout<<"结点: "<<tmp1<<" 和 "<<tmp2<<" 没有公共结点\n";
    }else{
        cout<<"结点: "<<tmp1<<" 和 "<<tmp2<<" 的最近公共结点为:"<<tmpnode->data<<"\n";
    }

    cout<<"10,销毁该二叉树\n";
    root = FreeTree(root);
    if (root == NULL)
        cout << "二叉树销毁成功" << "\n";

    return 0;
}

代码思路,编辑格式不易,大家觉得还可以可以点赞、收藏、关注一下吧!
也可以到我的个人博客参观一下,https://motongxue.gitee.io

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值