日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

二叉树的遍历(递归,非递归,Morris)

發(fā)布時間:2024/2/28 编程问答 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 二叉树的遍历(递归,非递归,Morris) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

二叉樹的遍歷


目錄

  • 遞歸遍歷
  • 非遞歸遍歷
  • Morris遍歷

  • 1. 遞歸遍歷

    遞歸版遍歷只要當(dāng)前節(jié)點不為null,就可以三次回到當(dāng)前節(jié)點。

    public static void preOrderRecur(Node head) {if (head == null) {return;}System.out.print(head.value + " ");preOrderRecur(head.left);preOrderRecur(head.right);}public static void inOrderRecur(Node head) {if (head == null) {return;}inOrderRecur(head.left);System.out.print(head.value + " ");inOrderRecur(head.right);}public static void posOrderRecur(Node head) {if (head == null) {return;}posOrderRecur(head.left);posOrderRecur(head.right);System.out.print(head.value + " ");}

    2. 非遞歸遍歷

    其中后序遍歷打印順序為左右中,由先序遍歷打印順序為中左右,所以可以對先序遍歷改進為中右左(改變添加順序),添加到另外一個棧中,最后遍歷打印就是左右中順序了。

    public static void preOrderUnRecur(Node head) {System.out.println("pre-order: ");while (head != null) {Stack<Node> stack = new Stack<>();stack.push(head);while (!stack.isEmpty()) {Node node = stack.pop();System.out.println(node.value + " ");if (node.right != null) {stack.push(node.right);}if (node.left != null) {stack.push(node.left);}}}}public static void inOrderUnRecur(Node head) {System.out.print("in-order: ");if (head != null) {Stack<Node> stack = new Stack<>();while (!stack.isEmpty() || head != null) {if (head != null) {stack.push(head.left);head = head.left;} else {head = stack.pop();System.out.println(head.value + " ");head = head.right;}}}System.out.println();}public static void posOrderUnRecur1(Node head) {System.out.print("pos-order: ");if (head != null) {Stack<Node> s1 = new Stack<>();Stack<Node> s2 = new Stack<>();s1.push(head);while (!s1.isEmpty()) {head = s1.pop();s2.push(head);if (head.left != null) {s1.push(head.left);}if (head.right != null) {s1.push(head.right);}while (!s2.isEmpty()) {System.out.print(s2.pop().value + " ");}}}System.out.println();}

    3. Morris遍歷

    Morris遍歷法,能以時間復(fù)雜度O(N),空間復(fù)雜度O(1)實現(xiàn)二叉樹的遍歷。

    程序流程:
    假設(shè)指針cur指向當(dāng)前節(jié)點,cur從頭結(jié)點開始。

  • 如果cur無左孩子,則cur = cur.right;
  • 如果cur有左孩子,則找到cur左子樹上最右的節(jié)點,記為mostRight,分為以下兩種情況:
  • 若mostRight的right指針為null,則讓其指向cur,且cur = cur.left;
  • 若mostRight的right指針指向cur,則讓其指回null,且cur = cur.right。

  • 假設(shè)二叉樹如下:

    12 34 5 6 7

    則Morris遍歷順序為:1,2,4,2,5,1,3,6,3,7

    Morris 遍歷代碼實現(xiàn):

    public static void morrisIn(Node head) {if (head == null) {return;}Node cur = head;Node mostRight = null;while (cur != null) {mostRight = cur.left;if (mostRight != null) {while (mostRight.right != null && mostRight.right != cur) {mostRight = mostRight.right;}if (mostRight.right == null) {mostRight.right = cur;cur = cur.left;continue;} else {mostRight.right = null;}}cur = cur.right;}}

    特點:

  • 當(dāng)某個節(jié)點有左子樹,則會到達該節(jié)點兩次,如果沒有左子樹,只會到達一次。
  • 當(dāng)?shù)诙位氐侥硞€節(jié)點時,它的左子樹已遍歷完。
  • 實質(zhì):
    Morris遍歷是利用左子樹最右節(jié)點的指針指向null或指向自己來標記是第一次來到該節(jié)點還是第二次來到該節(jié)點。


    Morris遍歷改先序遍歷

    在以下兩種情況下打印節(jié)點:

  • 當(dāng)節(jié)點沒有左子樹時,打印當(dāng)前節(jié)點;
  • 當(dāng)節(jié)點有左子樹時并且第一次訪問時打印該節(jié)點,就是當(dāng)mosrRight的右指針為null時。
  • public static void morrisPre(Node head) {if (head == null) {return;}Node cur = head;Node mostRight = null;while (cur != null) {mostRight = cur.left;if (mostRight != null) {while (mostRight.right != null && mostRight.right != cur) {mostRight = mostRight.right;}if (mostRight.right == null) {mostRight.right = cur;System.out.print(cur.value + " ");cur = cur.left;continue;} else {mostRight.right = null;}} else {System.out.print(cur.value + " ");}cur = cur.right;}System.out.println();}

    Morris遍歷改中序遍歷

    在以下兩種情況下打印節(jié)點:

  • 當(dāng)節(jié)點沒有左子樹時,說明第一次和第二次是重合在一起的,打印當(dāng)前節(jié)點即可。
  • 當(dāng)節(jié)點有左子樹時,那么需要處理完左子樹再打印,即當(dāng)前節(jié)點準備右移時打印。
  • public static void morrisIn(Node head) {if (head == null) {return;}Node cur = head;Node mostRight = null;while (cur != null) {mostRight = cur.left;if (mostRight != null) {while (mostRight.right != null && mostRight.right != cur) {mostRight = mostRight.right;}if (mostRight.right == null) {mostRight.right = cur;cur = cur.left;continue;} else {mostRight.right = null;}}System.out.print(cur.value + " ");cur = cur.right;}System.out.println();}

    Morris遍歷改后序遍歷

    在以下兩種情況下打印節(jié)點:

  • 只有當(dāng)?shù)竭_某個節(jié)點兩次時逆序打印該節(jié)點左子樹的右邊界;
  • 在代碼的最后逆序打印整棵樹的右邊界,而逆序的過程就和單向鏈表的反轉(zhuǎn)過程類似。
  • public static void morrisPos(Node head) {if (head == 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.right;}if (cur2.right == null) {cur2.right = cur1;cur1 = cur1.left;continue;} else {cur2.right = null;printEdge(cur1.left);}}cur1 = cur1.right;}printEdge(head);System.out.println();}public static void printEdge(Node head) {Node tail = reverseEdge(head);Node cur = tail;while (cur != null) {System.out.print(cur.value + " ");cur = cur.right;}reverseEdge(tail);}public static 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;}

    總結(jié)

    以上是生活随笔為你收集整理的二叉树的遍历(递归,非递归,Morris)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。