JAVA循环队列

关于自定义循环队列的实现原理和要点可以参见之前的博文系列:循环队列及C语言实现。这里主要对JAVA下的具体实现方式与原理进行说明。

一、JAVA 中已经自带了 Queue、DQueue、ArrayList、LinkedList 等常用的数据结构,为什么还要单独实现循环队列?

之所以使用自定义循环队列,出发点还是基于我们在实际应用中对于数据处理各种各样的需求。使用自定义数据结构的好处就在于可以更加灵活的处理各种数据,增加自己需要的接口。然而弊端就是你的 code 可能会引入各种未知的 Bug。所以,在满足我们使用前提的场景下,使用上述已有数据结构等是比较推荐的,如果满足不了实际项目需求,再通过自定义的方式等实现是我们理想的一种选择。

二、什么场景需要使用自定义循环队列?

对于数据的处理要求比较灵活,比如:我们需要开发一个安卓服务器程序,需要不断处理每个客户端的请求以及完成与客户端的交互。发送来的数据需要及时处理,但同时数据以自定义格式进行传输:包头+长度+数据+包尾+校验。如上格式,服务器端需要不断将接收的数据进行缓存与解析,如果未满一帧那么需要缓存到下次数据接收过来再进行解析。这时,我们需要批量从队列读取数据以及如果一帧数据不完全,将读取的数据复原到队列中(更改队列当前读位置)的功能。此时,就可以考虑自己实现队列满足这些特殊的需求。

三、循环队列的特点与要素

1、先进先出(FIFO);

2、队列首尾元素位置;

3、常用队列操作:初始化、销毁、遍历、读写等;

四、源码实现

为便于使用,这里将该循环队列以类的方式实现:

