salesforce零基础学习(七十七)队列的实现以及应用

 队列和栈简单的区别为栈是后进先出,队列是先进先出。队列也是特殊的线性表,所以队列也分为顺序存储结构和链式存储结构。本篇主要描述顺序存储结构。

我们先假定一个队列里有5个元素,当我们添加新元素时,添加到队列的最后一个位置,所以时间复杂度为O(1),当我们弹出元素时,需要将队列头部的元素弹出,并将后面的元素整体向前面平移,所以时间复杂度为O(n)。如果频繁的弹出,并且后面的元素向前面平移,这样对于性能还是影响挺大的,所以我们可以增加头指针,尾指针,不要求第一个元素必须在index为0的位置,只需要用头指针记录当前的头在哪里就好。

一.环形队列:

使用两个指针操作步骤为:

1.当在队尾添加元素情况下,队尾的指针+1,如下图,队列中添加a1,a2,a3,a4四个元素。此时队首front指针指向0,队尾rear指针指向4;

2.将队首元素进行弹出,此时队首指针front指向1,队尾指向4;

3.将元素a5添加到队尾,此时队尾指针指向到了内存长度的外面,但是下标为0还是有空缺的地方,这种情况称为假溢出。

为了避免假溢出这种情况,我们的做法为当队列满了以后,从头开始继续存储队列,直到队列满,即上图的情况下,a5进入队列以后,队尾rear指针指向下标0.

此时针对队列的空或者满的判断,可以通过队首指针和队尾指针来判断:

1.判断队列为空的条件为:front = rear,即首指针等于尾指针;

2.因为队尾可以从头开始,所以rear可以大于front,也有可能rear小于front。当队列满时,我们修改其条件保留一个元素空间。也就是说,队列满时,数组中还有一个空闲单元。这样我们可以通过下面的表达式来判断队列已满:(rear+1) % QueueSize = front.上图中当添加完a5以后,队列中只剩下一个空闲单元我们就假定此队列已满。

3.获取当前队列的元素个数:(rear - front + QueueSize)% QueueSize

二.代码实现

代码中封装了实现队列的基本方法,判断队列是否为空,是否是满的队列,添加元素,弹出元素等。其中针对添加元素,需要考虑队列是否已经满的情况,对于弹出元素,需要考虑队列是否为空队列的情况。

 1 public with sharing class Queue {
 2     //数据集
 3     private Object[] datas{get;set;}
 4     //栈最大容量
 5     private Integer maxSize{get;set;}
 6     //队头的位置指针
 7     private Integer front{get;set;}
 8     //队尾的位置指针
 9     private Integer rear{get;set;}
10 
11     public Queue() {
12         this(10);
13     }
14 
15     public Queue(Integer queueSize) {
16         datas = new Object[queueSize];
17         maxSize = queueSize;
18         front = 0;
19         rear = 0;
20     }
21 
22     //添加元素到队列尾部,如果添加成功返回true,添加失败返回false
23     public Boolean add(Object obj) {
24         if(datas == null) {
25             throw new QueueException('队列未初始化');
26         }
27         if(full()) {
28             throw new QueueException('队列已满');
29         }
30         datas[rear] = obj;
31         rear = Math.mod(rear + 1, maxSize);
32         //队列
33         return true;
34     }
35 
36     //返回队列头的元素,不弹出头元素
37     public Object peek() {
38         if(datas == null) {
39             throw new QueueException('队列未初始化');
40         }
41         return datas[front];
42     }
43 
44     //弹出头元素
45     public Object poll() {
46         if(datas == null) {
47             throw new QueueException('队列未初始化');
48         }
49 
50         if(empty()) {
51             throw new QueueException('队列为空!');
52         }
53 
54         Object returnObj = datas[front];
55         datas[front] = null;
56         front = Math.mod((front + 1),maxSize);
57         return returnObj;
58     }
59 
60     public Boolean empty() {
61         return front == rear;
62     }
63 
64     public Boolean full() {
65         return front == Math.mod(rear + 1, maxSize);
66     }
67 
68     public Integer size() {
69         return Math.mod(rear - front + maxSize ,maxSize);
70     }
71 
72     override public String toString() {
73         List<Object> objList = new List<Object>();
74         Integer tempRear;
75         if(rear < front) {
76             tempRear = rear + maxSize;
77         } else {
78             tempRear = rear;
79         }
80         for(Integer i = front;i<=tempRear;i++) {
81             if(datas[Math.mod(i, maxSize)] != null) {
82                 objList.add(datas[Math.mod(i, maxSize)]);
83             }
84         }
85         return String.join(objList, ',');
86     }
87 
88 
89     public class QueueException extends Exception{
90 
91     }
92 }

