【Java数据结构 -- 使用数组和链表实现栈】

发布时间:2024年01月17日

1. 栈

栈:是一种特殊的线性表只允许在固定的一端插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈(push):栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶
出栈(pop):栈的删除操作叫做出栈。出数据在栈顶

2. 栈的使用

  • Stack():构造一个空的栈
  • E push(E e): 将e入栈,并返回e
  • E pop() :将栈顶元素出栈并返回
  • E peek() :获取栈顶元素,不会删除栈顶元素
  • int size() :获取栈中有效元素个数
  • boolean empty() :检测栈是否为空
public static void main(String[] args) {
	Stack<Integer> s = new Stack();
	s.push(1);
	s.push(2);
	s.push(3);
	s.push(4);
	System.out.println(s.size()); // 获取栈中有效元素个数---> 4
	System.out.println(s.peek()); // 获取栈顶元素---> 4
	s.pop(); // 4出栈,栈中剩余1 2 3,栈顶元素为3
	System.out.println(s.pop()); // 3出栈,栈中剩余1 2 栈顶元素为3
	if(s.empty()){
		System.out.println("栈空");
	}else {
		System.out.println(s.size());
	}
}

3.通过数组实现栈

栈的底层是一个非常简单的数组,所以可以使用数组来模拟实现栈。类里面成员变量有数组elem,数组大小usedSize,默认容量DEFAULT_CAPCITY 。

public class MyStack {
    public int[] elem;
    public int usedSize;
    public static final int DEFAULT_CAPCITY = 10;
    public MyStack() {
        this.elem = new int[DEFAULT_CAPCITY];
    }
}

3.1 栈是否满

直接返回大小是否等于数组长度。

    public boolean isFull() {
        return usedSize == elem.length;
    }

3.2入栈push

判断数组是否满了,满了使用copyOf()进行扩容,通过直接在数组0下标开始存放元素,存一个used Size++接着往后存。

    public void push(int val) {
        if(isFull()) {
            this.elem = Arrays.copyOf(elem,2*elem.length);
        }
        elem[usedSize++] = val;
    }

3.3 出栈pop

通过从数组usedSize-1拿到元素实现出栈,然后usedSize–(不会删除元素,但下次push压栈时直接覆盖此数据),

    public int pop()throws EmptyStackException{
        if (isEmpty()){
            throw new EmptyStackException("栈为空");
        }
        int oldVal = elem[usedSize-1];
        usedSize--;   // 不会删除元素,但下次push压栈时直接覆盖此数据
        //elem[usedSize] = null;  如果是引用类型
        return oldVal;
    }

3.4 栈是否为空

    public boolean isEmpty() {
        return usedSize == 0;
    }

3.5 获取栈顶元素

    public int peek() {
        if (isEmpty()) {
            throw new EmptyStackException("栈为空");
        }
        return elem[usedSize-1];
    }

4. 通过链表实现栈

如果是单链表没有last引用,假设从头入栈时间复杂度O(1),从头出:删除头节点O(1),假设从尾巴入那么时间复杂度就为O(n),从尾巴出:O(n)。而双向链表,均为O(1),实现栈又称链式栈

import java.util.Iterator;
public class MyStack2<E> implements StackInterface<E>,Iterable<E>{

    static class Node<E> {
        public E value;
        Node<E> next;

        public Node() {
        }

        public Node(E value, Node<E> next) {
            this.value = value;
            this.next = next;
        }
    }

    private int size;
    private final int capacity;
    private final Node<E> sentry;

    public MyStack2(int capacity) {
        this.capacity = capacity;
        this.sentry = new Node<>(null,null);
    }
}

4.2 压栈push

通过在链表中进行头插节点实现入栈。

    @Override
    public boolean push(E value) {

        if (isFull()) {
            System.out.println("栈满");
            return false;
        }
        sentry.next = new Node<>(value,sentry.next);
        size++;
        return true;
    }

4.3 出栈pop

通过头删节点来实现出栈,先找到头节点,让sentry节点的后节点指向头节点的后节点。

    @Override
    public E pop() {
        if (isEmpty()) {
            return null;
        }
        Node<E> first = sentry.next;
        sentry.next = first.next;
        size--;
        return first.value;
    }

4.4 获取栈顶元素

    @Override
    public E peek() {
        if (isEmpty()) {
            return null;
        }
        Node<E> first = sentry.next;
        return first.value;
    }

4.5 判断栈是否空

    @Override
    public boolean isEmpty() {
        return size == 0;
        //return sentry.next == null;
    }

4.6 判断栈是否满

    @Override
    public boolean isFull() {
        return size == capacity;
    }
文章来源:https://blog.csdn.net/m0_63440113/article/details/135655937
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。