程序设计基础实训(代码)


最近在忙实训代码,其实就是几个数据结构的问题。

迷宫问题,图的遍历,prim算法

迷宫问题

#include <bits/stdc++.h>
using namespace std;
const int N = 1e3;

/*
author: stormjing
coding=utf-8
*/

int maze[N][N]; // 储存迷宫
char prin[N][N]; // 打印数组(递归是输出用)
int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; // 方向右、下、左、上,用1, 2, 3, 4表示
int vis[N][N]; // 标记数组
int cnt[N][N]; // 记录当前位置走过几个方向 (非递归迭代时用)
int m, n; // 迷宫长宽

struct pos{ // 坐标
int x, y;
pos(){}
pos(int x, int y):x(x), y(y){}
};

//*********************** 链栈 *******************************************

typedef struct List{ // 链表,作为栈的存储结构
pos data;
struct List *next;
} Link_list;

typedef struct node{ // 链栈,无头节点
Link_list *base; // 头指针
int size; // 栈的大小
node(){ // 初始化
base = NULL;
size = 0;
}
void push(pos x){ // 头插法
Link_list *temp = (Link_list *)malloc(sizeof(Link_list));
temp->data = x;
temp->next = base; //将新元素作为栈顶元素
base = temp;
size++;
}
pos top(){ // 返回栈顶元素
return base->data;
}
bool empty(){ // 判断栈空
if(size == 0)
return true;
else
return false;
}
pos pop(){ // 弹出元素
if(!empty()){
Link_list *temp = base;
base = base->next;
size--;
free(temp); // 释放内存
}
}
int print(pos a[]){ // 将栈元素存数组里,(打印时用)
Link_list *temp = base;
int i = 0;
while(temp){
a[i++] = temp->data;
temp = temp->next;
}
return i; // 返回数组大小
}
} Stack;

bool inside(int x, int y){ // 判断是否越界
if(x >= 1 && x <= m && y >= 1 && y <= n){
return true;
}else{
return false;
}
}

//*********************** 非递归输出一条路径 **********************************

void Print_Non_Recur(Stack path, Stack Dir){ // 打印时要倒着打印栈里的元素
printf("\n1, 2, 3, 4 represent right, bottom, left and top\nOne of the pathways of the maze is:\n"); // 迷宫的一条通路为
pos x[N], y[N]; // 存两个栈的元素
int lenx = path.print(x);
int leny = Dir.print(y);
int j = leny - 2;
printf("(1, 1, %d), ", y[j--].y);
for(int i = lenx-2; i >= 1; i--){
printf("(%d, %d, %d), ", x[i].x, x[i].y, y[j--].y);
}
printf("(%d, %d)\n", m, n); // 最后终点
}

int Non_Recur_DFS(){
Stack path, Dir;
int cur_x = 1; // 存当前位置
int cur_y = 1;
memset(vis, 0, sizeof(vis));
int flag = 0;
int temp = 1; // 保存下一次走的方向
do{ // 如果当前位置可通
if(!vis[cur_x][cur_y] && inside(cur_x, cur_y) && maze[cur_x][cur_y] == 0){
path.push(pos(cur_x, cur_y)); // 进栈
Dir.push(pos(0, temp));
if(cur_x == m && cur_y == n){ // 到达出口
flag = 1;
break;
}else{
int di = cnt[cur_x][cur_y]; // 选择一个方向
if(di != 4){
temp = di + 1;
cnt[cur_x][cur_y]++; // 每次一个位置选完一个方向,记录一下
cur_x += dir[di][0];
cur_y += dir[di][1];
}else{ // 回到老位置就跳出
break;
}
}
}else{
if(!path.empty()){ // 回溯
pos top = path.top();
while(cnt[top.x][top.y] == 4){ // 一直找到一个位置还有方向没有访问
vis[top.x][top.y] = 1; // 留下不能通过的标记
path.pop(); // 继续找栈顶元素
Dir.pop();
if(path.empty())
break;
top = path.top();
}
if(!path.empty()){ // 找到一个位置还有其他方向 没访问
int di = cnt[top.x][top.y];
temp = di + 1; // 记录下一个方向
cnt[top.x][top.y]++;
cur_x = top.x + dir[di][0];
cur_y = top.y + dir[di][1];
}
}
}
} while (!path.empty());
if(flag == 1){ // 找到路径就打印
Print_Non_Recur(path, Dir);
return true;
}else{
printf("There is no way out of this maze.\n");
return false;
}
}

//**************************** 递归输出所有路径 ******************************

int cas; // 路径编号

void Print_Maze(Stack path){
printf("\nThe %dth path is:\n", cas++);
for(int i = 1; i <= m; i++) // 先从 maze复制副本准备输出
for (int j = 1; j <= n; j++)
prin[i][j] = maze[i][j] + '0';
Link_list *p = path.base; // 遍历栈,先找到根指针
while(p){
prin[p->data.x][p->data.y] = '*'; // 设路径为 *
p = p->next;
}
prin[1][1] = '*';
for(int i = 1; i <= m; i++){ // 输出其中一条路径
for (int j = 1; j <= n; j++){
printf("%c ", prin[i][j]);
}
printf("\n");
}
}

