动态版本的通讯录是在静态版本上进行的一次优化,即实现按照需求开辟空间。和之前版本有所不同,不用一个结构体数组来存放联系人,而是用了一个结构体指针。如下:
#define NAME 20
#define SEX 5
#define TELE 12
#define ADDR 30
#define DEFAULT_SZ 3//初始容量
#define INC_SZ 2//扩容
//联系人信息
struct message
{
//姓名
char name[NAME];
//性别
char sex[SEX];
//电话
char tele[TELE];
//住址
char addr[ADDR];
//年龄
int age;
};
//通讯录
struct contact
{
struct message* data;//结构体指针
int sz;//个数
int capacity;//通讯录容量
};
由于是动态版本的,所以在初始化、增加联系人、以及最后的退出里,有了一定的修改,别的只要不涉及增加空间的操作,都与静态版本相同。这里就不一一再写了。
对于国际象棋中马的走位问题,我们可以使用二维数组来表示棋盘,并使用两个变量表示马当前所在的位置,然后编写一个函数来计算马下一步可能的可行位置,再根据这些位置进行下一步移动。代码实现如下:
#include <iostream>
#include <cstring>
using namespace std;
const int N = 8; // 棋盘的大小为 8x8
int board[N][N]; // 棋盘
// 判断当前点是否合法
bool isValid(int x, int y) {
if (x >= 0 && x < N && y >= 0 && y < N && board[x][y] == -1)
return true;
return false;
}
// 计算马下一步可能的可行位置
void getNextPossiblePositions(int x, int y, int nextX[], int nextY[], int &count) {
count = 0;
// 8 种可能的下一步位置
int dx[] = {2, 1, -1, -2, -2, -1, 1, 2};
int dy[] = {1, 2, 2, 1, -1, -2, -2, -1};
for (int i = 0; i < 8; i++) {
int next_x = x + dx[i];
int next_y = y + dy[i];
if (isValid(next_x, next_y)) {
nextX[count] = next_x;
nextY[count] = next_y;
count++;
}
}
}
// 马走到该点并打印该点的坐标和棋盘
void move(int x, int y, int step) {
board[x][y] = step;
printf("(%d,%d)\n", x, y);
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
printf("%2d ", board[i][j]);
}
printf("\n");
}
printf("\n");
}
// 深度优先搜索
bool dfs(int x, int y, int step) {
// 马走完了整个棋盘,返回 true
if (step == N * N)
return true;
// 获取下一步可能的可行位置
int nextX[N], nextY[N], count = 0;
getNextPossiblePositions(x, y, nextX, nextY, count);
// 对每个位置进行逐一尝试
for (int i = 0; i < count; i++) {
int next_x = nextX[i];
int next_y = nextY[i];
move(next_x, next_y, step + 1); // 马走到该点并打印该点的坐标和棋盘
if (dfs(next_x, next_y, step + 1))
return true;
board[next_x][next_y] = -1; // 回溯
}
return false;
}
int main() {
memset(board, -1, sizeof(board)); // 初始化棋盘
int start_x = 0, start_y = 0; // 马的起始位置
move(start_x, start_y, 0); // 打印起始位置并初始化棋盘
board[start_x][start_y] = 0; // 马走到起始位置
dfs(start_x, start_y, 0); // 深度优先搜索
return 0;
}
在主函数中,我们首先初始化棋盘为 -1(表示该位置没有走过),打印马的起始位置并初始化这个位置已走过,然后调用深度优先搜索函数 dfs 进行搜索。dfs 的参数是当前马所在的位置 (x, y) 和已经走过的步数 step,它会首先判断,如果 step 等于 N 的平方,也就是马走了整个棋盘,代表找到一个解,返回 true;否则,它会获取下一步可能的可行位置,然后依次尝试这些位置。如果尝试某个位置时能找到解,就返回 true;否则,它会回溯到上一步,将当前位置置为未走过(-1)。
getNextPossiblePositions 函数根据当前位置 (x, y) 计算马下一步可能的 8 个位置,返回这些位置的坐标数组 nextX 和 nextY,以及可行位置的数量 count。为了避免使用数组越界,函数中首先利用 isValid 函数判断下一步位置是否越界或者是否已经走过。
在 dfs 函数中需要调用 move 函数将马移动到下一个位置,并打印当前位置的坐标和棋盘。如果 dfs 函数返回 true,代表找到了解,此时就会逐层返回,遇到的每个函数都会将返回值返回给它的调用者,最终返回给主函数,退出程序。否则,主函数就会先尝试另一个起始位置 (1, 0),重复之前的操作,直到找到解或者所有起始位置都被尝试过为止。
值得一提的是,上述代码中使用的是递归实现深度优先搜索。由于一次运行过程中可能会出现很多函数调用,因此在实际应用中,可能会出现栈溢出等问题。为了避免出现这种情况,我们应该使用非递归的深度优先搜索或者广度优先搜索来实现。
hard