/** Copyright (c) 2017, SoldierJazz. All rights reserved.* Use is subject to license terms.**/package com.exmple.java.text;/*** DataQueue 类实现为FIFO循环队列** <p> 使用前需要根据实际需求为队列分配合理的队列空间大小** 创建一个4K空间的队列如下所示:** DataQueue mdataqueue= new DataQueue(4096);** <p> 更多使用信息可以参考引用该类的例程,有关问题,可发送到* SoldierJazz@163.com 寻求支持。** @author      SoldierJazz* @version	 1.0.0*/public class DataQueue {Queue q = null;public class Queue {byte[] data = null;int read;int write;int size;int space;}Object mSemaphore = new Object();DataQueue(int size) {q = new Queue();Queue_Init(q, size);}/*** 返回当前队列可用数据量** @param    q    目标队列**/int Avail(Queue q) {return q.size - q.space;}/*** 初始化队列** @param    q    目标队列* * @param    size    队列分配内存大小**/void Queue_Init(Queue q, int size) {synchronized (mSemaphore) {q.data = new byte[size];q.read = 0;q.write = 0;q.size = size;q.space = size;}}/*** 销毁队列** @param    q    目标队列**/void Queue_Destroy(Queue q) {synchronized (mSemaphore) {q.read = q.write = 0;q.space = q.size;}}/*** 判断当前队列是否为空** @param    q    目标队列** @return    true表示队列为空<br>false表示队列不为空**/boolean Queue_Empty(Queue q) {return (q.space == q.size);}/*** 判断当前队列是否已满** @param    q    目标队列** @return    true表示队列已满<br>false表示队列未满**/boolean Queue_Full(Queue q) {return (q.space == 0);}/*** 写一个byte到目标队列** @param    q    目标队列* * @param    val    写入的byte值** @return    true表示写入成功<br>false表示写入失败**/boolean AddQueue(Queue q, byte val) {if (!Queue_Full(q)) {q.data[q.write] = val;q.write = (q.write + 1) % q.size;q.space--;return true;} return false;}/*** 从队列中读取一个字节** @param    q    目标队列* * @param    data    读取的字节** @return    true表示读取成功<br>false表示读取失败**/boolean DelQueue(Queue q, Byte data) {if (!Queue_Empty(q)) {data = q.data[q.read];q.read = (q.read + 1) % q.size;q.space++;return true;}return false;}/*** 批量写入长度为len的字节到队列** @param    q    目标队列* * @param    data    写入的byte数组* * @param    len    写入的数组长度** @return    成功写入的字节数量**/int WriteQueue(Queue q, byte[] data, int len){int ret = 0;int rest = q.size - q.write;synchronized (mSemaphore) {if (!Queue_Full(q)) {if (q.space >= len) {ret = len;if (rest >= len) {System.arraycopy(data, 0, q.data, q.write, len);q.write = (q.write + len) % q.size;q.space -= len;} else {System.arraycopy(data, 0, q.data, q.write, rest);q.write = 0;System.arraycopy(data, rest, q.data, 0, len - rest);q.write = len -rest;q.space -= len;}} else {ret = q.space;if (rest >= q.space) {System.arraycopy(data, 0, q.data, q.write, q.space);q.write = (q.write + q.space) % q.size;q.space = 0;} else {System.arraycopy(data, 0, q.data, q.write, rest);q.write = 0;System.arraycopy(data, rest, q.data, 0, q.space - rest);q.write = q.space -rest;q.space = 0;}}   }return ret;}}/*** 从队列中恢复长度len个字节的数据** @param    q    目标队列* * @param    len    要恢复的长度** @return    成功恢复的字节数**/int RecoverReadQueue(Queue q, int len) {int ret = 0;int rest = q.read;synchronized (mSemaphore) {if (q.space >= len)ret = len;elseret = q.space;if (rest >= ret) {q.read -= ret;} else {q.read = q.size - (ret - rest);}q.space -= ret;return ret;}}/*** 从队列中读取len个字节数据到data数组中** @param    q    目标队列* * @param    data    用于存放数据的目标数组* * @param    start    拷贝至目标数组的起始位置* * @param    len    读取的长度* * @return    成功读取的字节数**/int ReadQueue(Queue q, byte[] data, int start, int len) {int rest = q.size - q.read;int ret = 0;synchronized (mSemaphore) {if (!Queue_Empty(q)) {if (Avail(q) >= len) {ret = len;if (rest >= len) {System.arraycopy(q.data, q.read, data, start, len);q.read = (q.read + len) % q.size;q.space += len;} else {System.arraycopy(q.data, q.read, data, start, rest);q.read = 0;System.arraycopy(q.data, 0, data, start + rest, len - rest);q.read = len -rest;q.space += len;}return len;} else {ret = Avail(q);if (rest >= Avail(q)) {System.arraycopy(q.data, q.read, data, start, Avail(q));q.read = (q.read + Avail(q)) % q.size;q.space = q.size;} else {System.arraycopy(q.data, q.read, data, start, rest);q.read = 0;System.arraycopy(q.data, 0, data, start + rest, Avail(q) - rest);q.read = Avail(q) -rest;q.space = q.size;}}} return ret;}}
}
以上内容为使用该类及相关方法的定义,比较简单,看注解即可。下面针对该类做一个使用与测试程序:

	public void TestDataQueue() {DataQueue dataq = new DataQueue(100);byte[] a1 = {1, 2, 3, 4, 5, 6};byte[] a2 = {7, 8, 9, 10};byte[] b = new byte[10];int nread = 0;dataq.WriteQueue(dataq.q, a1, a1.length);nread = dataq.ReadQueue(dataq.q, b, 0, 3);System.out.println("length of queue: " + dataq.Avail(dataq.q));for (int i = 0; i < nread; i++) {System.out.printf("byte[%d]: %d\n", i, b[i]);}dataq.WriteQueue(dataq.q, a2, a2.length);System.out.println("length of queue: " + dataq.Avail(dataq.q));nread = dataq.ReadQueue(dataq.q, b, 0, dataq.Avail(dataq.q));System.out.println("length of queue: " + dataq.Avail(dataq.q));for (int i = 0; i < nread; i++) {System.out.printf("byte[%d]: %d\n", i, b[i]);}}public static void main(String args[]) {test t = new test();t.TestDataQueue();}
运行结果如下所示:



有疑问或者问题就给我邮件或者评论吧,觉得有用就点赞吧~:-D



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/403048.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VMware 虚拟机占用磁盘空间

