非递归遍历二叉树的实现

参考:http://blog.csdn.net/kofsky/article/details/2886453/
#pragma once
#define NUM_NODE  8
#include<iostream>
#include<stack>
#include<ctime>
#include<assert.h>
class binnode {
public:
	int key;
	char value;
	binnode  *left, *right,*parent;
	bool beVisited;          //用于中序遍历的指针回溯版本
	bool bePushed;           //用于中序遍历的
	binnode(){}
	binnode(int k, char v) :key(k), value(v) { left = right = parent = nullptr; beVisited = false; bePushed = false; }
	binnode(const binnode& bn) {
		key = bn.key;
		value = bn.value;
		left = right = parent = nullptr;
		beVisited = false;
		bePushed = false;
	}
};
class bintree {
public:
	bintree();
	bool insert(const binnode& bn);
	void inorder();
	void postorder();
	void preorder();
	void menu();
protected:
	void inorder(binnode * bn);             //递归前序遍历
	void _inorder();                        //非递归前序遍历
	void __inorder(binnode * bn);
	void postorder(binnode * bn);
	void _postorder();
	void preorder(binnode * bn);
	void _preorder();
	void __preorder(binnode * bn);
private:
	void visit(binnode *bn);
	binnode *root;
	binnode *NIL;
};
#include"bintree.h"
bintree::bintree() {
	root = nullptr;
	NIL = nullptr;
}
bool bintree::insert(const binnode& bn) {
	binnode *tmp = root;                         //指向插入位置的指针
	binnode *parent_tmp = nullptr;               //插入位置的父节点

	while (tmp != NIL) {
		parent_tmp = tmp;                        //先赋值父节点
		if (bn.key <= tmp->key) {
			tmp = tmp->left;                     //指针指向子节点
		}
		else
			tmp = tmp->right;
	}
	tmp = new binnode(bn);                       //产生插入的节点
	if (tmp == nullptr) { std::cout << "allocated error!.\n"; return false; }
	tmp->parent = parent_tmp;                    //赋值子节点的父指针
	if (tmp->parent == NIL) {                    //若父节点为空,则当前插入的节点是根节点
		root = tmp;                              //赋值根节点
		return true;
	}
	if (tmp->key <= tmp->parent->key) {          //判断插入的位置是父节点的左子女还是右子女
		tmp->parent->left = tmp;
	}
	else
		tmp->parent->right = tmp;
	return true;
}
void bintree::visit(binnode *bn) {
	std::cout << bn->value << " ";
/*	if (bn->parent != nullptr) {
		std::cout << bn->value << "'s parent is " << bn->parent->value << " ";
	}*/
}
void bintree::menu() {
	int select;
	std::cout << "1.前序遍历. \t 2.中序遍历. \t 3.后序遍历. \t 4.退出\n";
	std::cin >> select;
	while (select != 1 && select != 2 && select != 3 && select != 4) {
		std::cout << "输入错误,请重新输入!";
		std::cin >> select;
	}
	switch (select)
	{
	case 1:preorder(); break;
	case 2:inorder(); break;
	case 3:postorder(); break;
	case 4:exit(0); break;
	default:
		break;
	}
}

