/* run this program using the console pauser or add your own getch, system("pause") or input loop */
// 用到的库文件
#include <stdio.h> // printf();scanf()
#include <stdlib.h> // exit()
#include <malloc.h> // malloc()
#include <time.h> // srand((unsigned)time(NULL));
// 函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
// Status是函数的类型,其值是函数结果状态代码
typedef int Status;
// #define ElemType int // 也可以用宏定义确定ElemType类型
typedef char SElemType;
// -----栈的链式存储结构-----
typedef struct SNode {
SElemType data; // 数据域
struct SNode *next; // 指针域
} SNode, *LinkStack;
// 操作结果:构造一个空栈S。
Status InitStack(LinkStack &S) {
S = (LinkStack)malloc(sizeof(SNode));
if(!S) // 存储分配失败
exit(OVERFLOW); // exit(-2)程序异常退出
S->next = NULL;
S->data = NULL;
return OK;
}// InitStack
// 操作结果:销毁栈S,S不再存在。
Status DestroyStack(LinkStack &S) {
LinkStack p = S->next, ptmp; // p指向栈顶
while(p) { // p指向栈底时,循环停止
ptmp = p->next;
free(p); // 释放每个数据结点的指针域
p = ptmp;
}
free(S);
return OK;
}// DestroyStack
// 操作结果:把S置为空栈。
Status ClearStack(LinkStack &S) {
LinkStack p = S->next, ptmp; // p指向栈顶
while(p) { // p指向栈底时,循环停止
ptmp = p->next;
free(p); // 释放每个数据结点的指针域
p = ptmp;
}
S->next = NULL;
return OK;
}// ClearStack
// 操作结果:若S为空栈,返回TRUE,否则返回FALSE
Status StackEmpty(LinkStack S) {
if(S->next == NULL)
return TRUE; // 返回1
else
return FALSE; // 返回0
}// StackEmpty
// 操作结果:返回S的元素个数,即栈的长度。
int StackLength(LinkStack S) {
int n = 0;
LinkStack p = S->next; // p指向栈顶
while(p) {
n++;
p = p->next;
}
return n;
}// StackLength
// 操作结果:若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR。
Status GetTop(LinkStack S, SElemType &e) {
if ( S->next == NULL )
return ERROR; // 栈空
e = S->next->data; // 取栈顶元素
// printf("获取的栈顶元素:%d\n", e);
return OK;
}// GetTop
// 操作结果:插入元素e为新的栈顶元素。
Status Push(LinkStack &S, SElemType e) {
LinkStack p = (LinkStack)malloc(sizeof(SNode));
p->next = S->next; // 新结点指向栈顶
p->data = e;
S->next = p; // 更新栈顶指针
// printf("插入的栈顶元素:%d\n", e);
return OK;
}// Push
// 操作结果:若栈不空,则删除S的栈顶元素,并用e返回其值;否则返回ERROR。
Status Pop(LinkStack &S, SElemType &e) {
// 若1个元素也没有:
if (S->next == NULL)
return ERROR;
// 若有1个以上元素
e = S->next->data;
LinkStack ptmp = S->next->next;
free(S->next);
S->next = ptmp;
// printf("删除的栈顶元素:%d\n", e);
return OK;
}// Pop
Status visit(SElemType e) {
printf("%c -> ", e);
return OK;
}
// 操作结果:从 栈底到栈顶 依次对栈中每个数据元素调用函数visit()。一旦vistit()失败,刚操作失败。
Status StackTraverse(LinkStack S, Status (*pfn_visit)(SElemType)) {
if(S->next == NULL)
{
printf("栈为空!\n");
return ERROR;
}
for(int i=StackLength(S); i>0; i--)
{
LinkStack p = S->next; // p指向栈顶
int j = 1; // j为计数器
while ( p && j<i ) { // 顺指针向后查找,直到p指向第i个元素或p为空
p = p->next;
++j;
}
visit(p->data);
}
printf("\n");
return OK;
}// StackTraverse_base_to_Top
// 操作结果:从 栈顶到栈底 依次对栈中每个数据元素调用函数visit()。一旦vistit()失败,刚操作失败。
Status StackTraverse_Top(LinkStack S, Status (*pfn_visit)(SElemType)) {
if(S->next == NULL)
{
printf("栈为空!\n");
return ERROR;
}
LinkStack p = S->next; // p指向栈顶
while(p) {
visit(p->data);
p = p->next;
}
printf("\n");
return OK;
}// StackTraverse_Top_to_base
// 3.2.1 数制转换
void conversion()
{ // 对于输入的任意一个非负十进制整数,打印输出与其等值的八进制数
unsigned N = 0; // 非负整数
SElemType e;
LinkStack S = NULL;
InitStack(S); // 初始化栈
printf("将十进制整数N转换为8进制数:", N);
//scanf("%u", &N);
N = 8;
while(N)
{
Push(S, N % 8); // 入栈
N = N/8;
}
while(!StackEmpty(S))
{
Pop(S, e); // 出栈
printf("%d ", e);
}
printf("\n");
DestroyStack(S); // 销毁栈
}// conversion 算法3.1
// 3.2.2 括号匹配的检验
void check()
{ // 检验表达式中括号<>、()、[]和{}是否配对
SElemType e;
int i = 0;
LinkStack S;
InitStack(S);
const char* expression
= "#include <stdio.h> int main() { int a[5][5]; int (*p)[4]; p = a[0]; printf(\"%d\\n\", &p[3][3] - &a[3][3]); return 0; }";
//gets(expression);
while (expression[i] != '\0')
{
switch (expression[i])
{
case '<':
case '(':
case '[':
case '{':
Push(S, expression[i]); // 当遇见左符号时压入栈中
break;
case '>':
case ')':
case ']':
case '}':
if (!StackEmpty(S)) // 当遇见右符号时从栈中弹出栈顶符号 // 进行匹配
{
Pop(S, e);
// 匹配成功:继续读入下一个字符 // 匹配失败:立即停止,并报错
if ( !( e == '<' && expression[i] == '>' ||
e == '(' && expression[i] == ')' ||
e == '[' && expression[i] == ']' ||
e == '{' && expression[i] == '}' ) )
{
printf("%c does not match!\n", expression[i]);
exit(ERROR);
}
}
else
{
printf("%c does not match!\n", expression[i]);
exit(ERROR);
}
default: // 当遇见普通字符时忽略
break;
}
i++;
}
if (StackEmpty(S)) // 成功:所有字符扫描完毕,且栈为空
printf("Succeed!\n");
else // 失败:匹配失败或所有字符扫描完结但栈非空
printf("Invalid code!\n");
DestroyStack(S);
}
//3.2.3 行编辑程序
FILE *fp;
Status copy(SElemType e) // 将字符e输入至fp所指的文件中
{
fputc(e, fp);
return OK;
}
void LineEdit()
{ printf("利用字符栈s,从终端接收一行并送至调用过程的数据区。\n");
LinkStack S;
InitStack(S);
char ch = getchar(); // 从终端接收第一个字符
while(ch != EOF) // EOF为全文结束符
{
while(ch != EOF && ch != '\n')
{
switch(ch)
{
case '#':
if(!StackEmpty(S))
Pop(S, ch); // 仅当栈非空时退栈
break;
case '@':
ClearStack(S); // 重置s为空栈
break;
default :
Push(S, ch); // 有效字符进栈,未考虑栈满情形
break;
}
ch = getchar(); // 从终端接收下一个字符
}
// 将从栈底到栈顶的栈内字符传送至调用过程的数据区;
StackTraverse(S, copy);
fputc('\n', fp); // 向文件输入一个换行符
ClearStack(S); // 重置s为空栈
if(ch != EOF) ch = getchar();
}
DestroyStack(S);
}// LineEdit 算法3.2
int main() {
conversion();
check();
fp = fopen("test.txt", "w");
if(fp)
{
LineEdit();
fclose(fp);
}
else
printf("建立文件失败!\n");
return 0;
}
《数据结构》(C语言版)——栈的应用举例
最新推荐文章于 2025-04-01 00:41:32 发布