http://www.cnblogs.com/fuck1/p/5996116.html

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

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

顺序队列的存储结构

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

~顺序队列的假溢出现象

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

~解决方法

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

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

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

//使用自定义的queue接口

//队列接口
Queue interface

//队列接口
public interface Queue { // 入队
public void append(Object obj) throws Exception; // 出队
public Object delete() throws Exception; // 获得对头元素
public Object getFront() throws Exception; // 判断是否为空
public boolean isEmpty(); }
//循环链表的具体实现
/*
* 循环顺序队列
*/
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();
}
}
}
}

Testcode

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 IO基础操作

    java IO基础,通熟易懂,好久没复习java 基础了.这里是传送门... http://www.cnblogs.com/nerxious/archive/2012/12/15/2818848.ht ...

  2. java socket 基础操作

    服务端: public class Server { public static void main(String[] args) throws Exception { //1.创建一个服务器端Soc ...

  3. JAVA基础知识(2)--队列的操作

    队列是一种线性表,它只允许在该表中的一端插入,在另一端删除. 允许插入的一端叫做队尾(rear),允许删除的一端叫做队头(front): 下面用Java的数组进行模拟队列的操作: /**2015-07 ...

  4. 原创】Java并发编程系列2:线程概念与基础操作

    [原创]Java并发编程系列2:线程概念与基础操作 伟大的理想只有经过忘我的斗争和牺牲才能胜利实现. 本篇为[Dali王的技术博客]Java并发编程系列第二篇,讲讲有关线程的那些事儿.主要内容是如下这 ...

  5. disruptor笔记之三:环形队列的基础操作(不用Disruptor类)

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  6. 【代码笔记】Java常识性基础补充(二)——数组、ArrayList集合、ASCII编码、 eclipse基础操作、eclipse调试、eclipse项目导入、eclipse快捷键

    1.0 如何定义数组以及访问数组中的元素,如下所示.ArrayDemo01.java public class ArrayDemo01 { public static void main(String ...

  7. JAVA大数类—基础操作(加减乘除、取模、四舍五入、设置保留位数)

    当基础数据类型长度无法满足需求时可以使用大数类 构造方法接受字符串为参数 BigInteger bInt = new BigInteger("123123"); BigDecima ...

  8. Java script基础

    Java script基础 Js的每个语句后面都要有分号. <script  type="text/java script">所有JS内容</script> ...

  9. Java 并发基础

    Java 并发基础 标签 : Java基础 线程简述 线程是进程的执行部分,用来完成一定的任务; 线程拥有自己的堆栈,程序计数器和自己的局部变量,但不拥有系统资源, 他与其他线程共享父进程的共享资源及 ...

随机推荐

  1. js中,全局变量与直接添加在window属性的区别

    在js中定义的全局变量是挂在window下的,而window的属性也一样,那么这两者有什么区别呢? 其实这两者还是有小小的区别的,全局变量是不能通过delete操作符删除的,而直接定义在window上 ...

  2. 动态加载jQuery

    success: function(data){ for(var i in data){ $('.x-details>ul:eq(0)').append("<li>&quo ...

  3. 前端开发week2

    从网页布局看思维方式以及思维方式对于前端制作的重要性 经过了两个星期的学习,对于静态网页的制作也已经有了比较完整的理论知识和实践基础,技术层面的东西固然还是很重要.是最基础的,但是在实际制作网页的过程 ...

  4. Volley之 JsonRequest 解析JSON 数据

    ReqestQueue 和 JsonRequest String jsonUrl = "http://ip.taobao.com/service/getIpInfo.php?ip=63.22 ...

  5. 算法导论----贪心算法,删除k个数,使剩下的数字最小

    先贴问题: 1个n位正整数a,删去其中的k位,得到一个新的正整数b,设计一个贪心算法,对给定的a和k得到最小的b: 一.我的想法:先看例子:a=5476579228:去掉4位,则位数n=10,k=4, ...

  6. ios中文转码的一个奇葩问题

    事情是这样的:我要在一个URL中截取一个名为‘vfname’的参数,因为这个参数的值带有中文(转码之前的形式),所以我必须将其转码. URL是这样的: http://devapi.amibaguanl ...

  7. 修改(table的section与上一个section的间距)section header背景颜色

    - (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { UIView * ...

  8. DateTime 详解

    //2008年4月24日 System.DateTime.Now.ToString("D"); //2008-4-24 System.DateTime.Now.ToString(& ...

  9. C++ Windows进程管理

    功能: 1.各个进程启动.挂起.恢复.停止等 2.监听进程的运行状态,进程退出(正常.非正常)时,通知用户 3.异步队列 4.线程安全 进程管理器类: #ifndef __ProcessManager ...

  10. PKU 1003解题

    首先庆祝一下,今天连A了3题.感觉后面这题太简单了.. 由于英文不好 ,找了个翻译: 若将一叠卡片放在一张桌子的边缘,你能放多远?如果你有一张卡片,你最远能达到卡片长度的一半.(我们假定卡片都正放在桌 ...