栈 实现:

文章介绍了如何使用动态数组实现一个栈的数据结构,包括初始化、入栈、出栈、判断栈空、计算栈元素个数以及返回栈顶元素等操作。栈顶指针有两种初始化方式,影响后续操作。文章还展示了栈在解决括号匹配问题中的应用,通过LeetCode上的有效括号字符串问题为例,展示了如何利用栈来判断括号的有效性。
摘要由CSDN通过智能技术生成

目录

结构定义:

初始化: void STInit(Stack* SL)

传参问题:

栈顶指针初始值:

入栈:void Push(Stack* SL,Type x)

出栈:void  pop(Stack* SL)

判断栈是否为空:bool Empty(Stack* SL)

计算栈元素个数:int StackSize(Stack* SL)

返回栈顶元素:Type Top(Stack* SL)

栈销毁:void Destory(Stack* SL)


结构定义:

typedef int Type;

//动态增长的栈

struct Stack
{
	Type* arr;
	int capacity;
	int pop;//栈顶指针

};

        用动态数组的方式队栈结构进行定义,而不用单链表,一是因为数组在CPU访问缓存时的命中率高,二是在进行入栈是,避免了链表尾插时每次都需要找尾节点的情况.

初始化: void STInit(Stack* SL)

 功能是为arr开辟4个元素类型的空间,capacity记录当前栈区容量,pop指向栈顶元素的下一个位置:

void STInit(Stack* SL)
{
	assert(SL);
	SL->arr = (Type*)malloc(sizeof(Type)*4);
	SL->capacity = 4;
	SL->pop = 0;
	//关于pop指针,初始指针有两种初始方式
	//1.指向栈顶元素的下一个元素
	//2.指向栈顶元素
	//不同的初始化要求在入栈时pop++ 与元素入栈的顺序

}

传参问题:

如果传入的形参类型是Stack SL,那么在堆区开辟空间后,初始化函数栈帧内SL的arr成员内的参数没有返回,所以需要传入一个栈指针,修改主函数内的arr成员参数:

 栈顶指针初始值:

两种初始化方式:

1. 指向栈顶元素

2.指向栈顶元素的下一个位置

初始化值不同,影响后续函数的设计,用前者,在写入栈函数时,pop先++,元素再入栈.

使用后者,元素直接入栈,pop再++.

入栈:void Push(Stack* SL,Type x)

void Push(Stack* SL,Type x)
{
	assert(SL);
	if (SL->capacity == SL->pop)
	{
		Type* tmp = (Type*)realloc(SL->arr, sizeof(Type) * SL->capacity * 2);
		if (tmp == NULL)
		{
			perror("capacity realloc error");
			return;

		}
		SL->arr = tmp;
		SL->capacity *= 2;
		
	}
	SL->arr[SL->pop] = x;
	SL->pop++;
	
}

        要先判断SL指针是否为NULL,参数检查会在程序出错时迅速定位到问题代码段.

        进来的第一步是先要判断栈区空间是否已经满,如果满了就重新开辟空间,栈区空间是否满的判断条件:SL->pop==SL->capacity;

        开辟好空间后或者栈区仍有足够的空间就将元素入栈,这里初始化函数pop的初始值为0,即设置pop指针指向栈顶元素的下一个位置,所以先将元素入栈,然后再++;

出栈:void  pop(Stack* SL)

void  pop(Stack* SL)
{
	assert(SL);
	assert(SL->pop);
	SL->pop--;
	
}

两种情况需要处理:

1.SL->pop要求SL指针不能为空,所以需要断言传入的栈指针是否有效.

2.当栈为空时,即pop==0,这时再--,会把pop赋值为-1,由于pop初始化值为0,要求元素先入栈再++,所以pop==-1会导致非法访问,所以需要断言处理SL->pop.

判断栈是否为空:bool Empty(Stack* SL)


bool Empty(Stack* SL)
{
	assert(SL);
	return SL->pop == 0;
}

这么简单的一个函数为什么还要封装呢?直接在主函数内用SL.pop==0判断不就好了吗??

       答: 你使用栈并且初始化的时候,你并不知道pop是采用的哪种初始化方式,当栈为空时,pop==0还是==-1使用者并不清楚,所以还是让设计者来实现一个函数.

计算栈元素个数:int StackSize(Stack* SL)

int StackSize(Stack* SL)
{
	assert(SL);
	return SL->pop ;

}

为什么要封装这个函数理由同上!

返回栈顶元素:Type Top(Stack* SL)

Type Top(Stack* SL)
{
	return SL->arr[SL->pop - 1];
}

其实在设计出栈函数时,可以考虑将元素出栈的同时返回,但是由于C++代码考虑到向前的兼容性,所以分开实现.

栈销毁:void Destory(Stack* SL)

void Destory(Stack* SL)

{
	free(SL->arr);
	SL->capacity = 0;
	SL->pop = 0;
}

OJ:

括号匹配问题:

给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/valid-parentheses

bool isValid(char * s)
{



Stack SL;
STInit(&SL);
while(*s!='\0')
{
    if(*s=='('||*s=='['||*s=='{')
    {
        Push(&SL,*s);
    }
    else
    {
        if(!Empty(&SL))
        {
            Type e=Top(&SL);
            pop(&SL);
            if((*s==')'&&e!='(')||(*s==']'&&e!='[')||(*s=='}' && e!='{'))
                {
                    Destory(&SL);
                    return false;
                }
        }
       else
       {
           Destory(&SL);
           return false;
       }
       
    }
    s++;
}
bool ret=Empty(&SL);
Destory(&SL);
return ret;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值