|
4 | 4 |
|
5 | 5 | ## ch1.算法评价 |
6 | 6 |
|
7 | | -* 算法有以下五个重要特性: |
8 | | - 1. 输入:算法在执行前需要外界提供0个或多个输入数据。 |
9 | | - 2. 输出:算法在执行后至少产生一个输出数据。 |
10 | | - 3. 有穷性:算法必须在执行有限步骤后终止。 |
11 | | - 4. 确定性:算法的每一步都有确定的含义,不能有歧义。 |
12 | | - 5. 可行性:算法的每一步都能通过有限的时间和空间来完成。 |
13 | | -* 时间复杂度比较: |
| 7 | +* 算法有以下五个重要特性: |
| 8 | + 1. 输入:算法在执行前需要外界提供0个或多个输入数据。 |
| 9 | + 2. 输出:算法在执行后至少产生一个输出数据。 |
| 10 | + 3. 有穷性:算法必须在执行有限步骤后终止。 |
| 11 | + 4. 确定性:算法的每一步都有确定的含义,不能有歧义。 |
| 12 | + 5. 可行性:算法的每一步都能通过有限的时间和空间来完成。 |
| 13 | +* 时间复杂度比较: |
14 | 14 | * $$ O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n) $$ |
15 | 15 |
|
16 | 16 | * 题目 |
|
27 | 27 | 时间复杂度为 O(n),因为外层循环执行 logn 次,内层循环执行 i 次,i 依次为 1,2,4,...,n/2,因此总的执行次数为 1 + 2 + 4 + ... + n/2 = n - 1 = O(n)。 |
28 | 28 |
|
29 | 29 |
|
30 | | - |
31 | | - |
32 | | - |
33 | 30 | ## ch2.线性表 |
34 | 31 |
|
35 | | - |
36 | | - |
| 32 | +### 2.1 定义与操作 |
| 33 | +* 定义:具有相同数据类型的n个数据元素的优先序列 |
| 34 | + |
| 35 | +* 基本操作: |
| 36 | + 1. InitList(&L) |
| 37 | + 2. Length(L) |
| 38 | + 3. LocateElem(L, e) |
| 39 | + 4. GetElem(L, i) |
| 40 | + 5. ListInsert(&L, i, e) |
| 41 | + 6. ListDelete(&L, i, e) |
| 42 | + 7. PrintList(L) |
| 43 | + 8. Empty(L) |
| 44 | + 9. DestroyList(&L) |
| 45 | +### 2.2 顺序表 |
| 46 | +* 定义:一组地址连续的存储单元依次存储线性表中的数据元素,使得逻辑相邻等于物理相邻。 |
| 47 | +* 优缺点 |
| 48 | + * 优点:存储密度高,随机存取,访问速度快。 |
| 49 | + * 缺点:插入和删除操作需要移动大量元素,空间利用率不高。 |
| 50 | +* 基本操作: |
| 51 | + 1. InitList(&L) |
| 52 | + * 初始化顺序表长度,根据动态与否分配一段连续的存储空间。 |
| 53 | + 2. ListInsert(&L, i, e) |
| 54 | + * 插入元素e到顺序表L的第i个位置,i从1开始计数。最好最坏平均分别为 O(1), O(n), O(n)。 |
| 55 | + 3. ListDelete(&L, i, e) |
| 56 | + * 删除顺序表L的第i个位置的元素,并将其值赋给e。最好最坏平均分别为 O(1), O(n), O(n)。 |
| 57 | + 4. LocateElem(L, e) |
| 58 | + * 查找顺序表L中值为e的元素,返回其位置。最好最坏平均分别为 O(1), O(n), O(n)。 |
| 59 | + 5. GetElem(L, i) |
| 60 | + * 获取顺序表L的第i个位置的元素。自然为 O(1)。 |
| 61 | +### 2.3 链表 |
| 62 | +* 定义:使用data|next结构存储线性表中的数据元素,data存储数据元素,next存储下一个元素的地址。 |
| 63 | + ``` |
| 64 | + typedef struct LNode { |
| 65 | + ElemType data; |
| 66 | + struct LNode *next; |
| 67 | + } LNode, *LinkList; |
| 68 | + ``` |
| 69 | +* 特性:非随机存取,离散,遍历,可带头结点(头结点不存储数据,可存表长)。 |
| 70 | +* 解决问题:插入删除O(1),头结点使得第一个点不特殊(不必头指针处理),便于处理。 |
| 71 | +* 基本操作: |
| 72 | + 1. InitList(&L) |
| 73 | + ``` |
| 74 | + L = (LNode *)malloc(sizeof(LNode)); |
| 75 | + L->next = NULL; |
| 76 | + return true; |
| 77 | + ``` |
| 78 | + 2. Length(L) |
| 79 | + 3. GetElem(L, i) |
| 80 | + 4. LocateElem(L, e) |
| 81 | + 5. ListInsert(&L, i, e) |
| 82 | + * 前插法需要找到第i-1个结点p,而后插法可以直接通过第i个结点p执行插入 |
| 83 | + 6. ListDelete(&L, i, e) |
| 84 | + 7. List_HeadInsert(&L, e) |
| 85 | + 8. List_TailInsert(&L, e) |
| 86 | +* 双向链表 |
| 87 | + ``` |
| 88 | + typedef struct DNode { |
| 89 | + ElemType data; |
| 90 | + struct DNode *prior, *next; |
| 91 | + } DNode, *DLinkList; |
| 92 | + ``` |
| 93 | + * 操作:插入删除 |
| 94 | +* 循环链表 |
| 95 | + * 单向循环链表:尾结点的next指向头结点 |
| 96 | + * 双向循环链表:头结点的prior指向尾结点,尾结点的next指向头结点 |
| 97 | +* 静态链表 |
| 98 | + * 用数组模拟链表,数组下标作为指针使用 |
| 99 | + * 适用于结点频繁插入删除的场景 |
| 100 | + * 需要一个备用链表来存储空闲结点 |
| 101 | + ``` |
| 102 | + typedef struct { |
| 103 | + ElemType data; |
| 104 | + int next; // 下一个元素的数组下标 |
| 105 | + } SLinkList[MAXSIZE]; |
| 106 | + ``` |
| 107 | + * next == -1 作为结束标志 |
37 | 108 |
|
38 | 109 | ## ch3.栈、队列和数组 |
39 | 110 |
|
| 111 | +### 3.1 栈 |
| 112 | +* 定义: LIFO(后进先出)数据结构 |
| 113 | +* 特性: 只能在栈顶进行插入和删除操作 |
| 114 | +* 基本操作: |
| 115 | + 1. InitStack(&S) |
| 116 | + 2. StackEmpty(S) |
| 117 | + 3. Push(&S, e) |
| 118 | + 4. Pop(&S, &e) |
| 119 | + 5. GetTop(S, &e) |
| 120 | + 6. DestroyStack(&S) |
| 121 | +* 特性: $n$ 个不同元素进栈时,出栈元素的不同排列数为 $C_n = \dfrac{1}{n+1} \binom{2n}{n}$(卡特兰数) |
| 122 | +
|
| 123 | +#### 3.1.1 栈的顺序存储 |
| 124 | +* 定义:使用一段地址连续的存储单元依次存储栈中的数据元素,top指向栈顶元素,初始值为-1. |
| 125 | + ```` |
| 126 | + typedef struct { |
| 127 | + ElemType data[MAXSIZE]; |
| 128 | + int top; // 栈顶指针 |
| 129 | + } SqStack; |
| 130 | + ```` |
| 131 | +* 操作: |
| 132 | + 1. InitStack(&S) |
| 133 | + 2. StackEmpty(S) |
| 134 | + 3. Push(&S, e) |
| 135 | + 4. Pop(&S, &e) |
| 136 | + 5. GetTop(S, &e) |
| 137 | +
|
| 138 | +* 共享栈 |
| 139 | + ```` |
| 140 | + 0 MAXSIZE-1 |
| 141 | + | | | | |
| 142 | +bottom 0 top0 top1 bottom 1 |
| 143 | + ```` |
| 144 | + * top0从左向右增长,top1从右向左增长 |
| 145 | + * top0 + 1 == top1 时栈满 |
| 146 | + * top0 == -1 时栈0空,top1 == MAXSIZE 时栈1空 |
| 147 | +
|
| 148 | +* 链式栈 |
| 149 | + * 定义:使用链表存储栈中的数据元素,LHead指向栈顶元素。 |
| 150 | + ```` |
| 151 | + typedef struct LNode { |
| 152 | + ElemType data; |
| 153 | + struct LNode *next; |
| 154 | + } LNode, *LinkStack; |
| 155 | + ```` |
| 156 | +### 3.2 队列 |
| 157 | +* 定义: FIFO(先进先出)数据结构 |
| 158 | +```` |
| 159 | +typedef struct { |
| 160 | + ElemType data[MAXSIZE]; |
| 161 | + int front, rear; // 队头和队尾指针 |
| 162 | +} SqQueue; |
| 163 | +```` |
| 164 | +* 特性: 只能在队头(Front)进行删除操作,在队尾(Rear)进行插入操作 |
| 165 | +* 基本操作: |
| 166 | + 1. InitQueue(&Q) |
| 167 | + 2. QueueEmpty(Q) |
| 168 | + 3. EnQueue(&Q, e) |
| 169 | + 4. DeQueue(&Q, &e) |
| 170 | + 5. GetHead(Q, &e) |
| 171 | + 6. DestroyQueue(&Q) |
| 172 | +* 问题: |
| 173 | + * 队列满: rear == MAXSIZE 产生"假队列溢出" |
| 174 | + * 队列空: front == rear |
| 175 | +* 循环队列 |
| 176 | + * 初始时: front == rear == 0 |
| 177 | + * 队首指针进1: front = (front + 1) % MAXSIZE |
| 178 | + * 队尾指针进1: rear = (rear + 1) % MAXSIZE |
| 179 | + * 队列长度: (rear - front + MAXSIZE) % MAXSIZE |
| 180 | + * 出队入队:指针顺时针加一 |
| 181 | + * 队列空: front == rear |
| 182 | + * 三种处理方式: |
| 183 | + * 牺牲一个单元区分队空和满,入队时少用一个队列单元 |
| 184 | + * 队满: (rear + 1) % MAXSIZE == front |
| 185 | + * 队空: front == rear |
| 186 | + * 元素个数: (rear - front + MAXSIZE) % MAXSIZE |
| 187 | + * 增加size变量记录队列长度 |
| 188 | + * 队满: size == MAXSIZE |
| 189 | + * 队空: size == 0 |
| 190 | + * 元素个数: size |
| 191 | + * 新加tag区分队空和满 |
| 192 | + * 队满: 插入导致rear == front 置tag == 1 |
| 193 | + * 队空: 删除导致front == rear 置tag == 0 |
| 194 | + * 元素个数: (rear - front + MAXSIZE) % MAXSIZE |
| 195 | +  |
| 196 | +* 队列的链式存储 |
| 197 | + * 定义:使用链表存储队列中的数据元素,QHead指向队头元素,QTail指向队尾元素。 |
| 198 | + ```` |
| 199 | + typedef struct LinkNode { |
| 200 | + ElemType data; |
| 201 | + struct LinkNode *next; |
| 202 | + } LinkNode; |
| 203 | + typedef struct { |
| 204 | + LinkNode *front, *rear; // 队头和队尾指针 |
| 205 | + } LinkQueue; |
| 206 | + ```` |
| 207 | + * 不带头结点时,front == rear == NULL,则队列空。但是常用头结点单链表 |
| 208 | +
|
| 209 | +
|
| 210 | +* 双端队列 |
| 211 | + * 定义:可以在队头和队尾进行插入和删除操作 |
| 212 | + * 输入/输出受限的队列:只能在一端进行插入操作,或只能另一端进行删除操作 |
| 213 | + * !!!这里需要做一下题 |
| 214 | +
|
| 215 | +
|
| 216 | +### 3.3 应用 |
| 217 | +记录几道题: |
| 218 | +!!!做题 |
| 219 | +### 3.4 数组和特殊矩阵 |
| 220 | +!!!做题 |
| 221 | +
|
40 | 222 | ## ch4.串 |
41 | 223 |
|
| 224 | +
|
42 | 225 | ## ch5.树与二叉树 |
43 | 226 |
|
44 | 227 | ## ch6.图 |
|
0 commit comments