二叉树的遍历算法

最近更新于 2022-10-03, 发布于 2022-08-08

0. 数据结构

template <typename DataType>
class BTNode
{
	DataType val_;
	BTNode<DataType>* lchild_;
	BTNode<DataType>* rchild_;
};

template <typename DataType>
using BTree = BTNode<DataType>*; // without header node;
typedef struct TreeNode {
	int data_ = 0;
	TreeNode* lchild_ = nullptr;
	TreeNode* rchild_ = nullptr;  
} TreeNode, *BiTree;

1. 递归遍历

1.1. 先序遍历

template <typename DataType>
void preOrdTraversal(BTree<DataType> tree)
{
	if (tree != nullptr) {
		/* visit node */


		preOrdTraversal<DataType>(tree->lchild_);
		preOrdTraversal<DataType>(tree->rchild_);
	}
	return;
}

1.2. 中序遍历

template <typename DataType>
void inOrdTraversal(BTree<DataType> tree)
{
	if (tree != nullptr) {
		inOrdTraversal<DataType>(tree->lchild_);
		/* visit node */


		inOrdTraversal<DataType>(tree->rchild_);
	}
	return;
}

1.3. 后序遍历

template <typename DataType>
void postOrdTraversal(BTree<DataType> tree)
{
	if (tree != nullptr) {
		postOrdTraversal<DataType>(tree->lchild_);
		postOrdTraversal<DataType>(tree->rchild_);
		/* visit node */


	}
	return;
}

2. 非递归遍历

2.1. 先序遍历

2.1.1. 栈法
template <typename DataType>
void preOrdTraversal(BTree<DataType> tree)
{
	if (tree == nullptr) { // empty tree;
		return;
	}

	stack<BTNode<DataType>*> stk = {};
	BTNode<DataType>* mov = tree;

	while (!stk.empty() || mov != nullptr) {
		if (mov != nullptr) {
			stk.push(mov);

			/* visit node */

			mov = mov->lchild_;
		}
		else {	// the current nullptr node is not in the stack yet;
			mov = stk.top();
			mov = mov->rchild_;
			stk.pop();
		}
	}

	return;
}
void preOrdTraversal(BiTree tree)
{
	typedef struct stackNode {
		TreeNode* tnode_ = nullptr;
		stackNode* next_ = nullptr;
	} stackNode, *stack;

	#define STKPUSH(m_elem) do { top = new stackNode; top->tnode_ = m_elem; top->next_ = stk->next_; stk->next_ = top; } while (0)
	#define STKPOP do { stk->next_ = top->next_; delete top; top = stk->next_; } while (0)

	stack stk = new stackNode;
	stackNode* top = nullptr;

	TreeNode* mov = tree;

	while (top != nullptr || mov != nullptr) {
		if (mov != nullptr) {
			STKPUSH(mov);

			/* visit node */

			mov = mov->lchild_;
		}
		else {
			mov = top->tnode_;
			mov = mov->rchild_;
			STKPOP;
		}
	}

	return;
}
2.1.2. 孩子双亲表示法

该方法需要给每个结点增加双亲指针 TreeNode* parent , 初值为 nullptr .

void preOrdTrav(BiTree tree)
{
	if (tree == nullptr) {
		return;
	}

	TreeNode* mov = tree;
	TreeNode* pred = new TreeNode; // header indicating empty stack;
	while (mov != tree->parent) {
		while (mov != nullptr) {
			/* visit node */
			std::cout << mov->data << ' ';

			mov->parent = pred;
			pred = mov;
			mov = mov->lchild;
		}

		// now mov == nullptr;
		mov = pred;
		pred = pred->parent;
		while (mov != tree->parent && (mov->rchild == nullptr || mov->rchild->parent != nullptr)) { // non-null parent indicates that the node has been visited;
			mov = mov->parent;
			pred = pred->parent;
		}
		if (mov == tree->parent) {
			break;
		}
		pred = mov;
		mov = mov->rchild;
	}

	delete tree->parent;
	tree->parent = nullptr;
	std::cout << std::endl;

	return;
}

2.2. 中序遍历

template <typename DataType>
void inOrdTraversal(BTree<DataType> tree)
{
	if (tree == nullptr) { // empty tree;
		return;
	}

	stack<BTNode<DataType>*> stk = {};
	BTNode<DataType>* mov = tree;

	while (!stk.empty() || mov != nullptr) {
		if (mov != nullptr) {
			stk.push(mov);
			mov = mov->lchild_;
		}
		else { // the current nullptr node is not in the stack yet;
			mov = stk.top();

			/* visit node */

			mov = mov->rchild_;
			stk.pop();
		}
	}

	return;
}

2.3. 后序遍历

template <typename DataType>
void postOrdTraversal(BTree<DataType> tree)
{
	if (tree == nullptr) { // empty tree;
		return;
	}

	stack<BTNode<DataType>*> stk = {};
	BTNode<DataType>* mov = tree;
	// set probe for most recently visited node;
	BTNode<DataType>* rtag = nullptr;

	while (!stk.empty() || mov != nullptr) {
		if (mov != nullptr) {
			stk.push(mov);
			mov = mov->lchild_;
		}
		else { // the current nullptr node is not in the stack yet;
			mov = stk.top();
			if (mov->rchild_ != nullptr && mov->rchild_ != rtag) {
				mov = mov->rchild_;
			}
			else {
				/* visit node */

				stk.pop();
				rtag = mov; // update rtag;
				mov = nullptr;
			}
		}
	}

	return;
}

2.4. 层序遍历

template <typename DataType>
void levOrdTraversal(BTree<DataType> tree)
{
	if (tree == nullptr) { // empty tree;
		return;
	}

	queue<BTNode<DataType>*> que = {};
	que.push(tree);
	BTNode<DataType>* mov = nullptr;
	/* visit root */

	while (!que.empty()) {
		size_t len = que.size(); // freeze size;

		for (size_t index = 0; index < len; ++index) {
			mov = que.front();

			if (mov->lchild_ != nullptr) {
				/* visit lchild node */

				que.push(mov->lchild_);
			}
			if (mov->rchild_ != nullptr) {
				/* visit rchild node */

				que.push(mov->rchild_);
			}

			que.pop();
		}
	}

	return;
}

附录

重要内容更新日志

2022-10-03 补全了递归遍历方式中缺漏的模板参数.