非递归遍历二叉树的实现

来源:互联网 发布:钻石皇朝流量软件 编辑:程序博客网 时间:2024/05/21 05:19
参考: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;                     //指针指向子节点}elsetmp = 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;}elsetmp->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);}}/*// 中序遍历伪代码:非递归版本,用栈实现,版本1void 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;}}}/*// 中序遍历伪代码:非递归版本,用栈实现,版本2void 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);}}}/*// 先序遍历伪代码:非递归版本,用栈实现,版本1void 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;}}}*//*// 先序遍历伪代码:非递归版本,用栈实现,版本2void 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)找准算法的出口,明确算法结束的判断条件。

0 0
原创粉丝点击