【c++】构建一棵简单的二叉树

本文详细介绍了如何用C++构建二叉树,包括递归和非递归实现的构造函数、拷贝构造函数、析构函数、赋值运算符重载、前中后序遍历、层序遍历等功能。同时,还涵盖了查找特定节点、计算叶子节点个数、树的深度等算法。

本文主要讲了如何使用c++来构建一个二叉树类,以及一些功能算法的实现。文中大部分函数的思想都是递归,其中赋值运算符重载有传统写法和现代写法两个版本,层序遍历是非递归,前、中、后序遍历有递归和非递归两个版本。

1、构造函数(递归)

2、拷贝构造函数(递归)

3、析构函数(递归)

4、赋值运算符重载(传统/现代)

5、前中后序遍历(递归/非递归)

6、层序遍历(非递归)

7、查找第k层结点个数(递归)

8、精确查找值为x的结点,并返回当前结点的指针(递归)

9、查找叶子结点个数(递归)

10、查找结点总个数(递归)

11、计算树的深度(递归)


树的结点类型,每个结点都需要有一个指向右孩子的指针,一个指向左孩子的指针,以及一个数据。(当然,如果你想构造三叉树的话,也可以增加一个指向父节点的指针。)

这里我写出了结点的构造函数,方便我们在创建树的时候使用。

注意:这棵树我使用了模板

template<typename T>
struct BinaryTreeNode
{
	BinaryTreeNode<T>* _left;//左孩子
	BinaryTreeNode<T>* _right;//右孩子
	T _data;//数据
	BinaryTreeNode(T data = T())//结点自己的构造函数,T()为一个匿名对象。
		:_left(NULL)//初始化为空
		, _right(NULL)
		, _data(data)
	{}
};

下面代码中会经常用到BinaryTreeNode<T>   所以将其重命名为Node
typedef BinaryTreeNode<T> Node;



当我们向写二叉树类的时候,直接给类设定一个根结点,以这个根结点为基础,构建二叉树。
class BinaryTree
{
 public:
 private:
    BinaryTreeNode<T>* _root;//根节点
};


1、构造函数
     BinaryTree(const T* a, size_t size,int index, const T& invalid)
构造函数有4个参数,T类型的指针a,传参时传一个数组,负责传入数据。size保存数组a 的大小,index记录下标,invalid表示非法值。
因为我们需要用到递归,所以在这个函数内部我们需要再封装一个递归函数_MakeTree(),并让它的返回值为一个Node*类型的指针。
BinaryTree(const T* a, size_t size,int index, const T& invalid)
{
	_root = _MakeTree(a,size,index,invalid);
}

我们先来观察一个树:

你会看到上面有许多NULL,这些NULL我们就可以理解为非法值invalid。这棵树的前序遍历为:

 1  2  3  NULL  NULL  4
<think>嗯,用户想了解C++构建二叉树的方法。根据提供的参考资料,我可以整理出三种主流方法:手动节点链接法、递归创建法和层序遍历创建法。 用户提到的引用材料很有针对性:[1]介绍了二叉树基础概念和节点结构,[2]展示了手动创建节点并连接的过程,[3]则提供了通过层序遍历计算深度的方法。这些恰好覆盖了构建二叉树的几个关键方面。 考虑到用户可能不同需求:如果是学习数据结构基础,手动链接最直观;如果想动态创建递归法更高效;而处理序列化数据时可能用到层序构建。需要特别说明构造函数注意事项,因为引用[2]中TreeNode(int x)的构造函数演示避免了常见的内存错误。 在示例代码部分,要突出每个方法的特点:手动法体现指针操作本质,递归法展示分治思想,层序法则引入队列辅助。最后的内存管理提醒很重要,引用[1][3]都强调了这点。 用户可能刚接触二叉树,所以相关问题的设计要层层递进:先从基础遍历延伸到进阶操作(引用[3]涉及的深度计算),再过渡到实际应用,最后引出优化方向。这样既巩固基础,又打开学习路径。 </think>在C++构建二叉树主要有以下几种常用方法,结合引用内容详细说明如下: --- ### **1. 手动节点链接法**(基础直接) **步骤**: 1. **定义节点结构体** 包含数据域和左右子节点指针(引用[1][2]): ```cpp struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} // 构造函数初始化 }; ``` 2. **创建节点对象** 动态分配节点内存: ```cpp TreeNode* node1 = new TreeNode(1); TreeNode* node2 = new TreeNode(2); // ... 创建更多节点 ``` 3. **手动连接节点** 通过指针建立树结构(引用[2]): ```cpp node1->left = node2; // node2 作为 node1 的左子树 node1->right = node3; // node3 作为 node1 的右子树 node2->left = node4; // node4 作为 node2 的左子树 // ... 继续连接 ``` **特点**:直观但灵活性差,适合静态小规模树。 --- ### **2. 递归创建法**(动态构建) 适用于根据特定规则(如有序数组构造二叉搜索树)或序/中序序列构建: ```cpp TreeNode* createTree(vector<int>& data, int& index) { if (index >= data.size() || data[index] == -1) { // -1 表示空节点 index++; return nullptr; } TreeNode* root = new TreeNode(data[index++]); root->left = createTree(data, index); // 递归构建左子树 root->right = createTree(data, index); // 递归构建右子树 return root; } // 调用示例:vector<int> preorder = {1,2,4,-1,-1,5,-1,-1,3,6,-1,-1,7}; // int idx = 0; TreeNode* root = createTree(preorder, idx); ``` **特点**:代码简洁,适合已知遍历序列的场景。 --- ### **3. 层序遍历创建法**(队列辅助) 按层级顺序输入节点值(空节点用特定值标记),使用队列逐层构建(引用[3]思路延伸): ```cpp TreeNode* buildLevelOrder(vector<int>& nodes) { if (nodes.empty() || nodes[0] == -1) return nullptr; queue<TreeNode*> q; TreeNode* root = new TreeNode(nodes[0]); q.push(root); int i = 1; while (!q.empty() && i < nodes.size()) { TreeNode* cur = q.front(); q.pop(); if (nodes[i] != -1) { // 左子节点非空 cur->left = new TreeNode(nodes[i]); q.push(cur->left); } i++; if (i < nodes.size() && nodes[i] != -1) { // 右子节点非空 cur->right = new TreeNode(nodes[i]); q.push(cur->right); } i++; } return root; } // 示例输入:vector<int> level = {1,2,3,4,5,6,7}; ``` --- ### **关键注意事项** 1. **内存管理** 动态分配的节点需在析构函数中递归释放(引用[1]强调): ```cpp void deleteTree(TreeNode* root) { if (!root) return; deleteTree(root->left); deleteTree(root->right); delete root; // 释放当节点 } ``` 2. **构造函数作用** 使用初始化列表 `TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}` 确保新建节点的子指针初始化为 `nullptr`,避免野指针(引用[2]示例)。 --- ### **
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值