使用顺序表实现栈的c语言程序,【C语言实现】顺序栈及其相关应用(内有完整代码)...

简书内代码已上传GitHub:点击我 去GitHub查看代码

顺序栈相关的应用实例已更新 :行编辑程序 、表达式求值 、迷宫求解

栈是重要的 线性结构

一.什么是栈?

栈是限定仅在表尾进行插入或删除操作的线性表。我们来看图理解:

49ae999802eb

顺序栈对栈来说,表尾称为栈顶,表头称为栈底。图中一开始top == base , 这是个空栈,因为 栈顶指针是指向下一个要添加的栈顶元素的位置 的,就像第二小图,A元素入栈后,top指针指向新的栈顶的位置。如果要删除元素,必须从栈顶开始删除。也就是说,A, B,C依次入栈,出栈的顺序应该是 C, B, A。这也是栈的一个特性,被称作 后进先出 (last in first out)。所以,栈又称为:后进先出的线性表,简称 LIFO结构。

我们来看一张很有历史意义的图片加深印象:

49ae999802eb

詹天佑修的栈

没错,就是京张铁路。火车从 位置1 到 位置2 , 其实就是一个入栈的过程。位置2相当于一个栈,当一列火车从头部开始驶入位置2 , 那先进入位置3 的就是火车的尾部了。

二.顺序栈的结构定义

顺序栈的存储结构是利用一组地址连续的存储单元依次存放栈底到栈顶的元素。

顺序栈需要两个指针top,base指向栈顶和栈底位置

需要一个变量存储栈的大小

定义如下:

typedef struct{

//基址,指向栈底

Elemtype* base;

//栈顶指针

Elemtype* top;

//栈空间大小(单位:元素)

int Stacksize;

}SqStack;

三.顺序栈的九种基本操作

1.构造一个空栈:InitStack(SqStack&)

在定义一个栈后,栈实际上只分配了2个指针变量和一个整型变量的空间,需要主动给栈分配空间存储元素.

//初始化栈(空栈)

Status InitStack(SqStack &S){

//给栈元素分配初始空间

S.base = (Elemtype*)malloc(sizeof(Elemtype)*INIT_SIZE);

//若内存分配失败,返回ERROR

if(!S.base){

printf("error: 内存分配失败\n");

return OVERFLOW;

}

//栈顶指针指向栈底

S.top = S.base;

//栈空间大小为初始化给的大小

S.Stacksize = INIT_SIZE;

return OK;

}

2.销毁一个栈:DestroyStack(SqStack&)

摧毁栈实际上就是把给栈元素分配的空间回收.

//摧毁栈

Status DestroyStack(SqStack &S){

//若栈未初始化,返回ERROR

if(!S.base){

printf("error: 栈未初始化\n");

return ERROR;

}

//释放栈内元素空间

free(S.base);

//栈顶栈底指针置空

S.base = S.top = NULL;

//栈大小归0

S.Stacksize = 0;

return OK;

}

3.清空一个栈:ClearStack(SqStack&)

清空栈实际上就是把栈顶指针指向栈底,其中分配的空间还在,只不过相当于被 “标记” 了, 栈顶指针 ~ 栈底指针 指向的范围内才是有效数据。

举个例子,平时我们删除文件, 其实文件也只是被“标记”了,所以在回收站里我们可以恢复文件。即使在回收站里彻底删除了,我们还可以通过其他手段尽可能多的恢复文件。

//清空栈

Status ClearStack(SqStack &S){

//若栈未初始化,返回ERROR

if(!S.base){

printf("error: 栈未初始化\n");

return ERROR;

}

//使栈顶指向栈底

S.top = S.base;

//栈大小归0

S.Stacksize = 0;

return OK;

}

4.判断一个栈是否为空栈:StackEmpty(SqStack&)

top == base && base != NULL 即为空栈

//判断S是否为空栈

Status StackEmpty(SqStack &S){

//若栈未初始化,返回ERROR

if(!S.base){

printf("error: 栈未初始化\n");

return ERROR;

}

//若栈底指针 == 栈顶指针 , 为空栈

if(S.base == S.top){

return True;

}

return False;

}

5.返回栈的长度(元素个数):StackLength(SqStack&)

栈的长度 不等于 栈的大小,他们的关系应该是 栈的长度 < 栈的大小

栈的长度 = S->top - S->base ,这里注意:两个同类型指针相减,结果不是以字节为单位的,而是以指针指向元素类型大小为单位。所以这里的S->top - S->base就是栈的长度

//返回栈里元素个数(栈的长度)

int StackLength(SqStack &S){

//如果栈未初始化,返回0

if(!S.base) return 0;

//栈长度 = (栈顶指针 - 栈底指针) / 栈元素大小

return S.top - S.base ;

}

6.返回栈顶元素到e:GetTop(SqStack&, Elemtype&)

