Java 数据结构(栈)——数组、链表模拟栈实现

栈(Stack) 

栈是一种特殊的线性表,仅能在线性表的一端操作,栈顶允许操作,栈底不允许操作,栈的重要特点为:后进先出先进后出


 

栈的特点:先进后出(FILO,First In Last Out),我们也称之为FILO表。

Java中有一个类Stack,用于表示栈,但这个类已经过时了。目前,如果需要使用栈,那么应该使用Deque的接口来实现,Deque的接口的实现类是LinkedList类。   

Java中没有单独的栈接口,栈相关方法包括在了表示双端队列的接口Deque中,主要有四个方法:

方法名

描述

void push(E e);

入栈,在头部添加元素,栈的空间可能是有限的,如果栈满了,会抛出异常。

E pop();

出栈,返回头部元素,并且从栈中删除,如果栈为空,会抛出异常。

E peek();

查看栈头部元素,不修改栈,如果栈为空,返回null。 

boolean isEmpty();

判断栈是否为空,如果为空则返回true;否则返回false。

【示例】使用LinkedList实现栈操作:

public class Test {
	public static void main(String[] args) {
		// 栈,先进后出
		Deque deque = new LinkedList();
		// 压栈,在栈顶添加元素
		deque.push(111); 
		deque.push(222); 
		deque.push(333); 
		deque.push(444);
		// 遍历栈中的所有元素,直到栈为空为止
		while(!deque.isEmpty()) {
			// 出栈,获取栈顶元素
			System.out.println(deque.pop());
		}
	}
}

每个栈都有一个栈顶指针,它初始值为-1,且总是指向最后一个入栈的元素,栈有两种处理方式,即进栈(push)和出栈(pop),因为在进栈只需要移动一个变量存储空间,所以它的时间复杂度为O(1),但是对于出栈分两种情况,栈未满时,时间复杂度也为O(1),但是当栈满时,需要重新分配内存,并移动栈内所有数据,所以此时的时间复杂度为O(n)。以下举例栈结构的两种实现方式,顺序表存储和链表存储。

 数组模拟栈实现:

 要求:需要限制栈的最大容量。

package com.whsxt.stack;
/**
 * 数组模拟栈(限制最大容量)
 */
public class ArrayStack<T> {
	/**
	 * 存放数据的容器
	 */
	private Object[] elementData;
	/**
	 * 指向栈顶的指针
	 */
	private int top = -1; // 默认值为-1
	/**
	 * 保存栈的最大容量
	 */
	private int maxSize;
	/**
	 * 构造方法
	 * @param maxSize 设置栈的最大容量
	 */
	public ArrayStack(int maxSize) {
		this.elementData = new Object[maxSize];
		this.maxSize = maxSize;
	}
	
	/**
	 * 入栈操作
	 * @param value
	 */
	public void push(T element) {
		// 1.判断栈是否已满
		if(isFull()) {
			throw new RuntimeException("栈已满,无法执行入栈操作");
		}
		// 2.添加数据入栈
		elementData[++top] = element;
	}
	/**
	 * 出栈操作
	 */
	public T pop() {
		// 1.判断栈是否为空
		if(isEmpty()) {
			throw new RuntimeException("栈为空,无执行出栈操作");
		}
		// 2.获取需要出栈的元素
		T value = (T)elementData[top];
		// 3.清空栈顶存放的数据
		elementData[top] = null;
		// 4.修改栈顶指针的指向
		top--;
		// 6.返回需要取出的栈顶元素
		return value;
	}
	/**
	 * 检查栈是否为空
	 * @return
	 */
	public boolean isEmpty() {
		return top == -1;
	}
	
	/**
	 * 判断栈是否已满
	 * @return
	 */
	private boolean isFull() {
		return maxSize - 1 == top;
	}
}

链表模拟栈实现: 

要求:无需限制链表的最大容量。

package com.whsxt.p3.demo;
/**
 * 链表模拟栈(不限制最大容量)
 */
public class LinkedListStack<T> {
    /**
     * 保存单链表首节点
     */
    private StackNode<T> headNode;
    /**
     * 保存实际添加元素的个数
     */
    private int size;
    /**
     * 入栈操作(链表的头部开始插入)
     * @param element 需要入栈的数据
     */
    public void push(T element) {
        // 处理链表为空的情况
        if(headNode == null) {
            // 把需要入栈的数据封装成节点对象,并设置为链表的首节点
            headNode = new StackNode<>(element, null);
        }
        // 处理链表不为null的情况
        else {
            // 把需要入栈的数据封装成节点对象,其next指向headNode
            StackNode<T> node = new StackNode<>(element, headNode);
            // 更新headNode节点
            headNode = node;
        }
        // 4.实际存放元素个数递增
        size++;
    }

    /**
     * 出栈操作(删除单链表首节点)
     * @return 返回栈顶的数据
     */
    public T pop() {
        // 判断栈是否为空
        if(isEmpty()) {
            throw new RuntimeException("栈为空,无执行出栈操作");
        }
        // 定义tempNode变量,来零时保存headNode节点
        StackNode<T> tempNode = headNode;
        // 更新headNode的值,让其指向下一个节点
        headNode = headNode.next;
        // 完成出栈操作后,size递减
        size--;
        // 返回栈顶的数据
        return tempNode.data;
    }

    /**
     * 获取栈顶元素(不会删除栈顶元素)
     * @return
     */
    public T peek() {
        // 判断栈是否为空
        if (isEmpty()) {
            throw new RuntimeException("栈为空,无执行出栈操作");
        }
        // 返回栈顶数据
        return headNode.data;
    }

    /**
     * 判断栈是否为空
     * @return 如果栈为空,则返回true;如果栈非空,则返回false。
     */
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * 栈节点类
     */
    private static class StackNode<T> {
        /**
         * 节点中存放的数据
         */
        private T data;
        /**
         * 指向下一个节点
         */
        private StackNode<T> next;
        /**
         * 构造方法
         * @param data
         */
        public StackNode(T data, StackNode<T> next) {
            this.data = data;
            this.next = next;
        }
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值