【数据结构】— 『栈』的实现以及 LeetCode『括号匹配问题』

꧁   各位大佬们好!很荣幸能够得到您的访问,让我们一起在编程道路上任重道远!꧂

☙ 博客专栏:【数据结构初阶】

⛅ 本篇内容简介:数据结构初阶中的栈的实现以及练习题【括号匹配问题】!

⭐ 了解作者:励志成为一名编程大牛的学子,目前正是大二的编程小白。

励志术语:编程道路的乏味,让我们一起学习变得有趣!


文章目录

✯ 顺序表与链表的总结

✡ 顺序表和链表的区别

✡ 顺序表和链表的优缺点

⛦ 顺序表的优缺点

⛦ 链表的优缺点

✯ 栈

✡ 栈的概念及结构

 ✡ 栈的实现

⛦ 栈的结构

⛦ 栈的初始化

⛦ 栈的入栈(压栈)

⛦ 栈的出栈

⛦ 获取栈顶的元素

⛦ 获取栈的有效元素个数

⛦ 栈的判空

⛦ 栈的销毁

⛦ 测试栈的接口功能

✡ 栈的源代码

⛦ Stack.h文件

⛦ Stack.c文件

⛦ test.c文件

✯【LeetCode】— 括号匹配问题

 ✡ 题目描述

 ✡ 解题思路

  ✡ 解题代码

✯ 结束语


✯ 顺序表与链表的总结

✡ 顺序表和链表的区别

不同点顺序表链表(双向循环带头)
存储空间上物理上一定连续逻辑上连续,但物理上不一定连续
随机访问支持O(1)  下标不支持:为O(N) 遍历
任意位置插入或者删除元素可能需要挪动元素,效率低,为O(N)只需要修改指针指向
插入动态顺序表,空间不够时需要扩容没有扩容的概念
应用场景元素高效存储+频繁访问任意位置插入与删除频繁
缓存利用率


✡ 顺序表和链表的优缺点

⛦ 顺序表的优缺点

优点:

· 尾插尾删效率很高

· 随机访问(用下标访问)

· CPU高速缓冲命中率更高(相比于链表)

缺点:

· 头部和中部的插入与删除效率很低(为O(N))

· 扩容时 —— 性能消耗+空间浪费

⛦ 链表的优缺点

优点:

· 任意位置插入与删除效率很高(为O(1))

· 按需申请与释放空间

缺点:

· 不支持随机访问

 CPU执行指令,不会直接访问内存

1. 先看数据在不在三级缓存,如果在(命中),直接访问

2. 如果不在(不命中),先加载到缓存,再访问


✯ 栈

✡ 栈的概念及结构

栈:一种特殊的线性表,其只允许在固定的一端进行插入与删除元素操作,进行数据的插入和删除操作的一端称为栈顶,另外一端为栈底。栈中的数据元素遵守后进先出(Last In First out)的原则。

压栈:栈的插入操作叫做 进栈 / 压栈 / 入栈,入数据是在栈顶

出栈:栈的删除操作叫做出栈,出数据也在栈顶。

 

 ✡ 栈的实现

栈的实现一般可以使用数组或者链表实现,但是相对而言数组实现结构更加优一些,因为数组在尾上插入数据的代价比较小。

⛦ 栈的结构

 看到上面栈的物理结构,可以看到栈是一个数组,有top值和容量值(capacity)。

栈的结构分为静态版本以及动态增长版本,但是静态版本的栈一般不实用,这里我们不做过多的介绍了,直接介绍动态增长版本的栈。

代码实现:

//动态栈
typedef int STDataType;

typedef struct Stack
{
	STDataType* a;
	int top;//栈顶
	int capacity;//容量
}Stack;

⛦ 栈的初始化

//初始化栈
void StackInit(Stack* ps);

栈的初始化有两种形式:

①. top初始的值为 0

 

②. top初始的值为 -1

这里我们介绍top初始化为0的值,因为top值的位置就栈中元素个数。

代码实现:

//初始化栈
void StackInit(Stack* ps)
{
	assert(ps);

	ps->a = NULL;
	ps->top = ps->capacity = 0;
}

⛦ 栈的入栈(压栈)

//入栈
void StackPush(Stack* ps, STDataType x);

在入栈的过程中,需要注意的点有:

