二叉树的遍历 (C++实现)

本文涉及三种常见的遍历方式 : 先序遍历、中序遍历、后序遍历,以及用C++实现的非递归版本代码。

首先我们定义一下二叉树结点类 

struct BinaryTreeNode {
	int val;
	BinaryTreeNode* leftchild;
	BinaryTreeNode* rightchild;
	BinaryTreeNode(int const& _val, BinaryTreeNode* _leftchild=NULL, BinaryTreeNode* _rightchild=NULL) :
		val(_val), leftchild(_leftchild), rightchild(_rightchild) {}
	

};

      三种遍历方式  访问节点的顺序是一致的,不同之处在于,有的遍历流程把访问到的节点暂存起来,达成某种条件后再将节点输出。约定, 根节点V, 其左孩子为L, 右孩子为R, 那么遍历顺序可以记为:

Pre-Order Traversal : 到达一个节点后,即刻输出该节点的值,并继续遍历其左右子树。                                VLR

In-Order Traversal  :   到达一个节点后,将其暂存,遍历完左子树后,再输出该节点的值,然后遍历右子树。LVR

Post-Order Traversal:   到达一个节点后,将其暂存,遍历完左右子树后,再输出该节点的值。                          LRV

                                          

          Pre-Order Traversal                                          In-Order Traversal                                          Post-Order Traversal

先序遍历

       

                                

 先序遍历与中序、后序遍历都使用了栈结构来暂存节点

void pre_traversal(BinaryTreeNode* root) {
	std::stack<BinaryTreeNode*> node_stack;       //用来暂存节点的栈
	while (root != nullptr || !node_stack.empty()) {
		if (root != nullptr) {                     //若当前的节点非空,
			std::cout << root->val << " ";         //则输出该节点的值
			node_stack.push(root);                 //该节点压入栈中。
			root = root->leftchild;                // 我们继续向左子树前进
		}
		else {
			root = node_stack.top();                
			node_stack.pop();
			root = root->rightchild;
		}

	}

}

中序遍历

与先序遍历类似,唯一区别是到达当前节点时  并不直接输出该节点。

void in_traversal(BinaryTreeNode* root) {
	std::stack<BinaryTreeNode*> stack_node;
	while (root != nullptr || !stack_node.empty()) {
		if (root != nullptr) {
			stack_node.push(root);
			root = root->leftchild;
		}
		else {
			root = stack_node.top();
			std::cout << root->val << " ";
			stack_node.pop();
			root = root->rightchild;
		}
	}
}

后序遍历

     与先序、中序遍历有所不同,后序遍历在决定是否可以输出当前节点的值的时候,需要考虑其左右子树是否都已经遍历完成。

     因此我们需要设置一个lastvisit游标。若lastvisit等于当前考查节点的右子树,表示该节点的左右子树都已经遍历完成,则可以输出当前节点(否则,继续向右子树进发)。并把lastvisit节点设置成当前节点,将当前游标节点root设置为空,下一轮就可以访问栈顶元素。

     



 

                              

void post_traversal(BinaryTreeNode* root) {
	std::stack<BinaryTreeNode*> stack_node;
	BinaryTreeNode* lastvisit = root;
	while (root != nullptr || !stack_node.empty()) {
		if (root != nullptr) {
			stack_node.push(root);
			root = root->leftchild;
		}
		else {
			root = stack_node.top();
			if (root->rightchild == nullptr || root->rightchild == lastvisit) {
				
				std::cout << root->val << " ";
				stack_node.pop();
			    lastvisit = root;
				root = nullptr;
			}
			else {
				root = root->rightchild;
			}
			
		}
	}

}

下面是测试用的代码:

int main(int argc, char* argv[]) {
	
	BinaryTreeNode* A = new BinaryTreeNode(1);
	BinaryTreeNode* B = new BinaryTreeNode(2);
	BinaryTreeNode* C = new BinaryTreeNode(4);
	BinaryTreeNode* D = new BinaryTreeNode(7);
	BinaryTreeNode* E = new BinaryTreeNode(3);
	BinaryTreeNode* F = new BinaryTreeNode(5);
	BinaryTreeNode* G = new BinaryTreeNode(6);
	BinaryTreeNode* H = new BinaryTreeNode(8);
	A->leftchild = B;
	A->rightchild = E;
	B->leftchild = C;
	C->rightchild = D;
	E->leftchild = F;
	E->rightchild = G;
	G->leftchild = H;
	std::cout << "Pre order traversal:" << std::endl;
	pre_traversal(A);
	std::cout << std::endl<< "In order traversal:" << std::endl;
	in_traversal(A);
	std::cout << std::endl << "Post order traversal:" << std::endl;
	post_traversal(A);
	

	return 0;
}

遍历结果: 

Reference: https://www.jianshu.com/p/456af5480cee

猜你喜欢

转载自blog.csdn.net/zhhp1001/article/details/88257018