int main() {
	bintree bt;
	int key[NUM_NODE] = {4,2,3,1,5,6,7};
	char value[NUM_NODE] = {'A','B','C','D','E','F','G','\0'};
	binnode bn[NUM_NODE];
	/*创建二叉查找树*/
	for (int i = 0; i < NUM_NODE; ++i) {
		bn[i].key = key[i];
		bn[i].value = value[i];
		bn[i].left = bn[i].right = bn[i].parent = nullptr;
		bn[i].beVisited = false;
		bn[i].bePushed = false;
	}
	for (int i = 0; i < NUM_NODE; ++i) {
		std::cout << bn[i].value << " ";
	}
	std::cout << std::endl;
	for (int i = 0; i < NUM_NODE; ++i) {
		bt.insert(bn[i]);
	}
	/*测试遍历*/
	bt.menu();
	return 0;
}
#include"bintree.h"
void bintree::inorder() {
	int select;
	std::cout << "1.递归中序遍历. \t2.非递归中序遍历.\t 3.非递归中序遍历2 \t 4.返回主菜单\n";
	std::cin >> select;
	while (select != 1 && select != 2 && select != 3 && select != 4) {
		std::cout << "输入错误,请重新输入!" << std::endl;
		std::cin >> select;
	}
	switch (select) {
	case 1:inorder(root); std::cout << std::endl; inorder(); break;
	case 2:_inorder(); std::cout << std::endl; inorder(); break;
	case 3:__inorder(root); std::cout << std::endl; inorder(); break;
	case 4:menu(); break;
		
	}
}
void bintree::inorder(binnode * bn) {            //递归中序遍历
	if (bn != nullptr) {
		inorder(bn->left);
		visit(bn);
		inorder(bn->right);
	}
}
/*
	// 中序遍历伪代码:非递归版本,用栈实现,版本1
void InOrder1(TNode* root)
{
    Stack S;
    while ( root != NULL || !S.empty() )
    {
        while( root != NULL )   // 左子树入栈
        {
            S.push(root);
            root = root->left;
        }
        if ( !S.empty() )
        {
            root = S.pop();
            Visit(root->data);   // 访问根结点
            root = root->right;  // 通过下一次循环实现右子树遍历
        }
    }
}
*/
void bintree::_inorder() {                       //非递归中序遍历
	std::stack<binnode*> s;
	binnode *p = root;
	while (p != NULL || !s.empty())              //循环结束条件:当节点为空且栈为空结束循环
	{
		while (p != NULL)                        //遍历左子树并进栈,直到左子树为空
		{
			s.push(p);
			p = p->left;
		}
		if (!s.empty())                          //若栈不为空则出栈,打印并进入节点的右子树
		{
			p = s.top();
			visit(p);
			s.pop();
			p = p->right;
		}
	}
}
/*
	// 中序遍历伪代码:非递归版本,不用栈,增加指向父节点的指针
void InOrder3(TNode* root)
{
    while ( root != NULL ) // 回溯到根节点时为NULL,退出
    {
        while ( root->left != NULL && !root->left->bVisited )
        {                  // 沿左子树向下搜索当前子树尚未访问的最左节点           
            root = root->left;
        }
        if ( !root->bVisited )
        {                  // 访问尚未访问的最左节点
            Visit(root);
            root->bVisited=true;
        }
        if ( root->right != NULL && !root->right->bVisited )
        {                  // 遍历当前节点的右子树  
            root = root->right;
        }
        else
        {                 // 回溯至父节点
            root = root->parent;
        }
    }
}
*/
void bintree::__inorder(binnode * bn) {
	binnode * p = bn;
	while (p != nullptr) {
		while (p->left != nullptr && !p->left->beVisited) {
			p = p->left;
		}
		if (!p->beVisited) {
			visit(p);
			p->beVisited = true;
		}
		if (p->right != nullptr && !p->right->beVisited) {
			p = p->right;
		}
		else {
			p = p->parent;
		}
	}
}
/*
	// 中序遍历伪代码:非递归版本,用栈实现,版本2
void InOrder2(TNode* root)
{
    Stack S;
    if( root != NULL )
    {
        S.push(root);
    }
    while ( !S.empty() )
    {
        TNode* node = S.pop(); 
        if ( node->bPushed )
        {   // 如果标识位为true,则表示其左右子树都已经入栈,那么现在就需要访问该节点了
            Visit(node);        
        }
        else
        {   // 左右子树尚未入栈,则依次将 右节点,根节点,左节点 入栈
            if ( node->right != NULL )
            {
                node->right->bPushed = false; // 左右子树均设置为false
                S.push(node->right);
            }
            node->bPushed = true;  // 根节点标志位为true
            S.push(node);
            if ( node->left != NULL )
            {
                node->left->bPushed = false;
                S.push(node->left);
            }
        }
    }
}
*/
#include"bintree.h"
void bintree::preorder() {
	int select;
	binnode * p = root;
	std::cout << "1.递归前序遍历. \t2.非递归前序遍历.\t 3.非递归遍历2. \t 4.返回主菜单\n";
	std::cin >> select;
	while (select != 1 && select != 2 && select != 3 && select != 4) {
		std::cout << "输入错误,请重新输入!" << std::endl;
		std::cin >> select;
	}
	switch (select) {
	case 1:preorder(p); std::cout << std::endl; preorder(); break;
	case 2:_preorder(); std::cout << std::endl; preorder(); break;
	case 3:__preorder(root); break;
	case 4:menu(); break;
	}
}
void bintree::preorder(binnode * bn) {
	if (bn == nullptr)return;
	std::cout << bn->value << " ";
	preorder(bn->left);
	preorder(bn->right);
}
void bintree::_preorder() {
	binnode * p = root;
	std::stack<binnode*> s;
	p = root;
	assert(s.empty());
	while (p != nullptr || !s.empty()) {
		if (p != nullptr) {
			visit(p);
			s.push(p);
			p = p->left;
		}
		else {
			p = s.top();
			s.pop();
			p = p->right;
		}
	}
}
void bintree::__preorder(binnode * bn) {
	binnode * p = bn;
	std::stack<binnode*> s;
	s.push(p);
	while (!s.empty()) {
		p = s.top();
		s.pop();
		if (p != nullptr) {           //入栈的时候可能有空指针,只有非空指针才能进行操作
			visit(p);
			s.push(p->right);
			s.push(p->left);
		}
	}
}
/*
// 先序遍历伪代码:非递归版本,用栈实现,版本1
void preOrder1(TNode* root)
{
	Stack S;
	while ((root != NULL) || !S.empty())
	{
		if (root != NULL)
		{
			Visit(root);
			S.push(root);       // 先序就体现在这里了,先访问,再入栈
			root = root->left;  // 依次访问左子树
		}
		else
		{
			root = S.pop();     // 回溯至父亲节点
			root = root->right;
		}
	}
}
*/
/*
// 先序遍历伪代码:非递归版本,用栈实现,版本2
void preOrder2(TNode* root)
{
	if ( root != NULL)
	{
		Stack S;
		S.push(root);
		while (!S.empty())
		{
			TNode* node = S.pop();
			Visit(node);          // 先访问根节点,然后根节点就无需入栈了
			S.push(node->right);  // 先push的是右节点,再是左节点
			S.push(node->left);
		}
	}
}
*/
#include"bintree.h"
void bintree::postorder() {
	int select;
	std::cout << "1.递归后序遍历. \t2.非递归后序遍历.\t 3.返回主菜单\n";
	std::cin >> select;
	while (select != 1 && select != 2 && select != 3) {
		std::cout << "输入错误,请重新输入!" << std::endl;
		std::cin >> select;
	}
	switch (select) {
	case 1:postorder(root); postorder(); break;
	case 2:_postorder(); postorder(); break;
	case 3:menu(); break;
	}
}

