Java数据结构之---Queue队列

  队列(简称作队,Queue)也是一种特殊的线性表,队列的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置插入和删除,而队列只允许在其一端进行插入操作在其另一端进行删除操作。

队列中允许进行插入操作的一端称为队尾,允许进行删除操作的一端称为队头。队列的插入操作通常称作入队列,队列的删除操作通常称作出队列。最简单的例子就是我们平时的排队,先进先出。

顺序队列的存储结构

下图是一个有6个存储空间的顺序队列的动态示意图,图中front指示队头,rear指示队尾。

~顺序队列的假溢出现象

假溢出是由于队尾rear的值和队头front的值不能由所定义数组下界值自动转为数组上界值而产生的。因此,解决的方法是把顺序队列所使用的存储空间构造成一个逻辑上首尾相连的循环队列( Circular Queue)。

~解决方法

当rear和front达到maxSize-1后,再加1就自动到0。这样,就不会出现顺序队列数组的头部已空出许多存储空间,但队尾却因数组下标越界而引起溢出的假溢出问题。这里在代码里面会详细解释~

在操作完成后,该队列中会有两个空格没有数据元素保存,造成资源浪费,这就是假溢出现象。

//==========================

//使用自定义的queue接口

 //队列接口
public interface Queue { // 入队
public void append(Object obj) throws Exception; // 出队
public Object delete() throws Exception; // 获得对头元素
public Object getFront() throws Exception; // 判断是否为空
public boolean isEmpty(); }

Queue interface

//循环链表的具体实现

 /*
* 循环顺序队列
*/
public class CircleSequenceQueue implements Queue { static final int defaultsize = 10;// 默认队列的长度
int front; // 对头
int rear; // 队尾
int count;// 统计元素个数的计数器
int maxSize; // 队的最大长度
Object[] queue; // 队列,使用数组实现 // 默认构造
public CircleSequenceQueue() {
init(defaultsize);
} public CircleSequenceQueue(int size) {
// 通过给定长度进行构造
init(size);
} public void init(int size) {
maxSize = size;
front = rear = 0;
count = 0;
queue = new Object[size];
} @Override
public void append(Object obj) throws Exception {
// TODO Auto-generated method stub
if (count > 0 && front == rear) {
throw new Exception("队列已满");
}
// 队尾插入数据
queue[rear] = obj;
// 通过这种方法让对标索引值不停的重复!!!
rear = (rear + 1) % maxSize;
count++;
} @Override
public Object delete() throws Exception {
// TODO Auto-generated method stub
if (isEmpty()) {
throw new Exception("队列为空");
}
// 去除对头的元素,同时修改对头的索引值
Object obj = queue[front];
// 对头索引值,一样通过+1驱魔运算来实现循环索引效果
front = (front + 1) % maxSize;
count--;
return obj;
} @Override
public Object getFront() throws Exception {
// TODO Auto-generated method stub
if (!isEmpty()) {
return queue[front];
} else {
// 对为空返回null
return null;
}
} @Override
public boolean isEmpty() {
// TODO Auto-generated method stub
return count == 0;
} }

//得到循环链表后,对其进行应用,之类主要是模拟卖票窗口

·  实例:使用顺序循环队列和多线程实现一个排队买票的例子。

·  生产者(等候买票)

·  消费者 (买票离开)

//代码的分割线,使用生产者消费者模式进行设计,主要是使用同步机制

 //卖票窗口
