java数据结构----栈

一、栈(Stack)的介绍

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

        说明:

  • 进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。
  • 栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
  • 压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
  • 出栈:栈的删除操作叫做出栈。出数据在栈顶。

栈可以分为:数据结构栈,java虚拟机栈,栈帧

Java虚拟机栈

  • JVM stack(Java虚拟机栈)只是JVM中的一块内存,该内存一般用于存放。例如:局部变量......
  • 这块内存同样具备栈的特性。例如在调用函数的时候,会为函数开辟一块内存,开辟的内存叫做栈帧。

二、栈的使用

在集合框架中,Stack(栈)是一个普通的类,实现了List接口,具体框架图如下

说明:

Stack实现了RandomAccess接口,表明Stack支持随机访问
Stack实现了Cloneable接口,表明Stack是可以clone的
Stack实现了Serializable接口,表明Stack是支持序列化的
Vector(向量)是一个封装了动态大小数组的顺序容器(Sequence Container)。跟任意其它类型容器一样,它能够存放各种类型的对象。可以简单的认为,向量是一个能够存放任意类型的动态数组。
Vector 与 ArrayList 基本是一致的,不同的是Vector是线程安全的,会在可能出现线程安全的方法前面使用 synchronized 关键字。

stack常用方法

栈的模拟实现

  • Java底层的栈使用了泛型,可以操作任何类型的数据,这里模拟实现使用了顺序表(整型数组)。
import java.util.Arrays;
 
public class MyStack {
    public int[] elem; //数组 -> 栈空间
    public int usedSize;//有效数据
    public MyStack(){
        this.elem = new int[5];
        this.usedSize = 0;
    }
    //入栈
    public void push(int val){
        //如果栈满了就进行扩容
        if(isFull()){
            this.elem = Arrays.copyOf(elem,2*this.elem.length);
        }
        this.elem[this.usedSize] = val;
        usedSize++;
    }
    //判断栈是否满
    public boolean isFull(){
        return usedSize==this.elem.length;
    }
 
    //出栈
    public int pop(){
        if(isEmpty()){
            throw new NullPointerException("栈为空!");
        }
        int oldVal = this.elem[usedSize-1];
        this.usedSize--;
        return oldVal;
    }
    //判断栈是否为空
    public boolean isEmpty(){
        return this.usedSize==0;
    }
 
    //读取栈顶元素
    public int peek(){
        if(isEmpty()){
            throw new NullPointerException("栈为空!");
        }
        return this.elem[usedSize-1];
    }
}

测试代码

import java.util.Stack;
 
public class TestDemo1 {
    public static void main(String[] args) {
        MyStack myStack = new MyStack();
        myStack.push(1);//入栈
        myStack.push(2);
        myStack.push(3);
        myStack.push(4);
        System.out.println(myStack.peek());//获取栈顶元素
        System.out.println(myStack.pop());//出栈
        System.out.println(myStack.pop());
        System.out.println(myStack.pop());
        System.out.println(myStack.pop());
        System.out.println(myStack.isEmpty());//判断栈是否为空,如果为空返回true,否则返回false
    }
}
 
运行结果:
4
4
3
2
1
true

⭐使用链表需要满足的条件:

先进后出
入栈和出栈的时间复杂度为O(1)
链表可以头插也可以尾插,那么入栈是使用头插法还是使用尾插法呢?

假设:如果入栈使用尾插法,那么时间复杂度是O(n),因为尾插法每次都要找最后一个结点。
假设:如果入栈使用头插法,那么时间复杂度是O(1);出栈的时候只需要删除头结点,时间复杂度也是O(1)
经过推导得出,使用头插法实现栈使满足条件,但是如果非要使用尾插法呢?

假设给一个last引用指向尾巴结点,此时入栈的时间复杂度为O(1)。
但是出栈的时间复杂度还是O(n)。因为,虽然知道了最后一个结点,但是去掉尾巴结点后还要知道它的前一个结点,那么就要遍历单链表去找尾巴结点的前驱结点。此时时间复杂度又是O(n)。
⭐最终的解决办法就是使用双向链表来实现一个栈。(双向链表可以知道一个结点的前驱结点与后继结点)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值