【Java】队列 && 循环队列 && Queue && Deque && BFS模板

队列

1.队列的实现

// "static void main" must be defined in a public class.

class MyQueue {
    // store elements
    private List<Integer> data;         
    // a pointer to indicate the start position
    private int p_start;            
    public MyQueue() {
        data = new ArrayList<Integer>();
        p_start = 0;
    }
    /** Insert an element into the queue. Return true if the operation is successful. */
    public boolean enQueue(int x) {
        data.add(x);
        return true;
    };    
    /** Delete an element from the queue. Return true if the operation is successful. */
    public boolean deQueue() {
        if (isEmpty() == true) {
            return false;
        }
        p_start++;
        return true;
    }
    /** Get the front item from the queue. */
    public int Front() {
        return data.get(p_start);
    }
    /** Checks whether the queue is empty or not. */
    public boolean isEmpty() {
        return p_start >= data.size();
    }     
};

public class Main {
    public static void main(String[] args) {
        MyQueue q = new MyQueue();
        q.enQueue(5);
        q.enQueue(3);
        if (q.isEmpty() == false) {
            System.out.println(q.Front());
        }
        q.deQueue();
        if (q.isEmpty() == false) {
            System.out.println(q.Front());
        }
        q.deQueue();
        if (q.isEmpty() == false) {
            System.out.println(q.Front());
        }
    }
}

2.循环队列

注意:

动画演示:https://leetcode-cn.com/leetbook/read/queue-stack/kgtj7/

  • 新增元素是增加tail
  • 删除一个元素是操作 head
  • 循环队列FULL的条件: (tail+1)%size==head;
class MyCircularQueue {
    
    private int[] data;
    private int head;
    private int tail;
    private int size;

    /** Initialize your data structure here. Set the size of the queue to be k. */
    public MyCircularQueue(int k) {
        data = new int[k];
        head = -1;
        tail = -1;
        size = k;
    }
    
    /** Insert an element into the circular queue. Return true if the operation is successful. */
    public boolean enQueue(int value) {
        if (isFull() == true) {
            return false;
        }
        if (isEmpty() == true) {
            head = 0;
        }
        tail = (tail + 1) % size;
        data[tail] = value;
        return true;
    }
    
    /** Delete an element from the circular queue. Return true if the operation is successful. */
    public boolean deQueue() {
        if (isEmpty() == true) {
            return false;
        }
        if (head == tail) {
            head = -1;
            tail = -1;
            return true;
        }
        head = (head + 1) % size;
        return true;
    }
    
    /** Get the front item from the queue. */
    public int Front() {
        if (isEmpty() == true) {
            return -1;
        }
        return data[head];
    }
    
    /** Get the last item from the queue. */
    public int Rear() {
        if (isEmpty() == true) {
            return -1;
        }
        return data[tail];
    }
    
    /** Checks whether the circular queue is empty or not. */
    public boolean isEmpty() {
        return head == -1;
    }
    
    /** Checks whether the circular queue is full or not. */
    public boolean isFull() {
        return ((tail + 1) % size) == head;
    }
}

/**
 * Your MyCircularQueue object will be instantiated and called as such:
 * MyCircularQueue obj = new MyCircularQueue(k);
 * boolean param_1 = obj.enQueue(value);
 * boolean param_2 = obj.deQueue();
 * int param_3 = obj.Front();
 * int param_4 = obj.Rear();
 * boolean param_5 = obj.isEmpty();
 * boolean param_6 = obj.isFull();
 */

3.Queue 应用

add 增加一个元索 如果队列已满,则抛出一个IIIegaISlabEepeplian异常
remove 移除并返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
element 返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
offer 添加一个元素并返回true 如果队列已满,则返回false
poll 移除并返问队列头部的元素 如果队列为空,则返回null
peek 返回队列头部的元素 如果队列为空,则返回null
put 添加一个元素 如果队列满,则阻塞
take 移除并返回队列头部的元素 如果队列为空,则阻塞

4.双端队列deque的应用

测试代码:

package collections;

import java.util.Deque;
import java.util.LinkedList;

/**
 * @Package collections
 * @date 2017-11-28下午5:53:32
 */
public class DequeTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        
        Deque<String> deque = new LinkedList<String>();
        deque.add("d");
        deque.add("e");
        deque.add("f");
        
        //从队首取出元素,不会删除
        System.out.println("队首取出元素:"+deque.peek());
        System.out.println("队列为:"+deque);
        
        //从队首加入元素(队列有容量限制时用,无则用addFirst)
        deque.offerFirst("c");
        System.out.println("队首加入元素后为:"+deque);
        //从队尾加入元素(队列有容量限制时用,无则用addLast)
        deque.offerLast("g");
        System.out.println("队尾加入元素后为:"+deque);
        
        //队尾加入元素
        deque.offer("h");
        System.out.println("队尾加入元素后为:"+deque);
        
        //获取并移除队列第一个元素,pollFirst()也是,区别在于队列为空时,removeFirst会抛出NoSuchElementException异常,后者返回null
        deque.removeFirst();
        System.out.println("获取并移除队列第一个元素后为:"+deque);
        
        //获取并移除队列第一个元素,此方法与pollLast 唯一区别在于队列为空时,removeLast会抛出NoSuchElementException异常,后者返回null
        deque.removeLast();
        System.out.println("获取并移除队列最后一个元素后为:"+deque);
        
        //获取队列第一个元素.此方法与 peekFirst 唯一的不同在于:如果此双端队列为空,它将抛出NoSuchElementException,后者返回null
        System.out.println("获取队列第一个元素为:"+deque.getFirst());
        System.out.println("获取队列第一个元素后为:"+deque);
        
        //获取队列最后一个元素.此方法与 peekLast 唯一的不同在于:如果此双端队列为空,它将抛出NoSuchElementException,后者返回null
        System.out.println("获取队列最后一个元素为:"+deque.getLast());
        System.out.println("获取队列第一个元素后为:"+deque);
        
        //循环获取元素并在队列移除元素
        while(deque.size()>0){
            System.out.println("获取元素为:"+ deque.pop()+" 并删除");
        }
        System.out.println("队列为:"+deque);
    }

}

结果如下:

队首取出元素:d
队列为:[d, e, f]
队首加入元素后为:[c, d, e, f]
队尾加入元素后为:[c, d, e, f, g]
队尾加入元素后为:[c, d, e, f, g, h]
获取并移除队列第一个元素后为:[d, e, f, g, h]
获取并移除队列最后一个元素后为:[d, e, f, g]
获取队列第一个元素为:d
获取队列第一个元素后为:[d, e, f, g]
获取队列最后一个元素为:g
获取队列第一个元素后为:[d, e, f, g]
获取元素为:d 并删除
获取元素为:e 并删除
获取元素为:f 并删除
获取元素为:g 并删除
队列为:[]

继承关系是:deque => queue => collection=>Iterable

  1. 使用队列的时候,new LinkedList的时候为什么用deque接收,不用LinkedList呢?

答:deque继承queue接口,因为它有两个实现,LinkedList与ArrayDeque。用deque接收是因为向上转型(子类往父类转,会丢失子类的特殊功能)了。可以试试,用get()方法,LinkedList接收才有。

  1. 为什么有一个实现还不够,还弄两个呢,它们总有区别吧?

答:ArrayDeque是基于头尾指针来实现的Deque,意味着不能访问除第一个和最后一个元素。想访问得用迭代器,可以正反迭代。

ArrayDeque一般优于链表队列/双端队列,有限数量的垃圾产生(旧数组将被丢弃在扩展),建议使用deque,ArrayDeque优先。

5.BFS

伪代码

/**
 * Return the length of the shortest path between root and target node.
 */
