【算法通关村第三关——如何基于数组(或者链表)实现栈】

前言

栈在工程中有大量的应用,而在算法中相对简单,而且在很多时候,该数据结构都是解决更高级问题的工具,可以直接使用,这里我们先理解栈的特征,实现原理已经在算法中如何应用。


提示:以下是本篇文章正文内容,下面案例可供参考

一、栈基础知识

1.1 栈的特征

栈是一种数据结构,它遵循"先进后出"(Last In First Out,LIFO)的原则。栈可以看做是一种特殊的线性表(访问受限的线性表),只能在表的一端进行插入和删除操作,这一端被称为栈顶(Top),另一端被称为栈底(Bottom),同时把插入元素的操作称为入栈(Push),删除元素的操作称为出栈(Pop)

栈的特点如下:

  1. 只能在栈顶进行插入和删除操作,即元素的添加和移除只能发生在同一位置。
  2. 最后插入的元素将成为第一个被删除的元素,因此,栈的插入和删除操作是按照后进先出顺序进行的。
  3. 栈的大小有限,当栈满时,无法继续插入新的元素;当栈为空时,无法进行删除操作。

1.2 栈的应用场景很广泛,例如:

  • 程序调用栈:在计算机编程中,函数调用和退回是通过使用栈来管理的。
  • 括号匹配:利用栈的特性,可以判断一个表达式中的括号是否匹配。
  • 浏览器历史记录:浏览器通过使用栈来记录用户访问的网页,用户可以通过后退按钮来回退到之前访问的网页。

1.3 栈的操作

栈有许多操作,常见的有:

  • 入栈:push(E),
  • 出栈:pop(),
  • 获取栈顶元素,出栈:pop(),
  • 显示栈顶元素,不出栈:peek()
  • 判断栈是否为空:empty()

通过这些操作,可以方便地对栈进行操作和管理。

1.4 Java中的栈

Java中提供了现成的数据结构实现,如java.util.Stack类,它使用向量(Vector)作为底层实现,向量本质上也是使用数组实现的动态数组。此外,Java中也可以自行实现栈的数据结构,使用数组或链表作为底层实现,根据需求选择合适的实现方式。

代码如下:

public class MainTest {
    public static void main(String[] args) {
        Stack<Integer> stack = new Stack();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        System.out.println("栈顶元素为:" + stack.peek());
        while (!stack.empty()) {
            //只显示没出栈
            System.out.println(stack.peek());
            //出栈并且显示
            System.out.println(stack.pop());
        }
    }
}

2.基于数组实现栈

代码如下:

class Arraystack<T> {
    //实现栈的数组
    private Object[] stack;
    //栈顶元素
    private int top;

    Mystack() {
        //初始容量为10
        stack = new Object[10];
    }

    //判断是否为空
    public boolean isEmpty() {
        return top == 0;
    }

    //返回栈顶元素
    public T peek() {
        T t = null;
        if (top > 0)
            t = (T) stack[top - 1];
        return t;
    }

    public void push(T t) {
        expandCapacity(top + 1);
        stack[top] = t;
        top++;
    }

    //出栈
    public T pop() {
        T t = peek();
        if (top > 0) {
            stack[top - 1] = null;
            top--;
        }
        return t;
    }

    //扩大容量
    public void expandCapacity(int size) {
        int len = stack.length;
        if (size > len) {
            size = size * 3 / 2 + 1;//每次扩大50%
            stack = Arrays.copyOf(stack, size);
        }
    }
 }

3.基于链表实现栈

基于链表实现栈可能就稍微比数组复杂一点,将链表的头结点设为栈顶,每次出栈,入栈,都对head节点进行操作。

代码如下:

class ListStack<T> {
    //定义链表
    class Node<T> {
        public T t;
        public Node next;
    }
    public Node<T> head;

    //构造函数初始化头指针
    ListStack() {
        head = null;
    }
    //入栈
    public void push(T t) {
        if (t == null) {
            throw new NullPointerException("参数不能为空");
        }
        if (head == null) {
            head = new Node<T>();
            head.t = t;
            head.next = null;
        } else {
            Node<T> temp = head;
            head = new Node<>();
            head.t = t;
            head.next = temp;
        }
    }
    //出栈
    public T pop() {
        if (head == null) {
            return null;
        }
        T t = head.t;
        head = head.next;
        return t;
    }
    //取栈顶元素
    public T peek() {
        if (head == null) {
            return null;
        }
        T t = head.t;
        return t;
    }
    //栈空
    public boolean isEmpty() {
        if (head == null)
            return true;
        else
            return false;
    }
 }

总结

要学好算法, 就要对常用的数据结构有一定的了解,这样在遇到问题的时候,我们才能选择合适的数据结构去实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值