线性表 - 栈(数组和链表两种方式实现栈)

线性表 - 栈(数组和链表两种方式实现栈)

1.1 栈的介绍

  • 栈和队列都属于线性数据的逻辑存储结构

  • 栈(stack)是一种线性数据结构,栈中的元素只能先入后出(First In Last Out,简称FILO)

  • 最早进入的元素存放的位置叫作栈底(bottom),最后进入的元素存放的位置叫作栈顶(top)

  • 存储原理
    在这里插入图片描述

    • 栈既可以用数组来实现,也可以用链表来实现

    • 栈的数组实现如下:

      • 数组实现的栈也叫顺序栈或静态栈,链表实现的栈也叫做链式栈或动态栈
      • 栈的链表实现如下:
        在这里插入图片描述
  • 操作

    • 入栈(压栈)

      • 入栈操作(push)就是把新元素放入栈中,只允许从栈顶一侧放入元素,新元素的位置将会成为新的栈顶
        在这里插入图片描述
        在这里插入图片描述
    • 出栈(弹栈)

      • 出栈操作(pop)就是把元素从栈中弹出,只有栈顶元素才允许出栈,出栈元素的前一个元素将会成为新的栈顶
        在这里插入图片描述
        在这里插入图片描述

1.2 数组实现栈(顺序栈 / 静态栈)

package com.lagou.entity;

import java.util.Arrays;

/**
 * @author 云梦归遥
 * @date 2022/5/12 17:18
 * @description
 */
public class MyArrayStack {
    private int[] array; //构建的数组对象
    private static final int ARRAY_LENGTH = 8; // 定义无参构造默认的数组长度
    private int length = 0; // 记录数组有效长度

    // 数组构造方法
    public MyArrayStack(){// 默认构造方法数组长度为 8
        this.array = new int[ARRAY_LENGTH];
    }
    public MyArrayStack(int len){// 有参构造则依靠传入的整型数字来构造数组
        this.array = new int[len];
    }

    // 入栈
    public void push(int num){
        array[length++] = num;
    }

    // 出栈
    public int pop(){
        return array[length--];
    }

    // 获取栈顶元素,但不删除栈顶元素
    public int top(){
        return array[length];
    }

    @Override
    public String toString() {
        return "MyArrayStack{" +
                "array=" + Arrays.toString(array) +
                '}';
    }
}

进行测试

package com.lagou.test;

import com.lagou.entity.MyArrayStack;

/**
 * @author 云梦归遥
 * @date 2022/5/12 17:22
 * @description
 */
public class MyArrayStackTest {
    public static void main(String[] args) {
        MyArrayStack stack = new MyArrayStack();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        stack.pop();
        int top = stack.top();
        System.out.println("此时的栈顶元素为:" + top);
        System.out.println("栈:" + stack);
    }
}

在这里插入图片描述

1.3 链表实现栈(链栈 / 动态栈)

package com.lagou.entity;

/**
 * @author 云梦归遥
 * @date 2022/5/12 17:25
 * @description
 */
public class MyLinkStack {
    public class MyLink{
        private int value;
        private MyLink link;

        public MyLink(){
            this.value = 0;
            this.link = null;
        }
        public MyLink(int value){
            this.value = value;
            this.link = null;
        }
        public MyLink(int value, MyLink link){
            this.value = value;
            this.link = link;
        }

        @Override
        public String toString() {
            return "MyLink{" +
                    "value=" + value +
                    ", link=" + link +
                    '}';
        }
    }

    private MyLink head = new MyLink(0, null); // 头结点

    public void push(int num){
        MyLink node = new MyLink(num);
        MyLink temp = head.link; // 创建临时节点吗,进行节点的遍历
        if (head.link == null){
            head.link = node;
        } else {
            while (true){
                if (temp.link == null){
                    break;
                } else {
                    temp = temp.link;
                }
            }
            temp.link = node;
        }
        head.value++; // 链表长度 + 1
    }

    // 出栈
    public int pop(){
        if (head.value == 0){
            return 0;
        } else {
            MyLink temp = head;
            for (int i = 1; i < head.value; i++){
                temp = temp.link;
            }
            MyLink popNode = temp.link;
            temp.link = null;
            head.value--;
            return popNode.value;
        }
    }

    // 只返回栈顶元素,而不让元素出栈
    public int top(){
        if (head.value == 0){
            return 0;
        } else {
            MyLink temp = head;
            for (int i = 1; i < head.value; i++){
                temp = temp.link;
            }
            return temp.link.value;
        }
    }

    // 获取整个栈
    public String select(){
        StringBuilder stringBuilder = new StringBuilder();
        if (head.value == 0){
            return "null";
        } else {
            stringBuilder.append("【栈中元素个数:" + head.value + "】");
            MyLink temp = head;
            for (int i = 1; i < head.value; i++){
                temp = temp.link;
                stringBuilder.append(temp.value + " => ");
            }
            stringBuilder.append(temp.link.value);
            return stringBuilder.toString();
        }
    }
}

进行测试

package com.lagou.test;

import com.lagou.entity.MyLinkStack;

/**
 * @author 云梦归遥
 * @date 2022/5/12 17:40
 * @description
 */
public class MyLinkStackTest {
    public static void main(String[] args) {
        MyLinkStack myLinkStack = new MyLinkStack();
        myLinkStack.push(1);
        myLinkStack.push(2);
        myLinkStack.push(3);
        System.out.println("当前整个栈:" + myLinkStack.select());
        myLinkStack.pop();
        int num = myLinkStack.top();
        System.out.println("当前栈顶元素为:" + num);
        System.out.println("当前整个栈:" + myLinkStack.select());
    }
}

在这里插入图片描述

1.4 栈的总结

  • 时间复杂度

    • 入栈和出栈的时间复杂度都是O(1)
    • 支持动态扩容的顺序栈
    • 当数组空间不够时,我们就重新申请一块更大的内存,将原来数组中数据统统拷贝过去。这样就实现了
    • 一个支持动态扩容的数组,通过前面学过的知识,可以得知入栈的时间复杂度是O(n)
  • 应用

    • 函数调用
      • 每进入一个函数,就会将临时变量作为一个栈入栈,当被调用函数执行完成,返回之后,将这个函数对应的栈帧出栈
    • 浏览器的后退功能
      • 我们使用两个栈,X 和 Y,我们把首次浏览的页面依次压入栈 X,当点击后退按钮时,再依次从栈X 中出栈,并将出栈的数据依次放入栈 Y。当我们点击前进按钮时,我们依次从栈 Y 中取出数据,放入栈 X 中。当栈 X 中没有数据时,那就说明没有页面可以继续后退浏览了。当栈 Y 中没有数据,那就说明没有页面可以点击前进按钮浏览了
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值