数据结构从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;
}
相关文章
|
19天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
97 9
|
10天前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
19 1
|
12天前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
15天前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
17天前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
46 4
|
1月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
31 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
22天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
1月前
初步认识栈和队列
初步认识栈和队列
60 10
|
1月前
数据结构(栈与列队)
数据结构(栈与列队)
20 1
|
1月前
|
存储 Java
数据结构第三篇【链表的相关知识点一及在线OJ习题】
数据结构第三篇【链表的相关知识点一及在线OJ习题】
26 7

热门文章

最新文章

下一篇
无影云桌面