队列、双端队列与优先队列

队列、双端队列与优先队列

队列:先进先出,从后面插入,从前面移除;处理类似排队的问题,先排先处理,插入和移除操作的时间复杂度都为O(1)。

双端队列:
即在队列两端都可以插入和删除。同时拥有栈和队列的功能,一般使用频率较低,时间复杂度 O(1)。

优先级队列:内部维护一个按优先级排序的序列。插入时需要比较查找插入的位置,时间复杂度O(N), 删除O(1)。

1、基于链表的队列实现

元素从链尾插入,从链头删除。队列的链表实现含有两个数据域:firstNode——引用链表的第一个结点,用于快速删除或访问队列的首数据;lastNode——引用链表的最后一个结点,用于向队列快速插入新元素。

队列接口

public interface QueueInterface<T> {
	public void enqueue(T newEntry);
	public T dequeue();
	public T getFront();
	public boolean isEmpty();
	public void clear();
}

链表队列实现

public class LinkedQueue<T> implements QueueInterface<T>{

	private Node firstNode;
	private Node lastNode;
	
	public LinkedQueue() {
		firstNode=null;
		lastNode=null;
	}

	@Override
	public void enqueue(T newEntry) {
		System.out.print(newEntry+" ");
		Node newNode=new Node(newEntry);
		if(isEmpty())
			firstNode=newNode;
		else
			lastNode.setNextNode(newNode);
		lastNode=newNode;
	}

	@Override
	public T dequeue() {
		T front=null;
		if(!isEmpty()){
			front=firstNode.getEntry();
			firstNode=firstNode.getNextNode();
			if(firstNode==null)
				lastNode=null;
		}
		return front;
	}

	@Override
	public T getFront() {
		T front=null;
		if(!isEmpty())
			front=firstNode.getEntry();
		return front;
	}

	@Override
	public boolean isEmpty() {
		return firstNode==null;
	}

	@Override
	public void clear() {
		firstNode=null;
		lastNode=null;
	}
	
	public void display(){
		Node front=firstNode;
		System.out.println();
		while(front!=null){
			System.out.print(front.getEntry()+" ");
			front=front.getNextNode();
		}
		System.out.println();
	}
	
	private class Node{

		private T entry;
		private Node nextNode;
		
		public Node(T newEntry) {
			entry=newEntry;
			nextNode=null;
		}
		
		public T getEntry() {
			return entry;
		}

		public void setEntry(T entry) {
			this.entry = entry;
		}

		public Node getNextNode() {
			return nextNode;
		}

		public void setNextNode(Node nextNode) {
			this.nextNode = nextNode;
		}
	}
}

测试代码

public class main_LinkedQueue {
	private static LinkedQueue<Integer> queue;
	public static void main(String[] args) {
		queue=new LinkedQueue<Integer>();
		Random ra =new Random();
		for(int i=0;i<20;i++)
			queue.enqueue(ra.nextInt(100));
		queue.display();
	}
}
基于链表的队列实现的各种操作(插入、删除、检索链头)的时间复杂度均为O(1)。

2、基于数组的队列实现

使用数组实现队列,用frontIndex和backIndex分别表示队列前端与后端的索引。如果检出把首个元素放在queue[0]处,那么删除时其余数据需要依次向前移动,这样效率太低了。
这里将采用 循环数组,删除前端时,其它元素仍保留在原位置上,frontIndex表示下一个元素的索引;当插入元素时,一旦到达数组末尾,就可以将后续的元素插入到数组的头部。如下图(a)删除队列的3个元素,得到图(b),然后插入5个元素得到图(c)。

如何检测何时数组已满?图(c)插入两个元素后得到图(d),此时数组已满;图(b)删除3个元素后得到图(e),此时数组是空的。可以看出,队列空与队列满时frontIndex=backIndex+1,因此无法以此判断数组是否满。
一种解决方案是对队列中的元素计数,但每一次插入和删除都必须更新该数据,当然这种方案也是个不错的选择。下面介绍另一种解决方案—— 含有一个未用位置的循环数组
若留出一个数组位置未用,则可以只通过考察frontIndex和backIndex就能区分空队列和满队列。

队列接口

public interface QueueInterface<T> {
	public void enqueue(T newEntry);
	public T dequeue();
	public T getFront();
	public boolean isEmpty();
	public void clear();
}

数组队列实现

public class ArrayQueue<T> implements QueueInterface<T>{
	
	private T[] queue;
	private int frontIndex;
	private int backIndex;
	private static final int DEFAULT_INITIAL_CAPACITY=20;
	
	public ArrayQueue() {
		this(DEFAULT_INITIAL_CAPACITY);
	}
	
	public ArrayQueue(int initialCapacity) {
		queue=(T[]) new Object[initialCapacity+1];
		frontIndex=0;
		backIndex=initialCapacity;
	}

	@Override
	public void enqueue(T newEntry) {
		  if(isArrayFull())
			  doubleArray();
		  backIndex=(backIndex+1)%queue.length;
		  queue[backIndex]=newEntry;
	}

	@Override
	public T dequeue() {
		T front=null;
		if(!isEmpty()){
			front=queue[frontIndex];
			queue[frontIndex]=null;
			frontIndex=(frontIndex+1)%queue.length;
		}
		return front;
	}

