MyQueue< T >

本文介绍了两种实现方式的MyQueue:MyLinkedQueue使用链表,支持自动扩容;MyCircularQueue基于数组,循环存储并动态调整容量。展示了如何在Java中操作这些队列并进行扩容和循环处理。
摘要由CSDN通过智能技术生成

  在 MyStack 的基础上,仿写了MyQueue。其中基于Array实现的Queue即是循环队列,又实现了队列满后自动增加容量。

  人生苦短,未言自明。

1. MyLinkedQueue

  链表实现更简单,先写链表的实现。双链表的实现是显然的,单链表在实现时,注意到enqueue中的tail。先令tail引用的节点的next链指向新建的节点,然后再让tail去引用新建的节点,就实现了tail变为新增的节点。tail是对象变量,这里充分利用了其引用的特性——我既然单链找不到tail前的节点,那tail就改变自己,再以tail的身份修改了当前的链后,就“不讲道义的变节”,去引用其后的节点。

package MyQueue;

import java.util.NoSuchElementException;

/**
 * 2021/7/20.
 * 
 * @author CatInCoffee.
 */
public class MyLinkedQueue<T> {

	private static class Node<T> {
		public T data;
		public Node<T> next;

		public Node(T paraData) {
			data = paraData;
			next = null;
		} // of Node's first constructor

		public Node(T paraData, Node<T> paraNext) {
			data = paraData;
			next = paraNext;
		} // of Node's second constructor
	} // of class Node<T>

	private Node<T> frontMarker = new Node<>(null);
	private Node<T> rear;
	private int theSize;

	// *****************************************************************************************

	public MyLinkedQueue() {
		clear();
	}// Of the first constructor

	public void clear() {
		rear = frontMarker;
		theSize = 0;
	}// of clear()

	// O(N)
	public MyLinkedQueue(T[] paraArray) {
		this();

		for (int i = 0; i < paraArray.length; i++) {
			enqueue(paraArray[i]);
		} // Of for i

	}// Of the second constructor

	// *****************************************************************************************

	public int size() {
		return theSize;
	}// of size()

	public boolean isEmpty() {
		return size() == 0;
	}// of isEmpty()

	// *****************************************************************************************

	public boolean enqueue(T x) {
		Node<T> newNode = new Node<>(x);

		rear.next = newNode;
		rear = newNode;
		theSize++;

		return true;
	}// of enqueue(T)

	public T dequeue() {
		if (!isEmpty()) {
			T old = frontMarker.next.data;
			frontMarker.next = frontMarker.next.next;
			
			if(frontMarker.next == null) {
				rear = frontMarker;
			} // of if

			theSize--;
			return old;
		} else {
			throw new NoSuchElementException();
		} // of if-else

	}// of dequeue()

	// *****************************************************************************************

	public String toString() {
		String s = "It's an empty queue.";

		if (!isEmpty()) {
			s = "{ ";

			Node<T> temp = frontMarker.next;
			while (temp.next != null) {
				s += temp.data + ", ";
				temp = temp.next;
			} // of while
			s += temp.data + " }";

//			for (Node<T> temp = frontMarker.next; temp != null; temp = temp.next) {
//				s += temp.data + " ";
//			} // of for temp
//			s += "}";

		} // of if

		return s;
	}// of toString()

	public static void main(String args[]) {
		Character[] ch = { 't', 'e', 's', 't' };
		MyLinkedQueue<Character> tempQueue = new MyLinkedQueue<>(ch);
		System.out.println("Initialized, the list is: " + tempQueue.toString());

		Character tempValue;
		for (int i = 0; i < 5; i++) {
			try {
				tempValue = tempQueue.dequeue();
				System.out.println("Looped dequeue: " + tempValue + ", the new queue is: " + tempQueue);
			} catch (NoSuchElementException e) {
				System.out.println("Nothing to dequeue.");
				tempQueue.clear();
			} // of try-catch
		} // Of for i

		for (char c = 'a'; c < 'f'; c++) {
			tempQueue.enqueue(Character.valueOf(c));
		} // Of for i
		System.out.println("Enqueued a to e successively, the queue is: " + tempQueue);
		tempQueue.dequeue();
		tempQueue.dequeue();
		System.out.println("Dequeued twice, the queue is: " + tempQueue);

		for (char c = 'f'; c < 'i'; c++) {
			tempQueue.enqueue(Character.valueOf(c));
		} // Of for i
		System.out.println("Enqueued, the queue is: " + tempQueue);
		System.out.println();

		for (int i = 0; i < 4; i++) {
			tempValue = tempQueue.dequeue();
			System.out.println("Looped dequeue: " + tempValue + ", the new queue is: " + tempQueue);
		} // Of for i

		tempQueue.enqueue('?');
		tempQueue.enqueue('!');
		System.out.println("Enqueued: '?' '!', the queue is: " + tempQueue);

	} // Of main

}// of class MyLinkedQueue<T>

  结果:

