💡 【教材】 ▲03 栈和队列

This commit is contained in:
康建伟
2018-01-04 20:18:48 +08:00
parent 3384a3cebf
commit 7a24d4e813
27 changed files with 2216 additions and 0 deletions
@@ -0,0 +1,110 @@
/******************************************
* *
* 文件夹: ▲03 栈和队列\01 SequenceStack *
* *
* 内 容: 顺序栈相关函数测试 *
* *
******************************************/
#include <stdio.h>
#include "SequenceStack.c" //**▲03 栈和队列**//
void PrintElem(SElemType_Sq e);
//测试函数,打印整型
int main(int argc, char **argv)
{
SqStack S;
int i;
SElemType_Sq e;
printf("▼1\n▲函数 InitStack 测试...\n"); //1.函数InitStack测试
{
printf("初始化顺序栈 S ...\n");
InitStack_Sq(&S);
printf("\n");
}
PressEnter;
printf("▼4\n▲函数 StackEmpty 测试...\n"); //4.函数StackEmpty测试
{
StackEmpty_Sq(S) ? printf(" S 为空!!\n") : printf(" S 不为空!\n");
printf("\n");
}
PressEnter;
printf("▼7\n▲函数 Push 测试...\n"); //7.函数Push测试
{
for(i=1; i<=6; i++)
{
printf("\"%2d\" 压入栈 S ", 2*i);
Push_Sq(&S, 2*i);
printf("(累计第 %d 个元素)...\n", S.top-S.base);
}
printf("\n");
}
PressEnter;
printf("▼9\n▲函数 StackTraverse 测试...\n"); //9.函数StackTraverse测试
{
printf(" S 中的元素为:S = ");
StackTraverse_Sq(S, PrintElem);
printf("\n\n");
}
PressEnter;
printf("▼8\n▲函数 Pop 测试...\n"); //8.函数Pop测试
{
Pop_Sq(&S, &e);
printf("栈顶元素 \"%d\" 出栈...\n", e);
printf(" S 中的元素为:S = ");
StackTraverse_Sq(S, PrintElem);
printf("\n\n");
}
PressEnter;
printf("▼5\n▲函数 StackLength 测试...\n"); //5.函数StackLength测试
{
i = StackLength_Sq(S);
printf(" S 的长度为 %d \n", i);
printf("\n");
}
PressEnter;
printf("▼6\n▲函数 GetTop 测试...\n"); //6.函数GetTop测试
{
GetTop_Sq(S, &e);
printf("栈顶元素的值为 \"%d\" \n", e);
printf("\n");
}
PressEnter;
printf("▼3\n▲函数 ClearStack 测试...\n"); //3.函数ClearStack测试
{
printf("清空 S 前:");
StackEmpty_Sq(S) ? printf(" S 为空!!\n") : printf(" S 不为空!\n");
ClearStack_Sq(&S);
printf("清空 S 后:");
StackEmpty_Sq(S) ? printf(" S 为空!!\n") : printf(" S 不为空!\n");
printf("\n");
}
PressEnter;
printf("▼2\n▲函数 DestroyStack 测试...\n"); //2.函数DestroyStack测试
{
printf("销毁 S 前:");
S.base!=NULL && S.top!=NULL ? printf(" S 存在!\n") : printf(" S 不存在!!\n");
DestroyStack_Sq(&S);
printf("销毁 S 后:");
S.base!=NULL && S.top!=NULL ? printf(" S 存在!\n") : printf(" S 不存在!!\n");
printf("\n");
}
PressEnter;
return 0;
}
void PrintElem(SElemType_Sq e)
{
printf("%d ", e);
}
@@ -0,0 +1,106 @@
/******************************************
* *
* 文件夹: ▲03 栈和队列\01 SequenceStack *
* *
* 文件名: SequenceStack.c *
* *
******************************************/
#ifndef SEQUENCESTACK_C
#define SEQUENCESTACK_C
#include "SequenceStack.h" //**▲03 栈和队列**//
Status InitStack_Sq(SqStack *S)
{
(*S).base = (SElemType_Sq *)malloc(STACK_INIT_SIZE*sizeof(SElemType_Sq));
if(!(*S).base)
exit(OVERFLOW);
(*S).top = (*S).base;
(*S).stacksize = STACK_INIT_SIZE;
return OK;
}
Status DestroyStack_Sq(SqStack *S)
{
free((*S).base);
(*S).base = NULL;
(*S).top = NULL;
(*S).stacksize = 0;
return OK;
}
Status ClearStack_Sq(SqStack *S)
{
(*S).top = (*S).base;
return OK;
}
Status StackEmpty_Sq(SqStack S)
{
if(S.top==S.base)
return TRUE;
else
return FALSE;
}
int StackLength_Sq(SqStack S)
{
return S.top - S.base;
}
Status GetTop_Sq(SqStack S, SElemType_Sq *e)
{
if(S.top==S.base)
return ERROR;
*e = *(S.top - 1); //并不破坏栈
return OK;
}
Status Push_Sq(SqStack *S, SElemType_Sq e)
{
if((*S).top-(*S).base>=(*S).stacksize) //栈满,追加存储空间
{
(*S).base = (SElemType_Sq *)realloc((*S).base, ((*S).stacksize+STACKINCREMENT)*sizeof(SElemType_Sq));
if(!(*S).base)
exit(OVERFLOW); //存储分配失败
(*S).top = (*S).base + (*S).stacksize;
(*S).stacksize += STACKINCREMENT;
}
*(S->top) = e; //进栈先赋值,栈顶指针再自增
(S->top)++;
return OK;
}
Status Pop_Sq(SqStack *S, SElemType_Sq *e)
{
if((*S).top==(*S).base)
return ERROR;
(*S).top--; //出栈栈顶指针先递减,再赋值
*e = *((*S).top);
return OK;
}
Status StackTraverse_Sq(SqStack S, void(Visit)(SElemType_Sq))
{ //遍历不应该破坏栈
SElemType_Sq *p = S.base;
while(p<S.top)
Visit(*p++);
return OK;
}
#endif
@@ -0,0 +1,84 @@
/******************************************
* *
* 文件夹: ▲03 栈和队列\01 SequenceStack *
* *
* 文件名: SequenceStack.h *
* *
* 内 容: 顺序栈相关操作列表 *
* *
******************************************/
#ifndef SEQUENCESTACK_H
#define SEQUENCESTACK_H
#include <stdio.h>
#include <stdlib.h> //提供malloc、realloc、free、exit原型
#include "../../▲01 绪论/Status.h" //**▲01 绪论**//
/* 宏定义 */
#define STACK_INIT_SIZE 100 //顺序栈存储空间的初始分配量
#define STACKINCREMENT 10 //顺序栈存储空间的分配增量
/* 顺序栈类型定义 */
/*在迷宫、表达式、二叉树二叉链表、孩子兄弟树等算法中,此类型需要重新定义*/
#if !defined MAZE_H && \
!defined EXPRESSION_H && \
!defined BINARYTREE_H && \
!defined CHILDSIBLINGTREE_H && \
!defined Question_8
typedef int SElemType_Sq;
#endif
typedef struct
{
SElemType_Sq *base; //在栈构造之前和销毁之后,base的值为NULL
SElemType_Sq *top; //栈顶指针
int stacksize; //当前已分配的存储空间,以元素为单位
}SqStack;
/* 顺序栈函数列表 */
Status InitStack_Sq(SqStack *S);
/*━━━━━━━━┓
┃(01)构造空栈S。 ┃
┗━━━━━━━━*/
Status DestroyStack_Sq(SqStack *S);
/*━━━━━━┓
┃(02)销毁S。 ┃
┗━━━━━━*/
Status ClearStack_Sq(SqStack *S);
/*━━━━━━┓
┃(03)置空S。 ┃
┗━━━━━━*/
Status StackEmpty_Sq(SqStack S);
/*━━━━━━━━━━┓
┃(04)判断S是否为空。 ┃
┗━━━━━━━━━━*/
int StackLength_Sq(SqStack S);
/*━━━━━━━━━━┓
┃(05)返回S元素个数。 ┃
┗━━━━━━━━━━*/
Status GetTop_Sq(SqStack S, SElemType_Sq *e);
/*━━━━━━━━━━━┓
┃(06)用e获取栈顶元素。 ┃
┗━━━━━━━━━━━*/
Status Push_Sq(SqStack *S, SElemType_Sq e);
/*━━━━━━━━┓
┃(07)元素e进栈。 ┃
┗━━━━━━━━*/
Status Pop_Sq(SqStack *S, SElemType_Sq *e);
/*━━━━━━━━┓
┃(08)元素e出栈。 ┃
┗━━━━━━━━*/
Status StackTraverse_Sq(SqStack S, void(Visit)(SElemType_Sq));
/*━━━━━━┓
┃(09)访问栈。┃
┗━━━━━━*/
#endif
@@ -0,0 +1,22 @@
/***************************************
* *
* 文件夹: ▲03 栈和队列\02 Conversion *
* *
* 内 容: 进制转换相关函数测试 *
* *
***************************************/
#include "Conversion.c" //**▲03 栈和队列**//
int main(int argc, char **argv)
{
int i = 342391;
printf("将十进制数转换为八进制数...\n");
conversion(i);
printf("\n\n");
return 0;
}
@@ -0,0 +1,41 @@
/***************************************
* *
* 文件夹: ▲03 栈和队列\02 Conversion *
* *
* 文件名: Conversion.c *
* *
* 算 法: 3.1 *
* *
***************************************/
#ifndef CONVERSION_C
#define CONVERSION_C
#include "Conversion.h" //**▲03 栈和队列**//
/*════╗
║ 算法3.1║
╚════*/
void conversion(int i)
{
SqStack S;
SElemType_Sq e;
InitStack_Sq(&S);
printf("十进制数 %d 转换为八进制数后为:0", i);
while(i)
{
Push_Sq(&S, i%8); //进栈时从低位到高位
i = i/8;
}
while(!StackEmpty_Sq(S))
{
Pop_Sq(&S, &e); //出栈时从高位到低位
printf("%d", e);
}
}
#endif
@@ -0,0 +1,23 @@
/***************************************
* *
* 文件夹: ▲03 栈和队列\02 Conversion *
* *
* 文件名: Conversion.h *
* *
* 内 容: 进制转换相关操作列表 *
* *
***************************************/
#ifndef CONVERSION_H
#define CONVERSION_H
#include <stdio.h>
#include "../01 SequenceStack/SequenceStack.c" //**▲03 栈和队列**//
/* 进制转换函数列表 */
void conversion(int i);
/*━━━━━━━━━━━━━━━━━┓
┃(01)算法3.1:十进制数转八进制数。 ┃
┗━━━━━━━━━━━━━━━━━*/
#endif
@@ -0,0 +1,26 @@
/*************************************
* *
* 文件夹: ▲03 栈和队列\03 LineEdit *
* *
* 内 容: 行编辑程序相关函数测试 *
* *
*************************************/
#include "LineEdit.c" //**▲03 栈和队列**//
int main(int argc, char *argv[])
{
char *buf = "whli##ilr#e(s#*s)\noutcha@ putchar(*s=#++);"; //需要录入的内容
printf("作为示范,用户输入的文本内容为:\n");
printf("%s\n", buf);
printf("\n");
printf("进入行编辑程序...\n");
printf("特殊符号:“#” 代表删除上一元素,“@”代表删除当前输入行,\n");
printf("\\n”代表确认此行无误,“\\0”代表输入结束。\n");
printf("最终存储的内容为:\n");
LineEdit(buf);
printf("\n\n");
return 0;
}
@@ -0,0 +1,67 @@
/*************************************
* *
* 文件夹: ▲03 栈和队列\03 LineEdit *
* *
* 文件名: LineEdit.c *
* *
* 算 法: 3.2 *
* *
*************************************/
#ifndef LINEEDIT_C
#define LINEEDIT_C
#include "LineEdit.h" //**▲03 栈和队列**//
/*════╗
║ 算法3.2║
╚════*/
/* 与严蔚敏课本所述算法略有差别,但算法思想一致 */
void LineEdit(char Buffer[])
{
SqStack S; //接收输入的字符
SElemType_Sq e;
int i;
char ch;
InitStack_Sq(&S);
i = 0;
ch = Buffer[i++];
while(ch!='\0')
{
while(ch!='\0' && ch!='\n')
{
switch(ch)
{
case '#': Pop_Sq(&S, &e);
break;
case '@': ClearStack_Sq(&S);
break;
default : Push_Sq(&S, ch);
}
ch = Buffer[i++];
}
if(ch=='\n')
{
Push_Sq(&S, ch);
StackTraverse_Sq(S, Print);
ClearStack_Sq(&S);
ch = Buffer[i++];
}
}
if(ch=='\0')
{
StackTraverse_Sq(S, Print);
DestroyStack_Sq(&S);
}
}
void Print(SElemType_Sq e)
{
printf("%c", e);
}
#endif
@@ -0,0 +1,28 @@
/*************************************
* *
* 文件夹: ▲03 栈和队列\03 LineEdit *
* *
* 文件名: LineEdit.h *
* *
* 内 容: 行编辑程序相关操作列表 *
* *
*************************************/
#ifndef LINEEDIT_H
#define LINEEDIT_H
#include <stdio.h>
#include "../01 SequenceStack/SequenceStack.c" //**▲03 栈和队列**//
/* 行编辑程序函数列表 */
void LineEdit(char Buffer[]);
/*━━━━━━━━━━━━━┓
┃(01)算法3.2:行编辑程序。 ┃
┗━━━━━━━━━━━━━*/
void Print(SElemType_Sq e);
/*━━━━━━━━┓
┃(02)打印元素e。 ┃
┗━━━━━━━━*/
#endif
@@ -0,0 +1,29 @@
/*********************************
* *
* 文件夹: ▲03 栈和队列\04 Maze *
* *
* 内 容: 迷宫相关函数测试 *
* *
*********************************/
#include "Maze.c" //**▲03 栈和队列**//
int main(int argc, char *argv[])
{
MazeType maze[N][N];
PosType start, end;
SElemType_Sq e;
char Re = 'Y';
while(Re=='Y' || Re=='y')
{
InitMaze(maze, &start, &end); //初始化迷宫,包括出入口
ShowMaze(maze); //显示迷宫的初始状态
MazePath(maze,start,end); //迷宫寻路
printf("重置?(Y/N):");
scanf("%c", &Re);
}
return 0;
}
@@ -0,0 +1,218 @@
/*********************************
* *
* 文件夹: ▲03 栈和队列\04 Maze *
* *
* 文件名: Maze.c *
* *
* 算 法: 3.3 *
* *
*********************************/
#ifndef MAZE_C
#define MAZE_C
#include "Maze.h" //**▲03 栈和队列**//
/*════╗
║ 算法3.3║
╚════*/
Status MazePath(MazeType maze[][N], PosType start, PosType end)
{
SqStack S;
SElemType_Sq nodeInf; //nodeInf存储当前通道块信息
PosType curPos; //当前位置
int curStep; //当前通道块序号
InitStack_Sq(&S);
curPos = start; //设定当前位置为"出口位置"
curStep = 1;
do
{
if(Pass(curPos, maze)) //当前位置可通过,即是未曾访问的通道块
{
FootPrint(curPos, maze); //留下足迹
ShowMaze(maze);
SetSElemType(&nodeInf, curStep, curPos, East); //设置通道块信息
Push_Sq(&S, nodeInf); //加入路径
if(EqualPosType(curPos, end)) //到达终点
{
printf("\n寻路成功!!\n\n");
return TRUE;
}
curPos = NextPos(curPos, East); //下一位置是当前位置的东邻
curStep++; //探索下一步
}
else //当前位置不能通过
{
if(!StackEmpty_Sq(S))
{
Pop_Sq(&S, &nodeInf); //修改结点指向
while(nodeInf.di==North && !StackEmpty_Sq(S)) //此通道块4个方向都遍历过
{
MarkPrint(nodeInf.seat, maze); //留下不能通过的标记,并退回一步
ShowMaze(maze);
Pop_Sq(&S, &nodeInf);
}
if(nodeInf.di<North)
{
maze[nodeInf.seat.x][nodeInf.seat.y] = ++nodeInf.di;//改变探索方向,在迷宫数组中留下标记
ShowMaze(maze);
Push_Sq(&S, nodeInf);
curPos = NextPos(nodeInf.seat, nodeInf.di);
}
}
}
}while(!StackEmpty_Sq(S));
printf("\n寻路失败!!\n\n");
return FALSE;
}
void InitMaze(MazeType maze[][N], PosType *start, PosType *end)
{ //迷宫规模为N×N
int i, j, tmp;
srand((unsigned)time(NULL)); //用系统时间做随机数种子
for(i=0; i<N; i++)
{
for(j=0; j<N; j++)
{
if(i==0 || j==0 || i==N-1 || j==N-1)
maze[i][j] = Wall; //迷宫外墙
else
{
tmp = rand()%X; //生成随机数填充迷宫
if(!tmp)
maze[i][j] = Obstacle; //1/X的概率生成障碍
else
maze[i][j] = Way; //其它地方加入路径
}
}
}
(*start).x = 1; //迷宫入口
(*start).y = 0;
(*end).x = N-2; //迷宫出口
(*end).y = N-1;
maze[1][0] = maze[N-2][N-1] = Way; //开放入口和出口
maze[1][1] = maze[N-2][N-2] = Way; //为了提高成功率,入口处和出口处临近的结点一直设为通路
}
void PaintMaze(MazeType maze[][N])
{
int i, j;
for(i=0; i<N; i++)
for(j=0; j<N; j++)
{
if(maze[i][j]==Wall) //外墙
printf("");
else if(maze[i][j]==Obstacle) //内部障碍
printf("");
else if(maze[i][j]==East) //朝东探索
printf("");
else if(maze[i][j]==South) //朝南探索
printf("");
else if(maze[i][j]==West) //朝西探索
printf("");
else if(maze[i][j]==North) //朝北探索
printf("");
else if(maze[i][j]==DeadLock) //访问过且不能通过的结点
printf("");
else //未访问过的路径结点
printf(" ");
if(j!=0 && j%(N-1)==0) //每隔N个结点换行
printf("\n");
}
}
void ShowMaze(MazeType maze[][N]) //相当于刷新操作
{
Wait(SleepTime); //暂停
system("cls"); //先清除屏幕现有内容
PaintMaze(maze); //在屏幕上画出迷宫
}
Status EqualPosType(PosType seat1, PosType seat2)
{
if(seat1.x==seat2.x && seat1.y==seat2.y)
return TRUE; //两通道块坐标相等返回1
else
return ERROR;
}
Status Pass(PosType seat, MazeType maze[][N])
{
int x = seat.x;
int y = seat.y;
if(!IsCross(seat) && maze[x][y]==Way) //结点不能越界
return TRUE;
else
return ERROR;
}
void FootPrint(PosType seat, MazeType maze[][N]) //所谓留下足迹即设置其下一次访问方向
{
maze[seat.x][seat.y] = East; //初始设置向东探索
}
void SetSElemType (SElemType_Sq *e, int ord, PosType seat, int di)
{
(*e).ord = ord;
(*e).seat = seat;
(*e).di = di;
}
PosType NextPos(PosType seat, int di)
{
PosType tmp = seat;
switch(di)
{
case East: tmp.y++; //向东
break;
case South: tmp.x++; //向南
break;
case West: tmp.y--; //向西
break;
case North: tmp.x--; //向北
break;
}
return tmp;
}
Status IsCross(PosType seat)
{
int x = seat.x;
int y = seat.y;
if(x<0 || y<0 || x>N-1 || y>N-1)
return TRUE; //越界
else
return FALSE;
}
void MarkPrint(PosType seat, MazeType maze[][N])
{
int x = seat.x;
int y = seat.y;
maze[x][y] = DeadLock; //留下不能通过的标记
}
#endif
@@ -0,0 +1,104 @@
/*********************************
* *
* 文件夹: ▲03 栈和队列\04 Maze *
* *
* 文件名: Maze.h *
* *
* 内 容: 迷宫相关操作列表 *
* *
*********************************/
#ifndef MAZE_H
#define MAZE_H
#include <stdio.h>
#include <stdlib.h> //提供system、rand、srand原型
#include <time.h> //提供time原型
#include "../../▲01 绪论/Status.h" //**▲01 绪论**//
/* 宏定义 */
#define N 15 //迷宫的大小为N×N
#define X 4 //X用于随机数取余,其生成的随机数范围是0到X-1
//X越大,生成可通行迷宫的概率就越大
#define SleepTime 3 //SleepTime代表休眠时间间隔
/* 迷宫类型定义 */
typedef enum //迷宫通道块类型
{
Wall, //外墙
Obstacle, //迷宫障碍
Way, //路径
DeadLock, //路径上的“死胡同”
East,South,West,North //访问方向-东南西北
}MazeNode;
typedef struct //迷宫通道块坐标
{
int x; //通道块的横、纵坐标定义
int y;
}PosType;
typedef struct //通道块信息
{
int ord; //通道块的“序号”
PosType seat; //通道块的“坐标位置”
int di; //下一个该访问的“方向”
}SElemType_Sq;
#include "../01 SequenceStack/SequenceStack.c" //**▲03 栈和队列**//
typedef int MazeType; //迷宫元素类型
/* 迷宫函数列表 */
Status MazePath(MazeType maze[][N], PosType start, PosType end);
/*━━━━━━━━━━━━━━━━┓
┃(01)算法3.3:迷宫寻路(穷举法) ┃
┗━━━━━━━━━━━━━━━━*/
void InitMaze(MazeType maze[][N], PosType *start, PosType *end);
/*━━━━━━━━━━━━━━━━━━┓
┃(02)迷宫的初始化,包括出入口的初始化 ┃
┗━━━━━━━━━━━━━━━━━━*/
void PaintMaze(MazeType maze[][N]);
/*━━━━━━━━━━┓
┃(03)在屏幕上画出迷宫┃
┗━━━━━━━━━━*/
void ShowMaze(MazeType maze[][N]);
/*━━━━━━━┓
┃(04)迷宫的显示┃
┗━━━━━━━*/
Status EqualPosType(PosType a, PosType b);
/*━━━━━━━━━━━━━━━━━━━┓
┃(05)比较迷宫中两个通道块是否为同一通道块┃
┗━━━━━━━━━━━━━━━━━━━*/
Status Pass(PosType seat, MazeType maze[][N]);
/*━━━━━━━━━━━━━┓
┃(06)判定此通道块是否未访问┃
┗━━━━━━━━━━━━━*/
void FootPrint(PosType seat, MazeType maze[][N]);
/*━━━━━━━━━━━━━━━━┓
┃(07)遇到未访问结点时留下初始足迹┃
┗━━━━━━━━━━━━━━━━*/
void SetSElemType(SElemType_Sq *e, int ord, PosType seat, int di);
/*━━━━━━━━━━┓
┃(08)更新通道块的信息┃
┗━━━━━━━━━━*/
PosType NextPos(PosType seat, int di);
/*━━━━━━━━━━┓
┃(09)当前通道块的后继┃
┗━━━━━━━━━━*/
Status IsCross(PosType seat);
/*━━━━━━━━━━━━┓
┃(10)判断当前位置是否越界┃
┗━━━━━━━━━━━━*/
void MarkPrint(PosType seat, MazeType maze[][N]);
/*━━━━━━━━━━━━━━━━━┓
┃(11)标记当前位置上的通道块不可访问┃
┗━━━━━━━━━━━━━━━━━*/
#endif
@@ -0,0 +1,23 @@
/***************************************
* *
* 文件夹: ▲03 栈和队列\05 Expression *
* *
* 内 容: 表达式求值相关函数测试 *
* *
***************************************/
#include "Expression.c" //**▲03 栈和队列**//
int main(int argc, char **argv)
{
char opnd;
char *exp = "(2+3)*4*6#";
opnd = EvaluateExpression(exp);
printf("作为示例,%s 的计算结果为:%d\n", exp, opnd-'0');
printf("\n");
return 0;
}
@@ -0,0 +1,180 @@
/***************************************
* *
* 文件夹: ▲03 栈和队列\05 Expression *
* *
* 文件名: Expression.c *
* *
* 算 法: 3.4 *
* *
***************************************/
#ifndef EXPRESSION_C
#define EXPRESSION_C
#include "Expression.h" //**▲03 栈和队列**//
/*════╗
║ 算法3.4║
╚════*/
OperandType EvaluateExpression(char exp[]) //从exp读入表达式
{
SqStack OPTR, OPND; //符号栈和数字栈
SElemType_Sq e, ch;
OperatorType theta, x; //符号
OperandType a, b; //数字
int i;
InitStack_Sq(&OPTR);
Push_Sq(&OPTR, '#');
InitStack_Sq(&OPND);
i = 0;
ch = exp[i++];
while(ch!='#' || GetTop_OPTR(OPTR)!='#')
{
if(!In(ch)) //c不是符号则入栈
{
Push_Sq(&OPND, ch);
ch = exp[i++];
}
else
{
switch(Precede(GetTop_OPTR(OPTR), ch))
{
case '<': //栈中符号优先级低,继续进栈
Push_Sq(&OPTR, ch);
ch = exp[i++];
break;
case '=': //优先级相等时,说明遇到括号,需要脱括号
Pop_Sq(&OPTR, &x);
ch = exp[i++];
break;
case '>':
Pop_Sq(&OPTR, &theta); //栈中操作符优先级高时,先计算,再降计算结果压入栈,
Pop_Sq(&OPND, &b);
Pop_Sq(&OPND, &a);
Push_Sq(&OPND, Operate(a, theta, b));
break; //这儿没有读字符,c保留的还是刚才读到的字符
}
}
}
return GetTop_OPTR(OPND);
}
OperatorType GetTop_OPTR(SqStack OPTR)
{
SElemType_Sq e;
GetTop_Sq(OPTR, &e);
return e;
}
Status In(SElemType_Sq c)
{
switch(c)
{
case '+':
case '-':
case '*':
case '/':
case '(':
case ')':
case '#':
return TRUE;
default :
return FALSE;
}
}
OperatorType Precede(OperatorType o1, OperatorType o2)
{
OperatorType f;
switch(o2)
{
case '+':
case '-':
if(o1=='(' || o1=='#')
f = '<';
else
f = '>';
break;
case '*':
case '/':
if(o1=='*' || o1=='/' || o1==')')
f = '>';
else
f = '<';
break;
case '(':
if(o1==')')
{
printf("括号匹配错误!\n");
exit(ERROR);
}
else
f = '<';
break;
case ')':
switch(o1)
{
case '(':
f = '=';
break;
case '#':
printf("输入了错误的括号!\n");
exit(ERROR);
default:
f = '>';
}
break;
case '#':
switch(o1)
{
case '#':
f = '=';
break;
case '(':
printf("表达式中有多余括号!\n");
exit(ERROR);
default:
f = '>';
}
}
return f;
}
OperandType Operate(OperandType a, OperatorType theta, OperandType b)
{
int x, y, z;
x = a - 48;
y = b - 48;
switch(theta)
{
case '+':
return x+y+48;
break;
case '-':
return x-y+48;
break;
case '*':
return x*y+48;
break;
case '/':
return x/y+48;
break;
}
}
#endif
@@ -0,0 +1,48 @@
/***************************************
* *
* 文件夹: ▲03 栈和队列\05 Expression *
* *
* 文件名: Expression.h *
* *
* 内 容: 表达式求值相关操作列表 *
* *
***************************************/
#ifndef EXPRESSION_H
#define EXPRESSION_H
#include <stdio.h>
/* 类型定义 */
typedef char SElemType_Sq;
#include "../01 SequenceStack/SequenceStack.c" //**▲03 栈和队列**//
typedef SElemType_Sq OperandType; //操作数类型
typedef SElemType_Sq OperatorType; //运算符类型
OperandType EvaluateExpression(char exp[]);
/*━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃(01)算法3.4:表达式求值,假设表达式中操作数均只有一位。 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
OperatorType GetTop_OPTR(SqStack OPTR);
/*━━━━━━━━━━━━━━┓
┃(02)获取操作符栈的栈顶元素。┃
┗━━━━━━━━━━━━━━*/
Status In(SElemType_Sq c);
/*━━━━━━━━━━━━━━┓
┃(03)判断c是否属于操作符集。 ┃
┗━━━━━━━━━━━━━━*/
OperatorType Precede(OperatorType o1, OperatorType o2);
/*━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃(04)判断栈中操作符o1与表达式中的操作符o2的优先级。┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━*/
OperandType Operate(OperandType a, OperatorType theta, OperandType b);
/*━━━━━━━━━━┓
┃(05)计算表达式的值。┃
┗━━━━━━━━━━*/
#endif
@@ -0,0 +1,27 @@
/**********************************
* *
* 文件夹: ▲03 栈和队列\06 Hanoi *
* *
* 内 容: 汉诺塔相关函数测试 *
* *
**********************************/
#include "Hanoi.c" //**03 栈和队列**//
int main(int argc, char **argv)
{
int n;
char x = 'x';
char y = 'y';
char z = 'z';
n = 3; //为控制时间,n不要超过10
printf("作为示例,假设圆盘个数为 %d ,操作步骤如下...\n", n);
hanoi(n,x,y,z);
printf("\n");
return 0;
}
@@ -0,0 +1,37 @@
/**********************************
* *
* 文件夹: ▲03 栈和队列\06 Hanoi *
* *
* 文件名: Hanoi.c *
* *
* 算 法: 3.5 *
* *
**********************************/
#ifndef HANOI_C
#define HANOI_C
#include "Hanoi.h" //**03 栈和队列**//
/*════╗
║ 算法3.5║
╚════*/
void hanoi(int n, char x, char y, char z)
{
if(n==1) //欲移动n个圆盘,需先移动其上的n-1个圆盘
move(x, 1, z); //将编号为1的圆盘从x移到z
else
{
hanoi(n-1, x, z, y); //将x上编号为1至n-1的圆盘移到y,z作辅助塔
move(x, n, z); //将编号为n的圆盘从x移到z
hanoi(n-1, y, x, z); //将y上编号为1至n-1的圆盘移动到z,x作辅助塔
}
}
void move(char x, int n, char z)
{
gStep++; //step为全局变量,在main函数之外定义
printf("第%2d步:将第 %d 个圆盘从 %c 移到 %c \n", gStep, n, x, z);
}
#endif
@@ -0,0 +1,30 @@
/**********************************
* *
* 文件夹: ▲03 栈和队列\06 Hanoi *
* *
* 文件名: Hanoi.h *
* *
* 内 容: 汉诺塔相关操作列表 *
* *
**********************************/
#ifndef HANOI_H
#define HANOI_H
#include <stdio.h>
/* 全局变量 */
int gStep; //统计移动步数
/* 汉诺塔函数列表 */
void hanoi(int n, char x, char y, char z);
/*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃(1)算法3.5:汉诺塔求解。以y为辅助,将x上前n个圆盘移动到z。┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
void move(char x, int n, char z);
/*━━━━━━━━━━━━┓
┃(2)将第n个圆盘从x移到z。┃
┗━━━━━━━━━━━━*/
#endif
@@ -0,0 +1,109 @@
/**************************************
* *
* 文件夹: ▲03 栈和队列\07 LinkQueue *
* *
* 内 容: 链队相关函数测试 *
* *
*************************************/
#include <stdio.h>
#include "LinkQueue.c" //**03 栈和队列**//
void PrintElem(QElemType_L e); //测试函数,打印整型
int main(int argc, char **argv)
{
LinkQueue Q;
int i;
QElemType_L e;
printf("▼1\n▲函数 InitQueue_L 测试...\n"); //1.函数InitQueue_L测试
{
printf("初始化链队 Q ...\n");
InitQueue_L(&Q);
printf("\n");
}
PressEnter;
printf("▼4\n▲函数 QueueEmpty_L 测试...\n"); //4.函数QueueEmpty_L测试
{
QueueEmpty_L(Q) ? printf(" Q 为空!!\n") : printf(" Q 不为空!\n");
printf("\n");
}
PressEnter;
printf("▼7\n▲函数 EnQueue_L 测试...\n"); //7.函数EnQueue_L测试
{
for(i=1; i<=6; i++)
{
printf("元素 \"%2d\" 入队,", 2*i);
EnQueue_L(&Q, 2*i);
printf("(累计第 %d 个元素)...\n", QueueLength_L(Q));
}
printf("\n");
}
PressEnter;
printf("▼9\n▲函数 QueueTraverse_L 测试...\n");//9.函数QueueTraverse_L测试
{
printf(" Q 中的元素为:Q = ");
QueueTraverse_L(Q, PrintElem);
printf("\n\n");
}
PressEnter;
printf("▼8\n▲函数 DeQueue_L 测试...\n"); //8.函数DeQueue_L测试
{
DeQueue_L(&Q, &e);
printf("队头元素 \"%d\" 出队...\n", e);
printf(" Q 中的元素为:Q = ");
QueueTraverse_L(Q, PrintElem);
printf("\n\n");
}
PressEnter;
printf("▼5\n▲函数 QueueLength_L 测试...\n"); //5.函数QueueLength_L测试
{
i = QueueLength_L(Q);
printf(" Q 的长度为 %d \n", i);
printf("\n");
}
PressEnter;
printf("▼6\n▲函数 GetHead_L 测试...\n"); //6.函数GetHead_L测试
{
GetHead_L(Q, &e);
printf("队头元素的值为 \"%d\" \n", e);
printf("\n");
}
PressEnter;
printf("▼3\n▲函数 ClearQueue_L 测试...\n"); //3.函数ClearQueue_L测试
{
printf("清空 Q 前:");
QueueEmpty_L(Q) ? printf(" Q 为空!!\n") : printf(" Q 不为空!\n");
ClearQueue_L(&Q);
printf("清空 Q 后:");
QueueEmpty_L(Q) ? printf(" Q 为空!!\n") : printf(" Q 不为空!\n");
printf("\n");
}
PressEnter;
printf("▼2\n▲函数 DestroyQueue_L 测试...\n"); //2.函数DestroyQueue_L测试
{
printf("销毁 Q 前:");
Q.front!=NULL && Q.rear!=NULL ? printf(" Q 存在!\n") : printf(" Q 不存在!!\n");
DestroyQueue_L(&Q);
printf("销毁 Q 后:");
Q.front!=NULL && Q.rear!=NULL ? printf(" Q 存在!\n") : printf(" Q 不存在!!\n");
printf("\n");
}
PressEnter;
return 0;
}
void PrintElem(QElemType_L e)
{
printf("%d ", e);
}
@@ -0,0 +1,133 @@
/**************************************
* *
* 文件夹: ▲03 栈和队列\07 LinkQueue *
* *
* 文件名: LinkQueue.c *
* *
*************************************/
#ifndef LINKQUEUE_C
#define LINKQUEUE_C
#include "LinkQueue.h" //**▲03 栈和队列**//
Status InitQueue_L(LinkQueue *Q)
{
(*Q).front = (*Q).rear = (QueuePtr)malloc(sizeof(QNode));
if(!(*Q).front)
exit(OVERFLOW);
(*Q).front->next = NULL;
return OK;
}
void ClearQueue_L(LinkQueue *Q)
{
(*Q).rear = (*Q).front->next;
while((*Q).rear)
{
(*Q).front->next = (*Q).rear->next;
free((*Q).rear);
(*Q).rear = (*Q).front->next;
}
(*Q).rear = (*Q).front;
}
void DestroyQueue_L(LinkQueue *Q)
{
while((*Q).front)
{
(*Q).rear = (*Q).front->next;
free((*Q).front);
(*Q).front = (*Q).rear;
}
}
Status QueueEmpty_L(LinkQueue Q)
{
if(Q.front==Q.rear)
return TRUE;
else
return FALSE;
}
int QueueLength_L(LinkQueue Q)
{
int count = 0;
QueuePtr p = Q.front;
while(p!=Q.rear)
{
count++;
p = p->next;
}
return count;
}
Status GetHead_L(LinkQueue Q, QElemType_L *e)
{
QueuePtr p;
if(Q.front==Q.rear)
return ERROR;
p = Q.front->next;
*e = p->data;
return OK;
}
Status EnQueue_L(LinkQueue *Q, QElemType_L e)
{
QueuePtr p;
p = (QueuePtr)malloc(sizeof(QNode));
if(!p)
exit(OVERFLOW);
p->data = e;
p->next = NULL;
(*Q).rear->next = p;
(*Q).rear=p;
return OK;
}
Status DeQueue_L(LinkQueue *Q, QElemType_L *e)
{
QueuePtr p;
if((*Q).front==(*Q).rear)
return ERROR;
p = (*Q).front->next;
*e = p->data;
(*Q).front->next = p->next;
if((*Q).rear==p)
(*Q).rear = (*Q).front;
free(p);
return OK;
}
void QueueTraverse_L(LinkQueue Q, void (Visit)(QElemType_L))
{
QueuePtr p;
p = Q.front->next;
while(p)
{
Visit(p->data);
p = p->next;
}
}
#endif
@@ -0,0 +1,82 @@
/**************************************
* *
* 文件夹: ▲03 栈和队列\07 LinkQueue *
* *
* 文件名: LinkQueue.h *
* *
* 内 容: 链队相关操作列表 *
* *
*************************************/
#ifndef LINKQUEUE_H
#define LINKQUEUE_H
#include <stdio.h>
#include <stdlib.h> //提供malloc、realloc、free、exit原型
#include "../../▲01 绪论/Status.h" //**▲01 绪论**//
/* 链队类型定义 */
/* 在模拟银行排队、二叉树三叉链表存储的算法中,QElemType_L需重新定义*/
#if !defined BANKQUEUING_H && \
!defined TRI_BINARYTREE_H
typedef int QElemType_L;
#endif
typedef struct QNode
{
QElemType_L data;
struct QNode *next;
}QNode;
typedef QNode* QueuePtr;
typedef struct
{
QueuePtr front; //头指针
QueuePtr rear; //尾指针
}LinkQueue; //队列的链式存储表示
/* 链栈函数列表 */
Status InitQueue_L(LinkQueue *Q);
/*━━━━━━━━━┓
┃(01)初始化链队Q。 ┃
┗━━━━━━━━━*/
void ClearQueue_L(LinkQueue *Q);
/*━━━━━━┓
┃(02)置空Q。 ┃
┗━━━━━━*/
void DestroyQueue_L(LinkQueue *Q);
/*━━━━━━┓
┃(03)销毁Q。 ┃
┗━━━━━━*/
Status QueueEmpty_L(LinkQueue Q);
/*━━━━━━━━━━┓
┃(04)判断Q是否为空。 ┃
┗━━━━━━━━━━*/
int QueueLength_L(LinkQueue Q);
/*━━━━━━━━━━┓
┃(05)返回Q元素个数。 ┃
┗━━━━━━━━━━*/
Status GetHead_L(LinkQueue Q, QElemType_L *e);
/*━━━━━━━━━━━┓
┃(06)用e获取队头元素。 ┃
┗━━━━━━━━━━━*/
Status EnQueue_L(LinkQueue *Q, QElemType_L e);
/*━━━━━━━━┓
┃(07)元素e入队。 ┃
┗━━━━━━━━*/
Status DeQueue_L(LinkQueue *Q, QElemType_L *e);
/*━━━━━━━━┓
┃(08)元素e出队。 ┃
┗━━━━━━━━*/
void QueueTraverse_L(LinkQueue Q, void(Visit)(QElemType_L));
/*━━━━━━━┓
┃(09)访问队列。┃
┗━━━━━━━*/
#endif
@@ -0,0 +1,109 @@
/****************************************
* *
* 文件夹: ▲03 栈和队列\08 CylSeqQueue *
* *
* 内 容: 循环队列相关函数测试 *
* *
****************************************/
#include <stdio.h>
#include "CylSeqQueue.c" //**▲03 栈和队列**//
void PrintElem(QElemType_CSq e); //测试函数,打印整型
int main(int argc, char **argv)
{
CSqQueue Q;
int i;
QElemType_CSq e;
printf("▼1\n▲函数 InitQueue_CSq 测试...\n"); //1.函数InitQueue_CSq测试
{
printf("初始化循环顺序队列 Q ...\n");
InitQueue_CSq(&Q);
printf("\n");
}
PressEnter;
printf("▼4\n▲函数 QueueEmpty_CSq 测试...\n"); //4.函数QueueEmpty_CSq测试
{
QueueEmpty_CSq(Q) ? printf(" Q 为空!!\n") : printf(" Q 不为空!\n");
printf("\n");
}
PressEnter;
printf("▼7\n▲函数 EnQueue_CSq 测试...\n"); //7.函数EnQueue_CSq测试
{
for(i=1; i<=6; i++)
{
printf("元素 \"%2d\" 入队Q", 2*i);
EnQueue_CSq(&Q, 2*i);
printf("(累计第 %d 个元素)...\n", QueueLength_CSq(Q));
}
printf("\n");
}
PressEnter;
printf("▼9\n▲函数 QueueTraverse_CSq 测试...\n"); //9.函数QueueTraverse_CSq测试
{
printf(" Q 中的元素为:Q = ");
QueueTraverse_CSq(Q, PrintElem);
printf("\n\n");
}
PressEnter;
printf("▼8\n▲函数 DeQueue_CSq 测试...\n"); //8.函数DeQueue_CSq测试
{
DeQueue_CSq(&Q, &e);
printf("队头元素 \"%d\" 出队...\n", e);
printf(" Q 中的元素为:Q = ");
QueueTraverse_CSq(Q, PrintElem);
printf("\n\n");
}
PressEnter;
printf("▼5\n▲函数 QueueLength_CSq 测试...\n"); //5.函数QueueLength_CSq测试
{
i = QueueLength_CSq(Q);
printf(" Q 的长度为 %d \n", i);
printf("\n");
}
PressEnter;
printf("▼6\n▲函数 GetHead_CSq 测试...\n"); //6.函数GetHead_CSq测试
{
GetHead_CSq(Q, &e);
printf("队头元素的值为 \"%d\" \n", e);
printf("\n");
}
PressEnter;
printf("▼3\n▲函数 ClearQueue_CSq 测试...\n"); //3.函数ClearQueue_CSq测试
{
printf("清空 Q 前:");
QueueEmpty_CSq(Q) ? printf(" Q 为空!!\n") : printf(" Q 不为空!\n");
ClearQueue_CSq(&Q);
printf("清空 Q 后:");
QueueEmpty_CSq(Q) ? printf(" Q 为空!!\n") : printf(" Q 不为空!\n");
printf("\n");
}
PressEnter;
printf("▼2\n▲函数 DestroyQueue_CSq 测试...\n"); //2.函数DestroyQueue_CSq测试
{
printf("销毁 Q 前:");
Q.base!=NULL ? printf(" Q 存在!\n") : printf(" Q 不存在!!\n");
DestroyQueue_CSq(&Q);
printf("销毁 Q 后:");
Q.base!=NULL ? printf(" Q 存在!\n") : printf(" Q 不存在!!\n");
printf("\n");
}
PressEnter;
return 0;
}
void PrintElem(QElemType_CSq e)
{
printf("%d ", e);
}
@@ -0,0 +1,95 @@
/****************************************
* *
* 文件夹: ▲03 栈和队列\08 CylSeqQueue *
* *
* 文件名: CylSeqQueue.c *
* *
****************************************/
#ifndef CYLSEQQUEUE_C
#define CYLSEQQUEUE_C
#include "CylSeqQueue.h" //**▲03 栈和队列**//
Status InitQueue_CSq(CSqQueue *Q)
{
(*Q).base = (QElemType_CSq *)malloc(MAXQSIZE*sizeof(QElemType_CSq));
if(!(*Q).base)
exit(OVERFLOW);
(*Q).front = (*Q).rear = 0;
return OK;
}
void ClearQueue_CSq(CSqQueue *Q)
{
(*Q).front = (*Q).rear = 0;
}
void DestroyQueue_CSq(CSqQueue *Q)
{
if((*Q).base)
free((*Q).base);
(*Q).base = NULL;
(*Q).front = (*Q).rear = 0;
}
Status QueueEmpty_CSq(CSqQueue Q)
{
if(Q.front==Q.rear) //队列空的标志
return TRUE;
else
return FALSE;
}
int QueueLength_CSq(CSqQueue Q)
{
return (Q.rear-Q.front+MAXQSIZE) % MAXQSIZE;//队列长度
}
Status GetHead_CSq(CSqQueue Q, QElemType_CSq *e)
{
if(Q.front==Q.rear) //队列空
return ERROR;
*e = Q.base[Q.front];
return OK;
}
Status EnQueue_CSq(CSqQueue *Q, QElemType_CSq e)
{
if(((*Q).rear+1)%MAXQSIZE == (*Q).front) //队列满
return ERROR;
(*Q).base[(*Q).rear] = e;
(*Q).rear = ((*Q).rear+1)%MAXQSIZE;
return OK;
}
Status DeQueue_CSq(CSqQueue *Q, QElemType_CSq *e)
{
if((*Q).front==(*Q).rear) //队列空
return ERROR;
*e = (*Q).base[(*Q).front];
(*Q).front = ((*Q).front+1)%MAXQSIZE;
return OK;
}
void QueueTraverse_CSq(CSqQueue Q, void(Visit)(QElemType_CSq))
{
int i = Q.front;
while(i!=Q.rear)
{
Visit(Q.base[i]);
i = (i+1)%MAXQSIZE;
}
}
#endif
@@ -0,0 +1,76 @@
/****************************************
* *
* 文件夹: ▲03 栈和队列\08 CylSeqQueue *
* *
* 文件名: CylSeqQueue.h *
* *
* 内 容: 循环队列相关操作列表 *
* *
****************************************/
#ifndef CYLSEQQUEUE_H
#define CYLSEQQUEUE_H
#include <stdio.h>
#include <stdlib.h> //提供malloc、realloc、free、exit原型
#include "../../▲01 绪论/Status.h" //**▲01 绪论**//
/* 宏定义 */
#define MAXQSIZE 1000 //最大队列长度
/* 循环队列类型定义 */
typedef int QElemType_CSq;
typedef struct //队列的顺序存储结构
{
QElemType_CSq *base; //初始化的动态分配存储空间
int front; //头指针,若队列不空,指向队头元素
int rear; //尾指针,若队列不空,指向队列尾元素的下一个位置
}CSqQueue;
/* 循环队列函数列表 */
Status InitQueue_CSq(CSqQueue *Q);
/*━━━━━━━━━━━┓
┃(01)初始化循环队列Q。 ┃
┗━━━━━━━━━━━*/
void ClearQueue_CSq(CSqQueue *Q);
/*━━━━━━┓
┃(02)置空Q。 ┃
┗━━━━━━*/
void DestroyQueue_CSq(CSqQueue *Q);
/*━━━━━━┓
┃(03)销毁Q。 ┃
┗━━━━━━*/
Status QueueEmpty_CSq(CSqQueue Q);
/*━━━━━━━━━━┓
┃(04)判断Q是否为空。 ┃
┗━━━━━━━━━━*/
int QueueLength_CSq(CSqQueue Q);
/*━━━━━━━━━━┓
┃(05)返回Q元素个数。 ┃
┗━━━━━━━━━━*/
Status GetHead_CSq(CSqQueue Q, QElemType_CSq *e);
/*━━━━━━━━━━━┓
┃(06)用e获取队头元素。 ┃
┗━━━━━━━━━━━*/
Status EnQueue_CSq(CSqQueue *Q, QElemType_CSq e);
/*━━━━━━━━┓
┃(07)元素e入队。 ┃
┗━━━━━━━━*/
Status DeQueue_CSq(CSqQueue *Q, QElemType_CSq *e);
/*━━━━━━━━┓
┃(08)元素e出队。 ┃
┗━━━━━━━━*/
void QueueTraverse_CSq(CSqQueue Q, void(Visit)(QElemType_CSq));
/*━━━━━━━┓
┃(09)访问队列。┃
┗━━━━━━━*/
#endif
@@ -0,0 +1,19 @@
/****************************************
* *
* 文件夹: ▲03 栈和队列\09 BankQueuing *
* *
* 内 容: 模拟银行排队相关函数测试 *
* *
****************************************/
#include "BankQueuing.c" //**▲03 栈和队列**//
int main(int argc, char **argv)
{
getchar();
Bank_Simulation_1(); //算法3.6
// Bank_Simulation_2(); //算法3.7,另一种算法
return 0;
}
@@ -0,0 +1,260 @@
/****************************************
* *
* 文件夹: ▲03 栈和队列\09 BankQueuing *
* *
* 文件名: BankQueuing.c *
* *
* 算 法: 3.6、3.7 *
* *
****************************************/
#ifndef BANKQUEUING_C
#define BANKQUEUING_C
#include "BankQueuing.h" //**▲03 栈和队列**//
/*════╗
║ 算法3.6║
╚════*/
void Bank_Simulation_1() //银行业务模拟,统计一天内客户在银行逗留的平均时间
{
char eventType;
OpenForDay(); //初始化
while(MoreEvent())
{
EventDrived(&eventType); //事件驱动
switch(eventType)
{
case 'A':
CustomerArrived();
break;
case 'D':
CustomerDeparture();
break;
default :
Invalid();
}
}
CloseForDay();
}
void OpenForDay()
{
int i;
gTotalTime = 0; //初始化累计时间和客户数为0
gCustomerNum = 0;
InitList_L(&gEv); //初始化事件链表为空表
gEn.OccurTime = 0; //设定第一个客户到达事件
gEn.NType = Arrive;
OrderInsert(gEv, gEn, cmp); //插入事件表
for(i=1; i<=4; ++i)
InitQueue_L(&gQ[i]); //置空队列
Show();
}
Status MoreEvent()
{
if(!ListEmpty_L(gEv))
return TRUE;
else
return FALSE;
}
void EventDrived(char *event)
{
ListDelete_L(gEv, 1, &gEn);
if(gEn.NType==Arrive)
*event = 'A';
else
*event = 'D';
}
void CustomerArrived() //处理客户到达事件,gEn.NType=0
{
int durtime, intertime;
int cur_LeftTime, suc_ArrivalTime;
int i;
++gCustomerNum; //总客户数增一
Random(&durtime, &intertime); //生成当前客户办理业务需要的时间和下一个客户达到时间间隔
cur_LeftTime = gEn.OccurTime + durtime; //当前客户的离开时间
suc_ArrivalTime = gEn.OccurTime + intertime;//下一个客户到达时间
gCustomerRcd.ArrivedTime = gEn.OccurTime; //记录当前客户信息
gCustomerRcd.Duration = durtime;
gCustomerRcd.Count = gCustomerNum;
i = Minimum(gQ); //求长度最短队列
EnQueue_L(&gQ[i], gCustomerRcd); //当前客户进入最短队列
Show();
if(suc_ArrivalTime<gCloseTime) //银行尚未关门,将下一客户到达事件插入事件表
{
gEn.OccurTime = suc_ArrivalTime; //gEn的参数已经改变
gEn.NType = Arrive;
OrderInsert(gEv, gEn, cmp);
}
if(QueueLength_L(gQ[i])==1) //设定第i队列的队头客户的离开事件并插入事件表
{
gEn.OccurTime = cur_LeftTime;
gEn.NType = i;
OrderInsert(gEv, gEn, cmp);
}
}
void CustomerDeparture() //处理客户离开事件,gEn.NType>0
{
int i = gEn.NType;
DeQueue_L(&gQ[i], &gCustomerRcd); //删除第i队列的排头客户
Show();
gTotalTime += gEn.OccurTime - gCustomerRcd.ArrivedTime; //累计客户逗留时间
if(!QueueEmpty_L(gQ[i])) //设定第i队列的第一个离开事件并插入事件表
{
GetHead_L(gQ[i], &gCustomerRcd);
gEn.OccurTime += gCustomerRcd.Duration;
gEn.NType = i;
OrderInsert(gEv,gEn,cmp);
}
}
void Invalid()
{
printf("运行错误!");
exit(OVERFLOW);
}
void CloseForDay()
{
printf("当天总共有%d个客户,平均逗留时间为%d分钟。\n",gCustomerNum,gTotalTime/gCustomerNum);
}
int cmp(Event a, Event b) //比较两事件发生次序
{
if(a.OccurTime<b.OccurTime) //a晚于b发生
return -1;
if(a.OccurTime==b.OccurTime) //a、b同时发生
return 0;
if(a.OccurTime>b.OccurTime) //a早于b发生
return 1;
}
void Random(int *durtime, int *intertime)
{
srand((unsigned)time(NULL));
*durtime = rand()%DurationTime+1; //办业务时间持续1到20分钟
*intertime = rand()%IntervalTime+1; //下一个顾客来的时间为间隔1到10分钟
}
Status OrderInsert(EventList gEv, Event gEn, int (cmp)(Event,Event))
{
int i;
EventList p, pre, s;
pre = gEv;
p = gEv->next; //p指向第一个事件
while(p && cmp(gEn, p->data)==1) //查找gEn在事件表中应该插入的位置
{
pre = p;
p = p->next;
}
s = (LinkList)malloc(sizeof(LNode));
if(!s)
exit(OVERFLOW);
s->data = gEn; //将gEn插入事件表
s->next = pre->next;
pre->next = s;
return OK;
}
int Minimum()
{
int i1 = QueueLength_L(gQ[1]);
int i2 = QueueLength_L(gQ[2]);
int i3 = QueueLength_L(gQ[3]);
int i4 = QueueLength_L(gQ[4]);
if(i1<=i2 && i1<=i3 && i1<=i4)
return 1;
if(i2<i1 && i2<=i3 && i2<=i4)
return 2;
if(i3<i1 && i3<i2 && i3<=i4)
return 3;
if(i4<i1 && i4<i2 && i4<i3 )
return 4;
}
void Show()
{
int i;
QueuePtr p; //记录到来的客户是第几个
system("cls");
for(i=1; i<=4; i++)
{
for(p=gQ[i].front; p; p=p->next)
{
if(p==gQ[i].front)
{
if(i==1)
printf("柜台①●");
if(i==2)
printf("柜台②●");
if(i==3)
printf("柜台③●");
if(i==4)
printf("柜台④●");
}
else
printf("%03d",p->data.Count);
if(p==gQ[i].rear)
printf("\n");
}
}
Wait(SleepTime);
}
/*════╗
║ 算法3.7║
╚════*/
void Bank_Simulation_2()
{
OpenForDay(); //初始化
while(!ListEmpty_L(gEv))
{
ListDelete_L(gEv, 1, &gEn);
if(gEn.NType==Arrive)
CustomerArrived(); //处理客户到达事件
else
CustomerDeparture(); //处理客户离开事件
}
printf("当天总共有%d个客户,平均逗留时间为%d分钟。\n",gCustomerNum,gTotalTime/gCustomerNum);//计算平均逗留时间
}
#endif
@@ -0,0 +1,130 @@
/****************************************
* *
* 文件夹: ▲03 栈和队列\09 BankQueuing *
* *
* 文件名: BankQueuing.h *
* *
* 内 容: 模拟银行排队相关操作列表 *
* *
****************************************/
#ifndef BANKQUEUING_H
#define BANKQUEUING_H
#include <stdio.h>
#include <stdlib.h> //提供malloc、realloc、free、exit原型
#include <time.h> //提供time原型
#include "../../▲01 绪论/Status.h" //**▲01 绪论**//
/* 宏定义 */
#define SleepTime 1 //SleepTime代表休眠时间
#define DurationTime 20 //办理业务持续时间从1到DurationTime分钟不等
#define IntervalTime 10 //下一个客户到来时间间隔为1到IntervalTime分钟不等
/* 类型定义 */
typedef enum
{
Arrive,Leave_1,Leave_2,Leave_3,Leave_4
}EventType; //事件类型,0代表到达事件,1至4表示四个窗口的离开事件
typedef struct //事件链表
{
int OccurTime; //事件发生时刻
EventType NType; //事件类型
}Event;
typedef Event LElemType_L; //事件链表元素
typedef struct LNode
{
LElemType_L data;
struct LNode *next;
}LNode;
typedef LNode* LinkList;
typedef LinkList EventList; //事件链表类型,定义为有序链表
#include "../../▲02 线性表/04 SinglyLinkedList/SinglyLinkedList.c" //**▲02 线性表**//
typedef struct
{
int ArrivedTime; //客户到达时间
int Duration; //办理事务所需的时间
int Count; //此变量记录来到每个队列的客户是第几个
}QElemType_L; //队列的数据元素类型
#include "../07 LinkQueue/LinkQueue.c" //**▲03 栈和队列**//
/* 全局变量 */
int gTotalTime, gCustomerNum; //累计客户逗留时间,客户数
int gCloseTime = 480; //关门时间,假设银行每天营业8小时,480分
EventList gEv; //事件表
Event gEn; //事件
LinkQueue gQ[5]; //4个客户队列,0号单元弃用
QElemType_L gCustomerRcd; //客户记录
/* 模拟银行排队函数列表 */
void Bank_Simulation_1();
/*━━━━━━━━━━━━━━━━┓
┃(01)算法3.6:模拟银行排队事件。 ┃
┗━━━━━━━━━━━━━━━━*/
void OpenForDay();
/*━━━━━━━━━━━━━━┓
┃(02)银行开门,初始化各变量。┃
┗━━━━━━━━━━━━━━*/
Status MoreEvent();
/*━━━━━━━━━━━━┓
┃(03)判断事件表是否为空。┃
┗━━━━━━━━━━━━*/
void EventDrived(char *event);
/*━━━━━━━━━━━━━━━━┓
┃(04)事件驱动,获取当前事件类型。┃
┗━━━━━━━━━━━━━━━━*/
void CustomerArrived();
/*━━━━━━━━━━━┓
┃(05)处理客户到达事件。┃
┗━━━━━━━━━━━*/
void CustomerDeparture();
/*━━━━━━━━━━━┓
┃(06)处理客户离开事件。┃
┗━━━━━━━━━━━*/
void Invalid();
/*━━━━━━━━━┓
┃(07)事件类型错误。┃
┗━━━━━━━━━*/
void CloseForDay();
/*━━━━━━━┓
┃(08)银行关门。┃
┗━━━━━━━*/
int cmp(Event a, Event b);
/*━━━━━━━━━━━━━━━━┓
┃(09)比较事件a和b发生的先后次序。┃
┗━━━━━━━━━━━━━━━━*/
void Random(int *durtime, int *intertime);
/*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃(10)生成随机数,包括当前客服办理业务所需时间和下一客户到达间隔的时间。┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/
Status OrderInsert(EventList gEv, Event gEn, int(cmp)(Event,Event));
/*━━━━━━━━━━━━━━━┓
┃(11)将事件插入事件表正确位置。┃
┗━━━━━━━━━━━━━━━*/
int Minimum();
/*━━━━━━━━━━━━━┓
┃(12)求长度最短队列的序号。┃
┗━━━━━━━━━━━━━*/
void Show();
/*━━━━━━━━━━━━━━━━┓
┃(13)显示当前队列的客户排队情况。┃
┗━━━━━━━━━━━━━━━━*/
void Bank_Simulation_2();
/*━━━━━━━━━━━━━━━━┓
┃(14)算法3.7:模拟银行排队事件。 ┃
┗━━━━━━━━━━━━━━━━*/
#endif