何モリス横断されます
実際には、バイナリツリートラバーサルアルゴリズムのO(1)にスペースを最適化する複雑。
一般トラバーサルアルゴリズムのために、我々は再び訪問した後、スタックを格納するノードのニーズを使用しています。最悪の場合、我々は全体のバイナリツリーノードを格納する必要があります。したがって、空間の複雑さはO(N)です。O(1)レベルまでの空間の複雑さを横断しながら、モリス吸い込ま。モリスは、「手がかりバイナリツリー」の概念を横断するために使用される、実際には、先行ノードのいくつかの種類を保存したり、後続ノードを横断するリーフノードの周りにNULLポインタを使用することです。だから、追加のスペースがありません。
モリスは、トラバーサルアルゴリズムを考えました
現在のノードがCURであり、開始時にルートルートに割り当てられたと仮定する。
- ノードが空CURであるかどうかを決定します
- 空でない場合は
なし左の子CUR場合は1)、CUR更新権、すなわち(CUR = cur.right)
2)CUR左の子がある場合は、子はノード前を見つけるために、右端ツリーのに任されています- 前空、そして右の子の右の子はCURを指している場合。pre.right = CUR
- 子供が右の前curがある場合、空を指しています。pre.right = nullを。(ツリー構造を減らします)
- curが空で、散歩を停止
予約注文トラバーサルモリス
簡潔には、プロセスを横断する前にモリスを説明し、単純なバイナリツリーの例として、以下を取ります。
- ルート・ノード1は、CURに設定されています。
- 左の子ノードCUR(ノード1)が空にされていないため、私たちは右端のノード5とノード2に左側のサブツリーのルートノードを見つけるようCUR(ノード1)2は、空ではありません。
- 5右の子ノードが空である場合、CUR値出力(ノード1)、および右の子ノード、我々は5 CUR、すなわちAノードを指摘しました。左の子ノードCUR更新CUR、そのノード2。
- CUR(ノード2)子供が空のままにされていないため、その左サブツリー右端ノード4を発見
- 4右の子ノードは、第1の出力値のCUR(ノード2)、及び右の子ノード4点CUR(ノード2)が空であり、その左の子ノード4にCUR(ノード2)を更新します。
- この時間CUR(ノード4)は、子供が、我々はCURノード2を更新しますので、自分の子供にアクセスする権利ので、子供は、ノード2に右のポイントを発見し、空のままにされます。
- 、今回は、左の子ノード4は、我々は再び左部分木の右端のノード4を見つける空でないノード2にターンポイントでそのCURを見つけるが、今回はノード右の子はCURの4点は、我々はそれを削除しますので、右の子ノード4へのポイントが空であることを、オリジナルのツリー構造を復元します。そしてので、子供たちが訪問し、ルートノードを残したので、今回はその右の子ノード5を訪問しています。
- ...
public void Morris_preorderTraversal(TreeNode root){
TreeNode cur = root;
while(cur!=null){
if(cur.left!=null){
TreeNode pre = cur.left;
while(pre.right!=null && pre.right!=cur){
pre = pre.right;
}
if(pre.right == null){ // 第一次到达左子树的最右端
System.out.print(cur.val);
pre.right = cur;
cur = cur.left;
}
else{ // 第二次到达左子树的最右端
pre.right = null;
cur = cur.right;
}
}
else{
System.out.print(cur.val);
cur = cur.right;
}
}
}
モリス予約限定!
モリスとトラバーサルシーケンス前順トラバーサル以下は、出力は、位置の変化を表示されます。
public void Morris_inorderTraversal(TreeNode root){
TreeNode cur = root;
while(cur!=null){
if(cur.left!=null){
TreeNode pre = cur.left;
while(pre.right!=null && pre.right!=cur){
pre = pre.right;
}
if(pre.right == null){
pre.right = cur;
cur = cur.left;
}
else{
pre.right = null;
System.out.print(cur.val);
cur = cur.right;
}
}
else {
System.out.print(cur.val);
cur = cur.right;
}
}
}
モリス順トラバーサルの後
この後順モリスは最も複雑です。子どもたちは、ルートノードの前に右の出力を必要とするので。図については、ときに後順トラバーサル順序:4,5,2,6,3,1。私たちは長い順トラバーサル後のアクセス順序を達成することができ、我々は逆出力、などとして、2と5が右の境界であるノード、左側のサブツリーノード1に見ることができます。したがって、我々はノード2に、そのノード5点を反転する機能を必要とします。そしてその後、(ツリーの構造を変更せずに)バック反転された出力、後。
public TreeNode reverseNode(TreeNode node){
TreeNode pre = null;
TreeNode next = null;
while(node!=null){
next = node.right;
node.right = pre;
pre = node;
node = next;
}
return pre;
}
public void printNode(TreeNode node){
TreeNode tail = reverseNode(node);
TreeNode cur = tail;
while(cur!=null){
System.out.println(cur.val);
cur = cur.right;
}
reverseNode(tail);
}
public void Morris_postorderTraversal(TreeNode root) {
TreeNode cur = root;
while(cur != null){
if(cur.left!=null){
TreeNode pre = cur.left;
while(pre.right!=null && pre.right!=cur){
pre = pre.right;
}
if(pre.right==null){
pre.right = cur;
cur = cur.left;
}
else{
pre.right = null;
printNode(cur.left);
cur = cur.right;
}
}
else{
cur = cur.right;
}
}
printNode(root);
}
概要
O(1)までの空間の複雑さのバイナリツリートラバーサルを横断モリスは、当然のことながら、依然として時間の複雑さはO(N)です。