欢迎光临散文网 会员登陆 & 注册

《数据结构(C语言版)》栈的实现与应用

2022-03-28 22:56 作者:回到唐朝当少爷  | 我要投稿

清华大学计算机系列教材   累计发行超400万册

严蔚敏 吴伟明 编著

数据结构(C语言版)

以下是本人对该紫皮书第三章栈中顺序栈的代码实现,并且完成了数制转换、括号匹配的检验、行编辑程序等功能,代码(含详细注释)在450行左右

(貌似专栏把我缩进吃了,懒得加了,另外建议用visual studio编译) 

//顺序栈的表示和实现

//用顺序栈实现数制转换、括号匹配检查、行编辑程序

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#define TRUE 1

#define FALSE 0

#define OK 1

#define ERROR 0

#define INFEASIBLE -1

#define OVERFLOW -2

#define STACK_INIT_SIZE 100//存储空间初始分配量

#define STACKINCREMENT 10//存储空间分配增量

typedef int SElemType;

typedef int Status;

typedef struct

{

SElemType* base;

SElemType* top;

int stacksize;//当前已分配的存储空间,以元素为单位

}Sqstack;

/*

通常top指示真正的栈顶元素之上的下标地址,初始值指向栈底

base始终指向栈底的位置,若base的值为NULL则表明栈结构不存在

栈空:top==base

栈满:top-base==stacksize

*/

Status InitStack(Sqstack& S);//初始化一个空栈

Status DestoryStack(Sqstack& S);//销毁栈

Status ClearStack(Sqstack& S);//把S置为空栈

Status StackEmpty(Sqstack S);//判断栈是否为空

int StackLength(Sqstack S);//求栈的长度

Status GetTop(Sqstack& S, SElemType& e);//返回栈顶元素,若为空则返回ERROR

Status Push(Sqstack& S, SElemType e);//顺序栈的入栈

Status Pop(Sqstack& S, SElemType& e);//顺序栈的出栈

Status StackTraverse(Sqstack S, Status(*visit)(SElemType*));//从栈底到栈顶一次对栈中每个元素调用函数visit(),一旦visit()失败则操作失败

Status ShowStack(SElemType* p);//打印顺序栈中的元素(从栈底到栈顶)

Status ShowStack2(SElemType* p);//该打印函数是为行编辑函数服务的,因为要打印字符

void conversion();//对于输入的任意一个非负十进制整数,打印输出与其值等值得八进制数

Status CheckParenMatching(char* str);//括号匹配检验

void LineEdit();//利用字符栈S,从终端接受一行并传送至调用过程的数据区

void Menu1()

{

printf("******************************\n");

printf("********0.退出本次使用********\n");

printf("********1.栈的基本功能********\n");

printf("********2.不同数制转换********\n");

printf("********3.括号匹配检验********\n");

printf("********4.行编辑程序**********\n");

printf("******************************\n");

}

void Menu2()

{

printf("**************************\n");

printf("********0.返回上步********\n");

printf("********1.入    栈********\n");

printf("********2.出    栈********\n");

printf("********3.求 栈 长********\n");

printf("********4.求 栈 顶********\n");

printf("********5.打 印 栈********\n");

printf("********6.置 空 栈********\n");

printf("********7.销 毁 栈********\n");

printf("********8.判断空栈********\n");

printf("**************************\n");

}

int main()

{

int option1 = -1;

int option2 = -1;

int value = 0;

char str[100] = { 0 };

Sqstack Mystack;

InitStack(Mystack);

Menu1();

while (scanf("%d", &option1) != EOF)

{

while (getchar() != '\n');

switch(option1)

{

case 1:

Menu2();

while (scanf("%d", &option2) != EOF)

{

while (getchar() != '\n');

switch (option2)

{

case 1:

printf("请输入你要入栈的元素:");

while (scanf("%d", &value) != 1)

{

printf("你输入了非法字符,请重新输入:");

while (getchar() != '\n');

}

if (Push(Mystack, value))

{

printf("入栈成功!\n");

}

break;

case 2:

if (Pop(Mystack, value))

{

printf("出栈成功!\t您出栈的元素为%d\n", value);

}

else

{

printf("该顺序栈已空!不能出栈!\n");

}

break;

case 3:

printf("该顺序栈的栈长为:%d\n", StackLength(Mystack));

break;

case 4:

if (GetTop(Mystack, value))

{

printf("该顺序栈栈顶元素为:%d\n", value);

}

else

{

printf("该顺序栈为空栈!\n");

}

break;

case 5:

if (StackEmpty(Mystack))

{

printf("该顺序栈为空栈!\n");

}

else

{

printf("从栈底到栈顶依次为:");

if (StackTraverse(Mystack, ShowStack))

{

printf("\n");

}

}

break;

case 6:

if (ClearStack(Mystack))

{

printf("栈已置空!\n");

}

break;

case 7:

if (DestoryStack(Mystack))

{

printf("栈已销毁!\n");

}

break;

case 8:

if (StackEmpty(Mystack))

{

printf("该顺序栈为空栈!\n");

}

else

{

printf("该顺序栈非空!\n");

}

case 0:

break;

default:

printf("你输入了非法字符,请重新输入\n");

break;

}

if (option2 == 0)

{

break;

}

Menu2();

}

break;


case 2:

conversion();

break;


case 3:

printf("您可以用此功能检查形如5-{3-[5*(9/3)-4]}的算术表达式括号是否匹配\n");

printf("请输入表达式:");

fgets(str, 100, stdin);

if (CheckParenMatching(str))

{

printf("括号成功匹配!\n");

}

else

{

printf("括号不匹配!\n");

}

break;


case 4:

printf("您可以用此功能在不小心输入错误时用#代替退格符Backspace,用@代替退行符\n");

printf("例如你输入了如下两段字符:\n");

printf("whli##ilr#e(s#*s)\n");

printf("  outcha@putchar(*s=#++);\n");

printf("则实际有效的是下列两行\n");

printf("while(*s)\n");

printf("putchar(*s++);\n");

printf("当你按住Ctrl+z可停止输入\n");

printf("请输入一串字符:\n");

LineEdit();

break;


case 0:

printf("感谢使用!\n");

exit(0);

default:

printf("你输入了非法字符,请重新输入\n");

}

Menu1();

}

return 0;

}

