栈的应用举例--行编辑程序
介绍:
一个简单的行编辑程序的功能是:接受用户从终端输入的程序或数据,并存入用户的数据区。由于用户在终端上进行输入时,不能保证不出差错,因此,若在编辑程序中,“每接受一个字符即存入用户数据区” 的做法显然不是最恰当的。
较好的做法是,设立一个输入缓冲区,用以接受用户输入的一行字符,然后逐行存入用户数据区。允许用户输入出差错,并在发现有误时可以及时更正。
例如,当用户发现刚刚键入的一个字符是错的时,可以补进一个退格符 “#” ,以表示前一个字符无效;如果发现当前键入的行内差错较多或难以补救,则可以键入一个退行符 “@” ,以表示当前行中的字符均无效。
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
typedef char SElemType; /* 定义栈元素的类型 */
#include<malloc.h> /* malloc()等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<process.h> /* exit() */
/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
/* -------------------------- 栈的顺序存储表示 -----------------------------*/
#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */
#define STACKINCREMENT 2 /* 存储空间分配增量 */
typedef struct SqStack
{
SElemType *base; /* 在栈构造之前和销毁之后,base的值为NULL */
SElemType *top; /* 栈顶指针 */
int stacksize; /* 当前已分配的存储空间,以元素为单位 */
}SqStack; /* 顺序栈 */
/* ----------------------------------------------------------------------------*/
Status visit(SElemType c)
{
printf("%d ", c);
return OK;
}
/* --------------------------------- 需要用到的顺序栈基本操作 ------------------------------------*/
Status InitStack(SqStack *S)
{ /* 构造一个空栈S */
(*S).base = (SElemType *)malloc(STACK_INIT_SIZE * sizeof(SElemType));
if (!(*S).base)
exit(OVERFLOW); /* 存储分配失败 */
(*S).top = (*S).base;
(*S).stacksize = STACK_INIT_SIZE;
return OK;
}
Status DestroyStack(SqStack *S)
{ /* 销毁栈S,S不再存在 */
free((*S).base);
(*S).base = NULL;
(*S).top = NULL;
(*S).stacksize = 0;
return OK;
}
Status ClearStack(SqStack *S)
{ /* 把S置为空栈 */
(*S).top = (*S).base;
return OK;
}
Status Push(SqStack *S, SElemType e)
{ /* 插入元素e为新的栈顶元素 */
if ((*S).top - (*S).base >= (*S).stacksize) /* 栈满,追加存储空间 */
{
(*S).base = (SElemType *)realloc((*S).base, ((*S).stacksize + STACKINCREMENT) * sizeof(SElemType));
if (!(*S).base)
exit(OVERFLOW); /* 存储分配失败 */
(*S).top = (*S).base + (*S).stacksize;
(*S).stacksize += STACKINCREMENT;
}
*((*S).top)++ = e;
return OK;
}
Status Pop(SqStack *S, SElemType *e)
{ /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
if ((*S).top == (*S).base)
return ERROR;
*e = *--(*S).top;
return OK;
}
Status StackTraverse(SqStack S, Status(*visit)(SElemType))
{ /* 从栈底到栈顶依次对栈中每个元素调用函数visit()。 */
/* 一旦visit()失败,则操作失败 */
while (S.top > S.base)
visit(*S.base++);
printf("\n");
return OK;
}
/* -------------------------------------------------------------------------------------------------*/
FILE *fp;
Status copy(SElemType c)
{ /* 将字符c送至fp所指的文件中 */
fputc(c, fp);
return OK;
}
void LineEdit()
{ /* 利用字符栈s,从终端接收一行并送至调用过程的数据区。算法3.2 */
SqStack s;
char ch, c;
InitStack(&s);
printf("请输入一个文本文件,^Z结束输入:\n");
ch = getchar();
while (ch != EOF)
{ /* EOF为^Z键,全文结束符 */
while (ch != EOF && ch != '\n')
{
switch (ch)
{
case '#':Pop(&s, &c);
break; /* 仅当栈非空时退栈 */
case '@':ClearStack(&s);
break; /* 重置s为空栈 */
default:Push(&s, ch); /* 有效字符进栈 */
}
ch = getchar(); /* 从终端接收下一个字符 */
}
StackTraverse(s, copy); /* 将从栈底到栈顶的栈内字符传送至文件 */
ClearStack(&s); /* 重置s为空栈 */
fputc('\n', fp);
if (ch != EOF)
ch = getchar();
}
DestroyStack(&s);
}
void main()
{
fp = fopen("ED.DAT", "w"); /* 在当前目录下建立ED.DAT文件,用于写数据, */
if (fp) /* 如已有同名文件则先删除原文件 */
{
LineEdit();
fclose(fp); /* 关闭fp所指的文件 */
}
else
printf("建立文件失败!\n");
}
运行结果: