C++で単一のキューを使って二分木をジグザグ(鋸歯状)レベル順に走査する方法
この問題では、二分木が与えられ、その木をジグザグ(鋸歯状)レベル順で走査して出力することが求められます。ポイントは、この走査をたった1つのキューだけを使って実現することです。
問題の例
まず、具体例で問題を理解しましょう。以下のような二分木を考えます。

出力:
3 1 7 2 8 9 5
ご覧のとおり、第1レベルは左から右へ、第2レベルは右から左へ、第3レベルは再び左から右へと、レベルごとに方向を交互に入れ替えながらノードを出力しています。
解決アプローチ:単一キュー+区切りフラグ
通常、ジグザグ走査には2つのスタックや双方向キュー(deque)を使う方法が知られていますが、ここでは単一のキューだけで実装します。
そのために活用するのが、次の2つの仕組みです。
- 区切りフラグ(NULLセンチネル): レベルの境界を示すために、キューの中に
NULLを挿入します。 - 方向フラグ: 現在のレベルを出力する方向(左→右 または 右→左)を管理するカウンターです。
アルゴリズムの流れは以下のとおりです。
- ルート要素をキューに挿入し、その前後に
NULLを配置します。 - キューから要素を取り出しながら、その子ノードを順次キューへ挿入していきます。
NULLに到達したら、それがレベルの終わりを意味するため、方向フラグを確認し、指定された方向に沿ってそのレベルの要素を出力します。- 最後の
NULLに到達するまで、この処理を繰り返します。
つまり、キュー内のNULLが「レベルの区切り」の役割を果たし、各レベルの要素範囲を前後から走査できるため、単一のキューでもジグザグ出力が可能になるのです。
C++実装例
上記の解法を実装したプログラムがこちらです。
#include <bits/stdc++.h>
using namespace std;
struct Node {
int data;
struct Node *left, *right;
};
struct Node* insertNode(int data) {
struct Node* node = new struct Node;
node->data = data;
node->left = node->right = NULL;
return (node);
}
void zigZagTraversal(struct Node* root, int n){
struct Node* queue[2 * n];
int top = -1;
int front = 1;
queue[++top] = NULL;
queue[++top] = root;
queue[++top] = NULL;
int prevFront = 0, count = 1;
while (1) {
struct Node* curr = queue[front];
if (curr == NULL) {
if (front == top)
break;
else {
if (count % 2 == 0) {
for (int i = prevFront + 1; i < front; i++)
cout<<queue[i]->data<<"\t";
}
else {
for (int i = front - 1; i > prevFront; i--)
cout<<queue[i]->data<<"\t";
}
prevFront = front;
count++;
front++;
queue[++top] = NULL;
continue;
}
}
if (curr->left != NULL)
queue[++top] = curr->left;
if (curr->right != NULL)
queue[++top] = curr->right;
front++;
}
if (count % 2 == 0) {
for (int i = prevFront + 1; i < top; i++)
cout<<queue[i]->data<<"\t";
}
else {
for (int i = top - 1; i > prevFront; i--)
cout<<queue[i]->data<<"\t";
}
}
int main() {
struct Node* root = insertNode(3);
root->left = insertNode(1);
root->right = insertNode(7);
root->left->left = insertNode(5);
root->left->right = insertNode(9);
root->right->left = insertNode(8);
root->right->right = insertNode(2);
cout<<"Zig Zag traversal of the tree is :\n";
zigZagTraversal(root, 7);
return 0;
}実行結果
Zig Zag traversal of the tree is : 3 1 7 2 8 9 5
コードのポイント解説
- キューの初期化:
NULL → ルート → NULLの順で挿入し、最初と最後に区切りを用意します。 - レベルの出力: カウンター
countが偶数なら左から右へ、奇数なら右から左へと、prevFrontからfrontまでの範囲を逆順・順序どおりに出力します。 - 終了条件:
frontがtopと一致したとき、すべてのレベルの走査が完了したことを意味します。
この手法により、余分なデータ構造を追加することなく、時間計算量 O(n)・空間計算量 O(n) でジグザグレベル順走査を実現できます。
-
【データ構造】二分探索木のレベル順走査(Level-Order Traversal)をC++で実装して理解しよう
本記事では、二分探索木(Binary Search Tree)におけるレベル順走査(Level-Order Traversal)の手法について詳しく解説します。レベル順走査は、木の根(ルート)から出発し、上の階層から下の階層へ、同じ深さのノードは左から右の順に訪問していく方法です。この走査は幅優先探索(BFS:Breadth-First Search)とも呼ばれ、木やグラフの探索において非常に重要な基本概念となっています。 例として、次のような二分探索木を考えてみましょう。 この木に対してレベル順走査を実行すると、ノードは次の順序で訪問されます。 10 → 5 → 16 → 8 → 15
-
Pythonで実装する二分木のジグザグレベル順走査(Zigzag Level Order Traversal)
二分木が与えられたとき、そのジグザグレベル順走査(Zigzag Level Order Traversal)の結果を求める問題を考えます。これは、第1レベルは左から右へ、第2レベルは右から左へ、第3レベルは再び左から右へ……というように、階層ごとに走査の向きを交互に切り替えながらノードを訪問する手法です。 例として、次のような二分木を扱います。 この木に対する走査結果は [[3], [20, 9], [15, 7]] になります。ルートの 3 を含む第1レベル、右から左へ読む第2レベル(20, 9)、そして左から右へ読む第3レベル(15, 7)という具合です。 アルゴリズムの流れ キュー