Morris 就是大家所知的KMP算法中的M。
一、Morris 算法遍历的大概流程如下:
定义一个节点Cur 指向当前节点。
1、如果Cur节点无左子树,则将Cur节点向右移动。
2、如果Cur节点有左子树,找到左子树上最右节点,mostright
(1)mostright的右孩子为空,则将mostright的右孩子的指针指向Cur。然后Cur向左移动
(2)如果mostright已经指向Cur,则将mostright指向空,Cur向右移动
二、代码如下:
struct Node {
int value;
Node right;
Node left;
Node(int data) :value(data), right(NULL), left(NULL) {}
};
void Morris (Node *Head)
{
if (root == null)
{
return;
}
Node Cur1 = Head;
Node Cur2 = NULL;
while (Cur1 != NULL)
{
Cur2 = Cur1.left;
if (Cur2 != NULL)
{
while (Cur2.right != NULL && Cur2->right != Cur1)
Cur2 = Cur2.rght;
if (Cur2.right == NULL)
{
Cur2.right = Cur1;
Cur1 = Cur1.left;
continue;
}
else
Cur2.right = NULL;
}
Cur1 = Cur1.right;
}
}
三、Morris 前续遍历:
void MorrisPre(Node *Head)
{
if (Head == null)
{
return;
}
Node Cur1 = root;
Node Cur2 = NULL;
while (Cur1 != NULL)
{
Cur2 = Cur1.left;
if (Cur2 != NULL)
{
while (Cur2.right != NULL && Cur2.right != Cur1)
{
Cur2 = Cur2.rght;
}
if (Cur2.right == NULL)
{
Cur2.right = Cur1;
cout << Cur1.value << "\t"; //第一次到达就打印
Cur1 = Cur1.left;
continue;
}
else
{
Cur2.right = NULL;
}
}else
cout << Cur1.value << "\t"; //左子树不存在直接打印
Cur1 = Cur1.right;
}
}
四、Morris 中续遍历:
void MorrisIn(Node *Head)
{
if (root == null)
{
return;
}
Node Cur1 = Head;
Node Cur2 = NULL;
while (Cur1 != NULL)
{
Cur2 = Cur1.left;
if (Cur2 != NULL)
{
while (Cur2.right != NULL && Cur2.right != Cur1)
{
Cur2 = Cur2.rght;
}
if (Cur2.right == NULL)
{
Cur2.right = Cur1;
Cur1 = Cur1.left;
continue;
}
else
{
Cur2.right = NULL;
}
}
cout << Cur1.value << "\t"; //如果没有左子树,则打印当前节点,如果有左子树,第二次来到该节点的时候打印当前节点,统一一下就是,如果该节点向右移动,就打印该节点。
Cur1 = Cur1.right;
}
}
五、Morris 后续遍历:
后续遍历就是将遍历到第二次的节点逆序打印该节点左子树右边界。
void MorrisPos(Node *Root)
{
if (Root == null)
{
return;
}
Node Cur1 = Root;
Node Cur2 = NULL;
while (Cur1 != NULL)
{
Cur2 = Cur1.left;
if (Cur2 != NULL)
{
while (Cur2.right != NULL && Cur2.right != Cur1)
{
Cur2 = Cur2.rght;
}
if (Cur2.right == NULL)
{
Cur2.right = Cur1;
Cur1 = Cur1.left;
continue;
}
else
{
Cur2.right = NULL;
printEdge(Cur1.left); //
}
}
Cur1 = Cur1.right;
}
printEdge(Head); //
}
//后续遍历的打印
void printEdge(Node head)
{
Node Tail = reverseEdge(head);
Node Cur = Tail;
while (Cur != NULL)
{
cout << Cur.value << "\t";
Cur = Cur.right;
}
reverseEdge(head);
}
//反转右边界,和链表的反转差不多
Node reverseEdge(Node From)
{
Node Pre = NULL;
Node Next = NULL;
while (From != NULL)
{
Next = From.right;
From.right = Pre;
Pre = From;
From = Next;
}
return Pre;
}