栈的实现(内含完整实现和例题)

目录

栈是什么?

主要实现两种操作:

实现栈有两种方式:

1.数组栈

2.链式栈 

数组栈的实现:stack

1.STInit初始化处理

2.STPush入栈

3.STPop出栈

4.bool STEmpty判空(如果是静态的需要判满)

5.int  STSize获取size

6.stdatatype STTop获取栈顶元素

例题:


栈是什么?

通俗来说:

特殊线性表,只允许在固定一端进行插入和删除元素,进行数据插入和删除操作的一端叫栈顶,另一端叫栈底,栈相比于链表,除了存储展示修改数据,数据还满足后进先出(后面进来的先出去)

主要实现两种操作:

压栈:栈的插入操作,入数据在栈顶

出栈:栈的删除,出数据也在栈顶

例如:

入栈 顺序1   2   3   4

 出栈顺序  有4321 1234(可以入一个出一个,1入了1又出了) 3241.....出的顺序很多

                            但也有不可能的顺序

实现栈有两种方式:

1.数组栈

除了扩容的缺点,你在栈顶出数据其实是非常方便的能够直接访问到,并且cpu高速缓存效率更高 

2.链式栈 

如果使用单链表,首先尾插尾删不方便,要不然得反过来搞,头做栈顶,尾做栈底,入数据是入栈就是头插,出数据就是出栈就是头删也比较方便

数组栈的实现:stack

首先要定义结构体(定不定义根据需求,有多个数据就要定义结构体)

需要数据类型指针a(数组栈与顺序表类似,用于开辟动态内存空间)

int top(标识栈顶位置就不叫size了,但与size的功能类似)

int capacity(记录容量)

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdbool.h>
#include<stdlib.h>
typedef int STDataType;
//利用数组定义栈,相当于顺序表的方式
typedef struct STack {
	int capacity;//控制容量方便realloc
	int top;//类似于顺序表中size的作用记录有效数据
	STDataType* p;//用于动态开辟内存空间
}ST;
void STackInit(ST*ps);//初始化
void STackPop(ST*ps);//出栈
void STackPush(ST*ps,STDataType x);//入栈
STDataType STTop(ST*ps);//获取栈顶元素
bool STEmpty(ST* ps);//判空函数,检查是空栈的情况
void STackDestroy(ST* ps);//释放栈
int STSize(ST* ps);//获取size

1.STInit初始化处理

void STackInit(ST* ps) {
	assert(ps);//注意null情况
	ps->p = NULL;
	ps->capacity =0;
	ps->top = 0;
}

//如果判为null不能直接malloc,因为我们通过一级指针访问结构体中的成员,如果想要改变ps(因为结构体指针现在为空),那么就应该传址,用二级指针实现

//top类似于size作用,如果设为0那么它将指向的是栈顶数据的下一个位置,如果是-1则指向与栈顶数据本身(从栈为空的角度看,top给0,先插入数据,然后top++,那么top就指向栈顶元素下一个),否则top指向4就要给-1,就是指向栈顶数据)

2.STPush入栈

void STackPush(ST* ps, STDataType x) {
	assert(ps);
	//让capacity==top时则需要扩容
	if (ps->capacity == ps->top) {
		int newcapacity = 0;//扩展新空间
		if (ps->capacity == 0) {  //原始空间为0
			newcapacity == 4;
		}
		else {
			newcapacity = (ps->capacity) * 4;
		}                                                        //计算内存占空间的大小
		STDataType* tmp = (STDataType*)realloc(ps->p,newcapacity*sizeof(STDataType));
		if (tmp == NULL) {
			perror("realloc error!");
		}
		ps->p = tmp;
		ps->capacity = newcapacity;
	}
	ps->p[ps->top] = x;
	ps->top++;

}

注意:扩容有异地扩容和原地扩容

创建新容量int  newcapacity

把新容量的地址tmp返回值如果和a相同就是原地扩容,否则就是异地扩容

realloc,如果是空指针其实和malloc实现一样

3.STPop出栈

void STackPop(ST* ps) {
	assert(ps);
	assert(!STEmpty(ps));//断言如果为空栈就不存在删,不用传地址因为不需要改变它
	ps->top--;
}

4.bool STEmpty判空(如果是静态的需要判满)

bool STEmpty(ST* ps) {//如果是空栈的情况
	assert(ps);//首先ps不能为空
	if (ps->top==0) {  
		return true;
	}
	return false;
}

5.int  STSize获取size

int STSize(ST* ps) {
	return ps->top;//因为top是0,如果top是-1的话就要+1
}

6.stdatatype STTop获取栈顶元素

STDataType STTop(ST* ps) {
	assert(ps);
    assert(!STEmpty(ps));//如果为空不能访问否则越界了
	return ps->p[ps->top-1];

}

