java 队列基础操作
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 队列基础操作的更多相关文章
- java IO基础操作
java IO基础,通熟易懂,好久没复习java 基础了.这里是传送门... http://www.cnblogs.com/nerxious/archive/2012/12/15/2818848.ht ...
- java socket 基础操作
服务端: public class Server { public static void main(String[] args) throws Exception { //1.创建一个服务器端Soc ...
- JAVA基础知识(2)--队列的操作
队列是一种线性表,它只允许在该表中的一端插入,在另一端删除. 允许插入的一端叫做队尾(rear),允许删除的一端叫做队头(front): 下面用Java的数组进行模拟队列的操作: /**2015-07 ...
- 原创】Java并发编程系列2:线程概念与基础操作
[原创]Java并发编程系列2:线程概念与基础操作 伟大的理想只有经过忘我的斗争和牺牲才能胜利实现. 本篇为[Dali王的技术博客]Java并发编程系列第二篇,讲讲有关线程的那些事儿.主要内容是如下这 ...
- disruptor笔记之三:环形队列的基础操作(不用Disruptor类)
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- 【代码笔记】Java常识性基础补充(二)——数组、ArrayList集合、ASCII编码、 eclipse基础操作、eclipse调试、eclipse项目导入、eclipse快捷键
1.0 如何定义数组以及访问数组中的元素,如下所示.ArrayDemo01.java public class ArrayDemo01 { public static void main(String ...
- JAVA大数类—基础操作(加减乘除、取模、四舍五入、设置保留位数)
当基础数据类型长度无法满足需求时可以使用大数类 构造方法接受字符串为参数 BigInteger bInt = new BigInteger("123123"); BigDecima ...
- Java script基础
Java script基础 Js的每个语句后面都要有分号. <script type="text/java script">所有JS内容</script> ...
- Java 并发基础
Java 并发基础 标签 : Java基础 线程简述 线程是进程的执行部分,用来完成一定的任务; 线程拥有自己的堆栈,程序计数器和自己的局部变量,但不拥有系统资源, 他与其他线程共享父进程的共享资源及 ...
随机推荐
- Bootstrap <基础二十三>页面标题(Page Header)
页面标题(Page Header)是个不错的功能,它会在网页标题四周添加适当的间距.当一个网页中有多个标题且每个标题之间需要添加一定的间距时,页面标题这个功能就显得特别有用.如需使用页面标题(Page ...
- c语言-四阶龙格-库塔法
#include<stdio.h> #include<math.h> #define n 14 //double func1(double x, double y); doub ...
- java install
http://www.cnblogs.com/a2211009/p/4265225.html
- Android 查缺补漏之Adapter 和 LayoutInflater
在之前的博客我也讲过 Adapter 和 inflater,但发现讲的不够清楚,好多读者看后有疑问,今天就结合API单独讲一次. Adapter : An Adapter object acts as ...
- 【转】一名大学生的PHP进阶之路
我是一名河南某职业学院的学生,比较喜欢PHP开发 的 工作,自己也曾经自学过php,but如果没有老师教还真是难以坚持啊,在这里给大家说一下寒假在麦子的学习感受,首先说麦子每一堂课程都给了特别详细的 ...
- SSH面试题收藏
Hibernate工作原理及为什么要用? 原理: 1. 读取并解析配置文件2. 读取并解析映射信息,创建SessionFactory3. 打开Sesssion4. 创建事务Transation5. 持 ...
- 模块化以及requirejs和seajs
我们用模块化的思想进行网页的编写是为了更好的管理我们的项目 模块与模块之间是独立存在的,每个模块可以独立的完成一个子功能. 模块化所涉及的规范commonjs,AMD,CMD,UMD 其中的commo ...
- DTD指定了游戏规则。
1.DTD的作用 DTD是XML的型,列出了XML中的元素有哪些.元素间的关系.元素可以有哪些内容,元素的属性也有哪些.DTD实质说明的是元素间的关系,也就是类之间的关系.是一棵树状结构的说明,与XM ...
- 排序系列 之 折半插入排序算法 —— Java实现
基本思想: 折半插入算法是对直接插入排序算法的改进,排序原理同直接插入算法: 把n个待排序的元素看成一个有序表和一个无序表,开始时有序表中只有一个元素,无序表中有n-1个元素:排序过程即每次从无序表中 ...
- Android深度探索--HAL与驱动开发----第七章读书笔记
首先创建led驱动的设备文件,可以使用cdev_init,register_chrdev_region,cdev_add等建立主设备号的设备文件.步骤如下: 1使用cdev_init初始化cdev 2 ...