二叉树的遍历 (递归实现)
用C++实现二叉树的“先根遍历”存储。
用C++实现二叉树的“先根遍历”、“中根遍历”、“后根遍历”分别输出二叉树中结点的数据。
#include <iostream>
using namespace std ;
struct BiNode
{
char data ;
BiNode *lchild , *rchild ;
} ;
BiNode *BiTree ;
int NodeID ;
BiNode *CreateBiTree (char *c , int n)
{
BiNode *T ;
NodeID ++ ;
if (NodeID > n)
{
return (NULL) ;
}
if (c[NodeID] == '0')
{
return (NULL) ;
}
T = new BiNode ;
T -> data = c[NodeID] ;
T -> lchild = CreateBiTree (c , n) ;
T -> rchild = CreateBiTree (c , n) ;
return (T) ;
}
void PreOrderTraverse (BiNode *T)
{
if (T)
{
cout << T -> data << " ";
PreOrderTraverse (T -> lchild) ;
PreOrderTraverse (T -> rchild) ;
}
}
void InOrderTraverse (BiNode *T)
{
if (T)
{
InOrderTraverse (T -> lchild) ;
cout << T -> data << " ";
InOrderTraverse (T -> rchild) ;
}
}
void PostOrderTraverse (BiNode *T)
{
if (T)
{
PostOrderTraverse (T -> lchild) ;
PostOrderTraverse (T -> rchild) ;
cout << T -> data << " ";
}
}
int main ()
{
int i , SampleNum ;
char c[100] ;
cin >> SampleNum ;
for (i = 1 ; i <= SampleNum ; i ++)
{
cin >> c[i] ;
}
NodeID = 0 ;
BiTree = CreateBiTree (c , SampleNum) ;
PreOrderTraverse (BiTree) ;
cout << endl ;
InOrderTraverse (BiTree) ;
cout << endl ;
PostOrderTraverse (BiTree) ;
return 0 ;
}
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(); //取栈顶节点
root = root->rightchild; //继续向右子树前进
node_stack.pop(); //删除栈顶节点
}
}
}
中序遍历
与先序遍历类似,唯一区别是到达当前节点时 并不直接输出该节点。
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 << " "; //访问节点数据
root = root->rightchild; //继续向右子树前进
stack_node.pop(); //删除栈顶
}
}
}
后序遍历
与先序、中序遍历有所不同,后序遍历在决定是否可以输出当前节点的值的时候,需要考虑其左右子树是否都已经遍历完成。
因此我们需要设置一个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;
}