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

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


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

迷宫问题,图的遍历,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:

 */

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值