二叉树的Morris非递归遍历

Morris loop定义

一个Morris loop是一个从一个节点,比如说v,开始到同一个节点结束的路径,路径上的第一个链接是(v, v.l),其余链接的形式都是(u, u.r)。这个节点v,被称作已标记的节点。一个Morris线索树是一个有根的图G,它满足:(1)如果将所有指向已标记节点的右链接替换成空节点,则G会变成一个二叉树;(2)存在一个节点a,它对于所有已标记节点都是右可达的(right-reachable)。这个节点不一定是唯一的。

引理

1.一个Morris线索树的任意节点至多只能被两个Morris loop共有。实际上,如果一个节点被两个Morris loop共有,在一个loop中它必须是被标记的,在另一个loop中它对于另一个已标记节点u,要么等于u.l要么对于u.l是右可达的。

2.一个Morris 线索树有一个唯一的从根开始经过所有已标记节点的路径。这个路径不含圈,它从离根节点最近的已标记节点到离根最远的已标记节点。如果一个Morris线索树不含Morris loop,它就成了一个二叉树,上述的路径为空。

接口定义

(1)createstack()生成一个任意的二叉树,它代表空栈。
(2)stackempty(G)判断G是否是一个二叉树。
(3)push(G, t)在G的基础上生成一个Morris线索树G’,t在G’中是被标记的。push操作如果不满足以下条件则是未定义的:(1)t在G中,(2)t.l != nil并且t在G中是未标记的,(3)G的t在包含离根最远的已标记节点的Morris loop上。
(4)pop(G)通过将指向最远已标记节点的右链接变成nil以生成G”。pop操作将是未定义的,如果G中不含Morris loop。
(5)top(G)生成G中最远的已标记节点。top操作将是未定义的,如果G中不含Morris loop。

算法定义

算法关键在于用Morris线索树模拟栈。现在“栈”正式由一个以T为根的Morris线索树和t组成(Morris线索树和当前节点t对于下面的操作是全局的)。

createstack()is defined as:
{the structure whose root is T is a binary tree}
skip;(do nothing)

stackempty() is defined as:
{all marked nodes are right-reachable from t}
t.r = nil

push(t) is defined as:
{t.l != nil and t is not marked
and t is on the loop of the farthest marked node}
p:=t.l;
do p.r != nil->p:=p.r od;
p.r:=t;
{t is marked}

pop() is defined as:
{t.r is the farthest marked node}
t.r:=nil;

top() is defined as:
{t.r is the farthest marked node}
t.r

Morris线索树和上面定义的操作组成了栈。

c++实现

//author: jsh
#include <iostream>
#include <stack>

template <class T>
struct TreeNode{
    T key;
    struct TreeNode<T> *left;
    struct TreeNode<T> *right;
    bool instack;

    TreeNode(T x = T()) : key(x), instack(false){}
};

template <class T>
class BSTtree{
public:
    typedef TreeNode<T> *NodePtr;
    typedef TreeNode<T> NodeType;
public:
    BSTtree() : root_(nullptr) {}

    void insert(T x);
    void preOrderTraversal();
    void inOrderTraversal();
    void postOrderTraversal();

    void inOrderTraversal_iter1();//with visible stack
    void inOrderTraversal_iter2();//without visible stack

    void preOrderTraversal_iter();

    void postOrderTraversal_iter();
private:
    NodePtr root_;

    void preOrderTraversal_aux(NodePtr node);
    void inOrderTraversal_aux(NodePtr node);
    void postOrderTraversal_aux(NodePtr node);

    void reverse(NodePtr from, NodePtr to);
    void printReverse(NodePtr from, NodePtr to);
};

template <class T>
void BSTtree<T>::insert(T x){
    auto node = new NodeType(x);
    if(!root_){
        root_ = node;
        return;
    }

    auto tmp = root_;
    NodePtr y = nullptr;

    while(tmp){
        y = tmp;
        if(x < tmp->key)
            tmp = tmp->left;
        else
            tmp = tmp->right;
    }

    if(x < y->key)
        y->left = node;
    else
        y->right = node;
}

template <class T>
void BSTtree<T>::inOrderTraversal(){
    inOrderTraversal_aux(root_);
    std::cout<<std::endl;
}

template <class T>
void BSTtree<T>::inOrderTraversal_aux(NodePtr node){
    if(!node)
        return;
    inOrderTraversal_aux(node->left);
    std::cout<<node->key<<" ";
    inOrderTraversal_aux(node->right);
}

template <class T>
void BSTtree<T>::preOrderTraversal(){
    preOrderTraversal_aux(root_);
    std::cout<<std::endl;
}

template <class T>
void BSTtree<T>::preOrderTraversal_aux(NodePtr node){
    if(!node)
        return;
    std::cout<<node->key<<" ";
    inOrderTraversal_aux(node->left);
    inOrderTraversal_aux(node->right);
}

template <class T>
void BSTtree<T>::postOrderTraversal(){
    postOrderTraversal_aux(root_);
    std::cout<<std::endl;
}

template <class T>
void BSTtree<T>::postOrderTraversal_aux(NodePtr node){
    if(!node)
        return;
    postOrderTraversal_aux(node->left);
    postOrderTraversal_aux(node->right);
    std::cout<<node->key<<" ";
}

template <class T>
void BSTtree<T>::inOrderTraversal_iter1(){
    auto tmp = root_;
    std::stack<NodePtr> s;

    while(tmp){
        if(tmp->left == nullptr){
            while(1){
                std::cout<<tmp->key<<" ";
                auto x = tmp->right;
                if(x || s.empty()){
                    tmp = x;
                    break;
                }
                else{
                    tmp = s.top();
                    s.pop();
                }
            }

        }
        else{
            s.push(tmp);
            tmp = tmp->left;
        }
    }
    std::cout<<std::endl;
}

template <class T>
void BSTtree<T>::inOrderTraversal_iter2(){
    auto tmp = root_;

    while(tmp){
        //
        if(tmp->left == nullptr){
            std::cout<<tmp->key<<" ";
            tmp = tmp->right;
        }
        else{
            auto p = tmp->left;
            while(p->right && p->right != tmp)
                p = p->right;
            if(p->right == nullptr){
                p->right = tmp;//push
                tmp = tmp->left;
            }
            else{
                std::cout<<tmp->key<<" ";
                p->right = nullptr;//pop
                tmp = tmp->right;
            }
        }
    }
    std::cout<<std::endl;
}

template <class T>
void BSTtree<T>::preOrderTraversal_iter(){
    auto tmp = root_;
    while(tmp){
        if(tmp->left == nullptr){
            std::cout<<tmp->key<<" ";
            tmp = tmp->right;
        }
        else{
            auto p = tmp->left;
            while(p->right && p->right != tmp)
                p = p->right;
            if(p->right == nullptr){
                std::cout<<tmp->key<<" ";
                p->right = tmp;
                tmp = tmp->left;
            }
            else{
                p->right = nullptr;
                tmp = tmp->right;
            }
        }
    }
    std::cout<<std::endl;
}

template <class T>
void BSTtree<T>::postOrderTraversal_iter(){
    NodeType d;
    d.left = root_;
    auto tmp = &d;
    while(tmp){
        if(tmp->left == nullptr){
            tmp = tmp->right;
        }
        else{
            auto p = tmp->left;
            while(p->right && p->right != tmp)
                p = p->right;
            if(p->right == nullptr){
                p->right = tmp;
                tmp = tmp->left;
            }
            else{
                //倒序输出从当前节点的左孩子到该前驱节点这条路径上的所有节点
                printReverse(tmp->left, p);
                p->right = nullptr;
                tmp = tmp->right;
            }
        }
    }
    std::cout<<std::endl;
}

template <class T>
void BSTtree<T>::reverse(NodePtr from, NodePtr to){
    if(from == to)
        return;
    NodePtr x = from, y = from->right, z;
    while(1){
        z = y->right;
        y->right = x;
        x = y;
        y = z;
        if(x == to)
            break;
    }
}

template <class T>
void BSTtree<T>::printReverse(NodePtr from, NodePtr to){
    reverse(from, to);
    auto p = to;
    while(1){
        std::cout<<p->key<<" ";
        if(p == from)
            break;
        p = p->right;
    }
    reverse(to, from);
}

int main(){
    BSTtree<int> tree;
    int nums[] = {5,2,4,9,8,3};
    for(int i = 0; i < 6; i++)
        tree.insert(nums[i]);

    tree.inOrderTraversal();
    tree.inOrderTraversal_iter1();
    tree.inOrderTraversal_iter2();
    tree.preOrderTraversal();
    tree.preOrderTraversal_iter();
    tree.postOrderTraversal();
    tree.postOrderTraversal_iter();
}

若一个节点有左子树,则该节点的前驱是左子树中的最右节点。利用该最右节点原本空闲的右指针来指向后继节点。如果这个链接已被设置,则该节点是当前离根最远的被标记节点,即栈顶节点。删除该链接,即出栈操作,然后遍历栈顶节点的右子树。

参考文献:

《MORRIS’ TREE TRAVERSAL ALGORITHM RECONSIDERED》

猜你喜欢

转载自blog.csdn.net/jshnaoko/article/details/80168264