void bintree::postorder(binnode * bn) {                 //递归后序遍历
	if (bn != nullptr) {
		postorder(bn->left);
		postorder(bn->right);
		std::cout << bn->value << " ";
	}
}
/*
	// 后序遍历伪代码:非递归版本,用栈实现
void PostOrder(TNode* root)
{
    Stack S;
    if( root != NULL )
    {
        S.push(root);
    }
    while ( !S.empty() )
    {
        TNode* node = S.pop(); 
        if ( node->bPushed )
        {   // 如果标识位为true,则表示其左右子树都已经入栈,那么现在就需要访问该节点了
            Visit(node);        
        }
        else
        {  
			node->bPushed = true;            // 根节点标志位为true
            S.push(node);
		// 左右子树尚未入栈,则依次将 右节点,左节点,根节点 入栈
            if ( node->right != NULL )
            {
                node->right->bPushed = false; // 左右子树均设置为false
                S.push(node->right);
            }
            if ( node->left != NULL )
            {
                node->left->bPushed = false;
                S.push(node->left);
            }
        }
    }
}
*/
void bintree::_postorder() {
	std::stack<binnode*> s;
	binnode *p = root;
	if (p != nullptr) {
		s.push(p);
	}
	while (!s.empty()) {
		p = s.top();
		s.pop();
		if (p->bePushed) {
			visit(p);
		}
		else {
			p->bePushed = true;
			s.push(p);
			if (p->right != nullptr) {
				s.push(p->right);
				p->right->bePushed = false;
			}
			if (p->left != nullptr) {
				s.push(p->left);
				p->left->bePushed = false;
			}
		}
	}
}




总结:1)递归改写成非递归,关键是要仿照递归的遍历顺序,不论是利用栈还是利用指针回溯,最终都是依靠条件来约束非递归时的遍历顺序。

    如中序遍历的指针回溯版本,先走到左子树的尽头,若左子树有右子树则进入右子树,若无右子树则回溯父节点,通过判断右子树的有无改变遍历的顺             序,使遍历的顺序跟递归调用的遍历顺序一样。

            2)找准算法的出口,明确算法结束的判断条件。

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