Emphasis

  • 算法的确定性是指指令不能有二义性

  • 数据在计算机内有链式顺序两种存储方式,在存储空间使用的灵活性上,链式存储要比顺序存储要

  • 数据在计算机存储器内表示时,物理地址与逻辑地址不相同的,称之为链式存储结构

  • 数据结构是指数据元素的组织形式

  • 线性结构的特点是元素之间的关系是一对一的关系

  • 输出一个二维数组b[m][n]中所有元素值的时间复杂度为 O(m*n)

  • 某算法的时间复杂度为 O(n*2) ,表明该算法的 执行时间与 n*2 成正比

  • 设f(n)=nsin(n),则f(n)的渐进时间复杂度为 O(n)

  • 被计算机加工的数据元素不是孤立的,它们彼此之间一般存在某种关系,通常把数据元素之间的这种关系称为 结构

  • 在Data structure=(D,R)中,D是 数据元素 的有限集合

  • 数据结构的讨论包括数据的逻辑结构存储结构基本运算等三个方面

  • 以下选项中 高效性 不是算法必须具备的特性

  • 顺序存储结构中数据元素之间的逻辑关系是由 存储位置 表示的

  • 数据元素是数据的基本单位

  • 与数据元素本身的形式、内容、相对位置、个数无关的是数据的 逻辑结构

  • 数据项是数据的最小单位

  • 树形结构是数据元素之间存在的一种 一对多关系

  • 计算机所处理的数据一般具备某种内在联系,这是指 元素和元素之间存在某种关系

  • 数据采用链式存储结构时,要求 每个结点占用一片连续的存储区域

  • 可以用 抽象数据类型 定义一个完整的数据结构

  • 以下属于逻辑结构的是 有序表

  • 计算机算法必须具备输入、输出和有限性、确定性、可执行性等五个特性

Linear list

  • 在一个以L为头指针的单循环链表中,p指针指向链尾的条件是 p->next==L

  • 设对 n(n>1)个元素的线性表的运算只有4种:删除第一个元素,删除最后一个元素,在第一个元素之前插入新元素,在最后一个元素之后插入新元素,则最好使用 只有头结点指针没有尾结点指针的循环双链表

  • 在一个单链表中,已知 q 所指结点是 p 所指结点的前驱结点,若在q和p之间插入结点s,则执行 q->next=s;s->next=p;

  • 在不带头结点的尾指针为tail的单循环链表中,线性表中只有一个结点的条件是
    tail->next==tail

  • 创建一个包括n个结点的有序单链表的时间复杂度是 O(n*2)

  • 在单链表中,要将s所指结点插入到p所指结点之后,其语句应 s->next=p->next;p->next=s;

  • 在双向链表存储结构中,删除p所指的结点时须修改指针 p->prior->next=p->next;p->next->prior=p->prior;

  • 在双向循环链表中,在p指针所指的结点后插入q所指向的新结点,其修改指针的操作是 q->prior=p;q->next=p->next;p->next->prior=q;p->next=q;

  • 不带头结点的单链表head为空的判定条件是 head==NULL

  • 已知指针h指向一个带头结点的非空单循环链表,结点结构为:(data,next),其中next是指向直接后继结点的指针,p是尾指针,q为临时指针。现要删除该链表的第一个元素,正确的语句序列是 q=h->next; h->next=q->next; if(p==q) p=h; free(q);

  • 现有非空双向链表 L,其结点结构为prer、data、next。prer 是指向前直接前驱结点的指针,next 是指向直接后继结点的指针。若要在 L 中指针 p 所指向的结点(非尾结点)之后插入指针 s 指向的新结点, 则在执行了语句序列:“**s->next=p->next;p->next=s;**”后,还要执行 s->prer=s->next->prer; s->next->prer=s;

  • 在循环链表中,将头指针改设为尾指针(rear)后,其首元结点和尾结点的存储位置分别是 rear->next->next和rear

