C++二叉树的创建与一些基本使用

二叉树的基本组成

结构体和类的构造和使用方法非常像,所以,在C++中,结构体也存在无参和有参构造;可以根据自己的需求来定义。

struct BiNode{
    int val;
    BiNode *lchild,*rchild;
    //BiNode() : val(0), lchild(nullptr), rchild(nullptr) {}
    // BiNode(int x) : val(x), lchild(nullptr), rchild(nullptr) {}
    // BiNode(int x, BiNode *lchild, BiNode *rchild) : val(x), lchild(lchild), rchild(rchild) {}
};

创建二叉树

这里我是通过队列的方式来创建二叉树的
每创建一个节点,就拿出一个数

void CreateTree(BiNode* &root,queue<int>& dp){   //通过队列创建二叉树
    if(dp.empty()) return ;
    int n=dp.front();
    dp.pop();
    if(n==0){   //等于0时,就是空节点
        return;
    }
    else{
        root =new BiNode();
        root->val=n;
        CreateTree(root->lchild,dp);
        CreateTree(root->rchild,dp);
    }
}

二叉树的4种常用遍历

先序遍历

void preOrder(BiNode* root){    //前序遍历
    if(root){
        cout<<root->val<<" ";
        preOrder(root->lchild);
        preOrder(root->rchild);
    }
}

中序遍历

void inOrder(BiNode* root){    //中序遍历
    if(root!=NULL){        
        inOrder(root->lchild);
        cout<<root->val<<" ";
        inOrder(root->rchild);
    }
}

后序遍历

void postOrder(BiNode* root){    //后序遍历
    if(root){        
        postOrder(root->lchild);        
        postOrder(root->rchild);
        cout<<root->val<<" ";
    }
}

层序遍历

前面的三种先、中、后遍历方法,很常用,也很简单,基本上学会了其中一种,另外两种自然也就会了,只要调换一下位置就行了,原理非常简单;
第四种方法:层序遍历,也是非常的常用,使用的场景也很多,我这里是使用两重vector容器,把它的每一层都单独放在一起,在一般的做题或者其他场景,不需要这么细致的话,使用一维vector也是一样的。

vector<vector<int>> levelOrder(BiNode*& root) {  //层序遍历
    vector<vector<int>> res;
    if(root==NULL)  return res;   
    queue<BiNode*> dp;
    dp.push(root);

    while(!dp.empty()){  //如果队列为空,则已经遍历完毕
        int n=dp.size();    //获取队列的大小,也就是这一层的节点数
        res.push_back(vector<int> ());
        for(int i=1;i<=n;i++){  //每一次都把这一层的所有节点输出,遍历完这一层的,队列剩下的就是下一层的
            auto p=dp.front();dp.pop();
            res.back().push_back(p->val);
            if(p->lchild)     dp.push(p->lchild);   //把非空的节点加入队列
            if(p->rchild)    dp.push(p->rchild);
        }
    }
    return res;
}

在二叉树中查找值为val的节点

思路:
1、当root == NULL; return NULL;
2、当root->val ==num; return root;
3、当root->val!=num ; 则先去左子树中找,FindNode(root->lchild,num);
4、以上都不满足,则去右子树找

BiNode* FindNode(BiNode* &root,int num){
    BiNode* p;
    if(!root)   return NULL;	//节点为空
    else if (root->val==num)    return root;
    else{
        
        p=FindNode(root->lchild,num);
        if(p){
            return p;
        }
        else{
            return FindNode(root->rchild,num);
        }
    }
}

二叉树的高度(深度)

直接递归左右子树,比大小

int HeightTree(BiNode* root){
    if(!root)   return 0;
    return max(HeightTree(root->lchild),HeightTree(root->rchild))+1;
}

查找二叉树中的叶子节点

通过叶子节点性质,直接查找左右子节点都为空的节点,把它加入进vector数组

void FindLeaf(BiNode* &root,vector<BiNode*> &leafnode){
    if(root){
        if(!root->lchild && !root->rchild){
            leafnode.push_back(root);
            return;
        }
        if(root->lchild)    FindLeaf(root->lchild,leafnode);
        if(root->rchild)    FindLeaf(root->rchild,leafnode);
    }
}

以上就是本次介绍的关于二叉树的创建以及一些基本的使用
这是本次演示所使用的二叉树
这是本次演示所使用的二叉树,下面附上一下演示的代码

