第 3 章 栈和队列(顺序栈,算法 3.3)

1. 背景说明:

若迷宫 maze 中存在从入口 start 到出口 end 的通道,则求得一条存放在栈中(从栈底到栈顶),并返回 TRUE;否则返回 FALSE,注意,该解并非最优解,

最优解需要求得最短路径且可能并非一条。

迷宫示意图:

第 3 章 栈和队列(顺序栈,算法 3.3)_第1张图片

    输入文本:

 

10 10

18

1 3
1 7
2 3
2 7
3 5
3 6
4 2
4 3
4 4
5 4
6 2
6 6
7 2
7 3
7 4
7 6
7 7
8 1

1 1

8 8

2. 示例代码

1) status.h

/* DataStructure 预定义常量和类型头文件 */

#ifndef STATUS_H
#define STATUS_H

/* 函数结果状态码 */
#define TRUE 					1			/* 返回值为真 */
#define FALSE 					0			/* 返回值为假 */
#define RET_OK 					0			/* 返回值正确 */
#define INFEASIABLE    		   	2			/* 返回值未知 */
#define ERR_MEMORY     		   	3			/* 访问内存错 */
#define ERR_NULL_PTR   			4			/* 空指针错误 */
#define ERR_MEMORY_ALLOCATE		5			/* 内存分配错 */
#define ERR_NULL_STACK			6			/* 栈元素为空 */
#define ERR_PARA				7			/* 函数参数错 */
#define ERR_OPEN_FILE			8			/* 打开文件错 */
typedef int Status;							/* Status 是函数的类型,其值是函数结果状态代码,如 OK 等 */
typedef int Bollean;						/* Boolean 是布尔类型,其值是 TRUE 或 FALSE */

#endif // !STATUS_H

2) sqStack.h

/* 栈的顺序存储表示头文件 */

#ifndef SQSTACK_H
#define SQSTACK_H

#include "status.h"

#define STACK_INIT_SIZE 10 		/* 存储空间初始分配量 */
#define STACKINCREMENT 2 		/* 存储空间分配增量 */

/* 迷宫位置坐标 */
typedef struct {
	int x;
	int y;
} MazePosition;

/* 定义栈元素类型 */
typedef struct {
	int order;					/* 通道块在路径上的序号 */
	int direction;				/* 下一块路径的方向,取值为 0 ~ 3, 分别表示上下左右 */
	MazePosition pos;			/* 当前通道块在迷宫中的坐标位置 */
} SElemType;

typedef struct SqStack {
	SElemType* base; 			/* 在栈构造之前和销毁之后,base的值为NULL */
	SElemType* top; 			/* 栈顶指针 */
	int stackSize; 				/* 当前已分配的存储空间,以元素为单位 */
} SqStack; 						/* 顺序栈 */

/* 构造一个空栈 S */
Status InitStack(SqStack* S);

/* 销毁栈 S */
void DestroyStack(SqStack* S);

/* 把 S 置为空栈 */
void ClearStack(SqStack* S);

/* 若栈 S 为空栈,则返回 TRUE,否则返回 FALSE */
Status StackEmpty(SqStack S);

/* 返回 S 的元素个数,即栈的长度 */
int StackLength(SqStack S);

/* 若栈不空,则用 e 返回 S 的栈顶元素,并返回 OK;否则返回 ERROR */
Status GetTop(SqStack S, SElemType* e);

/* 插入元素 e 为新的栈顶元素 */
Status Push(SqStack* S, SElemType e);

/* 若栈不空,则删除 S 的栈顶元素,用 e 返回其值,并返回 OK;否则返回 ERROR */
Status Pop(SqStack* S, SElemType* e);

/* 从栈底到栈顶依次对栈中每个元素调用函数 visit() */
void StackTraverse(SqStack S, void(*Visit)(SElemType));

#endif

3) sqStack.c

/* 栈的顺序存储表示源文件 */

#include "sqStack.h"
#include "status.h"
#include 
#include 

/* 构造一个空栈 S */
Status InitStack(SqStack* S)
{
	(*S).base = (SElemType*)malloc(STACK_INIT_SIZE * sizeof(SElemType));
	if (!(*S).base) {
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);
		return ERR_MEMORY_ALLOCATE;
	}

	(*S).top = (*S).base;
	(*S).stackSize = STACK_INIT_SIZE;

	return RET_OK;
}

/* 销毁栈 S */
void DestroyStack(SqStack* S)
{
	free((*S).base);
	(*S).base = NULL;
	(*S).top = NULL;
	(*S).stackSize = 0;
}

/* 把 S 置为空栈 */
void ClearStack(SqStack* S)
{
	(*S).top = (*S).base;
}

/* 若栈 S 为空栈,则返回 TRUE,否则返回 FALSE */
Status StackEmpty(SqStack S)
{
	return (S.top == S.base) ? TRUE : FALSE;
}

/* 返回 S 的元素个数,即栈的长度 */
int StackLength(SqStack S)
{
	return (int)(S.top - S.base);
}

/* 若栈不空,则用 e 返回 S 的栈顶元素,并返回 OK;否则返回 ERROR */
Status GetTop(SqStack S, SElemType* e)
{
	if (S.top > S.base) {
		*e = *(S.top - 1);
		return RET_OK;
	}

	printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_NULL_STACK);

	return ERR_NULL_STACK;
}

/* 插入元素 e 为新的栈顶元素 */
Status Push(SqStack* S, SElemType e)
{
	if (((*S).top - (*S).base) == (*S).stackSize) {
		(*S).base = (SElemType*)realloc((*S).base, (unsigned long long)(((*S).stackSize) + STACKINCREMENT) * sizeof(SElemType));
		if (!(*S).base) {
			printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);
			return ERR_MEMORY_ALLOCATE;
		}

		(*S).top = (*S).base + (*S).stackSize;
		(*S).stackSize += STACKINCREMENT;
	}

	*((*S).top)++ = e;

	return RET_OK;
}

/* 若栈不空,则删除 S 的栈顶元素,用 e 返回其值,并返回 OK;否则返回 ERROR */
Status Pop(SqStack* S, SElemType* e)
{
	if ((*S).top == (*S).base) {
		printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);
		return ERR_MEMORY_ALLOCATE;
	}

	*e = *(--(*S).top);

	return RET_OK;
}

/* 从栈底到栈顶依次对栈中每个元素调用函数 visit() */
void StackTraverse(SqStack S, void(*Visit)(SElemType))
{
	while (S.top > S.base) {
		Visit(*S.base++);
	}
}

4) algorithm.h

/* 算法定义头文件 */
#ifndef ALGORITHM_H
#define ALGORITHM_H

#include "sqStack.h"
#include "status.h"

#define MAXLENGTH 25			/* 设迷宫最大行列为 25 */

/* 定义墙元素值为 0,可通过路径为 -2, 不能通过路径为 -1 */
typedef int MazeType[MAXLENGTH][MAXLENGTH];

/* 算法 3.3, 若迷宫 maze 中存在从入口 start 到出口 end 的通道,则求得第一条
   路径存放在栈中(从栈底到栈顶),并返回 TRUE;否则返回 FALSE */
Status MazePath(MazePosition start, MazePosition end, MazeType* maze, int* totalStep);

/* 如果存在路径,输出求得的迷宫的解 */
void PrintMazePath(int row, int col, MazeType* maze);

#endif // !ALGORITHM_H

5) algorithm.c

/* 算法实现源文件 */

#include "algorithm.h"
#include 
#include 

/*  定义墙元素值为 0,可通过路径为 -2, 不能通过路径为 -1,通过路径为足迹
	当迷宫 maze 的 curPos 点的序号为 -2(可通过路径),return OK; 否则,return FALSE */
static Bollean PassPos(MazePosition curPos, MazeType* maze)
{
	return ((*maze)[curPos.x][curPos.y] == -2) ? TRUE : FALSE;
}

/* 使迷宫 maze 的 curPos 点的序号变为足迹 totalStep */
static void FootPrint(MazePosition curPos, MazeType* maze, int* totalStep)
{
	(*maze)[curPos.x][curPos.y] = *totalStep;
}

/* 根据当前位置及移动方向,返回下一位置 */
static MazePosition NextPos(MazePosition curPos, int direction)
{	/* 上下左右四个方向的行、列增量 */
	MazePosition direc[4] = { { -1, 0 }, { 1 , 0 }, { 0, -1 }, { 0, 1 } };
	curPos.x += direc[direction].x;
	curPos.y += direc[direction].y;
	return curPos;
}

