#pragma once
#include <stack>
#include <queue>
#include <vector>
#include <iostream>
using namespace std;
namespace BinaryTree
{
void PrintFunStr(string funStr)
{
printf("%s", funStr.c_str());
}
vector<char> Sting2VtChar(const string& str)
{
vector<char> v;
for (int i = 0; i < str.size(); ++i)
{
v.push_back(str[i]);
}
return v;
}
// 只能转换数字字符串
vector<int> Sting2VtInt(const string& str)
{
vector<int> v;
for (int i = 0; i < str.size(); ++i)
{
v.push_back(str[i] - '0');
}
return v;
}
template <typename T>
struct TreeNode
{
T val;
TreeNode<T> *left = nullptr;
TreeNode<T> *right = nullptr;
TreeNode(T v) : val(v), left(nullptr), right(nullptr) {}
};
/*
注意,要将模板类和实习都写在头文件中,否则编译有问题
*/
template <typename T>
class CBinaryTree
{
public:
CBinaryTree();
CBinaryTree(const vector<T>& vect);
virtual ~CBinaryTree();
void SetRoot(TreeNode<T>* node) { m_root = node; }
TreeNode<T>* GetRoot() { return m_root; }
TreeNode<T>* CreateBinaryTree();
// 创建的时候是按照前序创建的,注意结束符需要输入'#',如三个节点的满二叉树:{'1','2','#','#','3','#','#'}
TreeNode<T>* CreateBinaryTree(const vector<T>& vect);
void PreOrderTraverse1(TreeNode<T>* node);
void PreOrderTraverse2(TreeNode<T>* root);
void PreOrderTraverse3(TreeNode<T>* root);
void PreOrderTraverse4(TreeNode<T>* root);
void InOrderTraverse1(TreeNode<T>* node);
void InOrderTraverse2(TreeNode<T>* root);
void InOrderTraverse3(TreeNode<T>* root);
void InOrderTraverse4(TreeNode<T>* root);
void PostOrderTraverse1(TreeNode<T>* node);
void PostOrderTraverse2(TreeNode<T>* root);
void PostOrderTraverse3(TreeNode<T>* root);
void PostOrderTraverse4(TreeNode<T>* root);
void LevelTraverse1(TreeNode<T>* root);
int GetNodeNum1(TreeNode<T>* root);
int GetNodeNum2(TreeNode<T>* root);
int GetDepth1(TreeNode<T>* root);
int GetDepth2(TreeNode<T>* root);
// 序列化
// 反序列化
private:
TreeNode<T>* m_root;
int m_index;
};
template <typename T>
CBinaryTree<T>::CBinaryTree()
{
m_index = 0;
m_root = CreateBinaryTree();
}
template <typename T>
CBinaryTree<T>::CBinaryTree(const vector<T>& vect)
{
m_index = 0;
m_root = CreateBinaryTree(vect);
}
template <typename T>
CBinaryTree<T>::~CBinaryTree()
{
if (m_root != nullptr)
{
// TODO销毁树
}
}
/**
* 1. 创建二叉树
* 递归
* @return 树根节点
*/
template <typename T>
TreeNode<T>* CBinaryTree<T>::CreateBinaryTree()
{
T val;
cin >> val;
if (val == '#') //标识当前子树为空,转向下一节点
{
return nullptr;
}
else //递归的前序创建左右子树
{
TreeNode<T>* current_node = new TreeNode<T>(val);
if (current_node != nullptr)
{
current_node->left = CreateBinaryTree();
current_node->right = CreateBinaryTree();
}
return current_node;
}
}
template <typename T>
TreeNode<T>* CBinaryTree<T>::CreateBinaryTree(const vector<T>& vect)
{
if (vect.empty() || vect.size() == m_index)
return nullptr;
if (vect[m_index] == '#') //标识当前子树为空,转向下一节点
{
return nullptr;
}
TreeNode<T>* current_node = new TreeNode<T>(vect[m_index]);
m_index++;
current_node->left = CreateBinaryTree(vect);
m_index++;
current_node->right = CreateBinaryTree(vect);
return current_node;
}
/**
* 2. 前序遍历 - 深度优先搜索算法(Depth First Search),简称DFS
* 递归
* 思路:如果二叉树为空,空操作;如果二叉树不为空,先访问根节点,再访问左节点,再访问右节点
* @param root 树根节点
*/
template <typename T>
void CBinaryTree<T>::PreOrderTraverse1(TreeNode<T>* root)
{
if (root != nullptr)
{
cout << root->val << ", ";
if (root->left != nullptr)
PreOrderTraverse1(root->left);
if (root->right != nullptr)
PreOrderTraverse1(root->right);
}
}
/**
* 3. 前序遍历 -- 深度优先搜索算法(Depth First Search),简称DFS,建议使用这个,代码量小
* 非递归
* 思路:用一个辅助stack,总是先把右孩子放进栈,因为先访问左节点
* @param root 树根节点
*/
template <typename T>
void CBinaryTree<T>::PreOrderTraverse2(TreeNode<T>* root)
{
if (root == nullptr)
return;
stack<TreeNode<T>* > s;
s.push(root);
while (!s.empty())
{
TreeNode<T>* cur_node = s.pop();
if (cur_node != nullptr)
{
cout << root->val << ", ";
// 栈是先进后出,所以先push右节点
s.push(cur_node->right);
s.push(cur_node->left);
}
}
}
// 非递归前序遍历-教科书
template <typename T>
void CBinaryTree<T>::PreOrderTraverse3(TreeNode<T>* root)
{
if (root == nullptr)
return;
stack<TreeNode<T>*> s;
TreeNode<T>* cur_node = root;
while (cur_node != nullptr || !s.empty())
{
while (cur_node != nullptr)
{
cout << cur_node->val << ", ";
s.push(cur_node);
cur_node = cur_node->left;
}
if (!s.empty())
{
cur_node = s.top();
cur_node = cur_node->right;
s.pop();
}
}
}
// 非递归前序遍历-统一风格,但是使用的栈空间更多
template <typename T>
void CBinaryTree<T>::PreOrderTraverse4(TreeNode<T>* root)
{
if (root == nullptr)
return;
stack<pair<TreeNode<T>*, bool> > s;
TreeNode<T>* cur_node = root;
s.push(make_pair(cur_node, false));
bool visited; // 是根节点
while (!s.empty())
{
cur_node = s.top().first;
visited = s.top().second;
s.pop();
if (cur_node != nullptr)
{
if (visited)
{
cout << cur_node->val << ", ";
}
else
{
s.push(make_pair(cur_node->right, false));
s.push(make_pair(cur_node->left, false));
s.push(make_pair(cur_node, true));
}
}
}
}
/**
* 4. 中序遍历
* 递归
* 思路:如果二叉树为空,空操作;如果二叉树不为空,先访问左节点,再访问根节点,再访问右节点
* @param root 树根节点
*/
template <typename T>
void CBinaryTree<T>::InOrderTraverse1(TreeNode<T>* root)
{
if (root != nullptr)
{
InOrderTraverse1(root->left);
cout << root->val << ", ";
InOrderTraverse1(root->right);
}
}
/**
* 5. 中序遍历
* 非递归
* 思路:
* @param root 树根节点
*/
template <typename T>
void CBinaryTree<T>::InOrderTraverse2(TreeNode<T>* root)
{
if (root == nullptr)
return;
stack<TreeNode<T>* > s;
TreeNode<T>* cur_node = root;
//while (!s.empty() || curr_node != nullptr)
//{
// if (cur_node != nullptr)
// {
// s.push(curr_node);
// cur_node = cur_node->left; // 注意这里切换当前节点到左节点
// }
// else // cur_node = nullptr,栈顶就是叶子节点了
// {
// cur_node = s.top();
// cout << cur_node->val << ", ";
// cur_node = cur_node->right;
// s.pop(); // 因为是中序,根节点用完了直接可以pop,下次循环时将右节点入栈
// }
//}
// 建议使用这一块逻辑
// 先一股脑地把左子节点放到的栈中, 因为这时栈顶的叶结点就是我们遍历的起点
while (cur_node != nullptr)
{
s.push(cur_node);
cur_node = cur_node->left;
}
while (!s.empty())
{
// 遍历栈顶的节点
cur_node = s.top();
cout << cur_node->val << ", ";
s.pop();
// 即然遍历到了当前的节点,说明了它的左子树已经遍历完了,不需要管了。 我们现在
// 需要关注的是:当前节点的右子树是否为空了, 如果不为空,则需要将它入栈,再先去判断它的左子树是否为空。
cur_node = cur_node->right;
while (cur_node != nullptr)
{
s.push(cur_node);
cur_node = cur_node->left;
}
}
}
// 非递归中序遍历-教科书
template <typename T>
void CBinaryTree<T>::InOrderTraverse3(TreeNode<T>* root)
{
if (root == nullptr)
return;
stack<TreeNode<T>* > s;
TreeNode<T>* cur_node = root;
while (cur_node != nullptr || !s.empty())
{
while (cur_node != nullptr)
{
s.push(cur_node);
cur_node = cur_node->left;
}
if (!s.empty())
{
cur_node = s.top();
cout << cur_node->val << ", ";
cur_node = cur_node->right;
s.pop();
}
}
}
// 非递归中序遍历-统一风格,但是使用的栈空间更多
template <typename T>
void CBinaryTree<T>::InOrderTraverse4(TreeNode<T>* root)
{
if (root == nullptr)
return;
stack<pair<TreeNode<T>*, bool> > s;
TreeNode<T>* cur_node = root;
s.push(make_pair(cur_node, false));
bool visited; // 是根节点
while (!s.empty())
{
cur_node = s.top().first;
visited = s.top().second;
s.pop();
if (cur_node != nullptr)
{
if (visited)
{
cout << cur_node->val << ", ";
}
else
{
s.push(make_pair(cur_node->right, false));
s.push(make_pair(cur_node, true));
s.push(make_pair(cur_node->left, false));
}
}
}
}
template <typename T>
void CBinaryTree<T>::PostOrderTraverse1(TreeNode<T>* root)
{
if (root != nullptr)
{
PostOrderTraverse1(root->left);
PostOrderTraverse1(root->right);
cout << root->val << ", ";
}
}
template <typename T>
void CBinaryTree<T>::PostOrderTraverse2(TreeNode<T>* root)
{
if (root == nullptr)
return;
stack<TreeNode<T>* > s;
TreeNode<T>* curr_node = root;
while (curr_node != nullptr)
{
s.push(curr_node);
// 优先选择不为空的左节点,如果左节点为空,再考虑右节点(右节点为空也没有关系)
if (curr_node->left != nullptr)
{
curr_node = curr_node->left;
}
else
{
curr_node = curr_node->right;
}
}
while (!s.empty())
{
curr_node = s.top();
cout << curr_node->val << ", ";
s.pop();
// 既然遍历到了当前节点,说明它的左子树与右子树都遍历完了,不需要管了。我们现在
// 需要关注的是: 如果当前节点为父节点的左节点,则需要判断父节点的右节点是否为空.
// 如果不为空,则需要去处理父节点的右节点了。
//
// 另外,如果当前节点不是父节点的右节点,也不需要管,因为接下来会去遍历父节点。
if (!s.empty() && curr_node == s.top()->left)
{
curr_node = s.top()->right;
while (curr_node != nullptr)
{
s.push(curr_node);
// 优先选择不为空的左节点,如果左节点为空,再考虑右节点(右节点为空也没有关系)
if (curr_node->left != nullptr)
{
curr_node = curr_node->left;
}
else
{
curr_node = curr_node->right;
}
}
}
}
}
template <typename T>
void CBinaryTree<T>::PostOrderTraverse3(TreeNode<T>* root)
{
}
// 非递后中序遍历-统一风格,但是使用的栈空间更多
template <typename T>
void CBinaryTree<T>::PostOrderTraverse4(TreeNode<T>* root)
{
if (root == nullptr)
return;
stack<pair<TreeNode<T>*, bool> > s;
TreeNode<T>* cur_node = root;
s.push(make_pair(cur_node, false));
bool visited; // 是根节点
while (!s.empty())
{
cur_node = s.top().first;
visited = s.top().second;
s.pop();
if (cur_node != nullptr)
{
if (visited)
{
cout << cur_node->val << ", ";
}
else
{
s.push(make_pair(cur_node, true));
s.push(make_pair(cur_node->right, false));
s.push(make_pair(cur_node->left, false));
}
}
}
}
// 层级遍历-广度优先搜索算法(Breadth First Search),简称BFS-使用队列实现
template <typename T>
void CBinaryTree<T>::LevelTraverse1(TreeNode<T>* root)
{
if (root == nullptr)
return;
queue<TreeNode<T>* > q;
TreeNode<T>* cur_node = root;
q.push(cur_node);
while (!q.empty())
{
cur_node = q.front(); // 拿到最前结点
cout << cur_node->val << ", ";
q.pop();
if (cur_node->left != nullptr)
{
q.push(cur_node->left);
}
if (cur_node->right != nullptr)
{
q.push(cur_node->right);
}
}
}
template <typename T>
int CBinaryTree<T>::GetNodeNum1(TreeNode<T>* root)
{
if (root == nullptr)
return 0;
int left_num = GetNodeNum1(root->left);
int right_num = GetNodeNum1(root->right);
return left_num + right_num + 1;
}
template <typename T>
int CBinaryTree<T>::GetNodeNum2(TreeNode<T>* root)
{
return 0;
}
template <typename T>
int CBinaryTree<T>::GetDepth1(TreeNode<T>* root)
{
if (root == nullptr)
return 0;
int left_height = GetDepth1(root->left);
int right_height = GetDepth1(root->right);
return max(left_height, right_height) + 1;
}
template <typename T>
int CBinaryTree<T>::GetDepth2(TreeNode<T>* root)
{
return 0;
}
/****************************************/
void Test_BinaryTree()
{
printf("\n\n************ binary tree ***************\n");
//CBinaryTree<char> binary_tree(Sting2VtChar("12##3##"));
// 前序:124##5#6##37###
// 中序:#4#2#5#6#1#7#3#
// 后序:##4###652##7#31
CBinaryTree<char> binary_tree(Sting2VtChar("124##5#6##37###"));
// 前序:124##5#6##37###
PrintFunStr("PreOrderTraverse1: ");
binary_tree.PreOrderTraverse1(binary_tree.GetRoot());
printf("\n");
// 前序:124##5#6##37###
PrintFunStr("PreOrderTraverse2: ");
binary_tree.PreOrderTraverse1(binary_tree.GetRoot());
printf("\n");
// 前序:124##5#6##37###
PrintFunStr("PreOrderTraverse3: ");
binary_tree.PreOrderTraverse3(binary_tree.GetRoot());
printf("\n");
// 前序:124##5#6##37###
PrintFunStr("PreOrderTraverse4: ");
binary_tree.PreOrderTraverse4(binary_tree.GetRoot());
printf("\n");
// 中序:#4#2#5#6#1#7#3#
PrintFunStr("InOrderTraverse1: ");
binary_tree.InOrderTraverse1(binary_tree.GetRoot());
printf("\n");
// 中序:#4#2#5#6#1#7#3#
PrintFunStr("InOrderTraverse2: ");
binary_tree.InOrderTraverse2(binary_tree.GetRoot());
printf("\n");
// 中序:#4#2#5#6#1#7#3#
PrintFunStr("InOrderTraverse3: ");
binary_tree.InOrderTraverse3(binary_tree.GetRoot());
printf("\n");
// 中序:#4#2#5#6#1#7#3#
PrintFunStr("InOrderTraverse4: ");
binary_tree.InOrderTraverse4(binary_tree.GetRoot());
printf("\n");
// 后序:##4###652##7#31
PrintFunStr("PostOrderTraverse1: ");
binary_tree.PostOrderTraverse1(binary_tree.GetRoot());
printf("\n");
// 后序:##4###652##7#31
PrintFunStr("PostOrderTraverse2: ");
binary_tree.PostOrderTraverse2(binary_tree.GetRoot());
printf("\n");
// 后序:##4###652##7#31
PrintFunStr("PostOrderTraverse3: ");
binary_tree.PostOrderTraverse3(binary_tree.GetRoot());
printf("\n");
// 后序:##4###652##7#31
PrintFunStr("PostOrderTraverse4: ");
binary_tree.PostOrderTraverse4(binary_tree.GetRoot());
printf("\n");
// 层级遍历:##4###652##7#31 广度优先遍历
PrintFunStr("LevelTraverse1: ");
binary_tree.LevelTraverse1(binary_tree.GetRoot());
printf("\n");
// 求节点数:
PrintFunStr("GetNodeNum1: ");
int num = binary_tree.GetNodeNum1(binary_tree.GetRoot());
printf("%d\n", num);
// 求深度:
PrintFunStr("GetDepth1: ");
int height = binary_tree.GetDepth1(binary_tree.GetRoot());
printf("%d\n", height);
printf("");
}
}