Initialized, the list is: { t, e, s, t }
Looped dequeue: t, the new queue is: { e, s, t }
Looped dequeue: e, the new queue is: { s, t }
Looped dequeue: s, the new queue is: { t }
Looped dequeue: t, the new queue is: It's an empty queue.
Nothing to dequeue.
Enqueued a to e successively, the queue is: { a, b, c, d, e }
Dequeued twice, the queue is: { c, d, e }
Enqueued, the queue is: { c, d, e, f, g, h }

Looped dequeue: c, the new queue is: { d, e, f, g, h }
Looped dequeue: d, the new queue is: { e, f, g, h }
Looped dequeue: e, the new queue is: { f, g, h }
Looped dequeue: f, the new queue is: { g, h }
Enqueued: '?' '!', the queue is: { g, h, ?, ! }

2. MyCircularQueue

  这是一个基于数组的、实现了自动扩容循环存储的循环队列。

  自动扩容和循环存储都利用了一个功能,那就是 ensureCapacity(int),即保证容量。

  首先怎么扩容?
  一般来说,给定一个常数用于给出初始数组大小,如果存放的队列元素个数theSize和数组大小length相同了,那么创建一个大小翻倍的数组,并将原数组拷贝进新数组。

  那在循环存储的时候,队头front在数组中间时enqueue队满了,像贪吃蛇一样尾碰到头了,这时候该怎么扩容?
  ensureCapacity(int)方法就是实现上面的功能(同时可用于初始化),参数如果不小于给定数组规模,那么创建参数大小的数组,并 有条件 的复制。该条件是基于循环数组的特性而产生的,因为循环数组队头front可以为任意位置,所以不能直接复制,而是从front开始;同时数组下标超过length后,要%求模回到循环的前面。特别的,复制扩容后要 重置队头和队尾的位置

package MyQueue;

import java.util.NoSuchElementException;

/**
 * 2021/7/20.
 * 
 * @author CatInCoffee.
 */
public class MyCircularQueue<T> {

	private static final int DEFAULT_CAPACITY = 5;

	// Sometimes we don't use 'theSize', but it helps to make the code more clear
	// while it costs little.
	private T[] theItems;
	private int theSize;
	private int front;
	private int rear;

	// *****************************************************************************************

	public MyCircularQueue() {
		clear();
	} // Of the first constructor

	public void clear() {
		theSize = 0;
		ensureCapacity(DEFAULT_CAPACITY);
	} // of clear()

	// O(N)
	public MyCircularQueue(T[] paraArray) {
		this();
		rear = paraArray.length - 1;
		theSize = paraArray.length;
		theItems = (T[]) (new Object[DEFAULT_CAPACITY]);

		for (int i = 0; i < paraArray.length; i++) {
			theItems[i] = paraArray[i];
			// enqueue(paraArray[i]);
		} // Of for i
	} // Of the second constructor

	// O(N)
	private void ensureCapacity(int newCapacity) {
		if (newCapacity < DEFAULT_CAPACITY || newCapacity < size()) {
			return;
		} // if

		T[] old = theItems;
		theItems = (T[]) new Object[newCapacity];
		for (int i = 0; i < size(); i++) {
			theItems[i] = old[(front + i) % size()];
		} // of for i
		front = 0;
		rear = size() - 1;
	} // of ensureCapacity(int)

	// *****************************************************************************************

	public int size() {
		return theSize;
	} // of size()

