二叉树的遍历 (递归和非递归实现)

二叉树的遍历 (递归实现)

用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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值