java队列和栈的学习
本章学习了Queue和Deque的主要方法,很多东西都是可以从源码中直接查到的,可以进行基础学习。
首先看一下Queue集合的主要的一个子接口Deque:双端队列
几个重要的实现类:
ArrayDeque,PriorityQueue,LinkedList,还有几个基于多线程的队列,栈的实现:
ArrayBlokingQueue
,concurrentLinkedListQueue,
LinkedBlockingQueue,
PriorityBlockingQueue,等主要的几个。
首先看一下Queue的几个方法的使用:
实例代码一:
/**
* Queue接口方法的使用介绍
* Queue有一个PriorityQueue的实现类,还有一个Deque的接口,代表一个双端队列。
* 双端队列可以同时从两端添加和删除数据,因此可以当成队列和栈来使用,其有两个实现类,。
* ArrayDeque和LinkedList
* @author fcs
*
*/
public class QueueDemo {
public static void main(String[] args) {
Queue queue = new ArrayDeque();
queue.add("string"); //将指定的元素加入队列的尾部
queue.add("double");
queue.offer("int"); //将指定的元素加入队列的尾部,,当使用有限容量的队列时,该方法比add性能好。
System.out.println(queue);
Object obj = queue.element(); //获取队头元元素但是不删除。
System.out.println("obj = "+obj);
obj = queue.peek(); //获取队头元素,如果此队列为空则返回null
System.out.println("obj = "+obj);
obj = queue.poll(); //获取队头元素,如果此队列为空则返回null
}
}
在JDK中Queue有两种形式的方法:一种是抛出异常(操作失败时),另一种是返回特殊值(根据具体情况)
| 抛出异常 | 返回特殊值 |
插入 | ||
移除 | ||
检查 |
在添加元素的offer方法中,用于专门为有容量限制的Queue设计的,在大多数实现中通常不会产生异常。
注意Queue的两点:
1. Queue的实现通常不允许元素为null,LinkedList除外,当然null可以作为poll方法的返回值,并不会在没有元素的情况下抛出异常。
2. Queue的实现通常没有定义equals方法和hashcode方法的基于元素比较的方式,而是从Object中继承了基于身份的版本,这是由于具有相同元素但是有不同排序属性的队列而言,基于元素的相等性和比较性并不能满足排序的需求。
第二:ArrayDeque实现作为“栈“的使用方式
实例代码二:
/**
* ArrayDeque的作为栈的使用方式
* 两种:
* 1.直接使用
* 2.进行封装使用
* @author fcs
*
*/
public class ArrayDequeDemo {
public static void main(String[] args) {
//第一种方式: 使用自己的对象创建
ArrayDeque<String> arrdeque = new ArrayDeque<String>();
arrdeque.push("Java"); //内部调用的是addFirst();方法
arrdeque.push("c++");
arrdeque.push("andriod");
System.out.println(arrdeque);
System.out.println(arrdeque.peek()); //访问第一个元素,内部调用的是peekFirst方法
System.out.println(arrdeque.pop()); //访问第一个元素,并弹出栈顶元素,内部调用的是peekFirst()方法,
//然后peekFirst方法再次调用pollFirst()方法
System.out.println(arrdeque);
//第二种方式:直接使用内部实现的方法进行封装
StackInt stack = new StackInt();
for(int i = 0;i < 6;i++){
stack.push(i+1);
}
System.out.println(stack);
System.out.println("访问第一个元素: "+stack.peek());
System.out.println("删除第一个元素: "+stack.pop());
System.out.println(stack);
}
}
class StackInt{
private Deque<Integer> deque = new ArrayDeque<Integer>();
public void push(Integer ele){
deque.addFirst(ele);
}
public Integer pop(){
return deque.removeFirst();
}
public Integer peek(){
return deque.peekFirst();
}
public String toString(){
return deque.toString();
}
}
第三:PriorityQueue优先队列的练习和注意要点:
1.PriorityQueue是一个基于堆的无界优先级队列,默认使用按照自然排序的方式,当然可以通过提供的Comparator接口进行定制排序。
2.在自然排序中,如果插入的对象不同会引发ClassCastException.
3.默认队列的头是按指定排序的最小值,访问处于队列头部元素的方法有:
Poll(访问,并弹出元素),remove(访问并弹出元素),peek(只访问元素),element(只访问元素)
4.该优先级队列的数据结构是采用数组的方式,数组大小会动态增加,容量无限,不过建议如果数据量比较大的时候先初始化一个比较大的容量,以免扩容多次影响性能。
5.此实现方式不是同步的,也就是说不是线程安全的,如果多个线程中的任意线程从结构上修改了列表元素,则这些线程不应该同时访问PriorityQueue的实例,可以使用基于线程安全的PriorityBlockingQueue类。
6.此实现的插入方法(offer,poll,remove,add)的时间复杂度为O(log(n)),为remove(Object obj)和contains(Object obj)方法提供线性的时间复杂度。
为检索方法(peek,element和size)方法提供固定时间的复杂度。
7.可以在构造函数中指定如何排序,
PriorityQueue():使用默认的初始容量(11)创建一个PriorityQueue,并根据其自然顺序来排序元素(类实现Comparable接口)
PriorityQueue(intinitialCapacity,Comparator comparator):使用指定的初始容量创建一个PriorityQueue,并根据其自然顺序排序元素,使用指定的比较器comparator接口。
8.此类及其迭代器实现了Collection和Iterator接口的所有可选方法
PriorityQueue的内部实现:
PriorityQueue对元素采用的是堆排序,头是按指定排序方式的最小元素,堆排序只能保证根是最大(最小),整个堆并不是有序的,
方法Iteatro()中提供的迭代器可以能呢过只是对整个数组的依次遍历,也就是只能保证数组的第一个元素是最小的。
实例代码三:
/**
* Queue的实现类PriorityQueue的实现练习
* @author fcs
* PriorityQueue是一个比较标准的队列实现,因为该实现类保存队列元素的顺序并不是按照加入队列的顺序,而是按照
* 队列元素的大小进行重新排列,在进行peek,或者poll操作时,并不是取出的是
*/
public class PriorityQueueDemo {
public static void main(String[] args) {
PriorityQueue pqueue = new PriorityQueue();
pqueue.offer(6);
pqueue.offer(-2);
pqueue.offer(5);
pqueue.offer(1232);
System.out.println(pqueue); //注意输出的顺序并不是绝对按照大小进行输出的,原因是默认使用了tostring方法进行的转换。
System.out.println("size = "+pqueue.size());
//不过每次从队列中取出数据的poll方法可以看到元素从小到大的顺序“移出队列”
//使用for循环不能全部遍历,不知道为什么?????
for(int i =0 ; i < pqueue.size();i++){
System.out.println(pqueue.poll());
}
//而下面这种方式就可以
while(!pqueue.isEmpty()){
System.out.println(pqueue.poll());
}
}
}
这里有个问题:不过不是经常遇到,就是说使用基本的for循环对某些特殊的数据结构中的元素进行遍历的时候,不会遍历到最后,而只是遍历一部分就停止了,现在这个问题又出现了。有点不知为何。
对于该优先级队列的两种排序方式下面给出代码:
实例代码四:
/**
* 对PriorityQueue实现自然排序,和定制排序测试
* @author fcs
*
*/
@SuppressWarnings("rawtypes")
class Goods implements Comparable{
private int id;
private double price;
private String name;
private String type;
public Goods(){
}
public Goods(int id, double price, String name, String type) {
this.id = id;
this.price = price;
this.name = name;
this.type = type;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
//重写compareTo方法,按照id进行自然排序
@Override
public int compareTo(Object o) {
Goods goods = (Goods)o;
return this.id < goods.id ? 1:
this.id > goods.id ? -1:0;
}
}
public class SortPriorityQueue {
public static void main(String[] args) {
//自然排序实例测试
PriorityQueue<Goods> pqueue = new PriorityQueue<Goods>();
pqueue.offer(new Goods(2,234.1,"苹果","水果"));
pqueue.offer(new Goods(1,24.234,"橡胶","木材"));
pqueue.offer(new Goods(1,24.234,"橡胶","木材"));
pqueue.offer(new Goods(5,2.00,"雪糕","零食"));
pqueue.offer(new Goods(5,2.00,"雪糕","零食"));
//第一种遍历方式
while(!pqueue.isEmpty()){
System.out.println(pqueue.poll().getId());
}
System.out.println();
//第二种遍历方式:使用Iterator接口
Iterator<Goods> itGoods = pqueue.iterator();
while(itGoods.hasNext()){
System.out.print(itGoods.next().getId()+"--");
}
//定制排序实例,创建的PriorityQueue需要一个初始化队列的容量值和一个Comparator对象,进行定制排序
Comparator<Goods1> comparator = new Comparator<Goods1>(){
@Override
public int compare(Goods1 o1, Goods1 o2) {
return o2.getPrice() - o1.getPrice() ;
}
};
PriorityQueue<Goods1> pqueue1 = new PriorityQueue<Goods1>(5,comparator);
pqueue1.offer(new Goods1(2,20,"键盘"));
pqueue1.offer(new Goods1(1,40,"鼠标"));
pqueue1.offer(new Goods1(3,5004,"电脑"));
while(!pqueue1.isEmpty()){
Goods1 goods = pqueue1.poll();
System.out.print(goods.getId()+"--"+goods.getPrice()+" , ");
}
}
}
/**
* 采用定制排序的第一种方式:
* 类实现comparator接口,并实现compare方法作为排序标准
* @author fcs
*
*/
class Goods1{
private int id;
private int price;
private String name;
public Goods1(){}
public Goods1(int id, int price, String name) {
this.id = id;
this.price = price;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}