public class WindowQueue { // 卖票的队列默认长度10
int maxSize = 10;
CircleSequenceQueue queue = new CircleSequenceQueue(maxSize);
// 用来统计卖票的数量,一天最多卖100张票?
int num = 0;
boolean isAlive = true; // 判断是否继续卖票 // 排队买票,使用同步机制
public synchronized void producer() throws Exception {
// count队列中的元素个数,如果该值小于maxSize则可以买票
if (queue.count < maxSize) {
queue.append(num++); // 等待买票的数量+1
System.out.println("第" + num + "个客户排队等待买票");
this.notifyAll(); // 通知卖票线程可以卖票了
}
// 如果满了
else {
try { System.out.println("队列已满...请等待");
this.wait(); // 队列满时,排队买票线程等待,其实等待卖票队伍里面离开一个人后来唤醒自己 } catch (Exception e) {
e.printStackTrace();
}
}
} // 排队卖票,使用同步机制
public synchronized void consumer() throws Exception {
// count队列中的元素个数,如果该值大于0,则说明有票可以继续卖票
if (queue.count > 0) { Object obj = queue.delete();
// 第几个人买到票了
int temp = Integer.parseInt(obj.toString());
System.out.println("第" + (temp + 1) + "个客户排队买到票离开队列");
// 如果当前队列为空,并且卖出票的数量的大于等于100说明卖票要结束
if (queue.isEmpty() && this.num >= 100) {
this.isAlive = false;
}
// 排队队伍离开一个人,可以进来一个人进行买票了。
this.notifyAll(); // 通知买票线程可以买了,唤醒买票线程
}
// 如果满了
else {
try { System.out.println("队列已空...请进入队伍准备买票");
this.wait();// 队列空时,排队卖票线程等待,其实等待买票队伍里面进来一个人后买票来唤醒自己 } catch (Exception e) {
e.printStackTrace();
}
}
}
}