void MazePath(pos cur_pos, Stack & path){ // 递归找路径,参数: 当前位置,已经走过的路径
// cout << "fdsa" << endl;
if(cur_pos.x == m && cur_pos.y == n ){ // 到达终点输出路径
Print_Maze(path);
return; // 继续找其他的路径
}
for(int i = 0; i < 4; i++){ // 四个方向
int next_x = cur_pos.x + dir[i][0];
int next_y = cur_pos.y + dir[i][1]; // 如果没有访问过, 这个点可以走,则:
if(!vis[next_x][next_y] && inside(next_x, next_y) && maze[next_x][next_y] == 0){
vis[next_x][next_y] = 1;
path.push(pos(next_x, next_y));
MazePath(pos(next_x, next_y), path);
path.pop(); // 回溯
vis[next_x][next_y] = 0; // 才能输出所有的路径
}
}
}

void Recur_DFS(){ //递归输出所有路径
Stack path;
cas = 1;
memset(vis, 0, sizeof(vis));
vis[1][1] = 1;
printf("\nAll paths of the maze are:\n");
MazePath(pos(1, 1), path);
}

void Creat_Maze(){
printf("Please enter the length and width of the maze: \n");
scanf("%d%d", &m, &n);
printf("0 and 1 represent pathways and barriers.\nPlease enter a maze: \n");
for(int i = 1; i <= m; i++){
for (int j = 1; j <= n; j++){
scanf("%d", &maze[i][j]);
}
}
}

int main()
{
Creat_Maze();
if(Non_Recur_DFS()) // 非递归 DFS, 输出一条路径
Recur_DFS(); // 递归版本 DFS, 输出所有路径
return 0;
}

/*
test_1

3 3
0 1 1
0 0 0
1 0 0

test_2

8 8
0 0 1 0 0 0 1 0
0 0 1 0 0 0 1 0
0 0 0 0 1 1 0 0
0 1 1 1 0 0 0 0
0 0 0 1 0 0 0 0
0 1 0 0 0 1 1 1
0 1 1 1 0 1 0 0
1 0 0 0 0 0 0 0

4 4
0 0 1 0
0 0 1 0
0 0 0 0
0 1 1 1

5 4
0 0 0 0
1 1 1 0
0 0 0 0
0 1 1 1
0 0 0 0

*/

图的遍历

#include <bits/stdc++.h>
using namespace std;

/*
author: stormjing
coding=utf-8
*/

const int MAX = 1e2;

typedef struct node{ // 临界矩阵存图
int vexs[MAX]; // 图顶点向量
int arcs[MAX][MAX]; // 邻接矩阵;
int vexnum, arcnum; // 图顶点数,弧数。
int kind; // 0 代表有向图, 1代表无向图
node() {
memset(arcs, 0, sizeof(arcs)); //初始化边长度无穷
memset(vexs, 0, sizeof(vexs)); //顶点数为 0
}
} MGraph;

bool visited[MAX]; //记录是否访问过
int ID; //控制格式

void visit(MGraph G, int v){
if(ID++ == G.vexnum-1)
printf("v%d\n", v);
else
printf("v%d -> ", v);
}

//*********** DFS **********************************************

void DFS(MGraph G, int v){ //从第 v 个顶点出发递归深度优先遍历图 G
visited[v] = true;
visit(G, v);
for(int i = 0; i < G.vexnum; i++){ // 对于所有的顶点
int next_vex = G.vexs[i];
if(!visited[next_vex] && G.arcs[v][next_vex] == 1) //next_vex 没被访问,且 v 到 next_vex 有边
DFS(G, next_vex);
}
}

void DFSTraverse(MGraph G){
memset(visited, 0, sizeof(visited)); // 对访问数组初始化
ID = 0;
for(int i = 0; i < G.vexnum; i++){
if(!visited[G.vexs[i]]) // 对尚未访问过的顶点调用 DFS
DFS(G, G.vexs[i]); // 连通图只要进行一次
}
}

//*********** BFS ****************************************************

typedef struct queue{ // 循环队列
int data[MAX];
int front, rear;
queue(){ // 初始化队列
memset(data, 0, sizeof(data));
front = rear = 0;
}
bool empty(){ // 判空
if((rear + 1) % MAX == front)
return true;
else
return false;
}
void push(int x){ // 入队
data[rear++] = x;
rear %= MAX;
}
int pop(){ // 出队
int e = data[front++];
front %= MAX;
return e;
}
} Queue;

