基于数组实现Java 自定义Queue队列及应用

Java 自定义队列Queue:

队列的抽象数据类型就是一个容器,其中的对象排成一个序列,我们只能访问和取出排在最前端( Front)的对象,只能在队列的尾部( Rear)插入新对象。正是按照这一规则,才能保证最先被插入的对象首先被删除( FIFO)。java本身是有自带Queue类包,为了达到学习目的已经更好深入了解Queue队列,自己动手自建java Queue类是个很好的学习开始:

基于数组的实现

? 顺序数组

借助一个定长数组 Q 来存放对象,即可简单地实现队列。那么,为了符合 FIFO 准则,应该如何表示和记录队列中各对象的次序呢?

一种自然的办法就是仿照栈的实现,以 Q[0]作为队首,其它对象顺序往后存放。然而如此一来,每次首元素出队之后,都需要将后续的所有元素向前顺移一个单元若队长为 n,这项工作需要O(n)时间,因此效率很低。

? 循环数组

为了避免数组的整体移动,可以引入如下两个变量 f 和 r:

f:始终等于 Q 的首元素在数组中的下标,即指向下次出队元素的位置

r:始终等于 Q 的末元素的下标加一,即指向下次入队元素的位置

一开始, f = r = 0,此时队空。每次有对象入队时,将其存放于 Q[r],然后 r 加一,以指向下一单元。对称地,每次有对象出队之后,也将 f 加一,指向新的队首元素。这样,对 front()、 enqueue()和 dequeue()方法的每一次调用都只需常数时间。

然而,这还不够。细心的读者或许已经注意到,按照上述约定,在队列的生命期内, f 和 r 始终在单调增加。因此,若队列数组的容量为 N,则在经过 N 次入队操作后, r 所指向的单元必然超出数组的范围;在经过 N 次出队操作后, f 所指向的单元也会出现类似的问题。

解决上述问题的一种简便方法,就是在每次 f 或 r 加一后,都要以数组的长度做取模运算,以保证其所指单元的合法性。就其效果而言,这就相当于把数组的头和尾相联,构成一个环状结构。

基于上述构想,可以得到如 下所示java代码:

Queue类:

package com.queue;

import java.util.Arrays;

/**
 *
 * @author gannyee
 *
 */
public class Queue {
    // Define capacity constant: CAPACITY
    private static final int CAPACITY = 1024;
    // Define capacity of queue
    private static int capacity;
    // Front of queue
    private static int front;
    // Tail of queue
    private static int tail;
    // Array for queue
    private static Object[] array;

    // Constructor of Queue class
    public Queue() {
        this.capacity = CAPACITY;
        array = new Object[capacity];
        front = tail = 0;
    }

    // Get size of queue
    public static int getSize() {
        if (isEmpty())
            return 0;
        else
            return (capacity + tail - front) % capacity;
    }

    // Whether is empty
    public static boolean isEmpty() {
        return (front == tail);
    }

    // put element into the end of queue
    public static void enqueue(Object element) throws ExceptionQueueFull {
        if (getSize() == capacity - 1)
            throw new ExceptionQueueFull("Queue is full");
        array[tail] = element;
        tail = (tail + 1) % capacity;
    }

    // get element from queue
    public static Object dequeue() throws ExceptionQueueEmpty {
        Object element;
        if (isEmpty())
            throw new ExceptionQueueEmpty("Queue is empty");
        element = array[front];
        front = (front + 1) % capacity;
        return element;
    }

    // Get the first element for queue
    public static Object frontElement() throws ExceptionQueueEmpty {
        if (isEmpty())
            throw new ExceptionQueueEmpty("Queue is empty");
        return array[front];
    }

    // Travel all elements of queue
    public static void getAllElements() {
        Object[] arrayList = new Object[getSize()];

        for (int i = front,j = 0; j < getSize(); i ++,j ++) {
                arrayList[j] = array[i];
        }
        System.out.println("All elements of queue: "
                + Arrays.toString(arrayList));
    }
}

