关于队列的基础知识

2018-04-04  本文已影响10人  四喜汤圆

一、队列的特点

  1. 先进先出:从队尾进、队头出。

二、队列的实现

需提供的方法
// 队是否为空
public boolean isEmpty() 
// 从队尾进队(用数组实现时:若队满则扩充容量后进队)
public void enqueue(E data) 
// 返回并删除队头出队
public E dequeue()
// 返回队头元素,但不删除
public E peek()
// 打印队中元素
public void print()

2.1 基于数组实现顺序队列(泛型)

维护队头指针head,队尾指针tail,初始值都为-1。
进队时:先将tail加1,将元素放在该位置;
出队时:head加1,返回该位置元素。(有的文章中说将头指针和尾指针初始化为0,都可以,此处用-1初始化)

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.NoSuchElementException;

/**
 * 
 * <p>
 * Description: 队列:用数组、泛型实现
 * </p>
 * 
 * @author 杨丽金
 * @date 2018-4-1
 * @version 1.0
 */
public class MyQueue_array_generic<E> {
    // 用数组存储队列元素
    E[] queue;
    // 队头指针
    int head = -1;

    // 队尾指针
    int tail = -1;
    // 默认数组容量
    private static final int DEFAULT_SIZE = 3;

    // 构造函数中进行初始化
    public MyQueue_array_generic(Class<E> type) {
        this(type, DEFAULT_SIZE);
    }

    public MyQueue_array_generic(Class<E> type, int size) {
        queue = (E[]) Array.newInstance(type, size);
    }

    /**
     * 从队尾进队
     * 
     * @param data
     */
    public void enqueue(E data) {
        ensureCapacity();
        queue[++tail] = data;

    }

    private void ensureCapacity() {
        if (isFull()) {
            int newLength = queue.length * 2;
            queue = Arrays.copyOf(queue, newLength);
        }
    }

    /**
     * 返回并删除队头出队
     * 
     * @return
     */
    public E dequeue(){
        E r=peek();
        head++;
        return r;
    }
    
    /**
     * 返回队头元素,但不删除
     * @return
     */
    public E peek(){
        if(isEmpty()){
            throw new NoSuchElementException();
        }else{
            return queue[head+1];
        }
    }

    /**
     * 队是否为空
     * 
     * @return
     */
    public boolean isEmpty() {
        return tail==head;
    }

    /**
     * 是否满
     * 
     * @return
     */
    public boolean isFull() {
        return tail == queue.length - 1;
    }
    
    /**
     * 打印队中元素
     */
    public void print(){
        if(isEmpty()){
            return;
        }else{
            int cur=head+1;
            // 
            while(cur!=(tail+1)){// 循环条件
                System.out.print(queue[cur++]+" ");// 迭代条件
            }
        }
        System.out.println();
    }
    
    public static void main(String[] args) {
        MyQueue_array_generic<Integer> q=new MyQueue_array_generic<Integer>(Integer.class);
        q.enqueue(1);
        q.enqueue(2);
        q.enqueue(3);
        q.enqueue(4);
        q.enqueue(5);
        q.enqueue(6);
        q.print();
        System.out.println(String.format("队头元素为:%s", q.peek()));
        q.dequeue();
        q.dequeue();
        q.print();
        System.out.println(String.format("队头元素为:%s", q.peek()));
    }

}

运行结果.png

2.2 基于链表实现顺序队列

维护队头指针head,队尾指针tail,初始值都为null。队空状态为:head==null

import java.util.NoSuchElementException;

/**
 * 
 * <p>
 * Description: 队列:用链表、泛型实现
 * </p>
 * 
 * @author 杨丽金
 * @date 2018-4-1
 * @version 1.0
 */
public class MyQueue_linkedList<E> {
    class Node {
        // 数据域
        E data;
        // 指针域
        Node next;

        public Node(E data) {
            this.data = data;
        }
    }

    // 队头指针
    private Node head = null;
    // 队尾指针
    private Node tail = null;

    // 从队尾进队
    public void enqueue(E data) {
        Node newNode = new Node(data);
        if (isEmpty()) {
            // 若队为空,则将head和tail都指向节点
            // 队列是从队尾入队,但队为空时入队要把head指向新节点(因为不指向的话head没法和队列关联起来)
            head = newNode;
            tail = newNode;
        } else {
            // 若不为空,则将tail.next指向新节点,tail指向新节点
            tail.next = newNode;
            tail = newNode;
        }
    }

