思路是很簡單。
一種思路是對每一層的節點數進行計數,首先在隊列中預存好整棵樹的根節點。然後不斷地從隊列中取出當前層的節點,以及加入下一層的節點。如果你只是按照層序的順序遍歷,那很簡單。但如果你在每一層結束之後還需要做一些額外操作(比如換行等),那麼就有一些細節需要注意。這裏主要是剖析一下後面的情況。
如果在每一層的最後都需要一些額外操作,那麼每一層的尾節點(每一層的最後一個節點)很關鍵,必須先處理完所有普通節點都具有的操作(比如打印當前值、添加左右子節點到隊列等)後,然後再處理尾節點作爲一個特殊節點所特有的操作(比如換行等)。詳細看下圖和代碼。
代碼如下:
#include <iostream>
#include <queue>
using namespace std;
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;
Node() : val(0), left(NULL), right(NULL), next(NULL) {}
Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}
Node(int _val, Node* _left, Node* _right, Node* _next)
: val(_val), left(_left), right(_right), next(_next) {}
};
void f(Node* root) {
if (root == nullptr) {
return ;
}
queue<Node*> q;
q.push(root);
int cur_len = 1;
int next_len = 0;
while (!q.empty()) {
// 所有普通節點都有的操作
Node* cur = q.front();
q.pop();
cout << cur->val << " ";
--cur_len;
// 所有普通節點都有的操作
if (cur->left) {
q.push(cur->left);
++next_len;
}
if (cur->right) {
q.push(cur->right);
++next_len;
}
// 尾節點作爲一個特殊節點所特有的操作
if (cur_len <= 0) {
cur_len = next_len;
next_len = 0;
cout << endl;
}
}
}
int main() {
Node *node1 = new Node(1, nullptr, nullptr, nullptr);
Node *node2 = new Node(2, nullptr, nullptr, nullptr);
Node *node3 = new Node(3, nullptr, nullptr, nullptr);
Node *node4 = new Node(4, nullptr, nullptr, nullptr);
Node *node5 = new Node(5, nullptr, nullptr, nullptr);
Node *node6 = new Node(6, nullptr, nullptr, nullptr);
Node *node7 = new Node(7, nullptr, nullptr, nullptr);
node1->left = node2;
node1->right = node3;
node2->left = node4;
node2->right = node5;
node3->left = node6;
node3->right = node7;
f(node1);
}
另一種思路不是對每一層計數,而是用level_begin記錄下一層的首節點(下一層的第一個節點)的指針。當按照層序遍歷的順序遍歷到level_begin時,說明當前指針已經指向了新的一層。如果在每一層的最後都需要一些額外操作,那麼下一層的首節點(下一層的第一個節點)很關鍵。對於首節點的處理,與上一個思路正好相反,必須先處理完首節點作爲一個特殊節點所特有的操作(比如換行等)後,然後再處理所有普通節點都具有的操作(比如打印當前值、添加左右子節點到隊列等)。
代碼如下:
#include <iostream>
#include <queue>
using namespace std;
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;
Node() : val(0), left(NULL), right(NULL), next(NULL) {}
Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}
Node(int _val, Node* _left, Node* _right, Node* _next)
: val(_val), left(_left), right(_right), next(_next) {}
};
void f(Node* root) {
if (root == nullptr) {
return ;
}
queue<Node*> q;
q.push(root);
Node* level_begin = root;
while (!q.empty()) {
// 所有普通節點都有的操作
Node* cur = q.front();
q.pop();
// 首節點作爲一個特殊節點所特有的操作
if (cur == level_begin) {
level_begin = nullptr;
cout << endl;
}
// 所有普通節點都有的操作
cout << cur->val << " ";
// 所有普通節點都有的操作
if (cur->left) {
if (level_begin == nullptr) {
level_begin = cur->left;
}
q.push(cur->left);
}
if (cur->right) {
if (level_begin == nullptr) {
level_begin = cur->right;
}
q.push(cur->right);
}
}
}
int main() {
Node *node1 = new Node(1, nullptr, nullptr, nullptr);
Node *node2 = new Node(2, nullptr, nullptr, nullptr);
Node *node3 = new Node(3, nullptr, nullptr, nullptr);
Node *node4 = new Node(4, nullptr, nullptr, nullptr);
Node *node5 = new Node(5, nullptr, nullptr, nullptr);
Node *node6 = new Node(6, nullptr, nullptr, nullptr);
Node *node7 = new Node(7, nullptr, nullptr, nullptr);
node1->left = node2;
node1->right = node3;
node2->left = node4;
node2->right = node5;
node3->left = node6;
node3->right = node7;
f(node1);
}
兩種思路的區別在於,按照第一種思路遍歷完之後,則會多輸出一個換行符;而按照第二種思路,則會在輸出第一層的第一個節點之前,多輸出一個換行符。當然,多餘的換行符是可以避免輸出的。對於第一種思路,將尾節點的判斷條件if (cur_len <= 0)
改爲if (cur_len <= 0 && !q.empty())
,多了一個!q.empty()
;對於第二種思路,將level_begin
的初值從root
改爲nullptr
就好。
最終修改後的代碼如下:
第一種思路:
#include <iostream>
#include <queue>
using namespace std;
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;
Node() : val(0), left(NULL), right(NULL), next(NULL) {}
Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}
Node(int _val, Node* _left, Node* _right, Node* _next)
: val(_val), left(_left), right(_right), next(_next) {}
};
void f(Node* root) {
if (root == nullptr) {
return;
}
queue<Node*> q;
q.push(root);
int cur_len = 1;
int next_len = 0;
while (!q.empty()) {
// 所有普通節點都有的操作
Node* cur = q.front();
q.pop();
cout << cur->val << " ";
--cur_len;
// 所有普通節點都有的操作
if (cur->left) {
q.push(cur->left);
++next_len;
}
if (cur->right) {
q.push(cur->right);
++next_len;
}
// 尾節點作爲一個特殊節點所特有的操作
if (cur_len <= 0 && !q.empty()) {
cur_len = next_len;
next_len = 0;
cout << endl;
}
}
}
int main() {
Node* node1 = new Node(1, nullptr, nullptr, nullptr);
Node* node2 = new Node(2, nullptr, nullptr, nullptr);
Node* node3 = new Node(3, nullptr, nullptr, nullptr);
Node* node4 = new Node(4, nullptr, nullptr, nullptr);
Node* node5 = new Node(5, nullptr, nullptr, nullptr);
Node* node6 = new Node(6, nullptr, nullptr, nullptr);
Node* node7 = new Node(7, nullptr, nullptr, nullptr);
node1->left = node2;
node1->right = node3;
node2->left = node4;
node2->right = node5;
node3->left = node6;
node3->right = node7;
f(node1);
}
第二種思路:
#include <iostream>
#include <queue>
using namespace std;
class Node {
public:
int val;
Node* left;
Node* right;
Node* next;
Node() : val(0), left(NULL), right(NULL), next(NULL) {}
Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}
Node(int _val, Node* _left, Node* _right, Node* _next)
: val(_val), left(_left), right(_right), next(_next) {}
};
void f(Node* root) {
if (root == nullptr) {
return;
}
queue<Node*> q;
q.push(root);
Node* level_begin = nullptr;
while (!q.empty()) {
// 所有普通節點都有的操作
Node* cur = q.front();
q.pop();
// 首節點作爲一個特殊節點所特有的操作
if (cur == level_begin) {
level_begin = nullptr;
cout << endl;
}
// 所有普通節點都有的操作
cout << cur->val << " ";
// 所有普通節點都有的操作
if (cur->left) {
if (level_begin == nullptr) {
level_begin = cur->left;
}
q.push(cur->left);
}
if (cur->right) {
if (level_begin == nullptr) {
level_begin = cur->right;
}
q.push(cur->right);
}
}
}
int main() {
Node* node1 = new Node(1, nullptr, nullptr, nullptr);
Node* node2 = new Node(2, nullptr, nullptr, nullptr);
Node* node3 = new Node(3, nullptr, nullptr, nullptr);
Node* node4 = new Node(4, nullptr, nullptr, nullptr);
Node* node5 = new Node(5, nullptr, nullptr, nullptr);
Node* node6 = new Node(6, nullptr, nullptr, nullptr);
Node* node7 = new Node(7, nullptr, nullptr, nullptr);
node1->left = node2;
node1->right = node3;
node2->left = node4;
node2->right = node5;
node3->left = node6;
node3->right = node7;
f(node1);
}