队列的基本操作

队列入队出队实现

队列是种先进先出的数据结构。

队列的基本操作主要是入队和出队。

数据从队尾进入队列,从队首出队列。

下面来写一个简单的队列:

public class MyQueue {

private List data;

private int pointer;

public MyQueue() {

data = new ArrayList<>();

pointer = 0;

}

public boolean isEmpty() {

return pointer >= data.size();

}

/**

* Get the front item from the queue.

*/

public int Front() {

return data.get(pointer);

}

/**

* Insert an element into the queue. Return true if the operation is successful.

*/

public boolean enQueue(int x) {

data.add(x);

return true;

}

/**

* Delete an element from the queue. Return true if the operation is successful.

*/

public boolean deQueue() {

if (isEmpty()) {

return false;

}

pointer++;

return true;

}

}

其中,pointer代表头队首第一个位置的数据。

当头部有数据出队时,对应的pointer指针会往后移动一位。

如果有数据入队,会直接加在队尾:

我们会发现,随着队首数据的数据的出队,队首指针之前的空间都会被浪费掉,而且随着使用次数变多,空间浪费会越来越高。

为了重复使用这部分空间,避免浪费,我们可以设计一个队首与队尾相连接的队列,重复利用空间。

循环队列设计

如上图所示,数据1 ~ 10依次入队,队首head在1处,队尾tail在10处,如果将1出队列,head头指针将移动到2:

此时,有一个空位,我们还可以继续入队:

这样利用空间,刚好可以把队首浪费的空间利用上。

class MyCircularQueue {

private Integer[] data; //队列数据

private Integer size; //队列大小

private Integer head = -1; //头指针

private Integer tail = -1; //尾指针

/**

* 初始化队列

*/

public MyCircularQueue(int k) {

this.data = new Integer[k];

this.size = k;

}

/**

* 入队操作

*/

public boolean enQueue(int value) {

if (isFull()) {

return false;

}

if (head == -1) {

head++;

}

tail++;

data[tail % size] = value;

return true;

}

/**

* 出队操作

*/

public boolean deQueue() {

if (isEmpty()) {

return false;

}

if (head == tail % size) {

head = -1;

tail = -1;

} else {

head++;

}

return true;

}

/**

* 获取队首元素

*/

public int Front() {

if (isEmpty()) {

return -1;

}

return data[head];

}

/**

* 获取队尾元素

*/

public int Rear() {

if (isEmpty()) {

return -1;

}

return data[tail % size];

}

/**

* 判断队列是不是为空

*/

public boolean isEmpty() {

return tail == -1 && head == -1;

}

/**

* 检查队列是不是已经满了

*/

public boolean isFull() {

return (tail % size - head) == size - 1 || (head - tail % size) == 1;

}

}

广度优先搜索(BFS)及其实现

上面我们已经实现过基本的队列已经如果优化队列,下面我们来看一个队列在 BFS(广度优先搜索)算法中的应用。

首先我们来定义结点:

@Getter

@Setter

@EqualsAndHashCode

@NoArgsConstructor

class Node implements Serializable {

private static final long serialVersionUID = 3687337665231315466L;

String value;

Collection previews; //前置结点

Collection tails; //后置结点

public Node(String value, Collection previews, Collection tails) {

this.value = value;

}

public Node(String value) {

this.value = value;

}

}

之后,我们先用队列来实现简单的BFS:

int BFS(Node root, Node target) {

Queue queue = new LinkedBlockingQueue(); // store all nodes which are waiting to be processed

int step = 0; // number of steps neeeded from root to current node

queue.add(root);

while (!queue.isEmpty()) {

step++;

int size = queue.size();

for (int i = 0; i < size; i++) {

Node cur = queue.poll();

if (cur.equals(target)) {

return step;

}

if (cur.tails != null) {

for (Node node : cur.tails) {

queue.add(node);

}

}

}

}

return -1;

}

另外,考虑到图结构中,像上面这样访问,可能会存在访问重复结点的情况,所以,我们记录下访问过的结点,访问过就直接跳过。

下面是改进算法:

/**

* 避免一个节点访问两次,单独检查访问过的结点

*

* @param root

* @param target

* @return

*/