三.测试举例:

1.队列超出内存情况:初始化一个长度为5的队列,因为队列满的时候,会空出一个元素空间,所以说实际可以添加进队列的长度为4,当添加eee的时候会报错,因为队列已满。

Queue q = new Queue(5);
q.add('aaa');
q.add('bbb');
q.add('ccc');
q.add('ddd');
q.add('eee');
System.debug(LoggingLevel.INFO, '*** q: ' + q);

2.正常使用添加弹出效果,每次弹出是弹出队首指针对应的元素

Queue q = new Queue(5);
q.add('aaa');
q.add('bbb');
q.add('ccc');
q.add('ddd');
String result = (String)q.poll();
System.debug(LoggingLevel.INFO, '*** result: ' + result);
System.debug(LoggingLevel.INFO, '*** : ' + 'aaa'.equals(result));
q.add('eee');
System.debug(LoggingLevel.INFO, '*** q: ' + q);

总结:环形队列适用于已经知道需要分配多大内存的情况,如果不知道需要分配多少内存的情况,可以使用队列的链形结构。队列在程序中经常使用,比如场景为排队等的场景,如果有此种先进先出的场景,优先选择队列来实现。此篇只是简单的构造一下队列的模型,很多地方需要完善,有需要或者感兴趣的自行完善一下。篇中有错误的地方欢迎指出,有问题欢迎留言。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏风口上的猪的文章

.NET面试题系列[11] - IEnumerable<T>的派生类

ICollection<T>继承IEnumerable<T>。在其基础上,增加了Add,Remove等方法,可以修改集合的内容。IEnumerable<T>的直...

582
来自专栏Java3y

插入排序就这么简单

插入排序就这么简单 从上面已经讲解了冒泡和选择排序了,本章主要讲解的是插入排序,希望大家看完能够理解并手写出插入排序的代码,然后就通过面试了!如果我写得有错误的...

4048
来自专栏微信公众号:Java团长

Java集合类型详解

这篇文章总结了所有的Java集合(Collection)。主要介绍各个集合的特性和用途,以及在不同的集合类型之间转换的方式。

892
来自专栏java一日一条

Java HashMap 核心源码解读

本篇对HashMap实现的源码进行简单的分析。 所使用的HashMap源码的版本信息如下:

291
来自专栏Android机动车

数据结构学习笔记——队列

线性表有顺序存储和链式存储,栈是线性表,所以有这两种存储方式。同样,队列作为一种特殊的线性表,也同样存在这两种存储方式。

411
来自专栏专注 Java 基础分享

从源码解析LinkedList集合

     上篇文章我们介绍了ArrayList类的基本的使用及其内部的一些方法的实现原理,但是这种集合类型虽然可以随机访问数据,但是如果需要删除中间的元素就...

1875
来自专栏Java3y

List集合就这么简单【源码剖析】

1864
来自专栏你不就像风一样

Java核心数据结构(List,Map,Set)使用技巧与优化

JDK提供了一组主要的数据结构实现,如List、Map、Set等常用数据结构。这些数据都继承自 java.util.Collection 接口,并位于 java...

923
来自专栏ThoughtWorks

TW洞见 | 崔鹏飞:Scala中Stream的应用场景及其实现原理

假设一个场景 需要在50个随机数中找到前两个可以被3整除的数字。 听起来很简单,我们可以这样来写: ? 一个产生50个随机数的函数; 一个检查某数字是否能被3...

3114
来自专栏Java大联盟

23种设计模式详解(四)

792

扫码关注云+社区