栈顶元素是*(top - 1)元素

//返回栈顶元素

Status GetTop(SqStack &S, Elemtype &e){

//若栈是空栈,返回ERROR

if(S.top == S.base){

printf("error: 返回栈顶元素失败\n");

return ERROR;

}

//通过e返回栈顶元素

e = *(S.top - 1);

return OK;

}

7.插入新元素:Push(SqStack&, Elemtype)

如果栈长度*Elemtype_Size >= 栈大小 , 需要realloc更大的空间。

更新栈顶指针(重点看代码)

插入新的元素,移动栈顶指针

//压入元素e为新的栈顶元素

Status Push(SqStack &S, Elemtype e){

if(S.top - S.base >= S.Stacksize){

S.base = (Elemtype*)realloc(S.base, sizeof(Elemtype)* (S.Stacksize + INCREMENT_SIZE));

if(!S.base){

printf("error: 内存分配失败\n");

return OVERFLOW;

}

//若空间不足,重新分配,需要重新定位栈顶指针

S.top = S.base + S.Stacksize;

S.Stacksize += INCREMENT_SIZE;

}

*S.top++ = e;

return OK;

}

8.删除栈顶元素:Pop(SqStack& , Elemtype&)

通过e返回删除的栈顶元素

top指针自减

//弹出栈顶元素, 用e返回其值

Status Pop(SqStack &S, Elemtype &e){

//若为空栈,返回ERROR

if(S.base == S.top) return ERROR;

//移动栈顶指针后通过e保存栈顶元素的值

e = *--S.top;

return OK;

}

9.遍历栈:StackTraverse(SqStack, Status(visit)(Elemtype))

定义一个工作指针用visit函数遍历栈

//遍历栈,调用visit函数

Status StackTraverse(SqStack S, Status(*visit)(Elemtype*)){

for(Elemtype* p = S.base; p < S.top ; ++p){

Status s = visit(p);

if(s != OK){

printf("ERROR: StackTraverse False");

return ERROR;

}

}

return OK;

}

四.顺序栈的基本应用:

1.进制转换(十进制转二进制,其余类似):

把需要转换的数字按 低位~高位 进行转换

把转换的结果入栈

出栈并输出,这时候数字顺序就是 高位~低位 的顺序

代码如下:

void BaseConversion(){

SqStack s;

int N;

InitStack(s);

scanf("%d", &N);

while(N){

Push(s, N % 2);

N /= 2;

}

int e;

while(!StackEmpty(s)){

Pop(s, e);

printf("%d ", e);

}

}

测试:

49ae999802eb

测试

2.括号匹配的检验:

这个问题的一种巧解可以看 这一篇 ,现在我们用栈的特性也可以很轻松的实现。

其实上一种方法也是通过 类似栈的操作来达成的,而直接使用栈,思路更加清晰易懂。

下面是以上 链接 内同一题的栈实现

bool isValid(string s) {

SqStack S;

InitStack(S);

int len = s.length();

for(int i = 0 ; i < len ; ++i){

switch(s[i]){

//当检测到左括号,改为对应右括号存入栈中

case '(':

Push(S, ')');

break;

case '{':

Push(S, '}');

break;

case '[':

Push(S, ']');

break;

default:

//当第一次检测到右括号,此时需要满足:

// 1.右括号不是第一个出现的

// 2.栈顶元素与之匹配,

// 这里我们修改过左括号,所以只需要判断它们是否相等

char e;

GetTop(S, e);

if(s[i] != e || i == 0)

return false;

Pop(S, e);

}

}

return StackEmpty(S);

}

49ae999802eb

AC

五.完整代码:

#include

#include

//初始化时存储空间分配量

#define INIT_SIZE 100

#define INCREMENT_SIZE 10

//定义状态

#define OVERFLOW -1

#define OK 1

#define ERROR 0

#define True 1

#define False 0

//定义元素类型

typedef int Elemtype;

//定义状态类型

typedef int Status;

//顺序栈结构定义

typedef struct{

//基址,指向栈底

Elemtype* base;

//栈顶指针

Elemtype* top;

//栈空间大小(单位:元素)

int Stacksize;

}SqStack;

//初始化栈(空栈)

Status InitStack(SqStack &S){

//给栈元素分配初始空间

S.base = (Elemtype*)malloc(sizeof(Elemtype)*INIT_SIZE);

//若内存分配失败,返回ERROR

if(!S.base){

printf("error: 内存分配失败\n");

return OVERFLOW;

}

//栈顶指针指向栈底

S.top = S.base;

//栈空间大小为初始化给的大小

S.Stacksize = INIT_SIZE;

return OK;

}

//摧毁栈

