数据结构之栈

目录

一、栈的概念 

 二、栈的相关小题

三、栈中的一些方法

 四、栈的实现


一、栈的概念 

1.:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈 顶,另一端称为栈底。栈中的数据元素遵守 后进先出 LIFO Last In First Out )的原则
2.压栈:栈的插入操作叫做进栈 /压栈/ 入栈 入数据在栈顶
3.出栈:栈的删除操作叫做出栈。 出数据在栈顶
4.别的一些栈:
(1)虚拟机栈 (JVM Stack): 一块具有栈的特性的内存, 重点是存储 局部变量表 ( 当然也有其他信息 )
         栈帧:在调用函数时,我们会为这个函数开辟一块内存(在JVM Stack中开辟),叫做栈帧。
(2) 本地方法栈 (Native Method Stack): 本地方法栈与虚拟机栈的作用类似 . 只不过保存的内容是 Native 方法的局 部变量 . 在有些版本的 JVM 实现中 ( 例如 HotSpot), 本地方法栈和虚拟机栈是一起的

 二、栈的相关小题

1.出栈顺序,如:

已知一个栈的入栈序列是mnxyz,则不可能的出栈顺序是()

A.mnxyz                                                        B.xnyzm                                                   C.nymxz                                                    D.nmyzx

答案:C

分析如下:

A.进一个出一个即可达到这种效果,B、C如下图,D与之同理

 2.中缀表达式转后缀表达式

(1)中缀表达式是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4),中缀表达式是人们常用的算术表示方法。与前缀表达式(例:+ 3 4)或后缀表达式(例:3 4 +)相比,中缀表达式不容易被计算机解析,但仍被许多程序语言使用,因为它符合人们的普遍用法。与前缀或后缀记法不同的是,中缀记法中括号是必需的。计算过程中必须用括号将操作符和对应的操作数括起来,用于指示运算的次序。

(2)前缀表达式是一种没有括号的算术表达式,与中缀表达式不同的是,其将运算符写在前面,操作数写在后面。为纪念其发明者波兰数学家Jan Lukasiewicz,前缀表达式也称为“波兰式”。例如,- 1 + 2 3,它等价于1-(2+3)。

(3)后缀表达式:逆波兰式(Reverse Polish notation,RPN,或逆波兰记法),也叫后缀表达式(将运算符写在操作数之后)

算法定义:①如果E是一个变量或常量,则E的后缀式是E本身。②如果E是E1 op E2形式的表达式,这里op是任何二元操作符,则E的后缀式为E1'E2' op,这里E1'和E2'分别为E1和E2的后缀式。③如果E是(E1)形式的表达式,则E1的后缀式就是E的后缀式。

三、栈中的一些方法

方法解释
E push (E item)
压栈
E pop ()
出栈
E peek ()
查看栈顶元素
boolean empty ()
判断栈是否为空

 四、栈的实现

可以用顺序表实现,也也可以用链表实现,但是相对来说,用顺序表实现要简单一些,所以我们优先使用顺序表实现栈

import java.util.Arrays;

public class MyStack {
    public int[] elem;
    public int usedSize;

    public MyStack()
    {
        this.elem = new int[5];
    }

    public void push(int val)
    {
        if(isFull()){
            this.elem = Arrays.copyOf(this.elem,2*this.elem.length);//扩容
        }
        this.elem[this.usedSize++] = val;
    }
    public boolean isFull(){
        return this.usedSize == this.elem.length;
    }
    public int pop()
    {
        if(isEmpty())
        {
            throw new RuntimeException("栈为空!\n");
        }
        int oldVal = this.elem[usedSize - 1];
        this.usedSize--;
        return oldVal;
    }
    //入栈和出栈的时间复杂度为O(1)
    public boolean isEmpty()
    {
        return this.usedSize == 0;
    }
    public int peek(){
        if(isEmpty())
        {
            throw new RuntimeException("栈为空!\n");
        }
        return this.elem[usedSize-1];
    }
}
public class TestDemo {
    public static void main(String[] args) {
        MyStack stack = new MyStack();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        System.out.println(stack.pop());
        System.out.println(stack.peek());
        System.out.println(stack.isEmpty());
        System.out.println(stack.isEmpty());
    }
}

编译并运行,输出如下:

3
2
false
false

 我们也可以用链表实现一个栈,但是链表既可以是头插,也可以是尾插,那么当我们入栈的时候是用头插法还是尾插法呢?答案是头插法,因为尾插法的时间复杂度为O(n)(因为尾插法需要找尾巴);我们假设用头插法入栈,那么出栈的时候只需要删除头结点即可,时间复杂度仍为O(1)。但是尾插法也不是不行,我们可以增加一个变量记录尾结点,这样我们的入栈就可以做到时间复杂度为O(1)了,但是出栈呢?链表的删除节点操作需要找到前一个节点,此时我们还是需要通过遍历去找到该节点,时间复杂度又变成了O(n),为此,我们使用尾插法实现栈时,使用双向链表来实现它。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值