/* 使迷宫 maze 的 curPos 点的序号变为 -1(不能通过的路径) */
static void MarkPrint(MazePosition curPos, MazeType* maze)
{
	(*maze)[curPos.x][curPos.y] = -1;
}

/* 判断两个位置是否相同,相同返回 TRUE, 否则返回 FALSE */
static Bollean PostionSame(MazePosition pos1, MazePosition pos2)
{
	return ((pos1.x == pos2.x) && (pos1.y == pos2.y)) ? TRUE : FALSE;
}

/* 算法 3.3, 若迷宫 maze 中存在从入口 start 到出口 end 的通道,则求得一条
   存放在栈中(从栈底到栈顶),并返回 TRUE;否则返回 FALSE */
Status MazePath(MazePosition start, MazePosition end, MazeType* maze, int* totalStep)
{
	SqStack S = { 0 };
	InitStack(&S);
	MazePosition curPos = { 0 };
	(void)memcpy_s(&curPos, sizeof(MazePosition), &start, sizeof(MazePosition));
	SElemType sE = { 0 };
	do {
		if (PassPos(curPos, maze)) {
			FootPrint(curPos, maze, totalStep);
			sE.order = *totalStep;
			sE.pos.x = curPos.x;
			sE.pos.y = curPos.y;
			sE.direction = 0;
			++(*totalStep);
			Push(&S, sE);
			if (PostionSame(curPos, end)) {
				return TRUE;
			}

			curPos = NextPos(curPos, sE.direction);
		} else {
			if (!StackEmpty(S)) {
				Pop(&S, &sE);
				--(*totalStep);
				while ((sE.direction == 3) && (!StackEmpty(S))) {
					MarkPrint(sE.pos, maze);
					Pop(&S, &sE);
					--(*totalStep);
				}

				if (sE.direction < 3) {
					++(sE.direction);
					Push(&S, sE);
					++(*totalStep);
					curPos = NextPos(sE.pos, sE.direction);
				}
			}
		}
	} while (!StackEmpty(S));

	return FALSE;
}

/* 如果存在路径,输出求得的迷宫的解 */
void PrintMazePath(int row, int col, MazeType* maze)
{
	for (int i = 0; i < row; ++i) {
		for (int j = 0; j < col; ++j) {
			printf("%3d", (*maze)[i][j]);
		}

		printf("\n");
	}
}

6) main.c

/* 入口程序源文件 */

#include "status.h"
#include "algorithm.h"
#include 

int main(void)
{
	printf("Please input the row and col of the maze: ");
	int row = 0, col = 0;
	scanf_s("%d%d", &row, &col);
	MazeType maze = { 0 };
	for (int i = 0; i < col; ++i) {
		maze[0][i] = 0;
		maze[row - 1][i] = 0;
	}

	for (int i = 1; i < row - 1; ++i) {
		maze[i][0] = 0;
		maze[i][row - 1] = 0;
	}

	for (int i = 1; i < row - 1; ++i) {
		for (int j = 1; j < col - 1; ++j) {
			maze[i][j] = -2;
		}
	}

	printf("Please input the num of the wall: ");
	int wallNum = 0;
	scanf_s("%d", &wallNum);
	printf("Please input the position of the wall(x, y): \n");
	int x = 0, y = 0;
	for (int i = 0; i < wallNum; ++i) {
		scanf_s("%d%d", &x, &y);
		maze[x][y] = 0;
	}

	printf("The structure of the maze is:\n");
	PrintMazePath(row, col, &maze);
	MazePosition start = { 0 }, end = { 0 };
	printf("Please input the position of the start point(x, y):");
	scanf_s("%d%d", &start.x, &start.y);
	printf("Please input the position of the end point(x, y):");
	scanf_s("%d%d", &end.x, &end.y);
	int totalStep = 1;
	if (MazePath(start, end, &maze, &totalStep)) {
		printf("Use %d steps, one of the path from start to end of the maze is:\n", --totalStep);
		PrintMazePath(row, col, &maze);
	} else {
		printf("There is no way to the end.\n");
	}

	return 0;
}

3. 输出示例:

第 3 章 栈和队列(顺序栈,算法 3.3)_第2张图片

你可能感兴趣的:(#,数据结构(C语言版),算法,数据结构)