    // 返回并删除队头出队
    public E dequeue() {
        E r = peek();
        head = head.next;
        return r;
    }

    // 返回队头元素的值,但不删除
    public E peek() {
        if (isEmpty()) {
            throw new NoSuchElementException();
        } else {
            return head.data;
        }
    }

    // 打印队中元素
    public void print() {
        Node cur = head;
        while (cur != tail) {
            System.out.print(cur.data + " ");
            cur = cur.next;// 迭代条件
        }
        System.out.println(tail.data);
    }

    // 队是否为空
    public boolean isEmpty() {
        // head为空说明队列中没元素了
        return head == null;
    }

    public static void main(String[] args) {
        MyQueue_linkedList<Integer> q = new MyQueue_linkedList<Integer>();
        q.enqueue(1);
        q.enqueue(2);
        q.enqueue(3);
        q.enqueue(4);
        q.enqueue(5);
        q.enqueue(6);
        q.print();
        System.out.println(String.format("队头元素为:%s", q.peek()));
        q.dequeue();
        q.dequeue();
        q.print();
        System.out.println(String.format("队头元素为:%s", q.peek()));
    }

}

2.3 循环队列

普通的队列存在的情况是队尾指针已经=length-1,为队满状态,但前面还有很多闲置空间, 造成假溢出,即数组空间还有很多、但队列已经是满的状态不能入队,所以用循环队列改进。
特点:1. 循环队列必须损失一个存储空间,否则无法区分对空队满状态

/**
 * 
 * <p>
 * Description: 循环队列,基于int[]实现
 * </p>
 * 
 * @author 杨丽金
 * @date 2018-4-2
 * @version 1.0
 */
public class MyCircleQueue_array_int {

    // 默认数组长度
    private static final int MAX_SIZE = 4;
    // 数组存储队列元素
    private int[] queue;
    // 队头指针(循环队列,就要损失一个存储空间)
    private int head = 0;
    // 队尾指针
    private int tail = 0;

    public MyCircleQueue_array_int() {
        // 初始化操作
        queue = new int[MAX_SIZE];
    }

    /**
     * 从队尾进队,队满则扩充容量后再进队
     * 
     * @param data
     * @throws Exception
     */
    public void enqueue(int data) throws Exception {
        if (isFull()) {
            throw new Exception("队列已满不可入队");
        }
        tail = (tail + 1) % MAX_SIZE;
        queue[tail] = data;
    }

    private boolean isFull() {
        return (tail + 1) % MAX_SIZE == head;
    }

    /**
     * 返回并删除队头出队
     * 
     * @return
     * @throws Exception 
     */
    public int dequeue() throws Exception {
        int r = peek();
        head = (head + 1) % MAX_SIZE;
        return r;
    }

    /**
     * 返回队头元素,但不删除
     * 
     * @return
     * @throws Exception 
     */
    public int peek() throws Exception {
        if (isEmpty()) {
            throw new Exception("当前队列为空");
        } else {
            return queue[(head + 1) % MAX_SIZE];
        }
    }

    // 队是否为空
    public boolean isEmpty() {
        return head == tail;
    }

    // 从队尾进队(用数组实现时:若队满则扩充容量后进队)
    // 打印队中元素
    public void print() {
        if (isEmpty()) {
            System.out.println("当前队列为空");
        } else {
            int i = head + 1;
            while (i <= tail) {
                System.out.print(queue[i] + " ");
                i++;// 迭代条件
            }
        }
        System.out.println();
    }
    
    public static void main(String[] args) {
        MyCircleQueue_array_int m= new MyCircleQueue_array_int();
        try {
            m.enqueue(1);
            m.enqueue(2);
            m.enqueue(3);
//          m.enqueue(4);// 因为MAX_SIZE=4,故队列中最多可放3个元素
            m.print();
            System.out.println("队头元素:"+m.peek());
            // 将1出队
            m.dequeue();
            m.print();// 2,3
            // 将2出队
            m.dequeue();// 3
            m.print();
            // 将3出队
            m.dequeue();
            m.print();// 队空
            m.dequeue();// 抛出异常
            m.print();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
}

三、队列的应用

  1. 树的层次遍历
上一篇 下一篇

猜你喜欢

热点阅读