Stack and Queue

  • 栈和队列具有相同的 逻辑结构

  • 顺序栈存放在数组 a[n] 中,top指向栈顶,top= -1 表示栈空。在栈不满的情况下,元素x进栈的操作为 a[++top]=x

  • 若一个栈以向量 V[1,…,n] 存储,初始栈顶指针top设为n+1,则元素x进栈的正确操作是 top--; V[top]=x;

  • 一个递归算法必须包括 终止条件和递归部分

  • 将编号为0和1的两个栈存放于同一个数组空间 v[m] 中,栈底分别处于数组的两端。0号栈的栈顶 top[0]=-1 时栈空;1号栈的栈顶 top[1]=m 时栈空。则判断此共享栈已满的条件是 top[0]==top[1]-1

  • 循环队列存放在数组 Q[n] 中。h指向头元素,t指向队尾元素的后一个位置。设队列中元素个数小于n,则队列中一共有 (n+t-h)%n 个元素

作业A*寻路算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
#include <graphics.h>

using namespace std;

#define ROWS 10 // 行
#define COLS 10 // 列

#define ZXDJ 10
#define XXDJ 14

//图形化定义,一个格子的宽高
#define SPACE 50

IMAGE road, wall, pos, ren;

enum direct { p_up, p_down, p_left, p_right, p_lup, p_ldown, p_rup, p_rdown };

struct MyPoint {
int row; // y
int col; // x
int f, g, h;

void getF() { f = g + h; }
};

struct treeNode {
MyPoint pos;
treeNode* pParent;
vector<treeNode*> child;
};

treeNode* createNode(MyPoint pos) {
treeNode* pNew = new treeNode{
MyPoint{pos.row, pos.col, 0, 0, 0},
nullptr,
vector<treeNode*>()
};
return pNew;
}

int getH(MyPoint pos, MyPoint endPos);

void releaseMemory(const vector<treeNode*>& nodes) {
for (auto node : nodes) {
delete node;
}
}

void printMap(const vector<vector<bool>>& pathMap, const int map[ROWS][COLS]) {
for (int i = 0; i < ROWS; ++i) {
for (int j = 0; j < COLS; ++j) {
if (pathMap[i][j]) {
cout << "X "; // Mark the path
}
else if (map[i][j] == 1) {
cout << "# "; // Obstacle
}
else {
cout << ". "; // Empty space
}
}
cout << endl;
}
cout << endl;
}

//图形界面显示地图
void drawMap(int map[ROWS][COLS]);

void printCurrentPosition(const MyPoint& pos) {
cout << "当前位置: (" << pos.row + 1 << "," << pos.col + 1 << ")" << endl;
}

