为民造福 發表於 2026-1-6 09:00:00

剑指offer-59、按之字形顺序打印⼆叉树

<h2 id="题描述">题⽬描述</h2>
<p>请实现⼀个函数按照之字形打印⼆叉树,即第⼀⾏按照从左到右的顺序打印,第⼆层按照从右⾄左的顺序打印,第三⾏按照从左到右的顺序打印,其他⾏以此类推。</p>
<p>示例1<br>
输⼊:{8,6,10,5,7,9,11}<br>
返回值:[,,]</p>
<h2 id="思路及解答">思路及解答</h2>
<h3 id="双向链表推荐">双向链表(推荐)</h3>
<ol>
<li>借助双向链表,初始化⼀个添加⽅向 boolean 值,先将根节点添加进去:</li>
<li>获取 list ⾥⾯剩下的元素的个数,挨个取出就是⼀层,取出的时候,如果 reverse 为 true ,则往链表的第 0 个索引位置添加,否则直接在后⾯添加,然后判断每⼀个取出来的节点的左右节点是不是为空,不为空则加⼊链表。</li>
<li>每⼀层处理完之后,将 list 加⼊结果集中,然后翻转 reverse 的值,继续判断 list 是不是为空,执⾏第⼆步循环。</li>
</ol>
<pre><code class="language-java">public class Solution {
    public ArrayList &lt; ArrayList &lt; Integer &gt;&gt; Print(TreeNode pRoot) {
      LinkedList &lt; TreeNode &gt; nodes = new LinkedList &lt; &gt; ();
      ArrayList &lt; ArrayList &lt; Integer &gt;&gt; results = new ArrayList();
      boolean reverse = true;
      if (pRoot != null) {
            nodes.add(pRoot);
            while (!nodes.isEmpty()) {
                ArrayList &lt; Integer &gt; integers = new ArrayList();
                int size = nodes.size();
                for (int i = 0; i &lt; size; i++) {
                  TreeNode node = nodes.poll();
                  if (reverse) {
                        integers.add(node.val);
                  } else {
                        integers.add(0, node.val);
                  }
                  if (node.left != null) {
                        nodes.offer(node.left);
                  }
                  if (node.right != null) {
                        nodes.offer(node.right);
                  }
                }
                if (integers.size() != 0) {
                  results.add(integers);
                }
                reverse = !reverse;
            }
      }
      return results;
    }
}
</code></pre>
<ul>
<li>空间复杂度由于借助了额外的 list ,为 O(n)</li>
<li>时间复杂度,由于每个节点进⼊队列⼜出来,为 O(2n) ,也是 O(n) 。</li>
</ul>
<h3 id="队列--方向反转">队列 + 方向反转</h3>
<p>这是最直接的方法。我们进行标准的层序遍历,但用一个标志位记录当前层是奇数层还是偶数层。对于偶数层,我们在将该层的节点值列表加入最终结果前,先进行反转</p>
<pre><code class="language-java">import java.util.*;

public class Solution {
    public ArrayList&lt;ArrayList&lt;Integer&gt;&gt; Print(TreeNode pRoot) {
      ArrayList&lt;ArrayList&lt;Integer&gt;&gt; result = new ArrayList&lt;&gt;();
      if (pRoot == null) return result;

      Queue&lt;TreeNode&gt; queue = new LinkedList&lt;&gt;();
      queue.offer(pRoot);
      boolean leftToRight = true; // 方向标志,true表示从左到右

      while (!queue.isEmpty()) {
            int levelSize = queue.size(); // 当前层的节点数
            ArrayList&lt;Integer&gt; levelList = new ArrayList&lt;&gt;();

            // 遍历当前层的所有节点
            for (int i = 0; i &lt; levelSize; i++) {
                TreeNode node = queue.poll();
                levelList.add(node.val); // 将节点值加入当前层列表

                // 将下一层的节点按标准顺序(先左后右)加入队列
                if (node.left != null) queue.offer(node.left);
                if (node.right != null) queue.offer(node.right);
            }

            // 如果是偶数层(从第0层开始算则为奇数索引),反转当前层列表
            if (!leftToRight) {
                Collections.reverse(levelList);
            }
            result.add(levelList);
            leftToRight = !leftToRight; // 切换方向
      }
      return result;
    }
}
</code></pre>
<ul>
<li><strong>时间复杂度</strong>:O(n)。每个节点被访问一次,对于偶数层,<code>Collections.reverse</code>的时间复杂度为 O(当前层节点数),所有层的节点数相加为 n,因此总时间复杂度为 O(n)。</li>
<li><strong>空间复杂度</strong>:O(n)。队列和结果列表所需空间与节点数 n 成线性关系。</li>
</ul>
<h3 id="双栈交替">双栈交替</h3>
<p>利用栈后进先出(LIFO)的特性来自然地实现顺序的反转。我们使用两个栈,一个用于处理当前层,另一个用于存储下一层的节点</p>
<pre><code class="language-java">import java.util.*;

public class Solution {
    public ArrayList&lt;ArrayList&lt;Integer&gt;&gt; Print(TreeNode pRoot) {
      ArrayList&lt;ArrayList&lt;Integer&gt;&gt; result = new ArrayList&lt;&gt;();
      if (pRoot == null) return result;

      Stack&lt;TreeNode&gt; stack1 = new Stack&lt;&gt;(); // 处理奇数层(从左到右)
      Stack&lt;TreeNode&gt; stack2 = new Stack&lt;&gt;(); // 处理偶数层(从右到左)
      stack1.push(pRoot);

      // 当两个栈都为空时,遍历结束
      while (!stack1.isEmpty() || !stack2.isEmpty()) {
            ArrayList&lt;Integer&gt; levelList = new ArrayList&lt;&gt;();

            if (!stack1.isEmpty()) {
                // 处理stack1(奇数层),其子节点将以“从右到左”的顺序压入stack2
                while (!stack1.isEmpty()) {
                  TreeNode node = stack1.pop();
                  levelList.add(node.val);
                  // 关键:先左子节点后右子节点入栈,出栈顺序则为先右后左
                  if (node.left != null) stack2.push(node.left);
                  if (node.right != null) stack2.push(node.right);
                }
            } else {
                // 处理stack2(偶数层),其子节点将以“从左到右”的顺序压入stack1
                while (!stack2.isEmpty()) {
                  TreeNode node = stack2.pop();
                  levelList.add(node.val);
                  // 关键:先右子节点后左子节点入栈,出栈顺序则为先左后右
                  if (node.right != null) stack1.push(node.right);
                  if (node.left != null) stack1.push(node.left);
                }
            }
            result.add(levelList);
      }
      return result;
    }
}
</code></pre>
<ul>
<li><strong>时间复杂度</strong>:O(n)。每个节点被压入栈和弹出栈各一次。</li>
<li><strong>空间复杂度</strong>:O(n)。两个栈在最坏情况下共同存储 n 个节点。</li>
</ul>


</div>
<div id="MySignature" role="contentinfo">
    <p>本文来自在线网站:seven的菜鸟成长之路,作者:seven,转载请注明原文链接:www.seven97.top</p><br><br>
来源:https://www.cnblogs.com/sevencoding/p/19430421
頁: [1]
查看完整版本: 剑指offer-59、按之字形顺序打印⼆叉树