• 二叉树morris遍历,空间复杂度为 O(1)


    二叉树递归遍历如下:

    额外空间复杂度为:树的高度。原因:自己虽然没有申请额外空间,但是递归过程是要压栈占用栈内存的,栈帧数最大就为树的高度

    1. // 每个节点只到1或2次(有限次),时间复杂度为O(N)
    2. public static void process(Node root) {
    3. if (root == null) return;
    4. // 1.此处输出当前节点的值——前序
    5. process(root.left);
    6. // 2.此处输出当前节点的值——中序
    7. process(root.right);
    8. // 3.此处输出当前节点的值——后序
    9. }

    Morris遍历细节

    假设来到当前节点cur,开始时cur来到头节点位置

    1. 如果cur没有左孩子,cur向右移动(cur = cur.right)

    2. 如果cur有左孩子,就看左子树上最右的节点mostRight(如果左子树没有右节点,就是它自己):

      1. 如果左子树mostRight的右指针指向空,让其指向cur, 然后cur向左移动(cur = cur.left)

      2. 如果左子树mostRight的右指针指向cur,让其指向null, 然后cur向右移动(cur = cur.right)

    3. cur为空时遍历停止

    Morris序:任何节点有左树则到两次,没左数则到一次

    对于到两次的,如何确定是第一次还是第二次到?如果左子树最右节点没有指向cur,则说明是第一次到

    morris遍历

    1. public static void morris(Node head) {
    2. if (head == null) return;
    3. Node cur = head;
    4. Node mostRight = null;
    5. while (cur != null) {
    6. mostRight = cur.left;
    7. if (mostRight != null) {
    8. while (mostRight.right != null && mostRight.right != cur) {
    9. mostRight = mostRight.right;
    10. }
    11. if (mostRight.right == null) {
    12. mostRight.right = cur;
    13. cur = cur.left;
    14. continue;
    15. } else {
    16. mostRight.right = null;
    17. }
    18. }
    19. cur = cur.right;
    20. }
    21. }

    morris先序遍历

    1. public static void morrisPre(Node head) {
    2. if (head == null) return;
    3. Node cur = head;
    4. Node mostRight = null;
    5. while (cur != null) {
    6. mostRight = cur.left;
    7. if (mostRight != null) { // 如果有左子树
    8. while (mostRight.right != null && mostRight.right != cur) {
    9. mostRight = mostRight.right;
    10. }
    11. if (mostRight.right == null) {
    12. System.out.print(cur.val + " "); // 如果有左子树,则第一次来就打印
    13. mostRight.right = cur;
    14. cur = cur.left;
    15. continue;
    16. } else {
    17. mostRight.right = null;
    18. }
    19. } else { //没有左子树,只来一次,直接打印
    20. System.out.print(cur.val + " ");
    21. }
    22. cur = cur.right;
    23. }
    24. }

    morris中序遍历

    1. public static void morrisIn(Node head) {
    2. if (head == null) return;
    3. Node cur = head;
    4. Node mostRight = null;
    5. while (cur != null) {
    6. mostRight = cur.left;
    7. if (mostRight != null) { // 如果没有左子树
    8. while (mostRight.right != null && mostRight.right != cur) {
    9. mostRight = mostRight.right;
    10. }
    11. if (mostRight.right == null) {
    12. mostRight.right = cur;
    13. cur = cur.left;
    14. continue;
    15. } else {
    16. System.out.print(cur.val + " "); // 如果没有左子树,则第二次到的时候打印
    17. mostRight.right = null;
    18. }
    19. } else { //没有左子树,只来一次,直接打印
    20. System.out.print(cur.val + " ");
    21. }
    22. cur = cur.right;
    23. }
    24. }

    morris后序遍历

    1. public static void morrisPos(Node head) {
    2. if (head == null) return;
    3. Node cur = head;
    4. Node mostRight = null;
    5. while (cur != null) {
    6. mostRight = cur.left;
    7. if (mostRight != null) {
    8. while (mostRight.right != null && mostRight.right != cur) {
    9. mostRight = mostRight.right;
    10. }
    11. if (mostRight.right == null) {
    12. mostRight.right = cur;
    13. cur = cur.left;
    14. continue;
    15. } else {
    16. mostRight.right = null;
    17. printEdge(cur.left);
    18. }
    19. }
    20. cur = cur.right;
    21. }
    22. printEdge(head);
    23. }
    24. // 逆序打印右边界
    25. public static void printEdge(Node head) {
    26. Node tail = reverseEdge(head);
    27. Node cur = tail;
    28. while (cur != null) {
    29. System.out.print(cur.val + " ");
    30. cur = cur.right;
    31. }
    32. reverseEdge(tail);
    33. }
    34. // 其实跟反转链表一样的道理
    35. public static Node reverseEdge(Node head) {
    36. Node pre = null;
    37. Node next = null;
    38. while (head != null) {
    39. next = head.right;
    40. head.right = pre;
    41. pre = head;
    42. head = next;
    43. }
    44. return pre;
    45. }

    morris 遍历的优缺点

    优点:相比于递归遍历优化了空间复杂度,由O(logN)  到了 O(1)

    缺点:代码相对复杂一点点,并且虽然时间复杂度同样为 O(N),但它的整体过程较麻烦,跑起来是相对于递归来说还是慢一些的

  • 相关阅读:
    java开发环境安装-202209
    前端面试前端性能优化篇
    小白刷力扣 之SQL学习计划 第3天(第1667题,第1484题,第1527题)
    Pytorch常用的4种随机数生成方法
    浅析MySQL-基础篇01
    Web前端学习(HTML)学习---下(表格标签,列表标签,表单标签)案例
    怎么把照片分辨率变高?拍的照片如何调整分辨率?
    java-php-python-公益诊疗系统计算机毕业设计
    Nginx基本概念和ububtu环境上安装步骤
    【多AZ】浅述云计算多az
  • 原文地址:https://blog.csdn.net/qq_61557294/article/details/126562473