void BFSTraverse(MGraph G){
memset(visited, 0, sizeof(visited)); // 对访问数组初始化
ID = 0;
// queue<int> q; // 初始化队列
Queue q;
for (int i = 0; i < G.vexnum; i++){
int v = G.vexs[i];
if(!visited[v]){ // 如果这个点没有被访问过,从这个点开始BFS
visited[v] = true;
visit(G, v);
q.push(v); // 入队
while(!q.empty()){ // 开始BFS
int u = q.pop(); // 每次取出队头元素
for (int i = 0; i < G.vexnum; i++){
int next_vex = G.vexs[i];
if(!visited[next_vex] && G.arcs[u][next_vex] == 1){
visited[next_vex] = true;
visit(G, next_vex);
q.push(next_vex);
}
}
}
}
}
}

//*********** Create **************************************************

void Creat_Graph(MGraph &G){
printf("Please enter the number of vertices and edges of the graph.\n"); //顶点数,边数
scanf("%d%d", &G.vexnum, &G.arcnum);
printf("Please enter the vertex number\n");
for (int i = 0; i < G.vexnum; i++){ //输入顶点编号
scanf("%d", &G.vexs[i]);
}
printf("Please enter the type of graph, 0 for undirected graph and 1 for digraph.\n");
scanf("%d", &G.kind); //图的类型
printf("Please Enter all edges of the graph\n");
for(int i = 0, x, y; i < G.arcnum; i++){ // 输入边
scanf("%d%d", &x, &y);
G.arcs[x][y] = 1;
if(G.kind)
G.arcs[y][x] = 1;
}
}

int main()
{
MGraph G;
Creat_Graph(G);
printf("The depth-first access sequence is: \n"); //深度遍历序列为
DFSTraverse(G);
printf("\nThe breadth-first access aequence is: \n");
BFSTraverse(G);
return 0;
}

/*
first text data:
8 9
1 2 3 4 5 6 7 8
1
1 2
2 4
2 5
5 8
1 3
3 6
3 7
6 7
4 8

second text data:
9 9
1 2 3 4 5 6 7 8 9
1
7 8
1 2
1 3
3 7
3 4
3 5
2 5
5 6
5 9


*/

prim算法

#include <bits/stdc++.h>
using namespace std;

/*
author: stomrjing
coding=utf-8
*/

const int MAX = 1e2;
const int INF = 0x3f3f3f3f;

//**************** 临界矩阵存图 ************************************************

typedef struct node{ // 临界矩阵存图
int vexs[MAX]; // 图顶点向量
int arcs[MAX][MAX]; // 邻接矩阵;
int vexnum, arcnum; // 图顶点数,弧数。
int kind; // 0 代表有向图, 1代表无向图
node() {
memset(arcs, INF, sizeof(arcs)); //初始化边长度无穷
memset(vexs, 0, sizeof(vexs)); //顶点数为 0
}
} MGraph;

void Creat_Graph(MGraph &G){
printf("Please enter the number of vertices and edges of the graph.\n"); //顶点数,边数
scanf("%d%d", &G.vexnum, &G.arcnum);
printf("Please enter the vertex number\n");
for (int i = 0; i < G.vexnum; i++){ //输入顶点编号
scanf("%d", &G.vexs[i]);
}
printf("Please enter the type of graph, 0 for undirected graph and 1 for digraph.\n");
scanf("%d", &G.kind); //图的类型
printf("Please enter the edge weights of the graph\n");
for(int i = 0, x, y, z; i < G.arcnum; i++){ // 输入边
scanf("%d%d%d", &x, &y, &z);
G.arcs[x][y] = z;
if(G.kind) // 无向图要插两条边
G.arcs[y][x] = z;
}
}

//**************************** Prim ****************************************

void prim(MGraph G){
int min, k = 1;
int adjvex[MAX];
int lowcost[MAX];
lowcost[1] = 0; // 与当前生成树相连最小权值
adjvex[1] = 1; // adjvex[i] 表示第 i 条边与哪条边相连
for(int i = 1; i <= G.vexnum; i++){ // 自己与自己权值为 0
G.arcs[i][i] = 0;
}
for (int i = 1; i <= G.vexnum; i++){ // 默认第一个点为当前生成树
lowcost[i] = G.arcs[1][i];
adjvex[i] = 1;
}
for(int i = 1; i < G.vexnum; i++){ // 遍历(顶点数 - 1)次,找完所有点
min = INF;
for (int j = 1; j <= G.vexnum; j++){ //找最小权值边
if(lowcost[j] != 0 && lowcost[j] < min){
min = lowcost[j];
k = j;
}
}
printf("(%d, %d)\n", adjvex[k], k); //
lowcost[k] = 0;
for (int j = 1; j <= G.vexnum; j++){ // 通过权值边更新
if(lowcost[j] != 0 && G.arcs[k][j] < lowcost[j]){
lowcost[j] = G.arcs[k][j];
adjvex[j] = k; // j 通过 k 来更新
}
}
}
}

int main()
{
MGraph G;
Creat_Graph(G);
printf("The edges added to the minimum spanning tree are: \n");
prim(G);
return 0;
}

/*
first text data:
6 10
1 2 3 4 5 6
1
1 4 5
1 3 1
1 2 6
3 2 5
3 4 5
2 5 3
4 6 2
3 5 6
3 6 4
5 6 6


second text data:

*/