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. 读取java目录中相同目录、相同名称的文件

    使用ClassLoader的getResources方法(注意,不是getResource,少了s),可获得指定文件的包含jar包名称的多个路径值,然后依次读取文件即可. 使用class,只能通过ge ...

  2. Cross join in excel --- Copy from Internet

    Set up the Workbook In this example, there are two tables -- Raw Materials and Packaging -- and each ...

  3. 在eclipse中创建一个Maven项目

    1. 首先判断eclipse有没有自带Maven Window –> Perferences 如果有Maven,那就是自带了maven插件,如果没有,需要自行安装. 2.配置maven 2.1. ...

  4. Thinkphp 1.验证规则 2.静态定义 3.动态验证

    一.验证规则 数据验证可以对表单中的字段进行非法的验证操作.一般提供了两种验证方式: 静态定 义($_validate 属性)和动态验证(validate()方法). //验证规则 array( ar ...

  5. 利用mask layer 勾View

    #define SCREEN_WIDTH [[UIScreen mainScreen] bounds].size.width #define SCREEN_HEIGHT [[UIScreen main ...

  6. JavaScript数据类型 typeof, null, 和 undefined

    JavaScript 数据类型 在 JavaScript 中有 5 种不同的数据类型: string number boolean object function 3 种对象类型: Object Da ...

  7. 回文字符串的判断!关于strlen(char * str)函数

    #include <stdio.h> #include <string.h> int ishuiw(char * p); int main() { ;//true-false接 ...

  8. es6 ajax

    简单的co用例: var co=require("co") class view{ constructor(){ co(function*(){ var p1=this.ajax1 ...

  9. 解决警告“ld: warning: directory not found for option

    因为已经把文件编译到项目中,删除的话会出现找不到文件或文件夹的警告. 1选择工程, 编译的 (targets) 2选择 Build Settings 菜单 3查找 Library Search Pat ...

  10. WP8.1 模仿手机通讯记录的选择框

    2016年11月6日 更新: 其实 这个有一个非常简单的方法.非常简单... ListView SelectionMode="Multiple" 这个一XAML  代码就可以解决了 ...