先看一个有意思的问题, 我们定义一个二维数组表示迷宫。
它表示一个迷宫, 其中的1表示墙壁,0表示可以走的路, 只能横着走或竖着走,不能斜着走,
我们要编程序找出从左上角到右下角的路线。其实这个问题可以用深度优先搜索的方法搞定的了。
这个算法中涉及到了几个知识:
1. 一个是栈,每走过一个点会把这个点会把这个点压入栈中。
2. 用一个新的数据结构保存走迷宫的路线,每个走过的点都有一个前趋(Predecessor)的点,表示是从哪儿走到
当前点的,比如predecessor[4][4]是座标为(3, 4)的点,就表示从(3, 4)走到了(4, 4),一开始predecessor的各元素
初始化为无效座标(-1, -1)。在迷宫中探索路线的同时就把路线保存在predecessor数组中。
3. 已经走过的点在maze数组中记为2防止重复走。 算法的伪代码如下 :
分为几个文件来分开实现 :
/* main.c */
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/***********************************************************/ /* Copyright (C) SA14226214, USTC, 2014-2015 */ /* */ /* FILE NAME : main.c */ /* PRINCIPAL AUTHOR : GaoZhipeng */ /* SUBSYSTEM NAME : MakFile */ /* MODULE NAME : makefile */ /* LANGUAGE : C */ /* TARGET ENVIRONMENT : ANY */ /* DATE OF FIRST RELEASE : 2015/04/05 */ /* DESCRIPTION : This is a makefile program */ /***********************************************************/ /* *Revision log: * *Ceated by GaoZhipeng, 2015/04/05 * */ #include<stdio.h> #include"main.h" #include"stack.h" #include"maze.h" struct point predecessor[MAX_ROW][MAX_COL] = { {{-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}}, {{-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}}, {{-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}}, {{-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}}, {{-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}}, }; void visit(int row, int col, struct point pre) { struct point visit_point = {row, col}; maze[row][col] = 2; predecessor[row][col] = pre; push(visit_point); } int main(void) { struct point p = { 0, 0 }; maze[p.row][p.col] = 2; push(p); while (!is_empty()) { p = pop(); if (p.row == MAX_ROW - 1 /* goal */ && p.col == MAX_COL - 1) break; if (p.col+1 < MAX_COL /* right */ && maze[p.row][p.col+1] == 0) visit(p.row, p.col+1, p); if (p.row+1 < MAX_ROW /* down */ && maze[p.row+1][p.col] == 0) visit(p.row+1, p.col, p); if (p.col-1 >= 0 /* left */ && maze[p.row][p.col-1] == 0) visit(p.row, p.col-1, p); if (p.row-1 >= 0 /* up */ && maze[p.row-1][p.col] == 0) visit(p.row-1, p.col, p); print_maze(); } if (p.row == MAX_ROW - 1 && p.col == MAX_COL - 1) { printf("(%d, %d) ", p.row, p.col); while (predecessor[p.row][p.col].row != -1) { p = predecessor[p.row][p.col]; printf("(%d, %d) ", p.row, p.col); } } else printf("No path! "); return 0; }
/* main.h */
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/***********************************************************/ /* Copyright (C) SA14226214, USTC, 2014-2015 */ /* */ /* FILE NAME : main.h */ /* PRINCIPAL AUTHOR : GaoZhipeng */ /* SUBSYSTEM NAME : MakFile */ /* MODULE NAME : makefile */ /* LANGUAGE : C */ /* TARGET ENVIRONMENT : ANY */ /* DATE OF FIRST RELEASE : 2015/04/05 */ /* DESCRIPTION : This is a makefile program */ /***********************************************************/ /* *Revision log: * *Ceated by GaoZhipeng, 2015/04/05 * */ #ifndef MAIN_H #define MAIN_H typedef struct point{ int row, col; } item_t; #define MAX_ROW 5 #define MAX_COL 5 #endif
/* maze.c */
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/***********************************************************/ /* Copyright (C) SA14226214, USTC, 2014-2015 */ /* */ /* FILE NAME : maze.c */ /* PRINCIPAL AUTHOR : GaoZhipeng */ /* SUBSYSTEM NAME : MakFile */ /* MODULE NAME : makefile */ /* LANGUAGE : C */ /* TARGET ENVIRONMENT : ANY */ /* DATE OF FIRST RELEASE : 2015/04/05 */ /* DESCRIPTION : This is a makefile program */ /***********************************************************/ /* *Revision log: * *Ceated by GaoZhipeng, 2015/04/05 * */ #include<stdio.h> #include"maze.h" int maze[MAX_ROW][MAX_COL] = { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, }; void print_maze(void) { int i, j; for(i=0; i<MAX_ROW; i++) { for(j=0; j<MAX_COL; j++) { printf("%d ", maze[i][j]); } putchar(' '); } printf("********* "); }
/* maze.h */
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/***********************************************************/ /* Copyright (C) SA14226214, USTC, 2014-2015 */ /* */ /* FILE NAME : maze.h */ /* PRINCIPAL AUTHOR : GaoZhipeng */ /* SUBSYSTEM NAME : MakFile */ /* MODULE NAME : makefile */ /* LANGUAGE : C */ /* TARGET ENVIRONMENT : ANY */ /* DATE OF FIRST RELEASE : 2015/04/05 */ /* DESCRIPTION : This is a makefile program */ /***********************************************************/ /* *Revision log: * *Ceated by GaoZhipeng, 2015/04/05 * */ #ifndef MAZE_H #define MAZE_H #include"main.h" extern int maze[MAX_ROW][MAX_COL]; void print_maze(void); #endif
/* stack.c */
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/***********************************************************/ /* Copyright (C) SA14226214, USTC, 2014-2015 */ /* */ /* FILE NAME : stack.c */ /* PRINCIPAL AUTHOR : GaoZhipeng */ /* SUBSYSTEM NAME : MakFile */ /* MODULE NAME : makefile */ /* LANGUAGE : C */ /* TARGET ENVIRONMENT : ANY */ /* DATE OF FIRST RELEASE : 2015/04/05 */ /* DESCRIPTION : This is a makefile program */ /***********************************************************/ /* *Revision log: * *Ceated by GaoZhipeng, 2015/04/05 * */ #include"stack.h" static item_t stack[512]; static int top = 0; void push(item_t p) { stack[top++] = p; } item_t pop(void) { return stack[--top]; } int is_empty(void) { return top == 0; }
/* stack.h */
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/***********************************************************/ /* Copyright (C) SA14226214, USTC, 2014-2015 */ /* */ /* FILE NAME : stack.h */ /* PRINCIPAL AUTHOR : GaoZhipeng */ /* SUBSYSTEM NAME : MakFile */ /* MODULE NAME : makefile */ /* LANGUAGE : C */ /* TARGET ENVIRONMENT : ANY */ /* DATE OF FIRST RELEASE : 2015/04/05 */ /* DESCRIPTION : This is a makefile program */ /***********************************************************/ /* *Revision log: * *Ceated by GaoZhipeng, 2015/04/05 * */ #ifndef STACK_H #define STACK_H #include "main.h" extern void push(item_t); extern item_t pop(void); extern int is_empty(void); #endif
然后我们要做的就是在Linux下对上述程序进行编译和运行。
对于程序的编译命令, 最原始的编译指令可以这样写: $ gcc main.c stack.c maze.c -o main
不过还有一个更加简便的操作, 那就是写一个Makefile文件和源代码放在同一个目录下面。下面是一个写好的Makefile
# This is an simple makefile main : main.o stack.o maze.o gcc main.o stack.o maze.o -o main main.o : main.c main.h stack.h maze.h gcc -c main.c -o main.o stack.o : stack.c stack.h main.h gcc -c stack.c -o stack.o maze.o : maze.c maze.h main.h gcc -c maze.c -o maze.o clean : @echo "cleanning the project" -rm main *.o @echo "cleanning completed" .PHONY : clean
make 命令会自动读取当前目录下的Makefile 文件, 完成相应的编译步骤。Makefile由一组规则(Rule)组成,每条规则的格式是:
例如 : main: main.o stack.o maze.o
gcc main.o stack.o maze.o -o main
main 是这条规则的目标(Target),main.o、stack.o 和maze.o是这条规则的条件(Prerequisite)。目标和条件之间的关系是:欲更新目标,
必须首先更新它的所有条件;所有条件中只要有一个条件被更新了,目标也必须随之被更新。所谓“更新”就是执行一遍规则中的命令列表,
命令列表中的每条命令必须以一个Tab开头,注意不能是空格,Makefile的格式不像C语言的缩进那么随意,对于Makefile中的每个以Tab
开头的命令,make 会创建一个Shell进程去执行它。
Makefile中有一些常用的特殊变量 :
- $@ ,表示规则中的目标。
- $< ,表示规则中的第一个条件。
- $?,表示规则中所有比目标新的条件,组成一个列表,以空格分隔。
- $^ ,表示规则中的所有条件,组成一个列表,以空格分隔。
那么我们可以把Makefile进一步化简, 写成如下的形式:
#this is a makefile all : main main : main.o stack.o maze.o gcc $^ -o $@ main.o : main.h stack.h maze.h stack.o : stack.h main.h maze.o : maze.h main.h clean : -rm main *.o .PHONY: clean
把命令 gcc main.o stack.o maze.o -o main 改写成 gcc $^ -o $@。
这样即使以后又往条件里添加了新的目标文件,编译命令也不需要修改,减少了出错的可能。