写在前面
一直想写一下关于二叉树的C++实现, 之前学数据结构用的是Python, 简洁直观的语法十分舒适, 但是, 当时有多舒服, 用C++写之后就有多痛苦… 指针就是个大问题, 反复研究之后总算明白了指针, 但是Segmentation fault又开始折磨我了…
后来在@栋栋颻同学的帮助下搞定了这个问题(内存泄漏, 树结点需要初始化在堆
区而不是栈区), 基础还是太差, 还是得系统学习一下数据结构才行.
在二叉树的生成方式上, 顺便又加上了递归的生成方式(还是由@栋栋颻指出), 通过前序遍历的方法进行二叉树的生成, 这里需要加上为空指针的结点, 否则无法达到递归终止.
代码
头文件导入
#include <iostream>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
主要用到了STL中三个主要的数据结构: 栈,队列和动态数组.
打印树节点遍历的数组
采用vector
动态数组, 用起来很方便
void printvec(vector<int> &v){
for (int & it : v){
cout<<it<<(it != *(v.end()-1)?", ":". ");
}
cout<<endl;
}
节点类与二叉树类的实现
// 二叉树节点的结构体实现
struct TreeNode {
int val;
TreeNode* lchild;
TreeNode* rchild;
TreeNode() : val(0), lchild(nullptr), rchild(nullptr)
{ }
TreeNode(int x) : val(x), lchild(nullptr), rchild(nullptr)
{ }
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), lchild(left), rchild(right)
{ }
};
class BinaryTree
{
public:
BinaryTree() : root(nullptr)
{ }
~BinaryTree()
{ }
// 获取根节点
TreeNode* get_root(BinaryTree &tree);
// 树的创建
void add(int item);
TreeNode* add1();
TreeNode* add2(vector<int> &item);
// 广度遍历(层序遍历)
void breadth_travel(TreeNode* node);
// 前序遍历
void pre_order(TreeNode* node);
void pre_order1(TreeNode* node);
// 中序遍历
void in_order(TreeNode* node);
void in_order1(TreeNode* node);
void in_order2(TreeNode* node);
// 后序遍历
void post_order(TreeNode* node);
void post_order1(TreeNode* node);
void post_order2(TreeNode* node);
private:
TreeNode* root;
};
// 获取根节点
TreeNode* BinaryTree::get_root(BinaryTree &tree)
{
return tree.root;
}
树节点的实现上我直接拿来主义了, 用的LeetCode的二叉树实现, 比Python要复杂好多…
在树的生成上我用的STL里面的queue
(队列), 前序遍历用到了stack
(栈), 输出结点值的时候用vector
(动态数组)来存放遍历得到的结果.
下面就是对上面声明的各个函数进行定义.
树的生成
// 递归版本生成二叉树(需要捕获用户输入)
TreeNode* BinaryTree::add1()
{
int data;
cin>>data;
if (data < 0)
{
return nullptr;
}
TreeNode* node = new TreeNode(data);
node->val = data;
node->lchild = BinaryTree::add1();
node->rchild = BinaryTree::add1();
return node;
}
// 递归生成二叉树: 直接外部遍历数组实现
TreeNode* BinaryTree::add2(vector<int> &item)
{
if (item.empty() || item.front() == 0)
{
item.erase(item.begin());
return nullptr;
}
TreeNode* node = new TreeNode(item.front());
node->val = item.front();
item.erase(item.begin());
node->lchild = BinaryTree::add2(item);
node->rchild = BinaryTree::add2(item);
return node;
}
// 这是通过层序遍历生成树的方式, 利用循环
void BinaryTree::add(int item)
{
TreeNode* node = new TreeNode(item);
// 这是错误的代码
// 由于把新结点实例化在了栈区, 导致内存错误
// TreeNode node(item);
if (!root)
{
root = node;
return ;
}
// 用队列模拟二叉树的层序遍历
queue<TreeNode*> que;
que.push(root);
while(!que.empty()) {
TreeNode* cur_node = que.front();
que.pop();
if (!cur_node->lchild)
{
cur_node->lchild = node;
return ;
}
else
que.push(cur_node->lchild);
// 接下来同样判断右边
if (!cur_node->rchild)
{
cur_node->rchild = node;
return ;
}
else
que.push(cur_node->rchild);
}
}
层序遍历
void BinaryTree::breadth_travel(TreeNode* node)
{
queue<TreeNode*> que;
que.push(node);
vector<int> ret;
if (!node)
return ;
while(!que.empty()) {
TreeNode* cur_node = que.front();
que.pop();
// 也可以直接打印, 省去了定义数组的步骤
// cout<< cur_node->val<<endl;
ret.push_back(cur_node->val);
if (cur_node->lchild)
que.push(cur_node->lchild);
if (cur_node->rchild)
que.push(cur_node->rchild);
}
printvec(ret);
}
前序遍历
void recur_0(TreeNode* node, vector<int> &ret)
{
// 递归终止条件
if (!node)
return ;
ret.push_back(node->val);
recur_0(node->lchild, ret);
recur_0(node->rchild, ret);
}
void BinaryTree::pre_order(TreeNode* node)
{
vector<int> ret;
// if (!node)
// return ;
// cout<<node->val<<", ";
// pre_order(node->lchild);
// pre_order(node->rchild);
recur_0(node, ret);
printvec(ret);
}
void BinaryTree::pre_order1(TreeNode* node)
{
vector<int> ret;
stack<TreeNode*> st;
if (node)
st.push(node);
while(!st.empty()) {
node = st.top();
st.pop();
ret.push_back(node->val);
if (node->rchild)
st.push(node->rchild);
if (node->lchild)
st.push(node->lchild);
}
printvec(ret);
}
中序遍历
void recur_1(TreeNode* node, vector<int> &ret)
{
if (!node)
return ;
recur_1(node->lchild, ret);
ret.push_back(node->val);
recur_1(node->rchild, ret);
}
void BinaryTree::in_order(TreeNode* node)
{
vector<int> ret;
// if (!node)
// return ;
// pre_order(node->lchild);
// cout<<node->val<<", ";
// pre_order(node->rchild);
recur_1(node, ret);
printvec(ret);
}
void BinaryTree::in_order1(TreeNode* node)
{
vector<int> ret;
stack<TreeNode*> st;
auto cur = node;
while(cur || !st.empty()) {
if (cur)
{
st.push(cur);
cur = cur->lchild;
} else {
cur = st.top();
st.pop();
ret.push_back(cur->val);
cur = cur->rchild;
}
}
printvec(ret);
}
void BinaryTree::in_order2(TreeNode* node)
{
vector<int> ret;
stack<TreeNode*> st;
if (node)
{
st.push(node);
}
while(!st.empty()) {
node = st.top();
if (node)
{
st.pop();
if (node->rchild)
{
st.push(node->rchild);
}
st.push(node);
st.push(nullptr);
if (node->lchild)
{
st.push(node->lchild);
}
} else {
st.pop();
node = st.top();
st.pop();
ret.push_back(node->val);
}
}
printvec(ret);
}
后序遍历
void recur_2(TreeNode* node, vector<int> &ret)
{
if (!node)
return ;
recur_2(node->lchild, ret);
recur_2(node->rchild, ret);
ret.push_back(node->val);
}
void BinaryTree::post_order(TreeNode* node)
{
vector<int> ret;
// if (!node)
// return ;
// pre_order(node->lchild);
// pre_order(node->rchild);
// cout<<node->val<<", ";
recur_2(node, ret);
printvec(ret);
}
void BinaryTree::post_order1(TreeNode* node)
{
stack<TreeNode*> st;
vector<int> ret;
if (node)
{
st.push(node);
}
while(!st.empty()) {
node = st.top();
st.pop();
ret.push_back(node->val);
if (node->lchild)
st.push(node->lchild);
if (node->rchild)
st.push(node->rchild);
}
// 进行逆序操作: 或者用iterator的逆序算法
vector<int> ret1;
for (auto it=ret.rbegin();it!=ret.rend();it++)
ret1.push_back(*it);
printvec(ret1);
}
void BinaryTree::post_order2(TreeNode* node)
{
stack<TreeNode*> st;
vector<int> ret;
while(!st.empty() || node) {
while(node) {
st.push(node);
node = node->lchild?node->lchild:node->rchild;
}
node = st.top();
st.pop();
ret.push_back(node->val);
node = !st.empty() && st.top()->lchild == node ? st.top()->rchild:nullptr;
}
printvec(ret);
}
main函数
int main(int argc, char const *argv[]) {
BinaryTree tree;
// 第一种生成方式, 层序生成(使用队列进行循环)
for (int i = 0; i < 9; ++i)
{
tree.add(i);
}
// 第二种生成方式, 递归生成(前序递归), 需要传入用户输入
// TreeNode* node = tree.add1();
// 第三种(同第二种), 递归生成, 直接读取数组即可
// vector<int> item = {1,2,-1,4,-1,-1,3,-1,5,-1,-1}
// vector<int> item = {1,2,3,4,5,6,7,0,0,0,0,0,0,0,0};
// vector<int> item = {1,2,4,0,0,5,0,0,3,6,0,0,7,0,0};
// auto node = tree.add2(item);
// 下面是遍历
// 广度遍历
// tree.breadth_travel(node);
// 前序遍历(递归)
// tree.pre_order(tree.get_root(tree));
// 前序遍历(循环)
// tree.pre_order1(tree.get_root(tree));
// 中序遍历(递归)
// tree.in_order(node);
// 中序遍历(循环)
// tree.in_order1(tree.get_root(tree));
// tree.in_order2(tree.get_root(tree));
// 后序遍历(递归)
// tree.post_order(tree.get_root(tree));
// 后序遍历(循环)
tree.post_order1(tree.get_root(tree));
tree.post_order2(tree.get_root(tree));
return 0;
}
全部代码
见C-Cpp_Proj/Binary_Tree.cpp at main · Apocaly-pse/C-Cpp_Proj (github.com).