	@Override
	public T getFront() {
		T front=null;
		if(!isEmpty())
			front=queue[frontIndex];
		return front;
	}

	@Override
	public boolean isEmpty() {
		return frontIndex==(backIndex+1)%queue.length;
	}

	@Override
	public void clear() {
		while(!isEmpty()){
			dequeue();
		}
	}
	
	public void display(){
		System.out.println();
		int index=frontIndex;
		while(index!=backIndex+1){
			System.out.print(queue[index]+" ");
			index=(index+1)%queue.length;
		}
	}
	
	private boolean isArrayFull(){
		return frontIndex==(backIndex+2)%queue.length;
	}
	
	private void doubleArray(){
		T[] oldQueue=queue;
		int oldSize=oldQueue.length;
		queue=(T[]) new Object[2*oldSize];
		for(int index=0;index<oldSize-1;index++){
			queue[index]=oldQueue[frontIndex];
			frontIndex=(frontIndex+1)%oldSize;
		}
		frontIndex=0;
		backIndex=oldSize-2;
	}
}

测试代码

public class main_ArrayQueue {
	private static ArrayQueue<Integer> queue;
	public static void main(String[] args) {
		queue=new ArrayQueue<Integer>();
		Random ra =new Random();
		for(int i=0;i<15;i++)
			queue.enqueue(ra.nextInt(100));
		queue.display();
		for(int i=0;i<5;i++)
			queue.dequeue();
		for(int i=0;i<12;i++)
			queue.enqueue(ra.nextInt(100));
		queue.display();
	}
}

3、基于双端链表的双端队列实现

队列的每一个结点既能引用下一个结点,又能引用上一个结点。

队列接口

public interface QueueInterface<T> {
	public void addToBack(T newEntry);
	public void addToFront(T newEntry);
	public T removeBack();
	public T removeFront();
	public T getBack();
	public T getFront();
	public boolean isEmpty();
	public void clear();
}

双端队列实现

public class Doubly_LinkedQueue<T> implements QueueInterface<T>{
	
	private Node firstNode;
	private Node lastNode;

	public Doubly_LinkedQueue() {
		firstNode=null;
		lastNode=null;
	}
	
	@Override
	public void addToBack(T newEntry) {
		System.out.print(newEntry+" ");
		Node newNode=new Node(newEntry, lastNode, null);
		if(isEmpty())
			firstNode=newNode;
		else
			lastNode.setNextNode(newNode);
		lastNode=newNode;
	}

	@Override
	public void addToFront(T newEntry) {
		System.out.print(newEntry+" ");
		Node newNode=new Node(newEntry, null, firstNode);
		if(isEmpty())
			lastNode=newNode;
		else
			firstNode.setPreviousNode(newNode);
		firstNode=newNode;
	}

	@Override
	public T removeBack() {
		T back=null;
		if(!isEmpty()){
			back=lastNode.getData();
			lastNode=lastNode.getPreviousNode();
			if(lastNode==null)
				firstNode=null;
			else
				lastNode.setNextNode(null);
		}
		return back;
	}

	@Override
	public T removeFront() {
		T front=null;
		if(!isEmpty()){
			front=firstNode.getData();
			firstNode=firstNode.getNextNode();
			if(firstNode==null)
				lastNode=null;
			else
				firstNode.setPreviousNode(null);
		}
		return front;
	}

	@Override
	public T getBack() {
		T back=null;
		if(isEmpty())
			back=lastNode.getData();
		return back;
	}

	@Override
	public T getFront() {
		T front=null;
		if(isEmpty())
			front=firstNode.getData();
		return front;
	}

	@Override
	public boolean isEmpty() {
		return firstNode==null && lastNode==null;
	}

	@Override
	public void clear() {
		while(!isEmpty())
			removeFront();
	}
	
	public void displayF_to_B(){
		Node currentNode=firstNode;
		System.out.println();
		while(currentNode!=null){
			System.out.print(currentNode.getData()+" ");
			currentNode=currentNode.getNextNode();
		}
	}
	
	public void displayB_to_F(){
		Node currentNode=lastNode;
		System.out.println();
		while(currentNode!=null){
			System.out.print(currentNode.getData()+" ");
			currentNode=currentNode.getPreviousNode();
		}
	}

	private class Node{

		private T Data;
		private Node previousNode;
		private Node nextNode;
		
		public Node(T newEntry){
			this(newEntry,null,null);
		}
		
		public Node(T newEntry,Node previousNode,Node nextNode) {
			this.Data=newEntry;
			this.previousNode=previousNode;
			this.nextNode=nextNode;
		}
		
		public T getData() {
			return Data;
		}

		public void setData(T data) {
			Data = data;
		}

		public Node getPreviousNode() {
			return previousNode;
		}

		public void setPreviousNode(Node previousNode) {
			this.previousNode = previousNode;
		}

		public Node getNextNode() {
			return nextNode;
		}

		public void setNextNode(Node nextNode) {
			this.nextNode = nextNode;
		}
	}
}








猜你喜欢

转载自blog.csdn.net/hjy132/article/details/63706867
今日推荐