当前位置: 首页 > article >正文

28 线性表 · 栈

目录

一、概念与结构

(一)概念

1、栈

2、压栈

3、出栈

4、底层实现       

二、栈的实现

三、栈的算法题


一、概念与结构

(一)概念

1、栈

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

2、压栈

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

3、出栈

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

4、底层实现       

        底层使用数组、单链表、双向链表来实现都是没问题的。

        从内存角度出发,双向链表的节点比单链表节点多一个指正,在32位机器中就多出了4字节内存,在64位机器中就多出了8字节内存。在优化的角度来看,可以先排除掉双向链表。

        从增容的效率出发,数组每次是空间×2地去增容,相比单链表的尾插每增加一个节点就要动态申请一个节点大小的内存的频率,数组的增容频率要小很多,会减少系统的开销。

        从数据读取角度来看,数组的读取频率也比单链表的读取频率要低,因为从主存中读取数据时是取一块连续的空间到缓存中读取,而单链表的地址不一定是连续的,可能要多次从主存中进行读取,所以综合上面增容效率的论述,在优化的角度来看,可以排除单链表。

        综上所述,栈的底层为数组会更优

                

二、栈的实现

        栈的常用名:Stack。

栈的编写:

① 头文件:定义栈的结构体,声明要提供的操作(起到目录作用)。

② cpp文件:编写具体实现各种操作(起到内容作用)。

③ 测试文件:测试是否可以正常运行。

Stack.h

#pragma once
#include<stdlib.h>
#include<iostream>
#include<assert.h>
#include<stdbool.h>

using namespace std;
typedef int STDatapype;
//定义栈结构
typedef struct Stack
{
	STDatapype* arr;//栈底层为数组
	int capecity;//栈底层数组的总元素个数
	int top;//栈顶,相当于顺序表中的有效元素个数size
}ST;

//一、初始化栈、销毁栈、增容栈的数组、判断栈是否为空、取栈顶元素、获取栈中有效元素个数
//(一)初始化栈
void STInit(ST& st);
//(二)销毁栈
void STDestroy(ST& st);
//(三)增容栈的数组
void STCapacity(ST& st);
//(四)判断栈是否为空
bool STEmpty(ST& st);
//(五)取栈顶元素
STDatapype STGetTop(ST& st);
//(六)获取栈中有效元素个数
int STGetSize(ST& st);

//二、栈顶插入
void STPush(ST& st, STDatapype num);

//三、栈顶删除
void STPop(ST& st);

Stack.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"

//一、初始化栈、销毁栈、增容栈的数组、判断栈是否为空、取栈顶元素、获取栈中有效元素个数
//(一)初始化栈
void STInit(ST& st)
{
	st.arr = nullptr;
	st.capecity = st.top = 0;
}
//(二)销毁栈
void STDestroy(ST& st)
{
	if (st.arr)
	{
		free(st.arr);
		st.arr = nullptr;
	}
	st.capecity = st.top = 0;
}
//(三)增容栈的数组
void STCapacity(ST& st)
{
	if (st.capecity == st.top)
	{
		st.capecity = st.capecity == 0 ? 4 : st.capecity * 2;
		STDatapype* new_st = (STDatapype*)realloc(st.arr, sizeof(STDatapype) * (st.capecity));
		if (new_st == nullptr)
		{
			perror("STCapecity reallco fail");
			exit(1);
		}
		st.arr = new_st;
	}
}
//(四)判断栈是否为空
bool STEmpty(ST& st)
{
	return st.top == 0;
}
//(五)取栈顶元素(只能取到栈顶元素)
STDatapype STGetTop(ST& st)
{
	assert(!STEmpty(st));
	return st.arr[st.top - 1];

}
//(六)获取栈中有效元素个数
int STGetSize(ST& st)
{
	return st.top;
}

//二、栈顶插入
void STPush(ST& st, STDatapype num)
{
	STCapacity(st);
	/*st.arr[st.top] = num;
	st.top++;*/
	st.arr[st.top++] = num;
}

//三、栈顶删除
void STPop(ST& st)
{
	//assert(st.arr);
	assert(!STEmpty(st));
	st.top--;
	if (st.top <= 0)
		st.arr = nullptr;
}

test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"

void test()
{
	ST st;
	STInit(st);

	for (int i = 1; i < 6; i++)
	{
		STPush(st, i);
	}

	/*for (int i = 1; i < 11; i++)
	{
		STPop(st);
		STPrint(st);
	}
	STPrint(st);*/

	while (!STEmpty(st))
	{
		STDatapype num = STGetTop(st);
		cout << num << " ";
		STPop(st);
	}
	cout << endl;
 }

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

        注意:

                ① 栈没有遍历打印的操作,因为栈不能通过下标进行随机访问其中的数据,只能通过下标拿到栈顶元素。

                ② 空栈的时候,栈底等于栈顶。