Status InitStack(Sqstack& 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 DestoryStack(Sqstack& S)//销毁栈

{

if (S.base)

{

free(S.base);

S.stacksize = 0;

S.top = NULL;

S.base = NULL;

}

return OK;

}

Status ClearStack(Sqstack& S)//把S置为空栈

{

if (S.base)

{

S.top = S.base;

return OK;

}

}

Status StackEmpty(Sqstack S)//判断栈是否为空

{

if (S.top == S.base)

{

return TRUE;

}

else

{

return FALSE;

}

}

int StackLength(Sqstack S)//求栈的长度

{

return S.top - S.base;

}

Status GetTop(Sqstack& S, SElemType& e)//返回栈顶元素,若为空则返回ERROR

{

if (S.top == S.base)

{

return ERROR;

}

e = *(S.top - 1);

return OK;

}

Status Push(Sqstack& S, SElemType e)//顺序栈的入栈

{

if (S.top - S.base >= S.stacksize)

{

/*

这里和课本有一点点不同,我是先realloc一个指针为New_ptr的空间,再把这个指针分配给S.base

原因是visual studio太高级了,它觉得realloc不安全,可能会引出一个内存泄露的问题

当realloc分配失败的时候,会返回NULL。如果直接赋值给S.base的话,S.base的内存是没有被释放的

如果直接将realloc的返回值赋给S.base,那么当申请内存失败时,就会造成S.base原来指向的内存丢失,造成泄露。

*/

SElemType* New_ptr = (SElemType*)realloc(S.base, ((S.stacksize) + STACKINCREMENT) * sizeof(SElemType));

if (!New_ptr)

{

exit(OVERFLOW);

}

S.base = New_ptr;

S.top = S.base + S.stacksize;

S.stacksize += STACKINCREMENT;

}

*S.top++ = e;

return OK;

}

Status Pop(Sqstack& S, SElemType& e)//顺序栈的出栈

{

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)

{

if (!visit(S.base++))

{

return ERROR;

}

}

return OK;

}

Status ShowStack(SElemType* p)//打印顺序栈中的元素(从栈底到栈顶)

{

printf("%d ", *p);

return OK;

}

Status ShowStack2(SElemType* p)//该打印函数是为行编辑函数服务的,因为要打印字符

{

printf("%c", *p);

return OK;

}

void conversion()//对于输入的任意一个非负十进制整数,打印输出与其值等值得八进制数

{

Sqstack S;

int N = 0;

SElemType e = 0;

InitStack(S);

printf("请输入你想转换的数:");

while (scanf("%d", &N) != 1)

{

printf("你输入了非法字符,请重新输入:");

while (getchar() != '\n');

}

while (N)

{

Push(S, N % 8);

N = N / 8;

}

printf("转换成八进制后的数为:");

while (!StackEmpty(S))

{

Pop(S, e);

printf("%d", e);

}

printf("\n");

}

Status CheckParenMatching(char* str)//括号匹配检验

/*

算法具体描述如下

依次读取代码字符串中的字符

   若是非括号字符,则忽略并继续读取下一个字符;

   若是左括号字符,则压栈;

   否则为右括号,与栈顶元素进行匹配:

  若栈空,则是多余的右括号,报错返回;

  否则

若匹配成功,则栈顶元素弹栈,继续读取下一个字符;

否则匹配错误,报错返回;

代码字符串遍历结束时:

   若栈空,则匹配成功,正确返回;

   否则有左括号还没匹配,报错返回。

*/

{

Sqstack S;

InitStack(S);

int Length = strlen(str);

SElemType e = 0;

for (int i = 0; i < Length; i++)

{

switch (str[i])

{

case '{':

case '[':

case '(':

Push(S, str[i]);

break;

case '}':

if (StackEmpty(S))

{

return ERROR;

}

Pop(S, e);

if (e != '{')

{

return ERROR;

}

break;

case ']':

if (StackEmpty(S))

{

return ERROR;

}

Pop(S, e);

if (e != '[')

{

return ERROR;

}

break;

case ')':

if (StackEmpty(S))

{

return ERROR;

}

Pop(S, e);

if (e != '(')

{

return ERROR;

}

break;

default:

break;

}

}

if (!StackEmpty(S))

{

return ERROR;

}

return OK;

}

void LineEdit()//利用字符栈S,从终端接受一行并传送至调用过程的数据区

{

Sqstack S;

InitStack(S);

SElemType c = 0;

char ch = getchar();

while (ch != EOF)

{

while (ch != EOF && ch != '\n')

{

switch (ch)

{

case '#':

Pop(S, c);

break;

case '@':

ClearStack(S);

break;

default:

Push(S, ch);

}

ch = getchar();

}

printf("你最终输入的字符为:");

if (StackTraverse(S, ShowStack2))

{

printf("\n");

}

printf("已将你所编辑的字符传入到数据区\n");

ClearStack(S);

if (ch != EOF)

{

ch = getchar();

}

}

DestoryStack(S);

}


《数据结构(C语言版)》栈的实现与应用的评论 (共 条)

分享到微博请遵守国家法律