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》