数据结构从0到1之栈的实现及相关OJ题

简介: 实现栈有很多种方式,在这里我们使用的方法是动态数组实现。

前言


实现栈有很多种方式,在这里我们使用的方法是动态数组实现。


栈的概念及结构


一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。

进行数据插入和删除 操作的一端称为栈顶,另一端称为栈底。

栈中的数据元素遵守后进先出LIFO(Last In First Out) 的原则。

image.png

思路


拓展:assert()内的条件若返回错误则停止程序 非必要只是方便Debug

tips:主函数中得先定义一个结构体变量

1. 定义结构体

数组

栈顶

记录存储容量的变量

2.初始化

assert()断言:判断结构体是否存在

先给数组开辟一个初始空间4

判断开辟空间是否成功

存储容量为4

栈顶为0

3. 销毁

assert()断言:判断结构体是否存在

销毁数组,将数组置为NULL

将栈顶的值和存储容量的变量置为0

4. 入栈

assert()断言:判断结构体是否存在

先判断容量是否足够:

不够则增容(假设增两倍)

这里用的是realloc

会先将原数组的值先拷贝,开辟一个新空间增容

增容后判断是否成功增容

失败则打印增容失败

成功则把新空间的地址赋给结构体变量里的数组

存储容量的变量*2

容量足够入栈:

利用数组的性质将值赋给栈顶

栈顶自增

5. 出栈

取栈顶值

assert()断言:判断结构体是否存在

assert()断言:判断栈顶是否大于0

利用数组性质返回栈顶元素的值

删去栈顶

assert()断言:判断结构体是否存在 a

ssert()断言:判断栈顶是否大于0

栈顶位置减一

6. 栈长

assert()断言:判断结构体是否存在

返回栈顶下标即为栈长

7. 栈空

assert()断言:判断结构体是否存在

返回一个bool值 根据栈顶下标是否为0判断栈是否为空

代码实现

1. 定义结构体

typedef struct Sqstack
{
    Elemtype* a;
    int top;
    int capacity;
}Sq;

2. 初始化

void Initstack(Sq*st) {
    assert(st);
    st->a = (Elemtype*)malloc(sizeof(Elemtype) * 4);
    if (st->a == NULL) {
        printf("malloc fail\n");
        exit(-1);
    }
    st->capacity = 4;
    st->top = 0;
}

3. 销毁

void DestroySt(Sq* st) {
    assert(st);
    free(st->a);
    st->a = NULL;
    st->top = st->capacity = 0;
}

4. 入栈

void InsertSt(Sq* st,Elemtype x) {
    assert(st);
    if (st->top == st->capacity) {
        Elemtype* tem = (Elemtype*)realloc(st->a, st->capacity * 2 * sizeof(Elemtype));
        if (tem == NULL) {
            printf("realloc fail\n");
            exit(-1);
        }
        else
        {
            st->a = tem;
            st->capacity *= 2;
        }
    }
    st->a[st->top] = x;
    st->top++;
}


5. 出栈

Elemtype TopSt(Sq* st) {
    assert(st);
    assert(st->top > 0);
    return st->a[st->top -1];
}
void PopSt(Sq* st) {
    assert(st);
    assert(st->top > 0);
    st->top--;
}

6. 栈长

int Stsize(Sq* st) {
    assert(st);
    return st->top;
}

7. 栈空

bool StEmpty(Sq* st) {
    assert(st);
    return st->top == 0;
}

OJ题(简单)

有效的括号


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


有效字符串需满足:


左括号必须用相同类型的右括号闭合。


左括号必须以正确的顺序闭合。


每个右括号都有一个对应的相同类型的左括号。


示例 1:


输入:s = "()"

输出:true

示例 2:


输入:s = "()[]{}"

输出:true

示例 3:


输入:s = "(]"

输出:false

提示:


1 <= s.length <= 104


s 仅由括号 '()[]{}' 组成


题解


在这里我们使用了栈的思想,首先定义一个栈,然后拿栈顶和字符串的值配对

所以我们使用了循环遍历,直到字符串结束为止打破循环,在循环里面,使用Swich语句

如果是左括号则入栈,字符串遍历下一个

如果是右括号,则先判断是否为空

如果为空,则无需继续不可能配对成功了,打破循环结束,返回false

如果不是空,则拿栈顶的元素和字符串中的元素配对,这里要记得出栈

判断是否不匹配,如果不匹配则销毁栈,返回false,否则匹配继续遍历字符串,直到结束为止

最后判断栈内是否为空,若为空则说明全部匹配成功返回true,否则返回false。

typedef char Elemtype;
typedef struct Sqstack
{
    Elemtype* a;
    int top;
    int capacity;
}Sq;
void Initstack(Sq*st) {
    assert(st);
    st->a = (Elemtype*)malloc(sizeof(Elemtype) * 4);
    if (st->a == NULL) {
        printf("malloc fail\n");
        exit(-1);
    }
    st->capacity = 4;
    st->top = 0;
} 
void DestroySt(Sq* st) {
    assert(st);
    free(st->a);
    st->a = NULL;
    st->top = st->capacity = 0;
}
void InsertSt(Sq* st,Elemtype x) {
    assert(st);
    if (st->top == st->capacity) {
        Elemtype* tem = (Elemtype*)realloc(st->a, st->capacity * 2 * sizeof(Elemtype));
        if (tem == NULL) {
            printf("realloc fail\n");
            exit(-1);
        }
        else
        {
            st->a = tem;
            st->capacity *= 2;
        }
    }
    st->a[st->top] = x;
    st->top++;
}
Elemtype TopSt(Sq* st) {
    assert(st);
    assert(st->top > 0);
    return st->a[st->top -1];
}
void PopSt(Sq* st) {
    assert(st);
    assert(st->top > 0);
    st->top--;
}
int Stsize(Sq* st) {
    assert(st);
    return st->top;
}
bool StEmpty(Sq* st) {
    assert(st);
    return st->top == 0;
}
int lengths(char*s){
    int i=0;
    while(s[i]!='\0'){
        i++;
    }
    return i;
}
bool isValid(char * s){
    Sq st;
    Initstack(&st);
    while(*s !='\0'){
        switch(*s)
        {
            case '{':
            case '[':
            case '(':
            {
                InsertSt(&st,*s);
                ++s;
                break;
            }
            case '}':
            case ')':
            case ']':
            {
                if(StEmpty(&st)){
                    DestroySt(&st);
                    return false;
                }
                char top=TopSt(&st);
                PopSt(&st);
                if((*s=='}'&&top!='{')
                ||(*s==']'&&top!='[')
                ||(*s==')'&&top!='('))
                {
                    DestroySt(&st);
                    return false;
                }
                else{
                    ++s;
                }
                break;
            }
            default:
                break;
        }
    }
    bool ret=StEmpty(&st);
    DestroySt(&st);
    return ret;
}
相关文章
|
2月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
255 9
|
2月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
41 1
|
22小时前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
24 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
22小时前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
110 75
|
22小时前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
21 7
|
22小时前
|
存储 C语言 C++
【C++数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现链栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储整数,最大
22 9
|
2月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
76 5
|
2月前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
2月前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
2月前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
57 4
下一篇
开通oss服务