逻辑结构-栈

物理结构和逻辑结构

物理结构就是物质层次上的结构,是在内存中实实在在存在的存储结构。
逻辑结构是抽象的结构,不在现实中存在,主要是以来物理结构而存在。
物理结构主要就是数组和链表
逻辑结构就有顺序表、栈、队列和树、图等。
在这里插入图片描述

栈是一种线性结构,特点是先进后出,,first in last out,FILO。既是先进者后出,后进者先出。最早进入的元素存放的位置叫栈底,最后进入的元素叫做栈顶,

栈的理解

从栈的特性上看,栈是一种受限制的线性表,只允许在一端插入和删除数组,另一端是密封的。
这样一个受限制的数据结构明显没有数组和链表灵活,但为什么还要有这个数据结构呢。

特定的数据结构是对特定场景的抽象,且数组和链表 暴露太多接口了,操作上的灵活但是使用的时候有不可控性,更容易出错。

当某个数据集合只涉及在一端插入和删除数据,且满足先进后出、后进先出的特性,这个时候首先要选择栈结构。

栈 结构的实现

package java_test;

public class MyStack {
    private String[] arr;//数组
    private int count;//栈元素个数
    private int n ; //栈大小

    public MyStack(int n){
        this.arr = new String[n];
        this.n = n;
        this.count = 0;
    }
    public boolean push(String item){
        if (count==n) return false;
        arr[count] = item;
        ++count;
        return true;
    }
    public String pop(){
        if (count==0) return null;
        String tmp = arr[count-1];
        --count;
        return tmp;
    }
    public void output(){
        for (int i=0;i<count;++i){
            System.out.println(arr[i]);
        }
    }

    public static void main(String[] args) {
        MyStack myStack = new MyStack(3);
        myStack.push("A");
        myStack.push("B");
        myStack.push("C");
        myStack.output();
        System.out.println("------------------");
        myStack.pop();
        myStack.output();
    }

}

无论是顺序栈还是链式栈,都是存储一个n的数组,在入栈出栈的时候,只需要一两个临时变量存储空间,所以空间复杂度是O(1)。空间复杂度是指除了原本的数据存储空间外,算法运行还需要额外的存储空间。

动态扩容数组栈的时间复杂度分析

扩容栈不常用,这里只是分析时间复杂度,
1.出栈的话,时间复杂度O(1)。
2.当栈还有剩余空间的时候,入栈时间复杂度也是O(1)
3.但是栈没有空间的时候,需要申请内存和数据迁移,时间复杂度变成了O(n)。
所以最好复杂度是O(1),最坏是O(n)
当当前栈大小为K,且满了,当有新数据入栈时候,需要申请2倍大小的内存,并做k个数据的迁移,然后入栈。但是剩下的K-1个数据入栈的时候,不需要申请内存和迁移数据,所以k-1次入栈都只要O(1)的复杂度。
即 k次入栈操作,总共涉及了k个数据的迁移和k个数据的入栈操作。将k个数据迁移均摊到k次入栈操作,那么没次入栈操作只要一个数据迁移和一个数据入栈操作。所以入栈操作的均摊时间复杂度就是O(1),接近O(1)。

栈的经典应用场景

栈在函数调用的应用

操作系统 给每个线程分配了一个独立的空间,这个空间是栈的结构,用于存储函数调用的临时变量。没进入一个函数,就会将临时变量作为栈帧入栈,当变量被函数执行完成后,出栈。
例如


int main() {
   int a = 1; 
   int ret = 0;
   int res = 0;
   ret = add(3, 5);
   res = a + ret;
   printf("%d", res);
   reuturn 0;
}

int add(int x, int y) {
   int sum = 0;
   sum = x + y;
   return sum;
}

main方法先定义变量,然后调用add()函数,获取结果后然后与临时变量a相加,打印res。
在这里插入图片描述

链在表达式中的应用

例如34+13*9+44-12/3
编译器会实现两个栈,一个栈保存操作数的栈,一个是保存运算符的栈,
从左到右,遇到数字,压入操作数栈,遇到运算符,先与运算符栈的栈顶元素比较。
如果比栈顶元素的优先级高,压入栈中。
如果比栈顶元素的优先级低,从栈顶中取出栈顶运算符,从操作数栈中取出两个操作数,进行计算,然后把结果压入操作数栈中,继续比较。
在这里插入图片描述

链在括号匹配的应用

一组字符串,如何检验是否合法。
用栈来保存未匹配的左括号,从左到右扫描字符串,当扫到左括号,压入栈。
扫描到右括号,从栈顶取出左括号。
如果能匹配,则继续扫描,如果不能匹配或者栈为空,则说明是非法格式。
当所有括号扫描完成后,栈为空,则说明是合法字符串。

栈来实现浏览器的前进、后退功能

使用两个栈,x,y。 首次浏览的页面压入x,点击后退的时候,从x取出栈,再把取出的页面放入y中。
点击前进的时候,从y中取出页面,压入x中。当x没数据的时候,就没有页面可以后退,当y没数据,就没页面可以前进。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值