自定义ExceptionStackEmpty异常类:

package com.queue;

public class ExceptionQueueEmpty extends Exception {
    // Constructor
    public ExceptionQueueEmpty() {

    }

    // Constructor with parameters
    public ExceptionQueueEmpty(String mag) {
        System.out.println(mag);
    }
}

自定义ExceptionStackFull异常类

package com.queue;

public class ExceptionQueueFull extends Exception {

    // Constructor
    public ExceptionQueueFull() {

    }

    // Constructor with parameters
    public ExceptionQueueFull(String mag) {
        System.out.println(mag);
    }
}

测试类:

package com.queue;
/**
 * QueueTest
 * @author gannyee
 *
 */
public class QueueTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Queue queue = new Queue();
        System.out.println("The size of queue is: " + queue.getSize());
        System.out.println("Is empty: " + queue.isEmpty());
        try {
            queue.enqueue(8);
            queue.enqueue(3);
            queue.enqueue(5);
            queue.enqueue(7);
            queue.enqueue(9);
            queue.getAllElements();
            System.out.println("The size of queue is: " + queue.getSize());
            System.out.println("Is empty: " + queue.isEmpty());
            System.out.println("The front element of queue: "
                    + queue.frontElement());
            System.out.println(queue.dequeue());
            System.out.println(queue.dequeue());
            System.out.println(queue.dequeue());
            System.out.println(queue.dequeue());
            System.out.println(queue.dequeue());
            System.out.println("The size of queue is: " + queue.getSize());
            System.out.println("Is empty: " + queue.isEmpty());
        } catch (ExceptionQueueFull e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ExceptionQueueEmpty e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

测试结果:

The size of queue is: 0
Is empty: true
All elements of queue: [8, 3, 5, 7, 9]
The size of queue is: 5
Is empty: false
The front element of queue: 8
8
3
5
7
9
The size of queue is: 0
Is empty: true

队列的应用:

孩提时的你是否玩过“烫手山芋”游戏:一群小孩围成一圈,有一个刚出锅的山芋在他们之间传递。其中一个孩子负责数数,每数一次,拿着山芋的孩子就把山芋转交给右边的邻居。一旦数到某个特定的数,拿着山芋的孩子就必须退出,然后重新数数。如此不断,最后剩下的那个孩子就是幸运者。通常,数数的规则总是从 1 开始,数到 k 时让拿着山芋的孩子出列,然后重新从 1 开始。Josephus问题可以表述为: n 个孩子玩这个游戏,最后的幸运者是谁?

为了解答这个问题,我们可以利用队列结构来表示围成一圈的n个孩子。一开始,假定对应于队列首节点的那个孩子拿着山芋。然后,按照游戏的规则,把“土豆”向后传递到第k个孩子(交替进行k次dequeue()和k次enqueue()操作),并让她出队( dequeue())。如此不断迭代,直到队长(getSize())为 1。

Java代码如下:

package com.queue;

public class QueueBuilder {

    // Building string type array for queue
    public static Queue queueBuild(String[] str) {
        Queue queue = new Queue();

        for (int i = 0; i < str.length; i++) {
            try {
                queue.enqueue(str[i]);
            } catch (ExceptionQueueFull e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return queue;
    }

    // Weed out the kth kid who get the sweet potato
    public static String gameWiner(Queue queue, int k)
            throws ExceptionQueueFull, ExceptionQueueEmpty {

        if (queue.isEmpty())
            return null;
        while (queue.getSize() > 1) {
            queue.getAllElements();// Output recently queue
            for (int i = 0; i < k - 1; i++)
                queue.enqueue(queue.dequeue());
            System.out.println("\n\t" + queue.dequeue() + ": Weep out");
        }
        return (String) queue.dequeue();
    }
}
package com.queue;

public class QueueGame {

    public static void main(String[] args) throws ExceptionQueueFull, ExceptionQueueEmpty {
        // TODO Auto-generated method stub
        String[] kid = {"Alice", "Bob", "Cindy", "Doug", "Ed",
                        "Fred", "Gene", "Hope", "Irene", "Jack",
                        "Kim", "Lance", "Mike", "Nancy", "Ollie"};
        QueueBuilder qb = new QueueBuilder();
        System.out.println("The luck dog is: " + qb.gameWiner(qb.queueBuild(kid), 5));
    }

}

测试结果:

All elements of queue: [Alice, Bob, Cindy, Doug, Ed, Fred, Gene, Hope, Irene, Jack, Kim, Lance, Mike, Nancy, Ollie]

    Ed: weep out
All elements of queue: [Fred, Gene, Hope, Irene, Jack, Kim, Lance, Mike, Nancy, Ollie, Alice, Bob, Cindy, Doug]

    Jack: weep out
All elements of queue: [Kim, Lance, Mike, Nancy, Ollie, Alice, Bob, Cindy, Doug, Fred, Gene, Hope, Irene]

    Ollie: weep out
All elements of queue: [Alice, Bob, Cindy, Doug, Fred, Gene, Hope, Irene, Kim, Lance, Mike, Nancy]

    Fred: weep out
All elements of queue: [Gene, Hope, Irene, Kim, Lance, Mike, Nancy, Alice, Bob, Cindy, Doug]

    Lance: weep out
All elements of queue: [Mike, Nancy, Alice, Bob, Cindy, Doug, Gene, Hope, Irene, Kim]

    Cindy: weep out
All elements of queue: [Doug, Gene, Hope, Irene, Kim, Mike, Nancy, Alice, Bob]

    Kim: weep out
All elements of queue: [Mike, Nancy, Alice, Bob, Doug, Gene, Hope, Irene]

    Doug: weep out
All elements of queue: [Gene, Hope, Irene, Mike, Nancy, Alice, Bob]

    Nancy: weep out
All elements of queue: [Alice, Bob, Gene, Hope, Irene, Mike]

    Irene: weep out
All elements of queue: [Mike, Alice, Bob, Gene, Hope]

    Hope: weep out
All elements of queue: [Mike, Alice, Bob, Gene]

    Mike: weep out
All elements of queue: [Alice, Bob, Gene]

    Bob: weep out
All elements of queue: [Gene, Alice]

    Gene: weep out
The luck dog is: Alice

文章参考:数据结构与算法( Java 描述)邓俊辉 著

转载请注明出处,谢谢!

http://blog.csdn.net/github_27609763/article/details/46434301

时间: 2024-12-09 20:19:38

基于数组实现Java 自定义Queue队列及应用的相关文章

基于链表实现Java 自定义Queue队列

与栈一样,我们也可以借助单链表来实现队列ADT.同样地,出于效率方面的考虑,我们将以单链表的首(末)节点作为队列的首(末)节点??这样,可以回避单链表在尾部进行删除操作时效率低下的缺陷.此外,还需要两个实例变量分别指示表的首.末节点. java代码如下: QueueList: package com.list.queue; import java.util.Arrays; import com.list.stack.Node; import com.list.stack.ExceptionSta

基于数组实现Java 自定义Stack栈类及应用

栈是存放对象的一种特殊容器,在插入与删除对象时,这种结构遵循后进先出( Last-in-first-out,LIFO)的原则.java本身是有自带Stack类包,为了达到学习目的已经更好深入了解stack栈,自己动手自建java stack类是个很好的学习开始: 自建Java Stack 类 Stack 类: 1 package com.stack; 2 3 import java.util.ArrayList; 4 import java.util.Arrays; 5 6 /** 7 * St

基于链表实现Java 自定义Stack队列

接下来让我们看看,如何利用单链表结构来实现栈与队列.由于栈的操作只限于栈顶元素,而单链表只有对首元素才能在O(1)时间内完成插入和删除,故这里把单链表的首节点作为栈顶,其余元素依次排列.此外,为了保证getSize()方法也能够在O(1)时间内完成,还需借助一个实例变量来动态记录栈中元素的数目.具体的实现如 代码二.12 所示. Node类 Java代码见( Java 实现链表) StackLink 类: package com.list.stack; import java.util.Arra

使用goroutine+channel和java多线程+queue队列的方式开发各有什么优缺点?

我感觉很多项目使用java或者c的多线程库+线程安全的queue数据结构基本上可以实现goroutine+channel开发能达到的需求,所以请问一下为什么说golang更适合并发服务端的开发呢?使用goroutine+channel和java多线程+queue队列的方式开发各有什么优缺点? 使用goroutine+channel和java多线程+queue队列的方式开发各有什么优缺点? >> golang 这个答案描述的挺清楚的:http://www.goodpm.net/postreply

java 多线程阻塞队列 与 阻塞方法与和非阻塞方法

Queue是什么 队列,是一种数据结构.除了优先级队列和LIFO队列外,队列都是以FIFO(先进先出)的方式对各个元素进行排序的.无论使用哪种排序方式,队列的头都是调用remove()或poll()移除元素的.在FIFO队列中,所有新元素都插入队列的末尾.队列都是线程安全的,内部已经实现安全措施,不用我们担心 Queue中的方法 Queue中的方法不难理解,6个,每2对是一个也就是总共3对.看一下JDK API就知道了: 注意一点就好,Queue通常不允许插入Null,尽管某些实现(比如Link

atitit. java queue 队列体系and自定义基于数据库的队列总结o7t

atitit. java queue 队列体系and自定义基于数据库的队列总结o7t 1. 阻塞队列和非阻塞队列 1 2. java.util.Queue接口, 1 3. ConcurrentLinkedQueue 2 4. BlockingQueue阻塞队列 2 4.1. 1. ArrayBlockingQueue 3 4.2. 2. LinkedBlockingQueue 3 4.3. 3. DelayQueue 3 4.4. 4. PriorityBlockingQueue 3 4.5. 

基于双链表 实现Java Queue队列

除了可以通过一维数组,单链表实现queue队列,还可以通过双链表实现queue队列. 在基于NLNode类实现双向链表的时候,为了使编程更加简洁,通常我们都要在最前端和最后端各设置一个哑元节点( Dummy node ).这两个节点分别称作头节点( Header node )和尾节点( Trailer node) ㈠,起哨兵( Sentinel)的作用.也就是说,它们并不存储任何实质的数据对象,头(尾)节点的next( prev)引用指向首(末)节点,而prev(next)引用为空.如此构成的双

教你如何使用Java手写一个基于数组实现的队列

一.概述 队列,又称为伫列(queue),是先进先出(FIFO, First-In-First-Out)的线性表.在具体应用中通常用链表或者数组来实现.队列只允许在后端(称为rear)进行插入操作,在前端(称为front)进行删除操作.队列的操作方式和堆栈类似,唯一的区别在于队列只允许新数据在后端进行添加. 在Java中队列又可以分为两个大类,一种是阻塞队列和非阻塞队列. 1.没有实现阻塞接口: 1)实现java.util.Queue的LinkList, 2)实现java.util.Abstra

atitit. java queue 队列体系and自己定义基于数据库的队列总结o7t

atitit. java queue 队列体系and自己定义基于数据库的队列总结o7t 1. 堵塞队列和非堵塞队列 1 2. java.util.Queue接口. 1 3. ConcurrentLinkedQueue 2 4. BlockingQueue堵塞队列 2 4.1. 1. ArrayBlockingQueue 3 4.2. 2. LinkedBlockingQueue 3 4.3. 3. DelayQueue 3 4.4. 4. PriorityBlockingQueue 3 4.5.