int BFS(Node root, Node target) {
    Queue<Node> queue;  // store all nodes which are waiting to be processed
    Set<Node> used;     // store all the used nodes
    int step = 0;       // number of steps neeeded from root to current node
    // initialize
    add root to queue;
    add root to used;
    // BFS
    while (queue is not empty) {
        step = step + 1;
        // iterate the nodes which are already in the queue
        int size = queue.size();
        for (int i = 0; i < size; ++i) {
            Node cur = the first node in queue;
            return step if cur is target;
            for (Node next : the neighbors of cur) {
                if (next is not in used) {
                    add next to queue;
                    add next to used;
                }
            }
            remove the first node from queue;
        }
    }
    return -1;          // there is no path from root to target
}

模板一

/**
	 
	class Node {
		public int val;
	    public List<Node> children;
	    public Node() {}
	    public Node(int _val,List<Node> _children) {
	        val = _val;
	        children = _children;
	    }
	};


	 * 一:模板一
	 * 
	 * 返回找到该结点的最短路径
	 * Return the length of the shortest path between root and target node.
	 */
	int BFS(Node root, Node target) {
		
		/*
		 1、初始化队列
		 2、初始化step
		 3、队列中增加根结点 
		 */
		
	    Queue<Node> queue = null;  // store all nodes which are waiting to be processed
	    int step = 0;       // number of steps neeeded from root to current node
	    // initialize
	    // add root to queue;
	    queue.add(root);
	    // BFS
	    while (!queue.isEmpty()) {
	    	
	    	/*
	    	 1、步数加1
	    	 2、求队列的长度
	    	 3、循环,找到当前队列的第一个元素,与所求比较,若相等,则返回,
	    	  	若不等,把这个结点的孩子结点添加到队列中,然后移出队列的第一个元素
	    	**/
	    	
	    	
	        step = step + 1;
	        // iterate the nodes which are already in the queue
	        int size = queue.size();
	        for (int i = 0; i < size; ++i) {
	            //Node cur = the first node in queue;
	        	Node cur = queue.peek();
	        	//return step if cur is target;
	        	if(cur==target){
	        		return step;
	        	}
	            for (Node next : cur.children) {
	                queue.offer(next);
	            }
	            queue.remove();
	        }
	    }
	    return -1;          // there is no path from root to target
	}

模板二:新增了对已经遍历过的加标记

	/**
	 * 一:模板二
	 * 
	 * 返回找到该结点的最短路径
	 * Return the length of the shortest path between root and target node.
	 */
	int BFS2(Node root, Node target) {
		
		/*
		 1、初始化队列
		 2、初始化step
		 3、队列中增加根结点 
		 4、新增一个set集合,用于存储已经使用过的结点
		 */
		Set<Node> used = null;
	    Queue<Node> queue = null;  // store all nodes which are waiting to be processed
	    int step = 0;       // number of steps neeeded from root to current node
	    // initialize
	    // add root to queue;
	    queue.add(root);
	    used.add(root);
	    // BFS
	    while (!queue.isEmpty()) {
	    	
	    	/*
	    	 1、步数加1
	    	 2、求队列的长度
	    	 3、循环,找到当前队列的第一个元素,与所求比较,若相等,则返回,
	    	  	若不等,把这个结点的孩子结点添加到队列中,然后移出队列的第一个元素
	    	**/
	    	
	    	
	        step = step + 1;
	        // iterate the nodes which are already in the queue
	        int size = queue.size();
	        for (int i = 0; i < size; ++i) {
	            //Node cur = the first node in queue;
	        	Node cur = queue.peek();
	        	//return step if cur is target;
	        	if(cur==target){
	        		return step;
	        	}
	            for (Node next : cur.children) {
	            	if(!used.contains(next)){
	            		queue.offer(next);
	            	}
	            }
	            queue.remove();
	        }
	    }
	    return -1;          // there is no path from root to target
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值