//下面的两个类是生产者与消费者的具体实现,实现runnable接口

 //买票者

 public class Producer implements Runnable {
// 买票窗口
WindowQueue queue; // 保证和消费者使用同一个对象
public Producer(WindowQueue queue) {
this.queue = queue;
} @Override
public void run() {
// TODO Auto-generated method stub
//
while (queue.num < 100) {
try {
//执行买票,消费者
queue.producer();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
 //卖票者
public class Consumer implements Runnable {
WindowQueue queue; // 保证卖票与买票同步
public Consumer(WindowQueue queue) {
this.queue = queue;
} @Override
public void run() {
// 判断是否可以继续卖票
while (queue.isAlive) {
try {
// 卖票
queue.consumer(); } catch (Exception e) {
e.printStackTrace();
}
}
}
}

//测试。。。。。

 public class Test {
public static void main(String[] args) throws Exception {
/*
* CircleSequenceQueue queue = new CircleSequenceQueue();
* queue.append("a"); queue.append("b"); queue.append("c");
* queue.append("d"); queue.append("e");
*
* while (!queue.isEmpty()) { System.out.print(queue.delete() + " "); }
*/ // 卖票与买票模拟,使用同一个窗口对象
WindowQueue queue = new WindowQueue();
// 生产者
Producer P = new Producer(queue);
// 消费者
Consumer c = new Consumer(queue); // 排队买票线程
Thread pThread = new Thread(P);
// 买票线程
Thread cThread = new Thread(c); pThread.start(); // 开始排队买票
cThread.start(); // 卖票
}
}

Test Code

Java数据结构之队列的实现以及队列的应用之----简单生产者消费者应用的更多相关文章

  1. Java数据结构和算法(五)——队列

    前面一篇博客我们讲解了并不像数组一样完全作为存储数据功能,而是作为构思算法的辅助工具的数据结构——栈,本篇博客我们介绍另外一个这样的工具——队列.栈是后进先出,而队列刚好相反,是先进先出. 1.队列的 ...

  2. 自己动手实现java数据结构(四)双端队列

    1.双端队列介绍 在介绍双端队列之前,我们需要先介绍队列的概念.和栈相对应,在许多算法设计中,需要一种"先进先出(First Input First Output)"的数据结构,因 ...

  3. Java数据结构——用双端链表实现队列

    //================================================= // File Name : LinkQueue_demo //---------------- ...

  4. Java数据结构和算法之栈与队列

    二.栈与队列 1.栈的定义 栈(Stack)是限制仅在表的一端进行插入和删除运算的线性表. (1)通常称插入.删除的这一端为栈顶(Top),另一端称为栈底(Bottom). (2)当表中没有元素时称为 ...

  5. Java数据结构和算法(十四)——堆

    在Java数据结构和算法(五)——队列中我们介绍了优先级队列,优先级队列是一种抽象数据类型(ADT),它提供了删除最大(或最小)关键字值的数据项的方法,插入数据项的方法,优先级队列可以用有序数组来实现 ...

  6. 用阻塞队列实现一个生产者消费者模型?synchronized和lock有什么区别?

    多线程当中的阻塞队列 主要实现类有 ArrayBlockingQueue是一个基于数组结构的有界阻塞队列,此队列按FIFO原则对元素进行排序 LinkedBlockingQueue是一个基于链表结构的 ...

  7. java多线程15 :wait()和notify() 的生产者/消费者模式

    什么是生产者/消费者模型 一种重要的模型,基于等待/通知机制.生产者/消费者模型描述的是有一块缓冲区作为仓库,生产者可将产品放入仓库,消费者可以从仓库中取出产品,生产者/消费者模型关注的是以下几个点: ...

  8. java 数据结构 队列的实现

    java 数据结构队列的代码实现,可以简单的进行入队列和出队列的操作 /** * java数据结构之队列的实现 * 2016/4/27 **/ package cn.Link; import java ...

  9. 【Java数据结构学习笔记之二】Java数据结构与算法之队列(Queue)实现

      本篇是数据结构与算法的第三篇,本篇我们将来了解一下知识点: 队列的抽象数据类型 顺序队列的设计与实现 链式队列的设计与实现 队列应用的简单举例 优先队列的设置与实现双链表实现 队列的抽象数据类型 ...

随机推荐

  1. 安卓ndk参考资料

    http://developer.samsung.com/technical-doc/view.do;jsessionid=xKa-L5xQDvdrSyc1sN71lHAXjcv2YUH7I92zjH ...

  2. js 打印

    关于js打印很简单的一段代码 function doPrint() { var newWindow = window.open("打印窗口", "_blank" ...

  3. TotalCommander 之 日常使用技巧

    一. 常用操作 常用的操作如查看.复制.移动.删除退出已经在Total Commander下方列出,选择好文件后单击相应的按钮或是按下相应的快捷键(F3~F7)就可以完成操作.也可以像Windows中 ...

  4. Linux图形&命令行界面切换

    1.实时切换 1.1 命令行->图形 startx 1.2 图形->命令行 Ctrl+Alt+F1--F6 2.启动默认 2.1 启动进入命令行 修改/etc/inittab文件 &quo ...

  5. dynamoDb 使用

    如果写入时候结构体为: type Item struct {  DeviceId string `dynamo:"deviceid"` Play int `dynamo:" ...

  6. Find Missing Term in Arithmetic Progression 等差数列缺失项

    查找等差数列中的缺失项. e.g.Input: arr[] = {2, 4, 8, 10, 12, 14} Output: 6 Input: arr[] = {1, 6, 11, 16, 21, 31 ...

  7. JavaScript编码规范指南

    前言 本文摘自Google JavaScript编码规范指南,截取了其中比较容易理解与遵循的点作为团队的JavaScript编码规范. JavaScript 语言规范 变量 声明变量必须加上 var  ...

  8. Android JavaMail

    一.简介 JavaMail API提供了一种与平台无关和协议独立的框架来构建邮件和消息应用程序. JavaMail API提供了一组抽象类定义构成一个邮件系统的对象.它是阅读,撰写和发送电子信息的可选 ...

  9. win10没有新建文件夹

    win10没有新建文件夹 win10系统,电脑点击右键没有新建文件夹选项. 工具/原料   win10 系统台式机 方法/步骤     电脑左下角搜素出输入:cmd   出现以下画面   在命令指示符 ...

  10. 解决:tomcat部署时deploy location不能显示加载后的路径

    项目总是报错,添了删,删了又添了N次以后,发现添加部署的时候,Deploy Location 没有值了,Deploy Location 没有值在自带的Tomcat上就无法用浏览器浏览(Open in ...