mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-07 03:26:39 +08:00
build
This commit is contained in:
@@ -122,14 +122,6 @@ comments: true
|
||||
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="array.zig"
|
||||
// 配列を初期化
|
||||
var arr = [_]i32{0} ** 5; // { 0, 0, 0, 0, 0 }
|
||||
var nums = [_]i32{ 1, 3, 2, 5, 4 };
|
||||
```
|
||||
|
||||
### 2. 要素へのアクセス
|
||||
|
||||
配列内の要素は連続したメモリ空間に格納されるため、各要素のメモリアドレスを計算することが簡単になります。以下の図に示されている公式は、配列のメモリアドレス(特に、最初の要素のアドレス)と要素のインデックスを利用して、要素のメモリアドレスを決定するのに役立ちます。この計算により、目的の要素への直接アクセスが合理化されます。
|
||||
@@ -240,12 +232,6 @@ comments: true
|
||||
[class]{}-[func]{random_access}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="array.zig"
|
||||
[class]{}-[func]{randomAccess}
|
||||
```
|
||||
|
||||
### 3. 要素の挿入
|
||||
|
||||
配列要素はメモリ内で密に詰まっており、それらの間に追加データを収容するための空間はありません。以下の図に示すように、配列の中央に要素を挿入するには、後続のすべての要素を1つずつ後ろにシフトして、新しい要素のための空間を作る必要があります。
|
||||
@@ -356,12 +342,6 @@ comments: true
|
||||
[class]{}-[func]{insert}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="array.zig"
|
||||
[class]{}-[func]{insert}
|
||||
```
|
||||
|
||||
### 4. 要素の削除
|
||||
|
||||
同様に、以下の図に示すように、インデックス$i$の要素を削除するには、インデックス$i$に続くすべての要素を1つずつ前に移動する必要があります。
|
||||
@@ -466,12 +446,6 @@ comments: true
|
||||
[class]{}-[func]{remove}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="array.zig"
|
||||
[class]{}-[func]{remove}
|
||||
```
|
||||
|
||||
要約すると、配列の挿入と削除操作には以下の欠点があります:
|
||||
|
||||
- **高い時間計算量**:配列の挿入と削除の両方の平均時間計算量は$O(n)$で、ここで$n$は配列の長さです。
|
||||
@@ -590,12 +564,6 @@ comments: true
|
||||
[class]{}-[func]{traverse}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="array.zig"
|
||||
[class]{}-[func]{traverse}
|
||||
```
|
||||
|
||||
### 6. 要素の検索
|
||||
|
||||
配列内の特定の要素を見つけることは、配列を反復し、各要素をチェックして目的の値と一致するかどうかを決定することを含みます。
|
||||
@@ -699,12 +667,6 @@ comments: true
|
||||
[class]{}-[func]{find}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="array.zig"
|
||||
[class]{}-[func]{find}
|
||||
```
|
||||
|
||||
### 7. 配列の拡張
|
||||
|
||||
複雑なシステム環境では、安全な容量拡張のために配列の後にメモリ空間の可用性を確保することが困難になります。その結果、ほとんどのプログラミング言語では、**配列の長さは不変**です。
|
||||
@@ -819,12 +781,6 @@ comments: true
|
||||
[class]{}-[func]{extend}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="array.zig"
|
||||
[class]{}-[func]{extend}
|
||||
```
|
||||
|
||||
## 4.1.2 配列の利点と制限
|
||||
|
||||
配列は連続したメモリ空間に格納され、同じ型の要素で構成されます。このアプローチは、システムがデータ構造操作の効率を最適化するために活用できる実質的な事前情報を提供します。
|
||||
|
||||
@@ -171,26 +171,6 @@ comments: true
|
||||
|
||||
```
|
||||
|
||||
=== "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;
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## 4.2.1 連結リストの一般的な操作
|
||||
|
||||
### 1. 連結リストの初期化
|
||||
@@ -391,23 +371,6 @@ comments: true
|
||||
|
||||
```
|
||||
|
||||
=== "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`として参照されます。
|
||||
|
||||
### 2. ノードの挿入
|
||||
@@ -512,12 +475,6 @@ comments: true
|
||||
[class]{}-[func]{insert}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="linked_list.zig"
|
||||
[class]{}-[func]{insert}
|
||||
```
|
||||
|
||||
### 3. ノードの削除
|
||||
|
||||
下図に示すように、連結リストからノードを削除することも非常に簡単で、**1つのノードの参照(ポインタ)を変更するだけです**。
|
||||
@@ -631,12 +588,6 @@ comments: true
|
||||
[class]{}-[func]{remove}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="linked_list.zig"
|
||||
[class]{}-[func]{remove}
|
||||
```
|
||||
|
||||
### 4. ノードへのアクセス
|
||||
|
||||
**連結リストでのノードへのアクセスは効率が悪いです**。前述したように、配列の任意の要素には$O(1)$時間でアクセスできます。対照的に、連結リストでは、プログラムはヘッドノードから開始して目的のノードが見つかるまで順次ノードを巡回する必要があります。つまり、連結リストの$i$番目のノードにアクセスするには、プログラムは$i - 1$個のノードを反復処理する必要があり、時間計算量は$O(n)$になります。
|
||||
@@ -741,12 +692,6 @@ comments: true
|
||||
[class]{}-[func]{access}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="linked_list.zig"
|
||||
[class]{}-[func]{access}
|
||||
```
|
||||
|
||||
### 5. ノードの検索
|
||||
|
||||
連結リストを巡回して、値が`target`に一致するノードを見つけ、連結リスト内でのそのノードのインデックスを出力します。この手順も線形検索の例です。対応するコードは以下のとおりです:
|
||||
@@ -857,12 +802,6 @@ comments: true
|
||||
[class]{}-[func]{find}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="linked_list.zig"
|
||||
[class]{}-[func]{find}
|
||||
```
|
||||
|
||||
## 4.2.2 配列 vs. 連結リスト
|
||||
|
||||
下表は配列と連結リストの特性をまとめ、様々な操作における効率も比較しています。それぞれが対照的な格納戦略を使用するため、それぞれの特性と操作効率は明確に対比されています。
|
||||
@@ -1065,28 +1004,6 @@ comments: true
|
||||
|
||||
```
|
||||
|
||||
=== "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;
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 図 4-8 連結リストの一般的な種類 </p>
|
||||
|
||||
@@ -136,15 +136,6 @@ comments: true
|
||||
|
||||
```
|
||||
|
||||
=== "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 });
|
||||
```
|
||||
|
||||
### 2. 要素へのアクセス
|
||||
|
||||
リストは本質的に配列であるため、$O(1)$時間で要素にアクセスし更新することができ、非常に効率的です。
|
||||
@@ -260,16 +251,6 @@ comments: true
|
||||
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="list.zig"
|
||||
// 要素にアクセス
|
||||
var num = nums.items[1]; // インデックス1の要素にアクセス
|
||||
|
||||
// 要素を更新
|
||||
nums.items[1] = 0; // インデックス1の要素を0に更新
|
||||
```
|
||||
|
||||
### 3. 要素の挿入と削除
|
||||
|
||||
配列と比較して、リストは要素の追加と削除においてより柔軟性を提供します。リストの末尾への要素追加は$O(1)$操作ですが、リストの他の場所での要素の挿入と削除の効率は配列と同じままで、時間計算量は$O(n)$です。
|
||||
@@ -486,26 +467,6 @@ comments: true
|
||||
|
||||
```
|
||||
|
||||
=== "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の要素を削除
|
||||
```
|
||||
|
||||
### 4. リストの反復
|
||||
|
||||
配列と同様に、リストはインデックスを使用して反復することも、各要素を直接反復することもできます。
|
||||
@@ -678,23 +639,6 @@ comments: true
|
||||
|
||||
```
|
||||
|
||||
=== "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;
|
||||
}
|
||||
```
|
||||
|
||||
### 5. リストの連結
|
||||
|
||||
新しいリスト`nums1`が与えられたとき、それを元のリストの末尾に追加できます。
|
||||
@@ -792,16 +736,6 @@ comments: true
|
||||
|
||||
```
|
||||
|
||||
=== "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の末尾に連結
|
||||
```
|
||||
|
||||
### 6. リストのソート
|
||||
|
||||
リストがソートされると、「二分探索」や「双ポインタ」アルゴリズムなど、配列関連のアルゴリズム問題でよく使用されるアルゴリズムを使用できます。
|
||||
@@ -888,13 +822,6 @@ comments: true
|
||||
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="list.zig"
|
||||
// リストをソート
|
||||
std.sort.sort(i32, nums.items, {}, comptime std.sort.asc(i32));
|
||||
```
|
||||
|
||||
## 4.3.2 リストの実装
|
||||
|
||||
多くのプログラミング言語には、Java、C++、Pythonなどを含む組み込みリストが付属しています。それらの実装は、初期容量や拡張係数などの様々なパラメータを慎重に考慮した設定で、複雑になりがちです。興味のある読者は、さらなる学習のためにソースコードを調べることができます。
|
||||
@@ -1262,9 +1189,3 @@ comments: true
|
||||
```ruby title="my_list.rb"
|
||||
[class]{MyList}-[func]{}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="my_list.zig"
|
||||
[class]{MyList}-[func]{}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user