7.STDestroy栈的释放

void STackDestroy(ST* ps) {
	assert(ps);
	free(ps->p);//数组栈是连续的,给个头就全部释放掉了
	ps->p == NULL;
	ps->capacity = 0;
	ps->top = 0;
}

注意:

栈的访问和其他线性表不同,不能随便访问,所以要一直去访问栈顶元素然后将栈顶元素后弹出,出一个访问一个,栈访问完了栈也空了,这样才能体现出数组栈和顺序表的不同之处

例题:

 这道题就是典型的可以利用栈来实现:思路如下:

 当我们遇到左括号就让其入栈,如果遇到右括号,就获取栈顶元素与之进行比较,因为栈顶元素其实就是前一个元素,那么可以进行匹配

注意:1.是否可以用成对的数目来判断,我认为是 不可以的因为存在数目对但不匹配的现象比如“((){)}”

          2.如果给了只有一个“)”那么我们的栈为空如果访问的话会出问题,所以也存在到最后栈上留下一个右括号的情况,它出不去那么最后我们就需要加入一个判空步骤

代码如下:

typedef char STDataType;
//利用数组定义栈,相当于顺序表的方式
typedef struct STack {
	int capacity;//控制容量方便realloc
	int top;//类似于顺序表中size的作用记录有效数据
	STDataType* p;//用于动态开辟内存空间
}ST;
void STackInit(ST*ps);//初始化
void STackPop(ST*ps);//出栈
void STackPush(ST*ps,STDataType x);//入栈
STDataType STTop(ST*ps);//获取栈顶元素
bool STEmpty(ST* ps);//判空函数,检查是空栈的情况
void STackDestroy(ST* ps);//释放栈
int STSize(ST* ps);//获取size
//用栈来实现
void STackInit(ST*ps) {
	assert(ps);//如果判为null不能直接malloc,因为我们通过一级指针访问结构体中的成员,如果想要改变ps(因为结构体指针现在为空),那么就应该传址,用二级指针实现
	ps->p = NULL;
	ps->capacity =0;
	ps->top = 0;//top类似于size作用,如果设为0那么它将指向的是栈顶数据的下一个位置,如果是-1则指向与栈顶数据本身
}
bool STEmpty(ST* ps) {//如果是空栈的情况
	assert(ps);//首先ps不能为空
	if (ps->top==0) {  
		return true;
	}
	return false;
}
void STackPush(ST* ps, STDataType x) {
	assert(ps);
	//让capacity==top时则需要扩容
   
	if (ps->capacity == ps->top) { 
        int newcapacity = 0;
		//扩展新空间
		if (ps->capacity == 0) {  //原始空间为0
			newcapacity = 4;
		}
		else {
			newcapacity = (ps->capacity) * 4;
		}                                                        //计算内存占空间的大小
		STDataType* tmp = (STDataType*)realloc(ps->p,newcapacity*sizeof(STDataType));
		if (tmp == NULL) {
			perror("realloc error!");
		}
		ps->p = tmp;
		ps->capacity = newcapacity;
	}
	ps->p[ps->top] = x;
	ps->top++;

}
void STackPop(ST* ps) {
	assert(ps);
	assert(!STEmpty(ps));//断言如果为空栈就不存在删,不用传地址因为不需要改变它
	ps->top--;
}
STDataType STTop(ST* ps) {
	assert(ps);
    assert(!STEmpty(ps));///嗷嗷嗷不要忘记判空
	return ps->p[ps->top-1];
}
void STackDestroy(ST* ps) {
	assert(ps);
	free(ps->p);//数组栈是连续的,给个头就全部释放掉了
	ps->p == NULL;
	ps->capacity = 0;
	ps->top = 0;
}
int STSize(ST* ps) {
	return ps->top;//因为top是0,如果top是-1的话就要+1
}
//思路是让左括号入栈,如果遇到右括号就和栈顶元素进行比较,然后出栈
//首先创建一个栈
bool isValid(char * s){
ST ps;
STackInit(&ps);
while(*s){//遇到\0停止
    if(*s=='('||*s=='{'||*s=='['){//左括号入栈
        STackPush(&ps,*s);
    }
    else{
          if(STEmpty(&ps)){
            return false;
        }
        char top=STTop(&ps);//遇到右括号,获取栈顶元素
        STackPop(&ps);//弹出一个元素
        if(top!='('&& *s==')'||
        top!='{'&&*s=='}'||
        top!='['&&*s==']'){
            return false;
        }
        
    }s++;
} 
bool flag= STEmpty(&ps);
STackDestroy(&ps);
return flag;
}


如有问题,欢迎大佬批评指正

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值