①. 需要考虑扩容问题,如果需要扩容将数组成2倍增长。

②. 需要在数组的top位置插入元素,最后top++。

代码实现:

//入栈
void StackPush(Stack* ps, STDataType x)
{
	//考虑扩容
	assert(ps);

	if (ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
	//入栈
	ps->a[ps->top] = x;
	ps->top++;
	
}

⛦ 栈的出栈

//出栈
void StackPop(Stack* ps);

出栈需要注意的点:

①. 需要判断栈(Stack)是否为空。

②. 出栈就比较简单了,直接top - - 就行了。

代码实现:

//出栈
void StackPop(Stack* ps)
{
	assert(ps);
	//判空
	assert(!StackEmpty(ps));

	//直接 --
	ps->top--;
}

⛦ 获取栈顶的元素

//获取栈顶元素
STDataType StackTop(Stack* ps);

top位置的数据是元素的个数,在数组中数组末的数据就是元素个数 -1 的位置,即:top -1。

代码实现:

//获取栈顶元素
STDataType StackTop(Stack* ps)
{
	assert(ps);

	assert(!StackEmpty(ps));

	return ps->a[ps->top - 1];
}

⛦ 获取栈的有效元素个数

//栈的有效个数
int StackSize(Stack* ps);

元素个数就是top的值,在之前我们就已经解释过了!!!

//栈的有效个数
int StackSize(Stack* ps)
{
	assert(ps);

	return ps->top;
}

⛦ 栈的判空

//栈的判空  为空返回非0,不为空返回0
bool StackEmpty(Stack* ps);

在初始化时我们将top初始化为0,如果top一直是0,就说明栈是空的,返回非0,反之。

代码实现:

//栈的判空  为空返回非0,不为空返回0
bool StackEmpty(Stack* ps)
{
	assert(ps);

	return ps->top == 0;
}

⛦ 栈的销毁

//栈的销毁
void StackDestroy(Stack* ps);
//栈的销毁
void StackDestroy(Stack* ps)
{
	assert(ps);

	free(ps->a);
	//置空
	ps->a = NULL;
	ps->top = ps->capacity = 0;
}

⛦ 测试栈的接口功能

我们先将几个数据入栈,但栈不为空时,就获取栈顶的元素,并且要将栈顶的元素Pop,也就是出栈。


✡ 栈的源代码

⛦ Stack.h文件

#define _CRT_SECURE_NO_WARNINGS 1

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

//typedef int STDataType;
//#define N 100
静态栈
//typedef struct Stack
//{
//	STDataType a[N];
//	int top;//栈顶
//};

//动态栈
typedef int STDataType;

typedef struct Stack
{
	STDataType* a;
	int top;//栈顶
	int capacity;//容量
}Stack;

//初始化栈
void StackInit(Stack* ps);

//入栈
void StackPush(Stack* ps, STDataType x);

//出栈
void StackPop(Stack* ps);

//获取栈顶元素
STDataType StackTop(Stack* ps);

//栈的有效个数
int StackSize(Stack* ps);

//栈的判空  为空返回非0,不为空返回0
bool StackEmpty(Stack* ps);

//栈的销毁
void StackDestroy(Stack* ps);

⛦ Stack.c文件

#include"Stack.h"

//初始化栈
void StackInit(Stack* ps)
{
	assert(ps);

	ps->a = NULL;
	ps->top = ps->capacity = 0;
}

//入栈
void StackPush(Stack* ps, STDataType x)
{
	//考虑扩容
	assert(ps);

	if (ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
	//入栈
	ps->a[ps->top] = x;
	ps->top++;
	
}

//出栈
void StackPop(Stack* ps)
{
	assert(ps);
	//判空
	assert(!StackEmpty(ps));

	//直接 --
	ps->top--;
}

//获取栈顶元素
STDataType StackTop(Stack* ps)
{
	assert(ps);

	assert(!StackEmpty(ps));

	return ps->a[ps->top - 1];
}

//栈的有效个数
int StackSize(Stack* ps)
{
	assert(ps);

	return ps->top;
}

//栈的判空  为空返回非0,不为空返回0
bool StackEmpty(Stack* ps)
{
	assert(ps);

	return ps->top == 0;
}

//栈的销毁
void StackDestroy(Stack* ps)
{
	assert(ps);

	free(ps->a);
	//置空
	ps->a = NULL;
	ps->top = ps->capacity = 0;
}

⛦ test.c文件

#include"Stack.h"

void test()
{
	Stack st;
	//初始化
	StackInit(&st);

	//入栈
	StackPush(&st, 1);
	StackPush(&st, 2);
	StackPush(&st, 3);
	StackPush(&st, 4);
	StackPush(&st, 5);

	while (!StackEmpty(&st))
	{
		//获取栈顶元素
		printf("%d ",StackTop(&st));
		//出栈
		StackPop(&st);
	}


	//销毁
	StackDestroy(&st);
}

int main()
{
	test();
	return 0;
}

✯【LeetCode】— 括号匹配问题

 ✡ 题目描述

20. 有效的括号.  OJ链接

 

 ✡ 解题思路

①. 我们在这里使用的是C语言实现这个题目,因为C语言没有库,所以我们需要自己写一个栈,但是我们之前已经写好了一个栈了,可以直接使用。

②. 如果字符是左括号 '('  || ' [ ' || ' { ' ,我们就入栈,如果是右括号我们就取栈顶的元素,与字符串进行对比,如果左括号与相应的右括号不匹配时,就 return false。

 考虑边界情况:

③. 当栈中只有左括号时,就需要对栈进行判空处理,如果栈不为空,就 返回它的 bool 值。

④. 当没有左括号时,就说明没有括号入栈,也对栈进行判空,如果栈为空,就 return false。

 注意:养成好习惯,在每次 return 时,对栈进行销毁。

 

  ✡ 解题代码

typedef char STDataType;

typedef struct Stack
{
	STDataType* a;
	int top;//栈顶
	int capacity;//容量
}Stack;

//初始化栈
void StackInit(Stack* ps);

//入栈
void StackPush(Stack* ps, STDataType x);

//出栈
void StackPop(Stack* ps);

//获取栈顶元素
STDataType StackTop(Stack* ps);

//栈的有效个数
int StackSize(Stack* ps);

//栈的判空  为空返回非0,不为空返回0
bool StackEmpty(Stack* ps);

//栈的销毁
void StackDestroy(Stack* ps);

//初始化栈
void StackInit(Stack* ps)
{
	assert(ps);

	ps->a = NULL;
	ps->top = ps->capacity = 0;
}

//入栈
void StackPush(Stack* ps, STDataType x)
{
	//考虑扩容
	assert(ps);

	if (ps->top == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}
	//入栈
	ps->a[ps->top] = x;
	ps->top++;
	
}

//出栈
void StackPop(Stack* ps)
{
	assert(ps);
	//判空
	assert(!StackEmpty(ps));

	//直接 --
	ps->top--;
}

//获取栈顶元素
STDataType StackTop(Stack* ps)
{
	assert(ps);

	assert(!StackEmpty(ps));

	return ps->a[ps->top - 1];
}

//栈的有效个数
int StackSize(Stack* ps)
{
	assert(ps);

	return ps->top;
}

//栈的判空  为空返回非0,不为空返回0
bool StackEmpty(Stack* ps)
{
	assert(ps);

	return ps->top == 0;
}

//栈的销毁
void StackDestroy(Stack* ps)
{
	assert(ps);

	free(ps->a);
	//置空
	ps->a = NULL;
	ps->top = ps->capacity = 0;
}

bool isValid(char * s){
    //使用栈实现
    Stack st;
    //初始化
    StackInit(&st);

    
    while(*s!='\0')
    {
        //左括号就入栈
        if(*s=='('||*s=='['||*s=='{')
        {
            StackPush(&st,*s);
        }

        else
        {
            //右括号  出栈 对比

            // 栈为空时
            if(StackEmpty(&st))
            {
                StackDestroy(&st);
                return false;
            }

            char top=StackTop(&st);
            StackPop(&st);

            if((*s==')'&&top!='(')||
            (*s==']'&&top!='[')||
            (*s=='}'&&top!='{'))
            {
                StackDestroy(&st);
                return false;
            }

        }
        s++;
    }

    //栈不为空,为false
    bool flag=StackEmpty(&st);
    StackDestroy(&st);

    return flag;
}

✯ 结束语

【写在最后·想告诉你】

在互联网这个行业里

任何时候都要学好技术

永远都是 技术为王

  • 9
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

甘宸しぐれ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值