#include<iostream>
#include<vector>
using namespace std;
#include<queue>

struct BiNode{
    int val;
    BiNode *lchild,*rchild;
    //BiNode() : val(0), lchild(nullptr), rchild(nullptr) {}
    // BiNode(int x) : val(x), lchild(nullptr), rchild(nullptr) {}
    // BiNode(int x, BiNode *lchild, BiNode *rchild) : val(x), lchild(lchild), rchild(rchild) {}
};

void CreateTree(BiNode* &root,queue<int>& dp);  //创建二叉树

void preOrder(BiNode* root);    //先序遍历
void inOrder(BiNode* root);     //中序遍历
void postOrder(BiNode* root);   //后序遍历
vector<vector<int>> levelOrder(BiNode*& root);  //层序遍历,一层层的输出

//template<class T> 
BiNode* FindNode(BiNode* &root,int val);    //查找值为val 的结点,找到了返回该节点地址,没找到则返回NULL
int HeightTree(BiNode* root);   //求二叉树的高度(深度)
void FindLeaf(BiNode* &root,vector<BiNode*> &leafnode);    //查找到叶子节点,并输出

//中间的函数在上面,就不再写了
int main(){
    BiNode* root;
    queue<int> dp;
    vector<int> arr={1,2,4,0,6,0,0,0,3,0,5,0,0};
    for(int i=0;i<arr.size();i++){
        dp.push(arr[i]);
    }
    //创建二叉树
    CreateTree(root,dp);
    
    //先、中、后三中遍历
    cout<<"preOrder: "<<endl;
    preOrder(root);
    cout<<"\ninOrder: "<<endl;
    inOrder(root);
    cout<<"\npostOrder: "<<endl;
    postOrder(root);
    cout<<"\nlevelOrder:  "<<endl;

	//层序遍历,一层层的输出
    vector<vector<int>> res=levelOrder(root);
    for(auto &ch:res){  //一层一层的输出
        for(auto &num:ch){
            cout<<num<<" ";
        }
        cout<<endl;
    }
	
	//查找指定节点,这里我是没有定义,直接给了一个固定值10,纯属是为了演示
    BiNode* findnode;
    findnode=FindNode(root,10);
    if(findnode){
        cout<<"findnode->val="<<findnode->val<<endl;
    }
    else{
        cout<<"This node does not exist in this binary tree! "<<endl;
    }
	
	//定义了一个ans,接收该二叉树的高度
    int ans=HeightTree(root);
    cout<<"The height of the binary tree is "<<ans<<endl;
	
	//查找该二叉树的叶子节点,并输出
    vector<BiNode*> leafnode(dp.size());
    FindLeaf(root,leafnode);
    for(auto& leaf:leafnode){
        cout<<leaf->val<<" ";
    }
    cout<<endl;
}

疑问,希望有大佬能够帮忙解惑!

以上便是我本次学习所得,不过有一个疑问,
在我用struct定义二叉树的基本结构的时候,如果我写了无参构造

BiNode() : val(0), lchild(nullptr), rchild(nullptr) {}

那么我在创建二叉树的时候,无论是

BiNode* root =new BiNode();

亦或是

BiNode* root =new BiNode;

都可以运行,且得出的答案都一样,
但如果我不写这个无参构造
那么第二种定义,在vscode中,虽然不会报错,但不会得出答案,便直接结束了。在网上找了很久,依然没有找到,希望有懂得大佬看到了能帮忙解惑,先谢谢了!

上述问题的原因

上述问题,在前一段时间困扰了我很久,一直没找到原因。
直到今天终于找到了,原来:
在自定义的数据类型中

  1. 如果该类没有定义构造函数(由编译器合成默认构造函数)也没有虚函数,那么BiNode *root= new BiNode ;将不调用合成的默认构造函数,而BiNode *root = new BiNode ();则会调用默认构造函数。
  2. 如果该类没有定义构造函数(由编译器合成默认构造函数)但有虚函数,那么BiNode *root= new BiNode ;和BiNode *root= new BiNode ();一样,都会调用默认构造函数。
  3. 如果该类定义了默认构造函数,那么BiNode *root= new BiNode ;和BiNode *root= new BiNode ();一样,都会调用默认构造函数。

在内置的数据类型中,也是有区别的,但是因为现在还没有搞懂,所以就不写了。等以后明白了再回来补充!

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值