使用VMware创建的虚拟机尽管已经设定分配的磁盘大小&#xff0c;但仍然会发现虚拟机占用的磁盘空间会越来越大&#xff0c;而直观体现就是虚拟机系统文件 vmdk 不断增大。因此下面介绍一个简单的方法&#xff0c;使用 VMware 自带的工具对 vmdk 文件进行压缩以节省磁盘空间。拿…

frameworks/av/media/CedarX-Projects/CedarAndroidLib/LIB_KK44_/Android.mk: No such file or directory

在安卓系统编译过程中如果遇到上述或者与之类似的错误&#xff0c;可以采取相同的处理方法进行解决。直接进入到 CedarAndroidLib 目录下&#xff0c;也即此例中的 frameworks/av/media/CedarX-Projects/CedarAndroidLib。看一下当前文件&#xff1a; 注意第9行为包含标题中报错…

《言简意赅之Linux设备驱动编程》 前言

linux 内核与驱动开发是一门很深的学问&#xff0c;主要是由于覆盖知识面较广、内核架构设计层级较深、软硬件知识要兼具。因此自己在学习理解时会经常遇到某一章节需要反复阅读理解多次。所以&#xff0c;我想用一种言简意赅的方式讲述 Linux 内核与设备驱动开发。我认为把一个…

Windows与Linux下tftp服务的使用

tftp 协议是基于 udp 的&#xff0c;轻量小巧&#xff0c;用在局域网和嵌入式上很顺手。大部分帖子把在 linux 上配置的过程描述的过于复杂&#xff0c;其实只是个工具而已。研究协议抓下包对比协议内容也可以满足需求了&#xff0c;下面进入正文。分别讲下在 linux 以及 windo…

Vmware提示:the operation was canceled by the user

一般遇到这种情况是由于当前虚拟机资源中的资源文件被其他进程占用导致的。如果你的系统中有 DAEMON Tools Lite 软件&#xff0c;那么多半是因为这个原因。因此下面针对此情况提出两种解决办法&#xff1a; 1. 检查有无安装 DAEMON Tools Lite 软件&#xff0c;若安装此程序&a…

USB OTG 的进一步理解

一直以来在做安卓系统相关的嵌入式通讯&#xff08;USB、BLE、网络、串口等&#xff09;&#xff0c;最近在讨论 OTG 问题的时候&#xff0c;对该规范又重新理解了一次&#xff0c;这里仅做一些概要和核心点说明&#xff0c;下方会给出具体 OTG 包含协议的参考链接&#xff0c;…

中标麒麟/NeoKylin U盘安装系统

这里以 NeoKylin6 为例&#xff0c;其他版本与此相类似大同小异。但是下载指定版本的镜像时要注意配合该版本的软件包是否充足&#xff0c;不然就会遇到安装好系统很多软件无法安装或更新的情况。 1. 官方下载地址&#xff1a;http://download.cs2c.com.cn/neokylin/desktop/re…

中标麒麟/NeoKylin 安装QT开发环境

1. 如果你对中标麒麟系统安装有疑问&#xff0c;请阅读上一篇文章&#xff1a;《中标麒麟/NeoKylin U盘安装系统》。 2. 进入系统打开终端&#xff0c;以 root 模式操作。 <1> yum install gstream* libXext-devel libX11-devel<2> ln -s /usr/lib64/libXrender.so…

饥荒Mod 开发(二二):显示物品信息

饥荒Mod 开发(二一)&#xff1a;超大便携背包&#xff0c;超大物品栏&#xff0c;永久保鲜 饥荒中的物品没有详细信息&#xff0c;基本上只有一个名字&#xff0c;所以很多物品的功能都不知道&#xff0c;比如浆果吃了也不知道恢复什么&#xff0c; 采集的胡萝卜也不知道什么功…

解决 Windows Update 更新错误/无法创建还原点 代码 0x80246008

这个问题在我的电脑上由来已久&#xff0c;但是大部分的更新工作可以由其他第三方软件来完成&#xff0c;所有有时候得过且过。但同时&#xff0c;有一些棘手的问题&#xff0c;会提示系统进行 Windows Update&#xff0c;只有硬着头皮解决了。如果你遇到了“系统无法创建还原点…

