Java中实现栈和实现队列的方法对比

172 阅读2分钟

前言

当我刷leetcode上第503题leetcode.cn/problems/ne… 时,发现一句代码的改变,带来的效果差别很大,于是我查找了些资料,在这总和一下。

解此题的代码如下:

class Solution {
    public int[] nextGreaterElements(int[] nums) {
        //边界判断
        if(nums == null || nums.length <= 1){
            return new int[]{-1};
        }

        int size = nums.length;
        int[] re = new int[size];
        //将结果数组中的所有元素初始化为-1
        Arrays.fill(re, -1);

        //存放元素值对应的下标
        Deque<Integer> stack = new LinkedList<Integer>();

        //相当于将两个数组拼接在一起,却不改变原有结构
        for(int i = 0; i < size*2; i++){
            //当栈不为空且找到比栈顶元素更大值时
            while(!stack.isEmpty() && nums[i % size] > nums[stack.peek()]){
                re[stack.peek()] = nums[i % size];
                stack.pop();
            }
            stack.push(i % size);
        }

        return re;
    }
}


起初我用的Stack来实现单调栈,也就是:

Stack<Integer> stack = new Stack<>();


这种方法的提交结果是这样:

junk.png


后根据官方题解,用LinkedList来实现单调栈:

Deque<Integer> stack = new LinkedList<Integer>();


提交结果:

junk1.png


差距很大!!!



分析


Stack具有以下特点:

1. 线程安全,但是效率低。


因为Stack类继承自Vector类,而 Vector类在每个方法中都加了锁:

......
public synchronized void setSize(int newSize){...}
public synchronized int capacity(){...}
public synchronized int size(){...}
public synchronized boolean isEmpty(){...}
......

“加了锁”是指:Vector 类中的每个公共方法都通过同步块或方法声明中的 synchronized 关键字进行了同步。

通过在每个方法上使用 synchronizedVector 类确保了在多线程环境中对列表的操作是线程安全的。这意味着在一个时间点,只有一个线程可以执行 Vector 类的任何同步方法。

虽然同步确保了线程安全,但也带来了性能开销。因为同步会限制并发访问,所以可能会导致线程阻塞和等待。


2. 灵活性不好,数据频繁增减效率低,查找数据优势不明显。

Stack类继承自Vector类,而Vector类在内部使用了一个动态数组来存储元素,这意味着Stack的实现是基于数组的。 而数组具有查找快、增删元素慢的特点。


LinkedList是基于双向链表实现的,对于元素的插入和删除效率高,且因其不是线程安全的,所以对于单线程的环境中,开销会更小。因此在这道题效果会如此显著。



参考文章:
www.cnblogs.com/csq-66/p/17…
mp.weixin.qq.com/s/o6gnTbbKU…