mirror of
https://github.com/krahets/hello-algo.git
synced 2026-04-24 18:43:59 +08:00
build
This commit is contained in:
@@ -20,9 +20,9 @@ comments: true
|
||||
- 整数类型 `byte` 占用 $1$ byte = $8$ bits ,可以表示 $2^{8}$ 个数字。
|
||||
- 整数类型 `int` 占用 $4$ bytes = $32$ bits ,可以表示 $2^{32}$ 个数字。
|
||||
|
||||
下表列举了各种基本数据类型的占用空间、取值范围和默认值。此表格无须硬背,大致理解即可,需要时可以通过查表来回忆。
|
||||
表 3-1 列举了各种基本数据类型的占用空间、取值范围和默认值。此表格无须硬背,大致理解即可,需要时可以通过查表来回忆。
|
||||
|
||||
<p align="center"> 表:基本数据类型的占用空间和取值范围 </p>
|
||||
<p align="center"> 表 3-1 基本数据类型的占用空间和取值范围 </p>
|
||||
|
||||
<div class="center-table" markdown>
|
||||
|
||||
@@ -39,9 +39,9 @@ comments: true
|
||||
|
||||
</div>
|
||||
|
||||
对于上表,需要注意以下几点:
|
||||
对于表 3-1 ,需要注意以下几点:
|
||||
|
||||
- C, C++ 未明确规定基本数据类型大小,而因实现和平台各异。上表遵循 LP64 [数据模型](https://en.cppreference.com/w/cpp/language/types#Properties),其用于 Unix 64 位操作系统(例如 Linux , macOS)。
|
||||
- C, C++ 未明确规定基本数据类型大小,而因实现和平台各异。表 3-1 遵循 LP64 [数据模型](https://en.cppreference.com/w/cpp/language/types#Properties),其用于 Unix 64 位操作系统(例如 Linux , macOS)。
|
||||
- 字符 `char` 的大小在 C, C++ 中为 1 字节,在大多数编程语言中取决于特定的字符编码方法,详见“字符编码”章节。
|
||||
- 即使表示布尔量仅需 1 位($0$ 或 $1$),它在内存中通常被存储为 1 字节。这是因为现代计算机 CPU 通常将 1 字节作为最小寻址内存单元。
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@ comments: true
|
||||
|
||||
## 3.4.1 ASCII 字符集
|
||||
|
||||
「ASCII 码」是最早出现的字符集,全称为“美国标准信息交换代码”。它使用 7 位二进制数(即一个字节的低 7 位)表示一个字符,最多能够表示 128 个不同的字符。如下图所示,ASCII 码包括英文字母的大小写、数字 0-9 、一些标点符号,以及一些控制字符(如换行符和制表符)。
|
||||
「ASCII 码」是最早出现的字符集,全称为“美国标准信息交换代码”。它使用 7 位二进制数(即一个字节的低 7 位)表示一个字符,最多能够表示 128 个不同的字符。如图 3-6 所示,ASCII 码包括英文字母的大小写、数字 0-9 、一些标点符号,以及一些控制字符(如换行符和制表符)。
|
||||
|
||||

|
||||
|
||||
<p align="center"> 图:ASCII 码 </p>
|
||||
<p align="center"> 图 3-6 ASCII 码 </p>
|
||||
|
||||
然而,**ASCII 码仅能够表示英文**。随着计算机的全球化,诞生了一种能够表示更多语言的字符集「EASCII」。它在 ASCII 的 7 位基础上扩展到 8 位,能够表示 256 个不同的字符。
|
||||
|
||||
@@ -36,11 +36,11 @@ comments: true
|
||||
|
||||
Unicode 是一种字符集标准,本质上是给每个字符分配一个编号(称为“码点”),**但它并没有规定在计算机中如何存储这些字符码点**。我们不禁会问:当多种长度的 Unicode 码点同时出现在同一个文本中时,系统如何解析字符?例如给定一个长度为 2 字节的编码,系统如何确认它是一个 2 字节的字符还是两个 1 字节的字符?
|
||||
|
||||
对于以上问题,**一种直接的解决方案是将所有字符存储为等长的编码**。如下图所示,“Hello”中的每个字符占用 1 字节,“算法”中的每个字符占用 2 字节。我们可以通过高位填 0 ,将“Hello 算法”中的所有字符都编码为 2 字节长度。这样系统就可以每隔 2 字节解析一个字符,恢复出这个短语的内容了。
|
||||
对于以上问题,**一种直接的解决方案是将所有字符存储为等长的编码**。如图 3-7 所示,“Hello”中的每个字符占用 1 字节,“算法”中的每个字符占用 2 字节。我们可以通过高位填 0 ,将“Hello 算法”中的所有字符都编码为 2 字节长度。这样系统就可以每隔 2 字节解析一个字符,恢复出这个短语的内容了。
|
||||
|
||||

|
||||
|
||||
<p align="center"> 图:Unicode 编码示例 </p>
|
||||
<p align="center"> 图 3-7 Unicode 编码示例 </p>
|
||||
|
||||
然而 ASCII 码已经向我们证明,编码英文只需要 1 字节。若采用上述方案,英文文本占用空间的大小将会是 ASCII 编码下大小的两倍,非常浪费内存空间。因此,我们需要一种更加高效的 Unicode 编码方法。
|
||||
|
||||
@@ -53,7 +53,7 @@ UTF-8 的编码规则并不复杂,分为两种情况:
|
||||
1. 对于长度为 1 字节的字符,将最高位设置为 $0$ 、其余 7 位设置为 Unicode 码点。值得注意的是,ASCII 字符在 Unicode 字符集中占据了前 128 个码点。也就是说,**UTF-8 编码可以向下兼容 ASCII 码**。这意味着我们可以使用 UTF-8 来解析年代久远的 ASCII 码文本。
|
||||
2. 对于长度为 $n$ 字节的字符(其中 $n > 1$),将首个字节的高 $n$ 位都设置为 $1$ 、第 $n + 1$ 位设置为 $0$ ;从第二个字节开始,将每个字节的高 2 位都设置为 $10$ ;其余所有位用于填充字符的 Unicode 码点。
|
||||
|
||||
下图展示了“Hello算法”对应的 UTF-8 编码。观察发现,由于最高 $n$ 位都被设置为 $1$ ,因此系统可以通过读取最高位 $1$ 的个数来解析出字符的长度为 $n$ 。
|
||||
图 3-8 展示了“Hello算法”对应的 UTF-8 编码。观察发现,由于最高 $n$ 位都被设置为 $1$ ,因此系统可以通过读取最高位 $1$ 的个数来解析出字符的长度为 $n$ 。
|
||||
|
||||
但为什么要将其余所有字节的高 2 位都设置为 $10$ 呢?实际上,这个 $10$ 能够起到校验符的作用。假设系统从一个错误的字节开始解析文本,字节头部的 $10$ 能够帮助系统快速的判断出异常。
|
||||
|
||||
@@ -61,7 +61,7 @@ UTF-8 的编码规则并不复杂,分为两种情况:
|
||||
|
||||

|
||||
|
||||
<p align="center"> 图:UTF-8 编码示例 </p>
|
||||
<p align="center"> 图 3-8 UTF-8 编码示例 </p>
|
||||
|
||||
除了 UTF-8 之外,常见的编码方式还包括:
|
||||
|
||||
|
||||
@@ -10,14 +10,14 @@ comments: true
|
||||
|
||||
**逻辑结构揭示了数据元素之间的逻辑关系**。在数组和链表中,数据按照顺序依次排列,体现了数据之间的线性关系;而在树中,数据从顶部向下按层次排列,表现出祖先与后代之间的派生关系;图则由节点和边构成,反映了复杂的网络关系。
|
||||
|
||||
如下图所示,逻辑结构可被分为“线性”和“非线性”两大类。线性结构比较直观,指数据在逻辑关系上呈线性排列;非线性结构则相反,呈非线性排列。
|
||||
如图 3-1 所示,逻辑结构可被分为“线性”和“非线性”两大类。线性结构比较直观,指数据在逻辑关系上呈线性排列;非线性结构则相反,呈非线性排列。
|
||||
|
||||
- **线性数据结构**:数组、链表、栈、队列、哈希表。
|
||||
- **非线性数据结构**:树、堆、图、哈希表。
|
||||
|
||||

|
||||
|
||||
<p align="center"> 图:线性与非线性数据结构 </p>
|
||||
<p align="center"> 图 3-1 线性与非线性数据结构 </p>
|
||||
|
||||
非线性数据结构可以进一步被划分为树形结构和网状结构。
|
||||
|
||||
@@ -29,21 +29,21 @@ comments: true
|
||||
|
||||
在计算机中,内存和硬盘是两种主要的存储硬件设备。硬盘主要用于长期存储数据,容量较大(通常可达到 TB 级别)、速度较慢。内存用于运行程序时暂存数据,速度较快,但容量较小(通常为 GB 级别)。
|
||||
|
||||
**在算法运行过程中,相关数据都存储在内存中**。下图展示了一个计算机内存条,其中每个黑色方块都包含一块内存空间。我们可以将内存想象成一个巨大的 Excel 表格,其中每个单元格都可以存储一定大小的数据,在算法运行时,所有数据都被存储在这些单元格中。
|
||||
**在算法运行过程中,相关数据都存储在内存中**。图 3-2 展示了一个计算机内存条,其中每个黑色方块都包含一块内存空间。我们可以将内存想象成一个巨大的 Excel 表格,其中每个单元格都可以存储一定大小的数据,在算法运行时,所有数据都被存储在这些单元格中。
|
||||
|
||||
**系统通过内存地址来访问目标位置的数据**。如下图所示,计算机根据特定规则为表格中的每个单元格分配编号,确保每个内存空间都有唯一的内存地址。有了这些地址,程序便可以访问内存中的数据。
|
||||
**系统通过内存地址来访问目标位置的数据**。如图 3-2 所示,计算机根据特定规则为表格中的每个单元格分配编号,确保每个内存空间都有唯一的内存地址。有了这些地址,程序便可以访问内存中的数据。
|
||||
|
||||

|
||||
|
||||
<p align="center"> 图:内存条、内存空间、内存地址 </p>
|
||||
<p align="center"> 图 3-2 内存条、内存空间、内存地址 </p>
|
||||
|
||||
内存是所有程序的共享资源,当某块内存被某个程序占用时,则无法被其他程序同时使用了。**因此在数据结构与算法的设计中,内存资源是一个重要的考虑因素**。比如,算法所占用的内存峰值不应超过系统剩余空闲内存;如果缺少连续大块的内存空间,那么所选用的数据结构必须能够存储在离散的内存空间内。
|
||||
|
||||
如下图所示,**物理结构反映了数据在计算机内存中的存储方式**,可分为连续空间存储(数组)和离散空间存储(链表)。物理结构从底层决定了数据的访问、更新、增删等操作方法,同时在时间效率和空间效率方面呈现出互补的特点。
|
||||
如图 3-3 所示,**物理结构反映了数据在计算机内存中的存储方式**,可分为连续空间存储(数组)和离散空间存储(链表)。物理结构从底层决定了数据的访问、更新、增删等操作方法,同时在时间效率和空间效率方面呈现出互补的特点。
|
||||
|
||||

|
||||
|
||||
<p align="center"> 图:连续空间存储与离散空间存储 </p>
|
||||
<p align="center"> 图 3-3 连续空间存储与离散空间存储 </p>
|
||||
|
||||
值得说明的是,**所有数据结构都是基于数组、链表或二者的组合实现的**。例如,栈和队列既可以使用数组实现,也可以使用链表实现;而哈希表的实现可能同时包含数组和链表。
|
||||
|
||||
|
||||
@@ -18,11 +18,11 @@ comments: true
|
||||
- **反码**:正数的反码与其原码相同,负数的反码是对其原码除符号位外的所有位取反。
|
||||
- **补码**:正数的补码与其原码相同,负数的补码是在其反码的基础上加 $1$ 。
|
||||
|
||||
下图展示了原吗、反码和补码之间的转换方法。
|
||||
图 3-4 展示了原吗、反码和补码之间的转换方法。
|
||||
|
||||

|
||||
|
||||
<p align="center"> 图:原码、反码与补码之间的相互转换 </p>
|
||||
<p align="center"> 图 3-4 原码、反码与补码之间的相互转换 </p>
|
||||
|
||||
「原码 true form」虽然最直观,但存在一些局限性。一方面,**负数的原码不能直接用于运算**。例如在原码下计算 $1 + (-2)$ ,得到的结果是 $-3$ ,这显然是不对的。
|
||||
|
||||
@@ -131,9 +131,9 @@ $$
|
||||
|
||||

|
||||
|
||||
<p align="center"> 图:IEEE 754 标准下的 float 的计算示例 </p>
|
||||
<p align="center"> 图 3-5 IEEE 754 标准下的 float 的计算示例 </p>
|
||||
|
||||
观察上图,给定一个示例数据 $\mathrm{S} = 0$ , $\mathrm{E} = 124$ ,$\mathrm{N} = 2^{-2} + 2^{-3} = 0.375$ ,则有:
|
||||
观察图 3-5 ,给定一个示例数据 $\mathrm{S} = 0$ , $\mathrm{E} = 124$ ,$\mathrm{N} = 2^{-2} + 2^{-3} = 0.375$ ,则有:
|
||||
|
||||
$$
|
||||
\text { val } = (-1)^0 \times 2^{124 - 127} \times (1 + 0.375) = 0.171875
|
||||
@@ -143,9 +143,9 @@ $$
|
||||
|
||||
**尽管浮点数 `float` 扩展了取值范围,但其副作用是牺牲了精度**。整数类型 `int` 将全部 32 位用于表示数字,数字是均匀分布的;而由于指数位的存在,浮点数 `float` 的数值越大,相邻两个数字之间的差值就会趋向越大。
|
||||
|
||||
如下表所示,指数位 $E = 0$ 和 $E = 255$ 具有特殊含义,**用于表示零、无穷大、$\mathrm{NaN}$ 等**。
|
||||
如表 3-2 所示,指数位 $E = 0$ 和 $E = 255$ 具有特殊含义,**用于表示零、无穷大、$\mathrm{NaN}$ 等**。
|
||||
|
||||
<p align="center"> 表:指数位含义 </p>
|
||||
<p align="center"> 表 3-2 指数位含义 </p>
|
||||
|
||||
<div class="center-table" markdown>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user