Files
hello-algo/ja/docs/chapter_tree/array_representation_of_tree.md
T
Yudong Jin 7257641e0e Retranslate the complete Japanese online edition from Chinese (#2008)
* Retranslate the complete Japanese online edition from Chinese

* Fit Japanese homepage labels and localize heading permalinks

* Point Japanese contribution instructions to the Japanese preview

* Replace locale conditionals with multilingual UI tables
2026-10-30 02:12:26 +08:00

6.5 KiB

二分木の配列表現

連結リスト形式では、二分木の格納単位はノード TreeNode で、ノード同士はポインタでつながっています。前節では、この形式の二分木の基本操作を紹介しました。

では、二分木を配列で表すこともできるでしょうか。答えは、できます。

パーフェクト二分木の表現

まず単純な場合を考えます。パーフェクト二分木の全ノードをレベル順に配列へ格納すると、各ノードが一意のインデックスに対応します。

レベル順走査の特徴から、親と子のインデックスの対応式を導けます。ノードのインデックスが i なら、左の子は $2i + 1$、右の子は 2i + 2 です。下図に対応関係を示します。

パーフェクト二分木の配列表現

この対応式は、連結リストのノード参照(ポインタ)と同じ役割を果たします。配列内のどのノードからでも、式を使って左右の子にアクセスできます。

任意の二分木の表現

パーフェクト二分木は特殊な場合です。一般の二分木では、中間の層にも多くの None があります。レベル順の列にはそれらが含まれないため、その列だけでは None の数や位置を推測できません。つまり、同じレベル順の列に対応する二分木の構造が複数あります。

下図のように、パーフェクト二分木でない木には、上の配列表現をそのまま使えません。

同じレベル順の列に対応する複数の二分木

解決するには、レベル順の列にすべての None を明示的に書き込みます。下図のように、これで二分木を一意に表せます。コード例を示します。

=== "Python"

```python title=""
# 二分木の配列表現
# None で空の位置を表す
tree = [1, 2, 3, 4, None, 6, 7, 8, 9, None, None, 12, None, None, 15]
```

=== "C++"

```cpp title=""
/* 二分木の配列表現 */
// int の最大値 INT_MAX で空の位置を示す
vector<int> tree = {1, 2, 3, 4, INT_MAX, 6, 7, 8, 9, INT_MAX, INT_MAX, 12, INT_MAX, INT_MAX, 15};
```

=== "Java"

```java title=""
/* 二分木の配列表現 */
// int のラッパークラス Integer を使うと、null で空の位置を示せる
Integer[] tree = { 1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15 };
```

=== "C#"

```csharp title=""
/* 二分木の配列表現 */
// null 許容型 int? を使うと、null で空の位置を示せる
int?[] tree = [1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15];
```

=== "Go"

```go title=""
/* 二分木の配列表現 */
// any 型のスライスを使うと、nil で空の位置を示せる
tree := []any{1, 2, 3, 4, nil, 6, 7, 8, 9, nil, nil, 12, nil, nil, 15}
```

=== "Swift"

```swift title=""
/* 二分木の配列表現 */
// オプショナル型 Int? を使うと、nil で空の位置を示せる
let tree: [Int?] = [1, 2, 3, 4, nil, 6, 7, 8, 9, nil, nil, 12, nil, nil, 15]
```

=== "JS"

```javascript title=""
/* 二分木の配列表現 */
// null で空の位置を表す
let tree = [1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15];
```

=== "TS"

```typescript title=""
/* 二分木の配列表現 */
// null で空の位置を表す
let tree: (number | null)[] = [1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15];
```

=== "Dart"

```dart title=""
/* 二分木の配列表現 */
// null 許容型 int? を使うと、null で空の位置を示せる
List<int?> tree = [1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15];
```

=== "Rust"

```rust title=""
/* 二分木の配列表現 */
// None で空の位置を示す
let tree = [Some(1), Some(2), Some(3), Some(4), None, Some(6), Some(7), Some(8), Some(9), None, None, Some(12), None, None, Some(15)];
```

=== "C"

```c title=""
/* 二分木の配列表現 */
// int の最大値で空の位置を示すため、ノードの値に INT_MAX は使えない
int tree[] = {1, 2, 3, 4, INT_MAX, 6, 7, 8, 9, INT_MAX, INT_MAX, 12, INT_MAX, INT_MAX, 15};
```

=== "Kotlin"

```kotlin title=""
/* 二分木の配列表現 */
// null で空の位置を表す
val tree = arrayOf( 1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15 )
```

=== "Ruby"

```ruby title=""
### 二分木の配列表現 ###
# nil で空の位置を表す
tree = [1, 2, 3, 4, nil, 6, 7, 8, 9, nil, nil, 12, nil, nil, 15]
```

任意の二分木の配列表現

完全二分木は、配列で表すのに非常に適しています。定義を思い出すと、None は最下層の右側にしかありません。したがって、すべての None はレベル順の列の末尾に現れます。

つまり、完全二分木を配列で表す場合は、None の格納をすべて省けるので便利です。下図に例を示します。

完全二分木の配列表現

以下は配列で二分木を実装したコードで、次の操作を含みます。

  • 指定したノードの値、左右の子、親を取得します。
  • 行きがけ順、通りがけ順、帰りがけ順、レベル順の走査列を取得します。
[file]{array_binary_tree}-[class]{array_binary_tree}-[func]{}

長所と制約

配列表現の主な長所は次のとおりです。

  • 連続したメモリに格納されるのでキャッシュとの相性がよく、アクセスと走査が高速です。
  • ポインタの格納が不要なので、領域を節約できます。
  • ノードにランダムアクセスできます。

一方、次の制約もあります。

  • 連続したメモリが必要なので、データ量が非常に多い木には適しません。
  • ノードの追加・削除には配列の挿入・削除操作が必要で、効率が低くなります。
  • None が多い二分木では、配列内で実際のノードデータが占める割合が低く、領域の利用効率が下がります。