int BFS(Node root, Node target) {

Queue queue = new LinkedBlockingQueue(); // store all nodes which are waiting to be processed

Set userd = new HashSet<>(); // node that be used

int step = 0; // number of steps neeeded from root to current node

queue.add(root);

userd.add(root);

while (!queue.isEmpty()) {

step++;

int size = queue.size();

for (int i = 0; i < size; i++) {

Node cur = queue.poll();

if (cur.equals(target)) {

return step;

}

if (cur.tails != null) {

for (Node node : cur.tails) {

if (!userd.contains(node)) {

queue.add(node);

userd.add(node);

}

}

}

}

}

return -1;

}

Stack

与队列相反,栈是种先入后出的结构。

下面我们来看下Java里面的栈基本入栈和出栈是如何实现的:

首先是入栈操作:

/**

* Pushes an item onto the top of this stack. This has exactly

* the same effect as:

*

* addElement(item)

*

* @param item the item to be pushed onto this stack.

* @return the item argument.

* @see java.util.Vector#addElement

*/

public E push(E item) {

addElement(item);

return item;

}

/**

* Adds the specified component to the end of this vector,

* increasing its size by one. The capacity of this vector is

* increased if its size becomes greater than its capacity.

*

*

This method is identical in functionality to the

* {@link #add(Object) add(E)}

* method (which is part of the {@link List} interface).

*

* @param obj the component to be added

*/

public synchronized void addElement(E obj) {

modCount++;

ensureCapacityHelper(elementCount + 1);

elementData[elementCount++] = obj;

}

入栈 操作即将数据插入数组尾部。ps:入栈之前会去进行容量检查,如果不够,会进行内部数组的扩容操作,会重新产生大容量数组,并将原来老数组拷贝到新数组,完成扩容。过程跟 ArrayList 的类似。

下面来看下出栈:

/**

* Removes the object at the top of this stack and returns that

* object as the value of this function.

*

* @return The object at the top of this stack (the last item

* of the Vector object).

* @throws EmptyStackException if this stack is empty.

*/

public synchronized E pop() {

E obj;

int len = size();

obj = peek();

removeElementAt(len - 1);

return obj;

}

public synchronized void removeElementAt(int index) {

modCount++;

if (index >= elementCount) {

throw new ArrayIndexOutOfBoundsException(index + " >= " +

elementCount);

}

else if (index < 0) {

throw new ArrayIndexOutOfBoundsException(index);

}

int j = elementCount - index - 1;

if (j > 0) {

System.arraycopy(elementData, index + 1, elementData, index, j);

}

elementCount--;

elementData[elementCount] = null; /* to let gc do its work */

}

这里,直接将数组尾部的数移除。

深度优先搜索(DFS)

首先来看DFS的简单递归实现:

/*

* 基于递归实现 DFS

*/

boolean DFS(Node cur, Node target, Set visited) {

if (cur == target) {

return true;

}

if (cur.tails == null || cur.tails.size() < 1) {

return false;

}

for (Node n : cur.tails) {

visited.add(n);

if (DFS(n, target, visited)) {

return true;

}

}

return false;

}

基于递归的实现,系统会自动帮我们生成堆栈调用,但是如果递归的深度过高的话,终将造成堆栈溢出。这时候,我们就需要自己用Stack实现这一过程:

/**

* 基于 stack

*

* @param cur

* @param target

* @return

*/

boolean DFS(Node cur, Node target) {

Set visited = new HashSet<>();

Stack stack = new Stack();

stack.push(cur);

while (!stack.isEmpty()) {

Node temp = stack.pop();

if (temp == target) {

return true;

}

for (Node n : temp.tails) {

if (!visited.contains(n)) {

visited.add(n);

stack.push(n);

}

}

}

return false;

}

