从上往下打印出二叉树的每个节点,同层节点从左至右打印。

本文介绍了一种从上到下、同层节点从左至右打印二叉树的方法。通过使用队列实现层次遍历,依次访问每层节点并记录结果。此算法适用于面试题“剑指offer”中的一道题目。

剑指offer:从上往下打印出二叉树的每个节点,同层节点从左至右打印。

思路:利用一个队列就可以了。其实就是二叉树的层次遍历

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    vector<int> PrintFromTopToBottom(TreeNode* root) {
        vector<int> result;
        if(root == NULL)
            return result;
        queue<TreeNode*> q;
        q.push(root);
        while(!q.empty()){
            TreeNode* front = q.front();
            result.push_back(front->val);
            q.pop();
            if(front->left != NULL)
               q.push(front->left);
            if(front->right != NULL)
               q.push(front->right);
        }
       return result;
    }
};

<think>好的,用户想要实现一个按打印二叉树节点,并且节点的算法。首先,我需要回忆一下常见的二叉树遍历方法。通常,序遍历(广度优先搜索,BFS)是用队列实现的,按访问节点。但用户的需求是,这显然和标准序遍历的顺序相反。 那如何调整呢?首先想到的是,在标准序遍历的基础上,对每一节点进行逆序处理。也就是说,先按正常的序遍历收集每一节点,然后将该节点顺序反转,再添加到结果中。这种方法虽然可行,但可能效率稍低,因为需要额外的反转操作。不过实现起来比较简单,适合快速解决问题。 另一种方法是修改节点入队的顺序。通常,我们先将节点入队,再入队节点,这样队顺序是。如果反过来,先入队节点,再入队节点,那么队顺序就会变成。这可能更高效,因为不需要额外的反转步骤。不过需要测试这种方法是否正确。 然后,我需要考虑代码的结构。无论是Python还是C++,实现思路应该类似。以Python为例,用户提供的引用中的代码使用了队列,每次处理一节点。可能需要维护一个队列,记录当前的所有节点,然后将它们的子节点的顺序入队。 另外,用户提供的引用[3]中提到了使用栈和队列结合的方法来实现自下而上、从的遍历,但用户的需求是按从上到下,每内从。所以可能不需要栈,只需要调整入队顺序或者反转每的结果。 接下来,我需要验证这两种方法的正确性。第一种方法:正常序遍历后反转每的结果。例如,对于二叉树: 1 / \ 2 3 / \ / \ 4 5 6 7 标准序遍历得到的结构是[[1], [2,3], [4,5,6,7]],反转每后变成[[1], [3,2], [7,6,5,4]],这正是用户需要的输。 第二种方法:修改入队顺序,先。在处理每一时,将节点先入队,节点后入队。这样,队列中的节点顺序会是,从而在队时自然形成从的顺序。例如,根节点1入队后,处理根节点时,先入队3,再入队2。下一处理时,队列里是3、2,处理3时,入队7、6;处理2时,入队5、4。这样下一节点顺序是7、6、5、4,即从。这样得到的结构是[[1], [3,2], [7,6,5,4]],符合要求。 这两种方法哪种更好呢?第一种方法可能需要额外的反转操作,时间复杂度是O(n),因为每都要反转,但空间复杂度可能稍高。第二种方法通过调整入队顺序,无需反转,直接在访问时得到正确顺序,可能更高效。 然后,需要考虑代码的具体实现。在Python中,可以使用队列,每次处理一,记录当前节点数,循环处理每个节点,并将其子节点的顺序加入队列。例如,使用一个队列,每次处理一时,记录当前的长度,然后循环该次数,将节点值收集到当前的结果列表中,时将子节点入队。这样,每一节点都会被正确收集。 用户提供的引用中的Python代码使用了队列,每次弹队首元素,并将节点入队。如果要调整为从,可能需要改变入队顺序,先,这样下一的处理顺序就会是。但这样在下一处理时,队列中的顺序已经是了,所以处理当前的时候,每个节点节点需要反过来入队吗?或者,每次处理一的时候,先节点入队,再节点入队,这样下一的顺序就是,但当前的顺序是从吗? 可能需要更仔细的分析。例如,根节点入队后,处理根节点时,将节点入队,再节点入队。这样,队列中的顺序是。处理下一时,先处理节点,然后将它的节点节点入队,接着处理节点样先。这样,每一的处理顺序都是从,而下一的入队顺序也是,从而保证次正确。 不过,这样可能会导致下一的顺序不正确。例如,假设第三有四个节点:原顺序是4、5、6、7,在第二处理节点3时,先入队7,再6;处理节点2时,先入队5,再4。这样队列中的顺序是7、6、5、4,处理第三时,顺序是7、6、5、4,即从,符合要求。所以这种方法可以实现每的顺序,无需反转。 因此,正确的做法是在处理每个节点时,先将其节点入队,再节点入队。这样,队列中的顺序就是按排列的。不过,这样处理的话,每节点会被正确地按从的顺序处理,而无需反转。 但这样会不会导致下一的顺序混乱?比如,在处理第三节点时,每个节点节点先入队,节点后入队,这样队列中的顺序是,从而在处理下一时,样按的顺序。但用户的需求是按,每内部从,而每的顺序还是从上到下的。例如,对于深度为3的树,输应该是[[1], [3,2], [7,6,5,4]]。如果按照上述方法,队列中的处理顺序会是: 初始队列:[1] 处理1:弹1,入队3,再入队2。队列变为[3,2]。收集1的结果[1]。 处理2:弹3,入队7,6;弹2,入队5,4。队列变为[7,6,5,4]。收集2的结果[3,2]。 处理3:依次弹7、6、5、4,如果它们没有子节点,队列为空。收集3的结果[7,6,5,4]。 这样得到的顺序是正确的,每内部从。所以这种方法可行,无需反转每的结果。 但这样是否正确呢?因为通常的序遍历是按处理的,每次处理一的时候,记录当前队列的长度,然后处理该长度的次数,从而将节点处理完。如果入队的顺序是,那么在的处理中,节点是按的顺序被处理的,所以收集的顺序也是的。因此,这种方法可以正确实现每的输,而无需反转。 因此,代码实现的关键在于修改子节点的入队顺序:先节点,再节点。这样,在队列中节点会被按的顺序处理,从而收集到正确的结果。 现在,参考用户提供的Python代码示例,可以进行调整。原代码中,处理当前节点时,先入队节点,再节点。现在需要反过来,先入队节点,再节点。 例如,原代码中的部分: if t.left: q.append(t.left) if t.right: q.append(t.right) 现在需要改为: if t.right: q.append(t.right) if t.left: q.append(t.left) 这样,队列中的顺序就是节点在前,节点在后。这样处理每一的时候,节点的顺序就是从了。 不过,需要注意之间的分隔。在标准的序遍历中,我们通常会在每一开始前记录队列的长度,然后处理该长度的节点,这样就能区分每一。例如: 在Python中,可以通过循环队列的长度来实现分。例如: while q: level_size = len(q) current_level = [] for _ in range(level_size): node = q.pop(0) current_level.append(node.val) if node.right: q.append(node.right) if node.left: q.append(node.left) result.append(current_level) 这样,每次处理一的时候,先处理该的所有节点(level_size次),并将他们的节点节点入队(顺序为),这样下一的处理顺序也会是。但这样会导致下一的顺序也是,而我们需要的是每一的顺序都是,但之间从上到下。例如: 对于根节点1,处理时入队3、2。下一的处理顺序是3、2,收集到当前的结果是[3,2]。然后处理3的子节点,入队7、6;处理2的子节点,入队5、4。队列变为[7,6,5,4]。下一处理时,依次处理7、6、5、4,收集为[7,6,5,4]。这正是用户需要的输。 因此,这样的代码结构可以实现按打印节点的需求。因此,修改后的Python代码应该使用分处理,并在处理每个节点时,先入队。 总结来说,正确的实现步骤是: 1. 初始化队列,将根节点入队(如果根非空)。 2. 进入循环,直到队列为空。 3. 在每次循环开始时,记录当前节点数(队列的长度)。 4. 创建一个临时列表存储当前节点值。 5. 循环处理当前每个节点: a. 节点。 b. 将节点值加入当前列表。 c. 先入队节点(如果存在)。 d. 再入队节点(如果存在)。 6. 将当前列表加入结果列表。 7. 循环结束后,返回结果列表。 这样,每节点都会被按从的顺序收集,而子节点的入队顺序保证下一的处理顺序正确。 用户提供的引用中的代码是单的处理,没有显式分,所以可能需要调整结构。例如,原Python代码: def PrintFromTopToBottom(self, root): Tree_list=[] if not root: return [] q=[root] while len(q): t=q.pop(0) Tree_list.append(t.val) if t.left: q.append(t.left) if t.right: q.append(t.right) return Tree_list 这个代码将所有节点按顺序放入Tree_list,但无法区分次。如果要按,并且每,需要分处理,如前面的分析,使用分循环,并在每处理时先入队。 因此,最终的Python代码可能如下: def right_to_left_level_order(root): result = [] if not root: return result queue = [root] while queue: level_size = len(queue) current_level = [] for _ in range(level_size): node = queue.pop(0) current_level.append(node.val) if node.right: queue.append(node.right) if node.left: queue.append(node.left) result.append(current_level) return result 这样,返回的result是一个二维列表,每个子列表代表一,按从的顺序排列。 验证这个代码是否正确。例如,对于二叉树: 1 / \ 2 3 / \ / \ 4 5 6 7 根节点1入队。队列长度为1,处理该: current_level初始化为空。处理节点1,加入current_level。然后检查节点3,入队;节点2,入队。此时队列是[3,2]。current_level是[1],加入result。 下一轮循环,队列长度是2。处理第一个节点3,加入current_level。检查节点7,入队;节点6,入队。队列变为[2,7,6]。然后处理第二个节点2,加入current_level。检查节点5,入队;节点4,入队。队列变为[7,6,5,4]。current_level是[3,2],加入result。 下一轮循环,队列长度是4。依次处理7、6、5、4。每个节点没有子节点,所以队列在每次处理后变为[6,5,4]、[5,4]、[4]、[]。current_level收集为[7,6,5,4],加入result。最终result是[[1], [3,2], [7,6,5,4]],符合要求。 因此,这段代码是正确的。 用户可能还想了解其他语言的实现,比如C++。根据引用中的C++代码,样可以进行调整,将入队顺序改为先,并在分处理时收集每节点。例如: vector<vector<int>> levelOrder(TreeNode* root) { vector<vector<int>> result; if (!root) return result; queue<TreeNode*> q; q.push(root); while (!q.empty()) { int level_size = q.size(); vector<int> current_level; for (int i = 0; i < level_size; ++i) { TreeNode* node = q.front(); q.pop(); current_level.push_back(node->val); if (node->right) q.push(node->right); if (node->left) q.push(node->left); } result.push_back(current_level); } return result; } 这样,C++的实现也是类似的逻辑。 总结,用户的问题可以通过修改序遍历的子节点入队顺序,先,并分处理来实现按打印二叉树节点。这种方法的时间复杂度是O(n),空间复杂度也是O(n),与标准序遍历相,是高效的实现方式。</think>### 逐步解答 要实现二叉树打印节点,需在标准序遍历(BFS)基础上调整节点处理顺序。以下是实现思路和代码示例: --- #### 核心思路 1. **队列结构调整**:将子节点入队顺序改为**先**,确保每节点处理顺序自然形成从的序列 2. **分处理机制**:通过记录每节点数量,保证结果分存储 --- #### Python实现代码 ```python class TreeNode: def __init__(self, x): self.val = x self.left = None self.right = None def right_to_left_level_order(root): result = [] if not root: return result queue = [root] while queue: level_size = len(queue) current_level = [] for _ in range(level_size): node = queue.pop(0) # 从队列头部取节点 current_level.append(node.val) # 关键调整:先节点入队 if node.right: queue.append(node.right) if node.left: queue.append(node.left) result.append(current_level) return result ``` --- #### 执行过程示例 以二叉树: ``` 1 / \ 2 3 / \ / \ 4 5 6 7 ``` **处理流程**: 1. 根节点`1`入队 → 队列:`[1]` 2. 处理第一: - 取`1` → 当前结果:`[1]` - 先节点`3`入队 → 队列:`[3]` - 再节点`2`入队 → 队列:`[3,2]` 3. 处理第二: - 取`3` → 当前结果:`[3]` - 子`7`入队 → 队列:`[2,7]` - 子`6`入队 → 队列:`[2,7,6]` - 取`2` → 当前结果:`[3,2]` - 子`5`入队 → 队列:`[7,6,5]` - 子`4`入队 → 队列:`[7,6,5,4]` 4. 处理第三: - 依次取`7,6,5,4` → 当前结果:`[7,6,5,4]` **最终输**: $$ [[1],[3,2],[7,6,5,4]] $$ --- #### 关键点解析 1. **入队顺序调整**:通过先处理节点实现自然逆序 ```python if node.right: queue.append(node.right) # 先 if node.left: queue.append(node.left) # 后 ``` 2. **时间复杂度**:$O(n)$,每个节点恰好访问一次 3. **空间复杂度**:$O(n)$,队列最大存储最后一节点数 --- #### 扩展验证 可用以下二叉树验证代码: ```python # 构造测试树 root = TreeNode(1) root.left = TreeNode(2) root.right = TreeNode(3) root.left.left = TreeNode(4) root.left.right = TreeNode(5) root.right.left = TreeNode(6) root.right.right = TreeNode(7) print(right_to_left_level_order(root)) # 输:[[1], [3, 2], [7, 6, 5, 4]] ``` --- ### 相关问题 1. 如何实现自下而上的序遍历? 2. 怎样在每遍历时时记录级深度? 3. 能否用深度优先搜索(DFS)实现序遍历?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值