int main() {

//做窗口
initgraph(COLS * SPACE, ROWS * SPACE, SHOWCONSOLE);

loadimage(&road, L"road.bmp", SPACE, SPACE, true);
loadimage(&wall, L"wall.bmp", SPACE, SPACE, true);
// 加载 ren 图片
loadimage(&ren, L"ren.bmp", SPACE, SPACE, true);


// 0 路 1 墙
int map[ROWS][COLS] = {
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 0, 1, 0, 0, 1, 1, 0, 0, 1 },
{ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1 },
{ 1, 0, 1, 1, 0, 1, 1, 0, 1, 1 },
{ 1, 0, 0, 0, 0, 0, 1, 0, 1, 1 },
{ 1, 0, 1, 0, 1, 1, 1, 0, 1, 1 },
{ 1, 0, 1, 0, 0, 0, 0, 0, 1, 1 },
{ 1, 0, 1, 0, 1, 1, 1, 0, 0, 1 },
{ 1, 0, 1, 0, 1, 1, 1, 0, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
};

vector<vector<bool>> pathMap(ROWS, vector<bool>(COLS, false));


MyPoint begPos = { 1, 1 };
MyPoint endPos = { 7, 8 };

pathMap[begPos.row][begPos.col] = true;
treeNode* pRoot = createNode(begPos);

vector<treeNode*> buff;
vector<treeNode*>::iterator it;
vector<treeNode*>::iterator itMin;

treeNode* pCurrent = pRoot;
bool isFindEnd = false;

// 在图形界面中显示当前位置
putimage(pCurrent->pos.col * SPACE, pCurrent->pos.row * SPACE, &pos);
drawMap(map);

// 显示 ren 图像
putimage(pCurrent->pos.col * SPACE, pCurrent->pos.row * SPACE, &ren);

while (1) {
// 清除上一个位置的 ren 图像
putimage(pCurrent->pos.col * SPACE, pCurrent->pos.row * SPACE, &road);
for (int i = 0; i < 8; i++) {
treeNode* pTemp = createNode(pCurrent->pos);
switch (i) {
case p_up:
pTemp->pos.row--;
pTemp->pos.g += ZXDJ;
break;
case p_down:
pTemp->pos.row++;
pTemp->pos.g += ZXDJ;
break;
case p_left:
pTemp->pos.col--;
pTemp->pos.g += ZXDJ;
break;
case p_right:
pTemp->pos.col++;
pTemp->pos.g += ZXDJ;
break;
case p_lup:
pTemp->pos.row--;
pTemp->pos.col--;
pTemp->pos.g += XXDJ;
break;
case p_ldown:
pTemp->pos.row++;
pTemp->pos.col--;
pTemp->pos.g += XXDJ;
break;
case p_rup:
pTemp->pos.row--;
pTemp->pos.col++;
pTemp->pos.g += XXDJ;
break;
case p_rdown:
pTemp->pos.row++;
pTemp->pos.col++;
pTemp->pos.g += XXDJ;
break;
}

if (pTemp->pos.row >= 0 && pTemp->pos.row < ROWS &&
pTemp->pos.col >= 0 && pTemp->pos.col < COLS &&
!pathMap[pTemp->pos.row][pTemp->pos.col] &&
map[pTemp->pos.row][pTemp->pos.col] == 0) {
pTemp->pos.h = getH(pTemp->pos, endPos);
pTemp->pos.getF();
pCurrent->child.push_back(pTemp);
pTemp->pParent = pCurrent;
buff.push_back(pTemp);
}
else {
delete pTemp;
}
}

if (buff.empty()) {
break;
}

itMin = min_element(buff.begin(), buff.end(), [](const treeNode* a, const treeNode* b) {
return a->pos.f < b->pos.f;
});

pCurrent = *itMin;
pathMap[pCurrent->pos.row][pCurrent->pos.col] = true;
printMap(pathMap, map);
printCurrentPosition(pCurrent->pos);
buff.erase(itMin);

// 在新位置显示 ren 图像
putimage(pCurrent->pos.col* SPACE, pCurrent->pos.row* SPACE, &ren);

// 保留这一行用于显示图形窗口,不要关闭窗口
getchar();

if (pCurrent->pos.row == endPos.row && pCurrent->pos.col == endPos.col) {
isFindEnd = true;
break;
}
}

if (isFindEnd) {
cout << "找到终点了!" << endl;
cout << "最终路径: ";
while (pCurrent) {
cout << "(" << pCurrent->pos.row + 1 << "," << pCurrent->pos.col + 1 << ")";
pCurrent = pCurrent->pParent;
}
cout << endl;
}
else {
cout << "未找到路径!" << endl;
}

releaseMemory(buff);

return 0;
}

int getH(MyPoint pos, MyPoint endPos) {
int x = (pos.col > endPos.col) ? (pos.col - endPos.col) : (endPos.col - pos.col);
int y = (pos.row > endPos.row) ? (pos.row - endPos.row) : (endPos.row - pos.row);
return (x + y) * ZXDJ;
}

//图形界面显示地图
void drawMap(int map[ROWS][COLS]) {
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
if (map[i][j] == 1) { //墙壁
putimage(j * SPACE, i * SPACE, &wall);
}
else { //路
putimage(j * SPACE, i * SPACE, &road);
}
}
}
}