java中堆栈的基本操作_玩儿转队列和栈的基本操作及其应用:Java 版相关推荐

  1. java每轮排序结果_【算法队列面试题】面试问题:java选择题… - 看准网

    1.ArrayList类的底层数据结构是(  ) A.数组结构 B.链表结构 C.哈希表结构 D.红黑树结构 2.LinkedList类的特点是(  ) A.查询快 B.增删快 C.元素不重复 D.元 ...

  2. JAVA中堆栈和内存分配原理

    JAVA中堆栈和内存分配原理 1.栈.堆 1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制. 2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在 ...

  3. java中堆栈(stack)和堆(heap)

    http://www.ej38.com/showinfo/java-172156.html 堆栈是一种先进后出的数据结构,只能在一端进行输入或输出数据的操作  Stack类在java.util包中 向 ...

  4. java中堆栈内存_Java堆空间与堆栈– Java中的内存分配

    java中堆栈内存 Sometime back I wrote a couple of posts about Java Garbage Collection and Java is Pass by ...

  5. java 定义变量时 赋值与不赋值_探究Java中基本类型和部分包装类在声明变量时不赋值的情况下java给他们的默认赋值...

    探究Java中基本类型和部分包装类在声明变量时不赋值的情况下java给他们的默认赋值 当基本数据类型作为普通变量(八大基本类型: byte,char,boolean,short,int,long,fl ...

  6. java中static修饰函数_详解java中static关键词的作用

    在java中,static是一个修饰符,用于修饰类的成员方法.类的成员变量,另外可以编写static代码块来优化程序性能:被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载 ...

  7. java 基本类型 不赋值_探究Java中基本类型和部分包装类在声明变量时不赋值的情况下java给他们的默认赋值...

    探究Java中基本类型和部分包装类在声明变量时不赋值的情况下java给他们的默认赋值 当基本数据类型作为普通变量(八大基本类型: byte,char,boolean,short,int,long,fl ...

  8. java中审核订单流程图_看95后java妹子横扫阿里,京东,小米,滴滴,美团等大厂,一份热腾腾的面经(最终入职阿里)...

    内容目录 头条 美团 滴滴 京东 others 算法题 HR面 tips 自序 这次面试的公司有一点点多,主要是因为毕业后前两份工作找的都很草率,这次换工作就想着,emm,毕业三年了,该找个工作好好沉 ...

  9. 谈谈对java中分层的理解_让我们谈谈网页设计中的卡片设计

    谈谈对java中分层的理解 "I want a card", this is the first demand point that the customer said in th ...

最新文章

  1. SHOW PROCESSLIST 命令详解 (查看锁表)
  2. C#中Socket多线程编程实例
  3. python编程培训多少钱-python培训费用多少?
  4. jumpserver 节点部署_Jumpserver 部署
  5. pytorch torchvision 各种版本whl下载地址
  6. GoLang panic 用法
  7. html水调歌头实验总结,水调歌头教学课堂总结
  8. 手把手教你反编译小程序
  9. [spm操作] 什么是ROI,如何做ROI以及批量提取ROI的%signal change的示例程序
  10. SpringBoot banner更改
  11. Echarts双Y轴,右侧Y轴标签不显示
  12. 视频大数据产品-物联网、视频、大数据、三维、移动
  13. 小程序上如何计算倒计时截止时间
  14. 注释掉darknet加载yolo模型时打印的网络信息
  15. 【科研工具】博士师兄推荐的科研利器来咯!
  16. 形容等待时间长的句子_描写等待时间漫长的词语句子
  17. 使用leaflet或者openlayers 3 调用MapServer服务最佳实践完整说明
  18. 这篇文章告诉你几款必备软件
  19. 上海web前端培训选哪家?怎么选?
  20. 爬取steam csgo饰品市场初始版本(需自行加速访问)

热门文章

  1. 指数级暴增、复杂场景下,揭秘百度云原生湖仓架构等系列数据产品
  2. 扩展云存储边界,阿里云推出全球首个云定义存储产品
  3. 云原生全景图之六 | 托管 Kubernetes 和 PaaS 解决什么问题
  4. 为普及再助一把力!《2021年中国低代码/无代码市场研究报告》正式发布
  5. 移动云11.11,钜惠High不停!
  6. ​听说,私有云也出新一代了?
  7. Docker精华问答 | task与executor有什么关系?
  8. 云重磅 | 阿里云开源Blink;华为发布5G Cloud VR;AWS 将举行AI 大会 re;英伟达下调5亿美元业绩预期...
  9. 从 0 到 300,Instagram 创始人 CTO 分享工程团队成长的经验
  10. jquery中ajax完整例子get,jq的ajax方法,jquery中ajax完整例子