算法实现-二叉树相关

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章