Remove incomplete zig code from docs. (#1837)

This commit is contained in:
Yudong Jin
2025-12-31 19:47:59 +08:00
committed by GitHub
parent 2778a6f9c7
commit 10f76bd59a
68 changed files with 0 additions and 1343 deletions
@@ -116,14 +116,6 @@
```
=== "Zig"
```zig title="array.zig"
// 配列を初期化
var arr = [_]i32{0} ** 5; // { 0, 0, 0, 0, 0 }
var nums = [_]i32{ 1, 3, 2, 5, 4 };
```
### 要素へのアクセス
配列内の要素は連続したメモリ空間に格納されるため、各要素のメモリアドレスを計算することが簡単になります。以下の図に示されている公式は、配列のメモリアドレス(特に、最初の要素のアドレス)と要素のインデックスを利用して、要素のメモリアドレスを決定するのに役立ちます。この計算により、目的の要素への直接アクセスが合理化されます。
@@ -165,26 +165,6 @@
```
=== "Zig"
```zig title=""
// 連結リストノードクラス
pub fn ListNode(comptime T: type) type {
return struct {
const Self = @This();
val: T = 0, // ノード値
next: ?*Self = null, // 次のノードへのポインタ
// コンストラクタ
pub fn init(self: *Self, x: i32) void {
self.val = x;
self.next = null;
}
};
}
```
## 連結リストの一般的な操作
### 連結リストの初期化
@@ -385,23 +365,6 @@
```
=== "Zig"
```zig title="linked_list.zig"
// 連結リストを初期化
// 各ノードを初期化
var n0 = inc.ListNode(i32){.val = 1};
var n1 = inc.ListNode(i32){.val = 3};
var n2 = inc.ListNode(i32){.val = 2};
var n3 = inc.ListNode(i32){.val = 5};
var n4 = inc.ListNode(i32){.val = 4};
// ノード間の参照を構築
n0.next = &n1;
n1.next = &n2;
n2.next = &n3;
n3.next = &n4;
```
配列全体は1つの変数です。例えば、配列`nums`には`nums[0]`、`nums[1]`などの要素が含まれますが、連結リストは複数の異なるノードオブジェクトで構成されています。**通常、連結リストはそのヘッドノードで参照されます**。例えば、前のコードスニペットの連結リストは`n0`として参照されます。
### ノードの挿入
@@ -642,28 +605,6 @@
```
=== "Zig"
```zig title=""
// 双方向連結リストノードクラス
pub fn ListNode(comptime T: type) type {
return struct {
const Self = @This();
val: T = 0, // ノード値
next: ?*Self = null, // 後続ノードへのポインタ
prev: ?*Self = null, // 前任ノードへのポインタ
// コンストラクタ
pub fn init(self: *Self, x: i32) void {
self.val = x;
self.next = null;
self.prev = null;
}
};
}
```
![連結リストの一般的な種類](linked_list.assets/linkedlist_common_types.png)
## 連結リストの典型的な応用
@@ -132,15 +132,6 @@
```
=== "Zig"
```zig title="list.zig"
// リストを初期化
var nums = std.ArrayList(i32).init(std.heap.page_allocator);
defer nums.deinit();
try nums.appendSlice(&[_]i32{ 1, 3, 2, 5, 4 });
```
### 要素へのアクセス
リストは本質的に配列であるため、$O(1)$時間で要素にアクセスし更新することができ、非常に効率的です。
@@ -256,16 +247,6 @@
```
=== "Zig"
```zig title="list.zig"
// 要素にアクセス
var num = nums.items[1]; // インデックス1の要素にアクセス
// 要素を更新
nums.items[1] = 0; // インデックス1の要素を0に更新
```
### 要素の挿入と削除
配列と比較して、リストは要素の追加と削除においてより柔軟性を提供します。リストの末尾への要素追加は$O(1)$操作ですが、リストの他の場所での要素の挿入と削除の効率は配列と同じままで、時間計算量は$O(n)$です。
@@ -482,26 +463,6 @@
```
=== "Zig"
```zig title="list.zig"
// リストをクリア
nums.clearRetainingCapacity();
// 末尾に要素を追加
try nums.append(1);
try nums.append(3);
try nums.append(2);
try nums.append(5);
try nums.append(4);
// 中間に要素を挿入
try nums.insert(3, 6); // インデックス3に数値6を挿入
// 要素を削除
_ = nums.orderedRemove(3); // インデックス3の要素を削除
```
### リストの反復
配列と同様に、リストはインデックスを使用して反復することも、各要素を直接反復することもできます。
@@ -674,23 +635,6 @@
```
=== "Zig"
```zig title="list.zig"
// インデックスでリストを反復
var count: i32 = 0;
var i: i32 = 0;
while (i < nums.items.len) : (i += 1) {
count += nums[i];
}
// リスト要素を直接反復
count = 0;
for (nums.items) |num| {
count += num;
}
```
### リストの連結
新しいリスト`nums1`が与えられたとき、それを元のリストの末尾に追加できます。
@@ -788,16 +732,6 @@
```
=== "Zig"
```zig title="list.zig"
// 2つのリストを連結
var nums1 = std.ArrayList(i32).init(std.heap.page_allocator);
defer nums1.deinit();
try nums1.appendSlice(&[_]i32{ 6, 8, 7, 10, 9 });
try nums.insertSlice(nums.items.len, nums1.items); // nums1をnumsの末尾に連結
```
### リストのソート
リストがソートされると、「二分探索」や「双ポインタ」アルゴリズムなど、配列関連のアルゴリズム問題でよく使用されるアルゴリズムを使用できます。
@@ -884,13 +818,6 @@
```
=== "Zig"
```zig title="list.zig"
// リストをソート
std.sort.sort(i32, nums.items, {}, comptime std.sort.asc(i32));
```
## リストの実装
多くのプログラミング言語には、Java、C++、Pythonなどを含む組み込みリストが付属しています。それらの実装は、初期容量や拡張係数などの様々なパラメータを慎重に考慮した設定で、複雑になりがちです。興味のある読者は、さらなる学習のためにソースコードを調べることができます。
@@ -429,12 +429,6 @@
end
```
=== "Zig"
```zig title=""
```
次に、フレームワークコードに基づいて例題 3 を解きます。状態 `state` はノードの走査経路を表し、選択肢 `choices` は現在ノードの左子ノードと右子ノード、結果 `res` は経路リストです:
```src
@@ -316,12 +316,6 @@
```
=== "Zig"
```zig title=""
```
## 計算方法
空間計算量を計算する方法は時間計算量とほぼ同様で、統計対象を「操作数」から「使用空間のサイズ」に変更するだけです。
@@ -468,12 +462,6 @@
```
=== "Zig"
```zig title=""
```
**再帰関数では、スタックフレーム空間を考慮に入れる必要があります**。以下のコードを考えてみましょう:
=== "Python"
@@ -712,12 +700,6 @@
```
=== "Zig"
```zig title=""
```
`loop()`関数と`recur()`関数の時間計算量は両方とも$O(n)$ですが、それらの空間計算量は異なります。
- `loop()`関数はループ内で`function()`を$n$回呼び出し、各反復の`function()`は返ってそのスタックフレーム空間を解放するため、空間計算量は$O(1)$のままです。
@@ -177,21 +177,6 @@
```
=== "Zig"
```zig title=""
// 特定の操作プラットフォーム下で
fn algorithm(n: usize) void {
var a: i32 = 2; // 1 ns
a += 1; // 1 ns
a *= 2; // 10 ns
// n回ループ
for (0..n) |_| { // 1 ns
std.debug.print("{}\n", .{0}); // 5 ns
}
}
```
上記の方法を使用すると、アルゴリズムの実行時間は$(6n + 12)$ nsとして計算できます:
$$
@@ -441,29 +426,6 @@ $$
```
=== "Zig"
```zig title=""
// アルゴリズムAの時間計算量:定数オーダー
fn algorithm_A(n: usize) void {
_ = n;
std.debug.print("{}\n", .{0});
}
// アルゴリズムBの時間計算量:線形オーダー
fn algorithm_B(n: i32) void {
for (0..n) |_| {
std.debug.print("{}\n", .{0});
}
}
// アルゴリズムCの時間計算量:定数オーダー
fn algorithm_C(n: i32) void {
_ = n;
for (0..1000000) |_| {
std.debug.print("{}\n", .{0});
}
}
```
下図はこれら3つのアルゴリズムの時間計算量を示しています。
- アルゴリズム`A`には1つの印刷操作のみがあり、その実行時間は$n$とともに増加しません。その時間計算量は「定数オーダー」と考えられます。
@@ -641,20 +603,6 @@ $$
```
=== "Zig"
```zig title=""
fn algorithm(n: usize) void {
var a: i32 = 1; // +1
a += 1; // +1
a *= 2; // +1
// n回ループ
for (0..n) |_| { // +1 (毎回i++が実行される)
std.debug.print("{}\n", .{0}); // +1
}
}
```
アルゴリズムの操作数を入力サイズ$n$の関数として表す関数を$T(n)$とすると、以下の例を考えてみましょう:
$$
@@ -902,27 +850,6 @@ $f(n)$が決まれば、時間計算量$O(f(n))$が得られます。しかし
```
=== "Zig"
```zig title=""
fn algorithm(n: usize) void {
var a: i32 = 1; // +0 (技法1)
a = a + @as(i32, @intCast(n)); // +0 (技法1)
// +n (技法2)
for(0..(5 * n + 1)) |_| {
std.debug.print("{}\n", .{0});
}
// +n*n (技法3)
for(0..(2 * n)) |_| {
for(0..(n + 1)) |_| {
std.debug.print("{}\n", .{0});
}
}
}
```
以下の式は、簡略化前後のカウント結果を示しており、どちらも$O(n^2)$の時間計算量に導きます:
$$
@@ -159,12 +159,3 @@
```
=== "Zig"
```zig title=""
// 様々な基本データ型を使用して配列を初期化
var numbers: [5]i32 = undefined;
var decimals: [5]f32 = undefined;
var characters: [5]u8 = undefined;
var bools: [5]bool = undefined;
```
@@ -349,12 +349,6 @@ $$
```
=== "Zig"
```zig title="built_in_hash.zig"
```
多くのプログラミング言語では、**不変オブジェクトのみがハッシュ表の`key`として機能できます**。リスト(動的配列)を`key`として使用する場合、リストの内容が変更されると、そのハッシュ値も変更され、ハッシュ表で元の`value`を見つけることができなくなります。
カスタムオブジェクト(連結リストノードなど)のメンバー変数は可変ですが、ハッシュ可能です。**これは、オブジェクトのハッシュ値が通常そのメモリアドレスに基づいて生成されるためです**。オブジェクトの内容が変更されても、メモリアドレスは同じままなので、ハッシュ値は変更されません。
-12
View File
@@ -273,12 +273,6 @@
```
=== "Zig"
```zig title="hash_map.zig"
```
ハッシュ表を走査する一般的な方法は3つあります:キー値ペアの走査、キーの走査、値の走査。以下はコード例です:
=== "Python"
@@ -470,12 +464,6 @@
```
=== "Zig"
```zig title="hash_map.zig"
// Zigの例は提供されていません
```
## ハッシュ表の簡単な実装
まず、最も簡単なケースを考えてみましょう:**配列のみを使ってハッシュ表を実装すること**。ハッシュ表において、配列の各空きスロットは<u>バケット</u>と呼ばれ、各バケットはキー値ペアを格納できます。したがって、クエリ操作は`key`に対応するバケットを見つけ、そこから`value`を取得することになります。
-6
View File
@@ -408,12 +408,6 @@
```
=== "Zig"
```zig title="heap.zig"
```
## ヒープの実装
以下の実装は最大ヒープです。最小ヒープに変換するには、すべてのサイズ論理比較を反転させるだけです(例えば、$\geq$を$\leq$に置き換える)。興味のある読者は自分で実装することをお勧めします。
-11
View File
@@ -169,17 +169,6 @@
*/
```
=== "Zig"
```zig title=""
// 関数、クラス、テストサンプルなどをラベル付けするためのヘッダーコメント
// 詳細を説明するためのコメント
// 複数行
// コメント
```
## アニメーション図解による効率的学習
テキストと比較して、動画や画像は情報密度が高く、より構造化されており、理解しやすくなっています。この本では、**重要で難しい概念は主にアニメーションと図解を通じて提示され**、テキストは説明と補足として機能します。
-6
View File
@@ -330,12 +330,6 @@
```
=== "Zig"
```zig title="deque.zig"
```
## 両端キューの実装 *
両端キューの実装は通常のキューの実装と似ており、連結リストまたは配列を基盤となるデータ構造として使用できます。
-6
View File
@@ -308,12 +308,6 @@
```
=== "Zig"
```zig title="queue.zig"
```
## キューの実装
キューを実装するには、一方の端で要素を追加し、もう一方の端で要素を削除できるデータ構造が必要です。連結リストと配列の両方がこの要件を満たします。
-6
View File
@@ -302,12 +302,6 @@
```
=== "Zig"
```zig title="stack.zig"
```
## スタックの実装
スタックがどのように動作するかをより深く理解するために、自分でスタッククラスを実装してみましょう。
@@ -126,12 +126,6 @@
```
=== "Zig"
```zig title=""
```
![任意の種類の二分木の配列表現](array_representation_of_tree.assets/array_representation_with_empty.png)
注目すべきは、**完備二分木は配列表現に非常に適している**ということです。完備二分木の定義を思い出すと、`None`は最下位レベルでのみ、かつ右側に向かって現れます。**つまり、すべての`None`値は確実にレベル順探索シーケンスの最後に現れます**。
-6
View File
@@ -217,12 +217,6 @@ AVL木に関連する操作ではノードの高さを取得する必要があ
```
=== "Zig"
```zig title=""
```
「ノードの高さ」とは、そのノードから最も遠い葉ノードまでの距離、つまり通過する「辺」の数を指します。重要なのは、葉ノードの高さは$0$で、nullノードの高さは$-1$であることです。ノードの高さを取得し、更新するための2つのユーティリティ関数を作成します:
```src
-18
View File
@@ -192,12 +192,6 @@
```
=== "Zig"
```zig title=""
```
各ノードは2つの参照(ポインタ)を持ち、それぞれ<u>左の子ノード</u>と<u>右の子ノード</u>を指しています。このノードは、これら2つの子ノードの<u>親ノード</u>と呼ばれます。二分木のノードが与えられたとき、このノードの左の子とその下にあるすべてのノードで形成される木を、このノードの<u>左部分木</u>と呼びます。同様に、<u>右部分木</u>も定義できます。
**二分木では、葉ノードを除いて、他のすべてのノードは子ノードと空でない部分木を含みます。** 下図に示すように、「ノード2」を親ノードとして見ると、その左と右の子ノードはそれぞれ「ノード4」と「ノード5」です。左部分木は「ノード4」とその下にあるすべてのノードで形成され、右部分木は「ノード5」とその下にあるすべてのノードで形成されます。
@@ -435,12 +429,6 @@
```
=== "Zig"
```zig title="binary_tree.zig"
```
### ノードの挿入と削除
連結リストと同様に、二分木でのノードの挿入と削除はポインタを変更することで実現できます。下図に例を示します。
@@ -593,12 +581,6 @@
```
=== "Zig"
```zig title="binary_tree.zig"
```
!!! tip
ノードの挿入は二分木の元の論理構造を変更する可能性があり、ノードの削除は通常そのノードとそのすべての部分木を削除することになることに注意してください。したがって、二分木では、挿入と削除は通常一連の操作を通じて実行され、意味のある結果を得ます。