【数据结构】二叉树的三种遍历--(递归+非递归)

来源:互联网 发布:矩阵乘法规则 编辑:程序博客网 时间:2024/06/05 18:06

前序遍历:根节点—>左子树—>右子树
中序遍历:左子树—>根节点—>右子树
后序遍历:左子树—>右子树—>根节点

【构造一棵树】
我们用数组存树的节点
int a[15] = { 1, 2, ‘#’, 3, ‘#’, ‘#’, 4, 5, ‘#’, 6, ‘#’, 7, ‘#’, ‘#’, 8 }
“#”代表非法值,就是为空的节点

#include<iostream>#include<stack>#include<queue>using namespace std;template < class T>struct BinaryTreeNode{       BinaryTreeNode* _left;    BinaryTreeNode* _right;    T _data;    BinaryTreeNode(const T&x)        :_left(NULL)        , _right(NULL)        ,_data(x)    {}};template <class T>class BinaryTree{    typedef BinaryTreeNode<T> Node;public:    BinaryTree()        :_root(NULL)    {}    BinaryTree(const T* a, size_t n, const T& invalid)    {        size_t index = 0;        _root = _CreatTree(a, n, invalid, index);//构造树的函数    }//构造树Node* _CreatTree(const T*a, size_t n, const T& invalid, size_t& index)    {        Node* root = NULL;        if (index < n&&a[index] != invalid)        {            root = new Node(a[index]);            root->_left = _CreatTree(a,n,invalid,++index);            root->_right = _CreatTree(a, n, invalid, ++index);        }        return root;    }    ~BinaryTree()    {        _Destroy(_root);        cout << endl;    }protected:    Node* _root;

前序——–递归
前序就是遇到根节点就访问,之后访问左子树,再右子树,所以很容易可以写出如下非递归代码

void PrevOrder()    {        _PrevOrder(_root);        cout << endl;    }void _PrevOrder(Node* root)    {        if (root == NULL)        {            return;        }        cout << root->_data << " ";        _PrevOrder(root->_left);        _PrevOrder(root->_right);    }

前序——–非递归
这里我们要借用栈,因为栈的特性是后进先出。
先遍历树的最左节点,并把每个节点入栈。在入栈的同时就可以访问根节点。
当cur为NULL时,这颗树的最左边的根节点节点都全部入栈,
然后取出栈顶节点,访问右子树,
这里写图片描述
当栈为空,这个树就遍历结束

void PrevOrder_NonR()//非递归前序遍历    {        stack<Node*> s;        Node* cur = _root;        while (cur||!s.empty())        {            while (cur)            {                s.push(cur);                cout << cur->_data << " ";                cur = cur->_left;            }            Node* top = s.top();            s.pop();            cur = top->_right;        }        cout << endl;    }

中序—-递归

void InOrder()//中序{    _InOrder(_root);    cout << endl;}    void _InOrder(Node* root)    {        if (root == NULL)        {            return;        }        _InOrder(root->_left);        cout << root->_data << " ";        _InOrder(root->_right);    }

中序—-非递归

依然借助栈,把树的最左边的根节点cur全部入栈,
然后依次取栈顶节点访问,
再访问右子树,右子树不为空的时候继续入栈。

    void InOrder_NonR()//非递归中序遍历    {        Node* cur = _root;        stack<Node*> s;        while (cur||!s.empty())        {            while (cur)            {                s.push(cur);                cur = cur->_left;            }            Node* top = s.top();//此时访问的是最左节点            cout << top->_data << " ";            s.pop();            cur = top->_right;        }        cout << endl;    }

后序—-递归

void PosOrder()//后序{    _PosOrder(_root);    cout << endl;}void _PosOrder(Node* root){    if (root == NULL)    {        return;    }    _PosOrder(root->_left);    _PosOrder(root->_right);    cout << root->_data << " ";}

后序—-非递归
还是借助栈。但是此时有一个问题:后序是先访问左子树,在右子树,最后根节点,那么问题来了:–访问右子树,是需要通过先访问根节点,当cur=top->_right,cur不是NULL,把cur入栈,依次访问右子树,最后依次退到根节点访问,但是此时cur=top->_right,cur不等于NULL,再次入栈;可是我们已经把右树访问过了,所以我们会在这里陷入死循环。

那么如何解决呢?
我们可以设置一个标记prev,prev表示上一个访问的节点。当我们取出栈顶节点时,如果他的右子树已经访问过了,就不再把右子树入栈,而直接访问当前节点。

void PostOrder_NonR()//后序非递归{    stack<Node*> s;    Node* cur = _root;    Node* prev = NULL;    while (cur||!s.empty())    {        while (cur)        {            s.push(cur);            cur = cur->_left;        }        Node* top = s.top();        if (top->_right == NULL || top->_right == prev)        {            cout << top->_data << " ";            prev = top;            s.pop();        }        else        {            cur = top->_right;        }    }    cout << endl;}
阅读全文
0 0
原创粉丝点击