三、栈的算法题

        题目链接如下:

                https://leetcode.cn/problems/valid-parentheses/description/

        解题思路:

                使用栈的结构与方法,先遍历字符串数组,若字符串数组中为左括号(无论大中小括号),把该元素压入自定义的栈中;若字符串数组中为右括号(无论大中小括号)则取出栈顶元素进行判断,看看是否为一对,若为一对就把栈顶元素出栈,不是则return false;到最后要销毁栈

        注意点:

                ① 循环结束后要检查栈是否为空,若为空则是括号对应的情况,return true;否则 return false。

                ② 在取出栈顶元素时,要判断栈顶元素是否为空,若为空则 return false,因为要考虑只存在右括号的情况。

        答案代码如下:

typedef char STDataType;
//定义栈结构
typedef struct Stack
{
	STDataType* arr;//栈底层为数组
	int capacity;//栈底层数组的总元素个数
	int top;//栈顶,相当于顺序表中的有效元素个数size
}ST;
//初始化栈
void STInit(ST* ps)
{
	assert(ps);
	ps->arr = NULL;
	ps->capacity = ps->top = 0;
}
//销毁栈
void STDestroy(ST* ps)
{
	assert(ps);
	if (ps->arr)
		free(ps->arr);
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}
//插入
void STPush(ST* ps, STDataType x)
{
	assert(ps);
	
	//1.判断空间是否足够
	if (ps->capacity == ps->top)
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		STDataType* tmp = (STDataType*)realloc(ps->arr, newCapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
	//空间足够
	ps->arr[ps->top++] = x;
}
//判断是否为空
bool StackEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}
//删除尾元素
void STPop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));

	--ps->top;
}
//取栈顶元素
STDataType STGetTop(ST* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));

	return ps->arr[ps->top - 1];
}
//获取栈中有效元素个数
int STSize(ST* ps)
{
	assert(ps);
	return ps->top;
}
 
bool isValid(char* s) {
    //创建栈结构并初始化
    ST st;
    STInit(&st);

    //遍历s,若为左括号就入栈;若为右括号就与栈顶元素进行比较
    char* ps = s;
    while(*ps)
    {
        if(*ps == '(' || *ps == '[' || *ps == '{')
        {
            STPush(&st, *ps);
        }
        else
        {
            if(StackEmpty(&st))//栈不为空才能取栈顶元素,若为空直接返回false
                return false;
            char top_ele = STGetTop(&st);
            if((*ps == ')' && top_ele == '(')
            || (*ps == ']' && top_ele == '[')
            || (*ps == '}' && top_ele == '{'))
            {
                STPop(&st);
            }
            else
            {
                STDestroy(&st);
                return false;
            }
        }
        ps++;
    }
    //销毁栈
    bool re = StackEmpty(&st);
    STDestroy(&st);
    return re;
}

        以上内容仅供分享,若有错误,请多指正。 


http://www.kler.cn/news/306205.html

相关文章:

  • golang的GC(三色标记法+混合写屏障)学习笔记
  • 第一篇---滑动窗口最大值、前 K 个高频元素
  • 初识爬虫2
  • Linux删除SSH生成的密钥对
  • 探索Python的Excel世界:openpyxl的魔法之旅
  • 【homebrew安装】踩坑爬坑教程
  • 路由策略原理与配置
  • C#笔记11 获取线程及其信息,什么是优先级、单元状态、线程状态、执行状态、线程名称以及其他属性?
  • 一文速通calcite结合flink理解SQL从文本变成执行计划详细过程
  • Kubernetes Pod镜像的3种状态
  • STM32-UART配置注释
  • 标准库标头 <bit>(C++20)学习
  • 计算机网络 --- 计算机网络性能【七大性能指标】
  • 如何精确统计Pytorch模型推理时间
  • c语言写的环形队列
  • emWin5的图片半透明之旅
  • 高级java每日一道面试题-2024年9月12日-架构篇[DDD领域驱动篇]-如何使用领域驱动设计(DDD)中的事务脚本模式?
  • Spring4-IoC2-基于注解管理bean
  • comfyui中,sam detector与yoloworld图像分割算法测试以及影响
  • [极客大挑战 2019]PHP
  • 1、常用的数据库、表操作
  • 蒸!--数据在内存中的存储
  • node express 开启多进程
  • python多线程程序设计 之二
  • C#获取计算机信息
  • C++入门基础知识68(高级)——【关于C++ 异常处理】
  • 【系统架构设计师-2010年真题】案例分析-答案及详解
  • Superset二次开发之源码asyncEvent.ts 分析
  • 嵌入式C语言自我修养:C语言的面向对象编程思想
  • 问题 H: 三角数