diff --git a/ch2/README.md b/ch2/README.md index d73ff8e..24a4d51 100644 --- a/ch2/README.md +++ b/ch2/README.md @@ -101,3 +101,93 @@ Tips: - 不支持指针的低级语言。 - 数据元素数量固定不变的场景(如操作系统的文件分配表 FAT)。 + +## 9. 顺序表 VS 链表 + +三要素: + +1. 逻辑结构 +2. 物理结构/存储结构 +3. 数据的运算/基本操作 + +| | 顺序表 | 链表 | +| -------- | -------- | ------------ | +| 随机存取 | **支持** | 不支持 | +| 存储密度 | **高** | 不高 | +| 存储空间 | 大片连续 | **小且离散** | +| 改变容量 | 麻烦 | **方便** | + +基本操作 + +- **创** +- 销 +- **增** +- **删** +- 改 +- **查** + +### 9.1. 创建 + +- 顺序表:需要预分配大片联系空间。若分配空间过小,则之后不方便扩展容量;若分配空间过大,则浪费内存资源。 + - 静态分配,静态数据,容量不可改变。 + - 动态分配,动态数据(`malloc`,`free`),容量可以改变,但需要移动大量元素,时间代价高。 +- **链表**:只需要分配一个头结点(也可以不要头结点,只声明一个头指针),之后方便扩展。 + +### 9.2. 销毁 + +- 顺序表:修改 `Length=0`。 + - 静态分配,静态数组,系统自动回收空间。 + - 动态分配,动态数组,需要手动 `free`。(属于内存模型的堆区) +- 链表:依次删除各个结点(`free`)。 + +成对出现: + +```cpp +L.data = (ElemType *)malloc(sizeof(ElemType * InitSize)); +``` + +```cpp +free(L.data); +``` + +### 9.3. 增、删 + +- 顺序表:插入/删除元素要将后续元素都后移/前移。时间复杂度为 $O(n)$,时间开销主要来自移动元素。 +- **链表**:插入/删除元素只需要修改指针即可。时间复杂度为 $O(n)$,时间开销主要来自查找目标元素。 + +> 若数据元素很大,则移动的时间代价很高;查找元素的时间代价更低。 + +### 9.4. 查找 + +- **顺序表** + - 按位查找:时间复杂度为 $O(1)$。 + - 按值查找:时间复杂度为 $O(n)$,若表内元素有序,则时间复杂度为 $O(log_2n)$。 +- 链表: + - 按位查找:时间复杂度为 $O(n)$。 + - 按值查找:时间复杂度为 $O(n)$。 + +### 9.5. 总结 + +| | 顺序表 | 链表 | +| -------------- | ------ | ---- | +| 弹性(可扩容) | × | √ | +| 增、删 | × | √ | +| 查 | √ | × | + +根据场景选择顺序表或链表: + +- 表长难于预估、经常要增加/删除元素:链表 +- 表长可预估、查询(搜索)操作较多:顺序表 + +**问题**: + +请描述顺序表和链表的 bla bla bla +实现线性表时,用顺序表还是链表好? + +**答题思路**: + +顺序表和链表的逻辑结构都是线性结构,都属于线性表。 + +但是二者的存储结构不同,顺序表采用顺序存储...(特点,带来的优点缺点):链表采用链式存储...(特点、导致的优缺点)。 + +由于采用不同的存储方式实现,因此基本操作的实现效率也不同。当初始化时...当插入一个数据元素时...;当删除一个数据元素时...;当查找一合数据元素时...