安卓App报错:android.os.FileUriExposedException

安卓7.0开始&#xff0c;不再允许在App中把 file://Uri 暴露给其他App&#xff0c;因此在代码中需要做下版本判断&#xff0c;在7.0版本及以上需要使用 FileProvider 生成 content://Uri 来代替 file://Uri。同时安卓工程需要做以下调整&#xff1a; 1、在 AndroidManifest.xml…

Android/Linux 系统添加对多点触摸屏的支持

含有 HID 多点触摸控制器的触摸屏、触摸板在 Android 和 Linux 内核中都是由 "hid-multitouch" 驱动进行支持的。因此如果你的系统连接触摸屏没有反应&#xff0c;问题基本都出于驱动未加载或者与触摸屏的 VID 与 PID 不适配。以下分情形讨论&#xff1a; 1、系统中已…

安卓获取屏幕最大(绝对)分辨率

安卓开发时&#xff0c;在很多应用场景需要获取手机屏幕的真实分辨率&#xff0c;然而查阅了大部分博客提供的获取方法发现获取方法并不对。下面几种常用的方法&#xff08;错误&#xff09;和最终正确获取的方法均会展示在下面。 实验场景&#xff1a;Activity&#xff08;隐…

安卓BLE开发教程(一) BLE基础

我试图以一种简单的方式去把重要的事情讲清楚。目的是希望BLE协议栈和基础概念简单化&#xff0c;让自己及类似的安卓开发者可以在较短的时间内把握住BLE的核心及使用方法。BLE本身很复杂&#xff0c;但对于安卓开发而言只要抓住一些核心点&#xff0c;便已足够。如果你想全面了…

安卓BLE开发教程(二) BLE开发流程

在安卓上进行BLE开发时&#xff0c;就不必像理解BLE协议栈那样复杂了。因为安卓的BLE包为我们提供了十分丰富的API、各类常量、各类连接通信情况下的回调API等。 具体流程 一、声明权限 二、获取Adapter适配器 三、开启蓝牙 四、BLE扫描与停止 五、连接设备 六、枚举特征…

Linux驱动如何在不同版本上快速迭代升级

As well known&#xff0c;Linux内核版本更新很快&#xff0c;有些内核版本的迭代升级可能会导致在使用的驱动版本存在编译失败或使用的兼容性问题&#xff0c;如何快速定位到内核版本间变更的地方&#xff0c;并处理掉该问题&#xff0c;列一下我常用的解决方法。&#xff08;…

Ipad平板作为MAC苹果电脑的扩展屏幕的技术研究

直入主题&#xff0c;这方面的研究直接参考当前使用基数最大&#xff0c;反馈最好的两个产品。最新产品讯息&#xff0c;请分别进入各自官网。BTW&#xff0c;Duet Display也跟随Luna Display开始发布硬件了。 Duet Display 颠覆了基于 Wi-Fi 的传统运作原理&#xff0c;改经…

使用std::thread线程相关函数,-static静态编译的程序运行时的一些常见错误

使用std::thread的应用程序&#xff0c;编译时如果是动态链接pthread线程库运行正常&#xff0c;-static静态链接时在某些平台下可能会遇到一些意外错误。如常见编译命令&#xff1a;g -stdC11 test.c -o test -pthread 1、Segmentation fault&#xff08;段错误&#xff09; …

C++ Tips

1、析构函数调用时机 <1> 栈中定义的对象程序会自动调用析构函数 例如CLassName object;这样声明的对象&#xff0c;当程序运行到了对象作用域之外或者程序退出&#xff0c;对象都会被销毁&#xff0c;当然析构函数也会被调用 <2> 堆中new的对象 使用new声明的…

The futex facility returned an unexpected error code

在 linux 程序执行中若遇到该错误&#xff0c;考虑下是否是如下变量使用了强制内存对齐导致。 比如&#xff1a;在将如上变量包含到结构体中&#xff0c;强制1字节或2字节内存对齐。 如&#xff1a;信号量相关 struct semaphore&#xff0c;线程相关的 pthread_mutex_t&#…