赞
踩
学习数据结构,需要先搞清楚自己语言是怎么实现的。
栈与队列是每个学数据结构最早接触的数据结构,相信很多人对这两种数据结构的特性清楚地了解,但是也仅限于此。
所以本文以leetcode习题为例,深入探索这两种数据结构,以及如何灵活运用这两种数据结构的思想,为下篇leetcode栈与队列实战篇(链接)铺垫。
如果理论知识已经烂熟于心,可以直接看实战篇: leetcode栈与队列(下)之实战篇(java实现)
先进先出
在Java中,有写好的Queue接口,他是继承自Collection接口
在我们具体实现时,一般采用LinkedList
实现类作为队列的实现,LinkedList类实现了Deque接口,Deque接口继承自Queue接口
成员方法:
方法 | 含义 |
---|---|
boolean isEmpty() | 判断队列是否为空 |
int size() | 获取队列长度 |
boolean add(E) / boolean offer(E) | 入队操作,添加元素到队尾 |
E remove() / E poll() | 出队操作,获取队首元素并从队列中删除 |
E element() / E peek() | 获取队首元素但并不从队列中删除 |
注意,‘/’分开的两种方法的区别为,给出源代码中的解释:
主要区别,拿入队为例,add(e)如果添加失败会抛出异常,而offer(e)添加失败会返回false
主要原因是,在它的继承接口会继承类中,可能会限定队列的最大容量。如果队列达到了他的最大容量,再入队就会失败。
双端队列Deque的方法比较如下:
Queue 和Deque方法的比较(很多方法相同)
另外,Deque还可以作为栈使用,并且官方表示此接口优先于堆栈类使用。(见下面栈的实现)
import java.util.LinkedList; import java.util.Queue; /* Queue 是一个接口,继承自Collection接口,需要继承类来实现, LinkedList实现了Deque接口,Deque继承自Queue 入队: add(),offer() 出队:remove(),poll() 获取队首元素:element(),peek() */ public class QueueDemo { public static void main(String[] args) { // 创建一个队列对象 Queue<String> que = new LinkedList<>(); // 入队操作 que.offer("apple"); que.offer("banana"); que.offer("grape"); que.offer("peach"); que.offer("pear"); System.out.println("队首元素是: " + que.peek()); // 出队 while (que.size() > 0) { // 出队的同时并获取出队元素 String element = que.poll(); System.out.println(element); } // 判断队列是否为空 System.out.println(que.isEmpty()); } }
先进后出(FILO)。允许插入和删除的一端,称为栈顶,固定的一端称为栈底。所以最先插入的元素在栈底,最后插入的元素在栈顶。
如前面所介绍的,栈的实现一般由Stack和Deque 来实现(而Java中更推荐Deque)
Java中有给我们封装好Stack类,首先是类的结构层次
主要成员方法:
方法 | 含义 |
---|---|
boolean isEmpty() | 判断栈是否为空 |
int size() | 获取栈中元素的个数 |
T pop() | 弹出栈顶元素 |
void push(T t) | 向栈中压入元素 t |
栈的使用示例
public class StackDemo { public static void main(String[] args) { // 1. Initialize a stack. Stack<Integer> s = new Stack<>(); // 2. Push new element. s.push(5); s.push(13); s.push(8); s.push(6); // 3. Check if stack is empty. if (s.empty()) { System.out.println("Stack is empty!"); return; } // 4. Pop an element. s.pop(); // 5. Get the top element. System.out.println("The top element is: " + s.peek()); // 6. Get the size of the stack. System.out.println("The size is: " + s.size()); } }
如上面说的,Java推荐Deque作为栈的实现。当deque用作堆栈时,从deque的开头推送和弹出元素。堆栈方法等同于下表所示的Deque方法:
具体示例如下:
如上面所说,Deque既可以当作栈,也可以当作队列,而LinkedList作为Deque的一个实现类,已经被普遍使用
上面已经给了两个示例(分别实现了栈和队列),现在总结一下LinkedList的中的常用方法:
即,入栈,入队列等
boolean add(E e):在链表后添加一个元素,如果成功,返回true,否则返回false;
void addFirst(E e)
:在链表头部插入一个元素;
void addLast(E e)
:在链表尾部添加一个元素;
void add(int index, E element):在指定位置插入一个元素。
boolean offer(E e):在链表尾部插入一个元素;
boolean offerFirst(E e):与addFirst一样,实际上它就是addFirst;
boolean offerLast(E e):与addLast一样,实际上它就是addLast;
即出栈,出队列等
remove();移除链表中第一个元素;
boolean remove(Object o):移除链表中指定的元素;
remove(int index):移除链表中指定位置的元素;
removeFirst():移除链表中第一个元素,与remove类似;
removeLast():移除链表中最后一个元素;
boolean removeFirstOccurrence(Object o):移除链表中第一次出现所在位置的元素;
boolean removeLastOccurrence(Object o):移除链表中最后一次出现所在位置的元素;
即获取栈顶,队首(队尾)元素
get(int index):按照下标获取元素;
getFirst()
:获取第一个元素;
getLast():获取最后一个元素;
peek():获取第一个元素,但是不移除;
peekFirst():获取第一个元素,但是不移除;
peekLast():获取最后一个元素,但是不移除;
优先队列其实就是个二叉堆,因为优先队列对外接口只是从队头取元素,从队尾添加元素,再无其他取元素的方式。顾名思义,出队顺序是按照优先级来的。
堆是一棵完全二叉树,树中每个结点的值都不小于(或不大于)其左右孩子的值。
分为大顶堆和小顶堆
Java中实现了PriorityQueue,默认是最小堆,如果要把最小堆变成最大堆需要传入自己的比较器
代码示例:
public static void main(String[] args) { /* 初始化堆 */ // 初始化小顶堆 Queue<Integer> minHeap = new PriorityQueue<>(); // 初始化大顶堆(使用 lambda 表达式修改 Comparator 即可) Queue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a); /* 元素入堆 */ maxHeap.offer(1); maxHeap.offer(3); maxHeap.offer(2); maxHeap.offer(5); maxHeap.offer(4); int peek = maxHeap.peek(); // 5 int size = maxHeap.size(); /* 堆顶元素出堆 */ // 出堆元素会形成一个从大到小的序列 while(!maxHeap.isEmpty()) { System.out.print(maxHeap.poll()+" "); } System.out.println(); /*--------------------------*/ /* 输入列表并建堆 */ minHeap = new PriorityQueue<>(Arrays.asList(1, 3, 2, 5, 4,8,6)); while(!minHeap.isEmpty()) { System.out.print(minHeap.poll()+" "); }
输出:
5 4 3 2 1
1 2 3 4 5 6 8
如果是其他类型的也可以入队列,并按照自己设定的排序
// 新建一个顾客类,属性是名字和级别,排序根据level来定 public class Customer implements Comparable<Customer> { private String name; private int level; public Customer(String name, int level) { this.name = name; this.level = level; } // 注意这里重写compareTo方法 public int compareTo(Customer c) { return c.level-this.level; } @Override public String toString() { return "Customer{" + "name='" + name + '\'' + ", level=" + level + '}'; } } public class Main { public static void main(String[] args) { Queue<Customer> ps = new PriorityQueue<>(); ps.offer(new Customer("小红",3)); ps.offer(new Customer("小李",5)); ps.offer(new Customer("小王",2)); ps.offer(new Customer("小张",6)); while(!ps.isEmpty()) { System.out.println(ps.poll()); } } }
输出:
Customer{name=‘小张’, level=6}
Customer{name=‘小李’, level=5}
Customer{name=‘小红’, level=3}
Customer{name=‘小王’, level=2}
参考链接:
https://leetcode.cn/leetbook/detail/queue-stack/
https://blog.csdn.net/u013970897/article/details/106877472
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。