#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("");
}
}