	public boolean isEmpty() {
		return size() == 0;
	} // of isEmpty()

	// *****************************************************************************************

	public boolean enqueue(T x) {
		if (theItems.length == size()) {
			ensureCapacity(2 * size() + 1);
		} // of if

		rear++;
		if (rear == theItems.length) {
			rear = 0;
		} // of if
		theItems[rear] = x;

		// The codes above equal to the next one.
//		theItems[(rear++ == theItems.length) ? 0 : rear] = x;

		theSize++;
		return true;
	}// of enqueue(T)

	public T dequeue() {
		if (!isEmpty()) {
			if (front == theItems.length) {
				front = 0;
			} // of if

			T old = theItems[front++];
			theSize--;

			return old;
		} else {
			System.out.print(" !!!Nothing to dequeue!!!  ");
			clear();
			return null;
			// throw new NoSuchElementException();
		} // of if-else

	}// of dequeue()

	// *****************************************************************************************

	public String toString() {
		String s = "An empty queue.";

		if (!isEmpty()) {
			s = "{ ";

			for (int i = front; i <= (front > rear ? (rear + theItems.length) : rear); i++) {
				s += theItems[i % theItems.length] + " ";
			} // of for temp
			s += "}";

		} // of if

		return s;
	}// of toString()

	public int getLength() {
		return theItems.length;
	}// of getLength()

	public static void main(String args[]) {
		Character[] ch = { 't', 'e', 's', 't' };
		MyCircularQueue<Character> tempQueue = new MyCircularQueue<>(ch);
		System.out.println("Initialized, the list is: " + tempQueue.toString());

		Character tempValue;
		for (int i = 0; i < 5; i++) {
			tempValue = tempQueue.dequeue();
			System.out.println("Looped dequeue: " + tempValue + ", the new queue is: " + tempQueue);
//			try {
//				tempValue = tempQueue.dequeue();
//				System.out.println("Looped dequeue: " + tempValue + ", the new queue is: " + tempQueue);
//			} catch (NoSuchElementException e) {
//				System.out.println("Nothing to dequeue.");
//				tempQueue.clear();
//			} // of try-catch
		} // Of for i

		for (char c = 'a'; c < 'f'; c++) {
			tempQueue.enqueue(Character.valueOf(c));
		} // Of for i
		System.out.println("Enqueued a to e successively, the queue is: " + tempQueue);
		System.out.println("The length of the array to store the queue is: " + tempQueue.getLength() + "\n");
		tempQueue.dequeue();
		tempQueue.dequeue();
		System.out.println("Dequeued twice, the queue is: " + tempQueue);

		for (char c = 'f'; c < 'i'; c++) {
			tempQueue.enqueue(Character.valueOf(c));
		} // Of for i
		System.out.println("Enqueued, the queue is: " + tempQueue);
		System.out.println("The length of the array to store the queue is: " + tempQueue.getLength());

		System.out.println();

		for (int i = 0; i < 4; i++) {
			tempValue = tempQueue.dequeue();
			System.out.println("Looped dequeue: " + tempValue + ", the new queue is: " + tempQueue);
		} // Of for i

		tempQueue.enqueue('?');
		tempQueue.enqueue('!');
		System.out.println("Enqueued: '?' '!', the queue is: " + tempQueue);

	} // Of main

}// of class MyCircularQueue<T>

  结果:

Initialized, the list is: { t e s t }
Looped dequeue: t, the new queue is: { e s t }
Looped dequeue: e, the new queue is: { s t }
Looped dequeue: s, the new queue is: { t }
Looped dequeue: t, the new queue is: An empty queue.
 !!!Nothing to dequeue!!!  Looped dequeue: null, the new queue is: An empty queue.
Enqueued a to e successively, the queue is: { a b c d e }
The length of the array to store the queue is: 5

Dequeued twice, the queue is: { c d e }
Enqueued, the queue is: { c d e f g h }
The length of the array to store the queue is: 11

Looped dequeue: c, the new queue is: { d e f g h }
Looped dequeue: d, the new queue is: { e f g h }
Looped dequeue: e, the new queue is: { f g h }
Looped dequeue: f, the new queue is: { g h }
Enqueued: '?' '!', the queue is: { g h ? ! }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值