mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-10 22:46:07 +00:00
Re-translate the Japanese version (#1871)
* Retranslate Japanese docs with GPT-5.4 * Retranslate Japanese code with GPT-5.4
This commit is contained in:
@@ -1,66 +1,66 @@
|
||||
# まとめ
|
||||
|
||||
### 重要なポイント
|
||||
### 重要ポイントの振り返り
|
||||
|
||||
- データ構造は論理構造と物理構造の2つの観点から分類できます。論理構造はデータ間の論理的関係を記述し、物理構造はデータがメモリにどのように格納されるかを記述します。
|
||||
- よく使用される論理構造には、線形構造、木、ネットワークがあります。通常、論理構造に基づいてデータ構造を線形(配列、連結リスト、スタック、キュー)と非線形(木、グラフ、ヒープ)に分けます。ハッシュ表の実装は線形と非線形の両方のデータ構造を含む場合があります。
|
||||
- プログラムが実行中の際、データはメモリに格納されます。各メモリ空間には対応するアドレスがあり、プログラムはこれらのアドレスを通じてデータにアクセスします。
|
||||
- 物理構造は連続空間格納(配列)と離散空間格納(連結リスト)に分けることができます。すべてのデータ構造は配列、連結リスト、またはその両方の組み合わせを使用して実装されます。
|
||||
- コンピュータの基本データ型には、整数(`byte`、`short`、`int`、`long`)、浮動小数点数(`float`、`double`)、文字(`char`)、ブール値(`bool`)が含まれます。データ型の値の範囲は、そのサイズと表現に依存します。
|
||||
- 符号絶対値、1の補数、2の補数は、コンピュータで整数をエンコードする3つの方法であり、相互に変換することができます。符号絶対値の最上位ビットは符号ビットで、残りのビットは数値の値を表します。
|
||||
- 整数はコンピュータで2の補数によってエンコードされます。この表現の利点には、(i)コンピュータが正と負の整数の加算を統一できる、(ii)減算用の特別なハードウェア回路を設計する必要がない、(iii)正と負の0の曖昧さがない、があります。
|
||||
- 浮動小数点数のエンコーディングは、1つの符号ビット、8つの指数ビット、23の仮数ビットで構成されます。指数ビットのため、浮動小数点数の範囲は整数よりもはるかに大きくなりますが、精度を犠牲にします。
|
||||
- ASCIIは最初期の英語文字セットで、1バイトの長さで計127文字です。GBKは人気のある中国語文字セットで、2万文字以上の中国語文字を含みます。Unicodeは世界の様々な言語の文字を含む完全な文字セット標準を提供することを目的とし、文字エンコーディング方法の不一致による文字化け問題を解決します。
|
||||
- UTF-8は最も人気があり一般的なUnicodeエンコーディング方法です。これは可変長エンコーディング方法で、優れた拡張性と空間効率を持ちます。UTF-16とUTF-32は固定長エンコーディング方法です。中国語文字をエンコードする際、UTF-16はUTF-8よりも少ない空間を使用します。JavaやC#などのプログラミング言語はデフォルトでUTF-16エンコーディングを使用します。
|
||||
- データ構造は、論理構造と物理構造という 2 つの観点から分類できます。論理構造はデータ要素間の論理的関係を記述し、物理構造はデータのコンピュータメモリ上での格納方法を記述します。
|
||||
- 代表的な論理構造には、線形、木構造、網状構造などがあります。通常、論理構造に基づいてデータ構造を線形(配列、連結リスト、スタック、キュー)と非線形(木、グラフ、ヒープ)の 2 種類に分類します。ハッシュテーブルの実装には、線形データ構造と非線形データ構造が同時に含まれる場合があります。
|
||||
- プログラムの実行時、データはコンピュータメモリに格納されます。各メモリ空間には対応するメモリアドレスがあり、プログラムはそれらのメモリアドレスを通じてデータにアクセスします。
|
||||
- 物理構造は主に連続領域への格納(配列)と分散領域への格納(連結リスト)に分けられます。すべてのデータ構造は、配列、連結リスト、またはその両方の組み合わせによって実装されます。
|
||||
- コンピュータにおける基本データ型には、整数 `byte`、`short`、`int`、`long`、浮動小数点数 `float`、`double`、文字 `char`、真偽値 `bool` があります。これらの値域は、使用する記憶領域の大きさと表現方式によって決まります。
|
||||
- 符号付き絶対値表現、1 の補数、2 の補数は、コンピュータで数値を符号化する 3 つの方法であり、相互に変換できます。整数の符号付き絶対値表現では最上位ビットが符号ビットで、残りのビットが数値の値です。
|
||||
- 整数はコンピュータ内では 2 の補数の形式で格納されます。2 の補数表現では、コンピュータは正数と負数の加算を同じように扱うことができ、減算のために特別なハードウェア回路を別途設計する必要がなく、さらに正負のゼロが重複する問題もありません。
|
||||
- 浮動小数点数の符号化は、1 ビットの符号部、8 ビットの指数部、23 ビットの仮数部で構成されます。指数部があるため、浮動小数点数の値域は整数よりはるかに広くなりますが、その代償として精度が犠牲になります。
|
||||
- ASCII コードは最も早く登場した英字文字集合で、長さは 1 バイト、収録文字数は 127 です。GBK 文字集合はよく使われる中国語文字集合で、2 万字以上の漢字を収録しています。Unicode は完全な文字集合標準を提供することを目指しており、世界中のさまざまな言語の文字を収録することで、文字コード方式の不一致によって生じる文字化けの問題を解決します。
|
||||
- UTF-8 は最も広く使われている Unicode の符号化方式で、汎用性が非常に高いです。可変長の符号化方式であり、拡張性に優れ、記憶領域の利用効率を効果的に高めます。UTF-16 と UTF-32 は固定長の符号化方式です。中国語を符号化する場合、UTF-16 は UTF-8 よりも使用領域が小さくなります。Java や C# などのプログラミング言語は、デフォルトで UTF-16 を使用します。
|
||||
|
||||
### Q & A
|
||||
|
||||
**Q**: なぜハッシュ表は線形と非線形の両方のデータ構造を含むのですか?
|
||||
**Q**:なぜハッシュテーブルには線形データ構造と非線形データ構造が同時に含まれるのですか?
|
||||
|
||||
ハッシュ表の基礎構造は配列です。ハッシュ衝突を解決するために、「チェイン法」を使用する場合があります(後の節「ハッシュ衝突」で説明):配列の各バケットは連結リストを指し、その長さが特定の閾値より大きくなると木(通常は赤黒木)に変換される可能性があります。
|
||||
格納の観点から、ハッシュ表の基礎構造は配列で、各バケットには値、連結リスト、または木が含まれる場合があります。したがって、ハッシュ表は線形データ構造(配列、連結リスト)と非線形データ構造(木)の両方を含む場合があります。
|
||||
ハッシュテーブルの基盤は配列であり、ハッシュ衝突を解決するために「チェイン法」(後続の「ハッシュ衝突」の章で説明します)を使うことがあります。配列内の各バケットは 1 つの連結リストを指し、その連結リストの長さがある閾値を超えると、木(通常は赤黒木)に変換されることもあります。
|
||||
|
||||
**Q**: `char`型の長さは1バイトですか?
|
||||
格納の観点から見ると、ハッシュテーブルの基盤は配列であり、各バケットスロットには値が入ることもあれば、連結リストや木が入ることもあります。したがって、ハッシュテーブルには線形データ構造(配列、連結リスト)と非線形データ構造(木)が同時に含まれる場合があります。
|
||||
|
||||
`char`型の長さは、プログラミング言語のエンコーディング方法によって決まります。例えば、Java、JavaScript、TypeScript、C#はすべてUTF-16エンコーディング(Unicodeコードポイントを保存するため)を使用するため、`char`型の長さは2バイトです。
|
||||
**Q**:`char` 型の長さは 1 バイトですか?
|
||||
|
||||
**Q**: 配列ベースのデータ構造を「静的データ構造」と呼ぶことに曖昧さはありませんか?スタックもプッシュやポップなどの「動的」操作を実行できます。
|
||||
`char` 型の長さは、プログラミング言語が採用する符号化方式によって決まります。たとえば、Java、JavaScript、TypeScript、C# はいずれも UTF-16 符号化(Unicode コードポイントを保持)を採用しているため、`char` 型の長さは 2 バイトです。
|
||||
|
||||
スタックは動的なデータ操作を実装できますが、データ構造は依然として「静的」です(長さが固定)。配列ベースのデータ構造は動的に要素を追加または削除できますが、その容量は固定されています。スタックサイズが事前に割り当てられたサイズを超える場合、古い配列は新しく作成されたより大きな配列にコピーされます。
|
||||
**Q**:配列ベースで実装されたデータ構造を「静的データ構造」と呼ぶのは曖昧ではありませんか? スタックも push や pop などの操作ができ、これらの操作はどれも「動的」です。
|
||||
|
||||
**Q**: スタック(キュー)を構築する際、そのサイズが指定されていないのに、なぜ「静的データ構造」なのですか?
|
||||
スタックは確かに動的なデータ操作を実現できますが、データ構造自体は依然として「静的」(長さが不変)です。配列ベースのデータ構造でも要素を動的に追加または削除できますが、その容量は固定です。データ量が事前に確保した大きさを超えた場合は、より大きな新しい配列を作成し、古い配列の内容を新しい配列にコピーする必要があります。
|
||||
|
||||
高級プログラミング言語では、スタック(キュー)の初期容量を手動で指定する必要はありません。このタスクはクラス内で自動的に完了されます。例えば、Javaの`ArrayList`の初期容量は通常10です。さらに、拡張操作も自動的に完了されます。詳細については、後続の「リスト」の章を参照してください。
|
||||
**Q**:スタック(キュー)を構築するときにサイズを指定していないのに、なぜそれらは「静的データ構造」なのですか?
|
||||
|
||||
**Q**: 符号絶対値を2の補数に変換する方法は「最初に否定してから1を加える」ですので、2の補数を符号絶対値に変換することはその逆操作「最初に1を減算してから否定する」であるべきです。
|
||||
しかし、2の補数も「最初に否定してから1を加える」を通じて符号絶対値に変換できます。なぜですか?
|
||||
高水準プログラミング言語では、スタック(キュー)の初期容量を人手で指定する必要はなく、この作業はクラス内部で自動的に行われます。たとえば、Java の `ArrayList` の初期容量は通常 10 です。また、容量拡張も自動的に実装されています。詳しくは後続の「リスト」の章を参照してください。
|
||||
|
||||
**A**: これは、符号絶対値と2の補数間の相互変換が「補数」の計算と等価だからです。まず補数を定義します:$a + b = c$と仮定すると、$a$は$b$の$c$に対する補数と言い、逆に$b$は$a$の$c$に対する補数と言います。
|
||||
**Q**:符号付き絶対値表現から 2 の補数への変換方法は「先にビット反転してから 1 を加える」ですが、2 の補数から符号付き絶対値表現への変換は逆演算である「先に 1 を引いてからビット反転する」べきなのに、同じく「先にビット反転してから 1 を加える」でも求められます。これはなぜですか?
|
||||
|
||||
長さ$n = 4$の二進数$0010$が与えられた場合、この数が符号絶対値(符号ビットを無視)の場合、その2の補数は「最初に否定してから1を加える」ことで得られます:
|
||||
これは、符号付き絶対値表現と 2 の補数の相互変換が、実際には「補数」を計算する過程だからです。まず補数の定義を示します。$a + b = c$ とすると、$a$ を $b$ から $c$ への補数と呼び、逆に $b$ も $a$ から $c$ への補数と呼びます。
|
||||
|
||||
長さ $n = 4$ ビットの 2 進数 $0010$ が与えられたとします。この数を符号付き絶対値表現(符号ビットは考慮しない)とみなすと、その 2 の補数は「先にビット反転してから 1 を加える」ことで得られます。
|
||||
|
||||
$$
|
||||
0010 \rightarrow 1101 \rightarrow 1110
|
||||
$$
|
||||
|
||||
符号絶対値と2の補数の和が$0010 + 1110 = 10000$であることを観察します。つまり、2の補数$1110$は符号絶対値$0010$の$10000$に対する「補数」です。**これは、上記の「最初に否定してから1を加える」が$10000$に対する補数の計算と等価であることを意味します**。
|
||||
ここで、符号付き絶対値表現と 2 の補数の和は $0010 + 1110 = 10000$ となります。つまり、2 の補数 $1110$ は符号付き絶対値表現 $0010$ から $10000$ への「補数」です。**これは、上記の「先にビット反転してから 1 を加える」が、実際には $10000$ への補数を計算する過程であることを意味します。**
|
||||
|
||||
では、$1110$の$10000$に対する「補数」は何でしょうか?「最初に否定してから1を加える」ことで計算できます:
|
||||
では、2 の補数 $1110$ から $10000$ への「補数」はいくつでしょうか。これもやはり「先にビット反転してから 1 を加える」ことで求められます。
|
||||
|
||||
$$
|
||||
1110 \rightarrow 0001 \rightarrow 0010
|
||||
$$
|
||||
|
||||
言い換えると、符号絶対値と2の補数は互いに$10000$に対する「補数」であるため、「符号絶対値から2の補数」と「2の補数から符号絶対値」は同じ操作(最初に否定してから1を加える)で実装できます。
|
||||
言い換えると、符号付き絶対値表現と 2 の補数は互いに相手から $10000$ への「補数」なので、「符号付き絶対値表現から 2 の補数への変換」と「2 の補数から符号付き絶対値表現への変換」は同じ操作(先にビット反転してから 1 を加える)で実現できます。
|
||||
|
||||
もちろん、「最初に否定してから1を加える」の逆操作を使用して2の補数$1110$の符号絶対値を求めることもできます。つまり、「最初に1を減算してから否定する」:
|
||||
もちろん、逆演算を用いて 2 の補数 $1110$ の符号付き絶対値表現を求めることもでき、その場合は「先に 1 を引いてからビット反転する」ことになります。
|
||||
|
||||
$$
|
||||
1110 \rightarrow 1101 \rightarrow 0010
|
||||
$$
|
||||
|
||||
要約すると、「最初に否定してから1を加える」と「最初に1を減算してから否定する」は両方とも$10000$に対する補数を計算しており、等価です。
|
||||
まとめると、「先にビット反転してから 1 を加える」と「先に 1 を引いてからビット反転する」の 2 つの演算は、どちらも $10000$ への補数を計算しており、等価です。
|
||||
|
||||
本質的に、「否定」操作は実際には$1111$に対する補数を求めることです(`符号絶対値 + 1の補数 = 1111`が常に成り立つため)。そして1の補数に1を加えることは$10000$に対する2の補数と等しくなります。
|
||||
本質的には、「ビット反転」という操作は実際には $1111$ への補数を求めています(常に `符号付き絶対値表現 + 1 の補数 = 1111` が成り立つため)。そして、1 の補数にさらに 1 を加えて得られる 2 の補数が、$10000$ への補数です。
|
||||
|
||||
上記では$n = 4$を例に取りましたが、任意の桁数の任意の二進数に一般化できます。
|
||||
上記では $n = 4$ を例にしましたが、この考え方は任意のビット長の 2 進数に一般化できます。
|
||||
|
||||
Reference in New Issue
Block a user