队列的简单实现(一)

与栈相似的线性结构还有一种,那就是队列。

栈遵循后进先出(Last In First Out, LIFO)原则,而队列则恰好相反,遵循先进先出(First In First Out, FIFO)原则。

与栈相同,从存储结构来对队列进行划分,队列可以分为两类:

  • 顺序队列结构:用一组地址连续的内存单元依次保存队列中的数据。
  • 链式队列结构:用链表的形式保存队列中的数据。

如上图所示,队列是两端操作,入队列的一端为队尾,而出队列的一端为队头。一般的队列的基本操作有两个:

  1. 入队列(Enter):将数据保存到队列尾部。
  2. 出队列(Out):将对头的数据弹出(读取后删除)。
这里先简单实现顺序队列结构,之后再实现链式队列结构。

代码如下:

package ds.queue;

public class Queue<E> {
	private static final int MAX_LENGTH = 20;// 队列的默认最大长度
	private Object[] objData = null; // 存放队列的数据的数组
	private int nHead;// 用于标记队列头部下标
	private int nTail;// 用于标记队列尾部下标
	private int nLen;// 用于记录队列初始化时的最大长度

	/**
	 * 初始化队列,默认队列长度为50
	 */
	Queue() {
		this(MAX_LENGTH);
	}

	/**
	 * 初始化队列
	 * 
	 * @param nInitSize
	 *            队列的最大长度
	 */
	Queue(int nInitSize) {
		if (nInitSize > 0) {
			objData = new Object[nInitSize];
			nLen = nInitSize;
			nHead = 0;
			nTail = -1;
		} else {
			System.out.println("栈的初始化长度不能小于等于0:" + nInitSize);
		}
	}

	/**
	 * 获取队列的已使用的长度
	 * 
	 * @param queue
	 *            队列的引用
	 * @return 队列已使用的长度
	 */
	int getSize(Queue<E> queue) {
		// if (nHead == 0 && nTail == -1) {
		// return 0;
		// }
		if (nHead > nTail) {
			return 0;
		}
		return (queue.nTail - queue.nHead + 1);
	}

	/**
	 * 判断队列是否空
	 * 
	 * @param queue
	 *            队列的引用
	 * @return 若队列为空,则返回true,否则返回false
	 */
	boolean isEmpty(Queue<E> queue) {
		return (getSize(queue) == 0);
	}

	/**
	 * 判断队列是否满
	 * 
	 * @param queue
	 *            队列的引用
	 * @return 若队列为满,则返回true,否则返回false
	 */
	boolean isFull(Queue<E> queue) {
		return (queue.nTail + 1 == nLen);
	}

	/**
	 * 清空队列,但不释放内存
	 * 
	 * @param queue
	 *            队列的引用
	 */
	void clear(Queue<E> queue) {
		nHead = 0;
		nTail = -1;
	}

	/**
	 * 清空队列,并释放内存
	 * 
	 * @param queue
	 *            队列的引用
	 */
	void free(Queue<E> queue) {
		clear(queue);
		if (queue != null) {
			queue = null;
		}
	}

	/**
	 * 入队列
	 * 
	 * @param queue
	 *            队列的引用
	 * @param eData
	 *            入队列的数据
	 */
	void enter(Queue<E> queue, E eData) {
		if (isFull(queue)) {
			System.out.println("队列已满,无法入队列:" + eData);
			return;
		}
		queue.objData[++queue.nTail] = eData;
		System.out.println(eData + "已入队列");
	}

	/**
	 * 出队列
	 * 
	 * @param queue
	 *            队列的引用
	 * @return 队列头部的数据
	 */
	@SuppressWarnings("unchecked")
	E out(Queue<E> queue) {
		if (isEmpty(queue)) {
			System.out.println("队列已空,无法出队列");
			return null;
		}
		System.out.println((E) queue.objData[queue.nHead] + "出队列");
		return (E) queue.objData[queue.nHead++];
	}

	/**
	 * 读取队列头部数据
	 * 
	 * @param queue
	 *            队列的引用
	 * @return 队列头部的数据
	 */
	@SuppressWarnings("unchecked")
	E peek(Queue<E> queue) {
		if (isEmpty(queue)) {
			System.out.println("队列已空,无法读取队列头部");
			return null;
		}
		System.out.println((E) queue.objData[queue.nHead] + "已读取");
		return (E) queue.objData[queue.nHead];
	}

}

测试代码:

package ds.queue;

public class Simple {

	public static void main(String[] args) {
		System.out.println("----新建空队列----");
		Queue<String> queue = new Queue<String>(5);
		System.out.println("队列的现有长度:" + queue.getSize(queue));

		System.out.println("----测试入队列操作----");
		for (int i = 0; i < 6; i++) {
			System.out.println("将test" + i + "压入队列");
			queue.enter(queue, "test" + i);
		}
		System.out.println("队列的现有长度:" + queue.getSize(queue));

		System.out.println("----测试读取队列顶操作----");
		queue.peek(queue);
		queue.peek(queue);

		System.out.println("----测试出队列操作----");
		for (int i = 0; i < 7; i++) {
			queue.out(queue);
		}
		System.out.println("队列的现有长度:" + queue.getSize(queue));
	}
}

测试结果:

----新建空队列----
队列的现有长度:0
----测试入队列操作----
将test0压入队列
test0已入队列
将test1压入队列
test1已入队列
将test2压入队列
test2已入队列
将test3压入队列
test3已入队列
将test4压入队列
test4已入队列
将test5压入队列
队列已满,无法入队列:test5
队列的现有长度:5
----测试读取队列顶操作----
test0已读取
test0已读取
----测试出队列操作----
test0出队列
test1出队列
test2出队列
test3出队列
test4出队列
队列已空,无法出队列
队列已空,无法出队列
队列的现有长度:0

上述代码实现的队列是队列长度不可变的顺序队列结构,这里就不再实现队列长度可变的顺序队列结构了。

如需队列长可变的读者,可以根据栈的简单实现(二)进行相应的改动即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值