Status DestroyStack(SqStack &S){

//若栈未初始化,返回ERROR

if(!S.base){

printf("error: 栈未初始化\n");

return ERROR;

}

//释放栈内元素空间

free(S.base);

//栈顶栈底指针置空

S.base = S.top = NULL;

//栈大小归0

S.Stacksize = 0;

return OK;

}

//清空栈

Status ClearStack(SqStack &S){

//若栈未初始化,返回ERROR

if(!S.base){

printf("error: 栈未初始化\n");

return ERROR;

}

//使栈顶指向栈底

S.top = S.base;

//栈大小归0

S.Stacksize = 0;

return OK;

}

//判断S是否为空栈

Status StackEmpty(SqStack &S){

//若栈未初始化,返回ERROR

if(!S.base){

printf("error: 栈未初始化\n");

return ERROR;

}

//若栈底指针 == 栈顶指针 , 为空栈

if(S.base == S.top){

return True;

}

return False;

}

//返回栈里元素个数(栈的长度)

int StackLength(SqStack &S){

//如果栈未初始化,返回0

if(!S.base) return 0;

//栈长度 = (栈顶指针 - 栈底指针) / 栈元素大小

return S.top - S.base ;

}

//返回栈顶元素

Status GetTop(SqStack &S, Elemtype &e){

//若栈是空栈,返回ERROR

if(S.top == S.base){

printf("error: 返回栈顶元素失败\n");

return ERROR;

}

//通过e返回栈顶元素

e = *(S.top - 1);

return OK;

}

//压入元素e为新的栈顶元素

Status Push(SqStack &S, Elemtype e){

if(S.top - S.base >= S.Stacksize){

S.base = (Elemtype*)realloc(S.base, sizeof(Elemtype)* (S.Stacksize + INCREMENT_SIZE));

if(!S.base){

printf("error: 内存分配失败\n");

return OVERFLOW;

}

//若空间不足,重新分配,需要重新定位栈顶指针

S.top = S.base + S.Stacksize;

S.Stacksize += INCREMENT_SIZE;

}

*S.top++ = e;

return OK;

}

//弹出栈顶元素, 用e返回其值

Status Pop(SqStack &S, Elemtype &e){

//若为空栈,返回ERROR

if(S.base == S.top) return ERROR;

//移动栈顶指针后通过e保存栈顶元素的值

e = *--S.top;

return OK;

}

//遍历栈,调用visit函数

Status StackTraverse(SqStack S, Status(*visit)(Elemtype* )){

for(Elemtype* p = S.base; p < S.top ; ++p){

Status s = visit(p);

if(s != OK){

printf("ERROR: StackTraverse False");

return ERROR;

}

}

return OK;

}

49ae999802eb

End

END

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
顺序表是一种基于数组实现的线性表,它的应用非常广泛。以下是一个简单的顺序表应用代码实现C语言): ```c #include <stdio.h> #include <stdlib.h> #define MAXSIZE 100 // 最大元素个数 typedef struct { int data[MAXSIZE]; // 存储数据的数组 int length; // 当前元素个数 } SqList; // 初始化顺序表 void initList(SqList *L) { L->length = 0; } // 插入元素 int insertList(SqList *L, int i, int e) { if (i < 1 || i > L->length + 1 || L->length == MAXSIZE) { // 插入位置不合法或表满 return 0; } for (int j = L->length; j >= i; j--) { L->data[j] = L->data[j - 1]; // 将元素后移 } L->data[i - 1] = e; // 插入新元素 L->length++; // 元素个数加一 return 1; } // 删除元素 int deleteList(SqList *L, int i) { if (i < 1 || i > L->length) { // 删除位置不合法 return 0; } for (int j = i; j < L->length; j++) { L->data[j - 1] = L->data[j]; // 将元素前移 } L->length--; // 元素个数减一 return 1; } // 查找元素 int searchList(SqList *L, int e) { for (int i = 0; i < L->length; i++) { if (L->data[i] == e) { return i + 1; } } return 0; // 没有找到 } // 输出顺序表 void printList(SqList *L) { for (int i = 0; i < L->length; i++) { printf("%d ", L->data[i]); } printf("\n"); } int main() { SqList L; initList(&L); // 初始化顺序表 insertList(&L, 1, 10); // 在第1个位置插入元素10 insertList(&L, 2, 20); // 在第2个位置插入元素20 insertList(&L, 3, 30); // 在第3个位置插入元素30 printList(&L); // 输出顺序表:10 20 30 deleteList(&L, 2); // 删除第2个元素 printList(&L); // 输出顺序表:10 30 int pos = searchList(&L, 30); // 查找元素30的位置 if (pos > 0) { printf("元素30的位置是:%d\n", pos); // 输出:元素30的位置是:2 } else { printf("没有找到元素30!\n"); } return 0; } ``` 这段代码实现顺序表的基本操作,包括初始化、插入、删除、查找和输出。可以根据需要对代码进行修改和扩展,实现更复杂的应用

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值