zoukankan      html  css  js  c++  java
  • 7.5 Queue集合


    Queue用于模拟队列这种数据结构,队列通常是指“先入先出”(FIFO)的容器。队列头部保存在队列中存放时间最长的元素,队列尾部通常保留在队列中存放时间最短的元素。新元素插入(offer)到队列的尾部,访问(poll)操作将会返回队列头部的元素。通常队列不允许随机访问队列中的元素。
    Queue接口中定义的方法:
    ★void add(Object e):指定元素添加到队列的尾部
    ★Object element():获取队列的头部元素,不删除该元素
    ★boolean offer(Object e):将指定元素加入此队列的尾部。当使用容量限制的队列时,此方法通常比add()方法更好。
    ★Object peek():获取队列的头部元素,但不删除该元素。如果此队列为空,则返回null。
    ★Object poll():获取队列的头部元素,并删除该元素。如果此队列为空,则返回null。
    ★Object remove():获取队列头部元素,并删除该元素。

    一、PriorityQueue实现类

    1、基本方法使用

    PriorityQueue是一个比较标准的队列实现类:PriorityQueue保存队列元素的顺序,并不是按加入队列的顺序,而是按队列元素的大小顺序重新排序。因此调用peek()或poll()方法取出队列中的元素时,并不是取出最先进入队列的元素,而是取出队列中最小的元素。从这个层面上分析,Priority已经违反了队列的基本规则:先入先出(FIFO)。

    import java.util.PriorityQueue;
    public class PriorityQueueTest 
    {
    	public static void main(String[] args) 
    	{
    		var pq=new PriorityQueue();
    		//插入元素offer()比add()方法更好
                    //Java常用包装类已经实现了Comparable接口中的抽象方法compareTo(Object obj)
    		pq.offer(6);
    		pq.offer(-9);
    		pq.offer(20);
    		pq.add(15);
    		//返回队列得元素并不是按元素加入顺序排列的
    		System.out.println(pq);//[-9, 6, 20, 15]
    		//访问队列的第一个元素
    		System.out.println(pq.peek());//此时不删除队列的第一个元素
    		System.out.println(pq.element());//-9
    		System.out.println(pq.poll());//-9
    		System.out.println(pq);//[6, 15, 20]
    	}
    }
    

    2、排序方式

    PriorityQueue不允许插入null元素,它需要对队列元素排序,PriorityQueue的元素排序有两种用法:

    2.1 自然排序:采用自然顺序的PriorityQueue集合中的元素必须实现Coparable接口,而且是同一个类的多个实例,否则引发ClassCastException异常

    import java.util.PriorityQueue;
    class  Z implements Comparable
    {
    	String str;
    	public Z(String str)
    	{
    		this.str=str;
    	}
    	@Override
    	public boolean equals(Object obj)
    	{
    		if(this==obj)
    			return true;
    		else if(obj!=null&&obj.getClass()==Z.class)
    		{
    			var r=(Z)obj;
    			return r.str==this.str;
    		}
    		else
    			return false;
    	}
    	@Override
    	public int compareTo(Object obj)
    	{
    		var r=(Z)obj;
    		return this.str.length()>r.str.length()?1:this.str.length()==r.str.length()?0:-1;
    	}
    	@Override
    	public String toString()
    	{
    		return "Z[str="+str+"]";
    	}
    }
    public class PriorityQueueSort1
    {
    	public static void main(String[] args)
    	{
    		var pq=new PriorityQueue();
    		pq.offer(new Z("疯狂Java讲义"));
    		pq.offer(new Z("疯狂Android讲义"));
    		pq.offer(new Z("轻量级Java EE企业应用实战"));
    		System.out.println(pq);
    
    		//改变队列的第一个元素,排序不会改变
    		var first=(Z)(pq.peek());
    		first.str="相关学习网站:www.fkjava.com";
    		System.out.println(pq);
    	}
    }
    ---------- 运行Java捕获输出窗 ----------
    [Z[str=疯狂Java讲义], Z[str=疯狂Android讲义], Z[str=轻量级Java EE企业应用实战]]
    [Z[str=相关学习网站:www.fkjava.com], Z[str=疯狂Android讲义], Z[str=轻量级Java EE企业应用实战]]
    
    输出完成 (耗时 0 秒) - 正常终止
    

    2.2 定制排序:创建定制排序时,传入一个Comparable对象,该对象负责对队列中的所有元素进行排序。采用定制排序时,不要求队列实现Comparable接口

    import java.util.PriorityQueue;
    class M 
    {
    	int age;
    	public M(int age)
    	{
    		this.age=age;
    	}
    	@Override
    	public String toString()
    	{
    		return "M[age:"+age+"]";
    	}
    }
    public class PriorityQueueSort2
    {
    	public static void main(String[] args)
    	{
    		//此处传入lambda表达式的目标类型是Comparator
    		var pq=new PriorityQueue((o1,o2)->{
    			var m1=(M)o1;
    			var m2=(M)o2;
    			//age越大的排序越靠前
    			return m1.age>m2.age?-1:m1.age<m2.age?1:0;
    		});
    		pq.offer(new M(1));
    		pq.offer(new M(-8));
    		pq.offer(new M(5));
    		pq.offer(new M(20));
    		System.out.println(pq);
    	}
    }
    ---------- 运行Java捕获输出窗 ----------
    [M[age:20], M[age:5], M[age:1], M[age:-8]]
    
    输出完成 (耗时 0 秒) - 正常终止
    

    二、Deque接口与ArrayDeque实现类

    Deque接口是Queue接口的子接口,它代表一个双端队列,Deque接口里定义了一些双端队列的操作方法,这些方法允许从两端来操作队列的元素。
    ★void addFirst(Object e):将指定元素插入到该双端队列的开头。
    ★void addLast(Object e):将指定元素插入到该双端队列的末尾。
    ★Iterator descendingIterator():放回该双端队列的对应的迭代器,该迭代器以逆向顺序来迭代队列中的元素。
    ★Object getFirst():获取但不删除双端队列的第一个元素。
    ★Object getLast():获取但不删除双端队列的最后一个元素。
    ★boolean offerFirst(Object e):将指定元素插入到双端队列的开头。
    ★boolean offerLast(Object e):将指定元素插入到双端队列的末尾。
    ★Object peekFirst():获取但不删除双端队列的第一个元素;如果此双端队列为空,则返回null。
    ★Object peekLast():获取但不删除双端队列的最后一个元素;如果此双端队列为空,则返回null。
    ★Object pollFirst():获取并删除双端队列的第一个元素;如果此双端队列为空,则返回null。
    ★Object pollLast():获取并删除双端队列的最后一个元素;如果此双端队列为空,则返回null。
    ★Object pop()(栈方法):pop出双端队列所表示的栈的栈顶元素。相当于removeFirst()。
    ★void push()(栈方法):将一个元素push进双端队列所表示的栈的栈顶。相当于addFirst()。
    ★Object removeFirst():获取并删除双端队列的第一个元素。
    ★Object removeFirstOccurrence(Object o):删除双端队列第一次出现的元素o。
    ★Object removeLast():获取并删除双端队列的最后一个元素。
    ★Object removeLastOccurence(Object o):删除双端队列最后一次出现的元素o。
    Deque不仅可以当作双端队列使用,也可以被当作栈来使用,因为该类话包含了pop(出栈)、push(入栈)两个方法
    Deque的方法与Queue方法对照表:

    Queue方法 Deque方法
    插入:add(e)/offer(e) addLast(e)/offerLast(e)
    删除:remove()/poll() removeFirst()/pollFirst()
    获取头部元素:element()/peek() getFirst()/peekFirst()

    Deque的方法与Stack的方法对照表:

    Stack的方法 Deque方法
    进栈:push(e) addFirst()/offerFirst()
    出栈:pop() removeFirst()/pollFirst()
    获取栈顶元素:peek() getFirst()/peekFirst()

    Deque接口提供了一个典型的实现类:ArrayDeque,它是一个基于数组实现的双端队列,创建Deque时,同样可以指定一个numElement参数,该参数用于指定Object[]数组的长度;如果不指定numElements参数,Deque底层数组的长度为16.

    1、ArrayDeque当作栈使用

    import java.util.ArrayDeque;
    public class ArrayDequeTest 
    {
    	public static void main(String[] args) 
    	{
    		var stack=new ArrayDeque();
    		//依次将三个元素push入栈
    		stack.push("疯狂Java讲义");
    		stack.push("轻量级Java EE企业应用实战");
    		stack.push("疯狂Android讲义");
    		System.out.println(stack);//[疯狂Android讲义, 轻量级Java EE企业应用实战, 疯狂Java讲义]
    
    		//访问第一个元素但不删除
    		System.out.println(stack.getFirst());//疯狂Android讲义
    		System.out.println(stack.peekFirst());//疯狂Android讲义
    
    		//访问第一个元素并删除
    		System.out.println(stack.pop());//疯狂Android讲义
    		System.out.println(stack);//[轻量级Java EE企业应用实战, 疯狂Java讲义]
    	}
    }
    

    当程序中需要使用栈这种数据结构时,推荐使用ArrayDeque,尽量避免Stack这种古老的集合,性能比较差。

    2、ArrayDeque当作队列使用

    按照先入先出的方法来操作集合元素

    import java.util.ArrayDeque;
    public class ArrayDequeQueue
    {
    	public static void main(String[] args) 
    	{
    		var queue=new ArrayDeque();
    		//将三个元素依次加入队列
    		queue.offer("疯狂Java讲义");
    		queue.offer("疯狂Java EE企业应用实战");
    		queue.offer("疯狂Android讲义");
    		System.out.println(queue);
    
    		//访问头部元素,但不将它poll出栈
    		System.out.println(queue.peek());//疯狂Java讲义
    		//poll出第一个元素
    		System.out.println(queue.poll());//疯狂Java讲义
    		System.out.println(queue);//[疯狂Java EE企业应用实战, 疯狂Android讲义]
    
    		//访问尾部元素,不删除
    		System.out.println(queue.peekLast());//疯狂Android讲义
    	}
    }
    #三、LinkedList实现类
    LinkedList类是一个List接口的实现类——这意味着它是一个List集合,可以根据索引访问集合中的元素。除此之外,LinkedList还实现了Deque接口,还可以被当作双端队列来使用,因此既可以被当作栈来使用,也可以被当作队列使用。
    ```java
    import java.util.LinkedList;
    public class LinkedListTest
    {
    	public static void main(String[] args)
    	{
    		var books=new LinkedList();
    		//将一个元素加入队列的尾部
    		books.offer("疯狂Java讲义");
    		//将一个字符串加入栈顶(相当于队列的头部)
    		books.push("轻量级Java EE企业应用实战");
    		System.out.println(books);
    		//将字符串降入到队列的头部,相当于栈顶
    		books.offerFirst("疯狂Android讲义");
    		System.out.println(books);//[疯狂Android讲义, 轻量级Java EE企业应用实战, 疯狂Java讲义]
    
    		//以List方式遍历集合元素
    		for(int i=0;i<books.size();i++)
    		{
    			System.out.println(books.get(i));
    		}
    		//访问不删除栈顶元素
    		System.out.println(books.peek());//疯狂Android讲义
    		//访问不删除队列的最后一个元素
    		System.out.println(books.peekLast());//疯狂Java讲义
    		//将栈顶元素弹出栈
    		System.out.println(books.pop());//疯狂Android讲义
    		//删除队列最后一个元素
    		System.out.println(books.pollLast());//疯狂Java讲义
    	}
    }
    

    LinkedList与ArrayList、ArrayQueue的实现机制完全不同,ArrayList、ArrayQueue内部以数组的形式来保存结合中的元素,因此随机访问数组元素时具有较好的性能;而LinkedList内部以链表的形式来保存集合的元素,因此随机访问数组元素时性能较差,但在插入删除元素时性能比较出色(只改变指针所指的地址即可)。虽然Vector也是以数组形式存储集合元素的,但因为它实现了线程同步功能(而且实现机制也不好),所以各方方面性能比较差。

  • 相关阅读:
    WebService中Dataset的压缩序列化和解压反序列化(DataSetSurrogate的使用)
    IOleControl 代码一,测试有问题,备忘
    关于Stream和byte之间的转换 .
    webbrowser 实现IOleControl接口2
    JavaScropt获取网页、浏览器、屏幕高度和宽度
    Oracle默认的用户名和密码
    window.showModalDialog()用法及注意事项
    Android1.6开发环境配置
    string与stream互相转换
    GirdView实现单选、FooterTemplate实现新建和PagerTemplate实现分页
  • 原文地址:https://www.cnblogs.com/weststar/p/12574120.html
Copyright © 2011-2022 走看看