循环队列

为充分利用向量空间,克服”假溢出”现象的方法是:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列称为循环队列(Circular Queue)。循环队列是把顺序队列首尾相连,把存储队列元素的表从逻辑上看成一个环,成为循环队列。

数组队列的时间复杂度为O(n),循环队列的时间复杂度为O(1)。
代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
public class LoopQueue<E> implements Queue<E> {
    private E[] data;//泛型数组
    private int tail;//尾部指针,初始化为0
    private int front;//头部指针,初始化为0
    private int size;//数据长度,初始化为0

    public LoopQueue(int capacity){
        data = (E[]) new Object[capacity + 1];//预留一个位置给tail,防止数组装满时tail 等于 front
    }
    public LoopQueue(){
        this(10);
    }

    //获取循环队列的容量
    public int getCapacity(){
        return data.length - 1;
    }

    //获取数据长度
    @Override
    public int getSize() {
        return size;
    }

    //判断循环队列是否为空
    @Override
    public boolean isEmpty() {
        return tail == front;//return size == 0;
    }

    //将元素e插入队列
    @Override
    public void enqueue(E e) {
        if((tail+1) % data.length == front)//判断数组是否装满
            changeLoopQueue(2*getCapacity());//将循环队列的容量增加至原来的两倍
        data[tail] = e;
        tail = (tail + 1) % data.length; //防止tail溢出
        size ++;
    }

    //改变循环队列的容量
    private void changeLoopQueue(int capacity) {
        E[] newData = (E[]) new Object[capacity + 1];
        for (int i = 0; i < size ; i++) {
            newData[i]  = data[(i + front) % data.length];//可以将循环队列按照从头部到尾部顺序重新赋值入新数组
        }
        data = newData;
        front = 0; //front要置0
        tail = size;
    }

    //出队
    @Override
    public E dequeue() {
        if(size == 0)
            throw new IllegalArgumentException("当前队列没有元素");
        else if(size == getCapacity() / 4 && (getCapacity() / 2 ) != 0)//不要忘了(getCapacity() / 2 ) != 0,防止创建容量为0的数组
            changeLoopQueue(getCapacity() / 2);
        E e = data[front];
        data[front] = null; //将出队元素置空
       front = (front + 1) % data.length; // 错误想法:(貌似不用 (front + 1) % data.length;   front也不会溢出 ,因为有size控制。),因为当有元素出队时(size!=0),此时再有元素入队,占用先前出队元素的位置,那么front就需要循环回此时的数组索引
        size --;
        return e;
    }

    @Override
    public E getFront() {
        if(size == 0)
            throw new IllegalArgumentException("当前队列没有元素");
        return data[front];
    }

    @Override
    public String toString() {
        StringBuilder str = new StringBuilder();
        str.append(String.format("Array: size = %d , capacity = %d\n ",size,getCapacity()));
        str.append("LoopQueue : ");
        str.append("front [");
        for (int i = front; i != tail % data.length ; i = (i+1) % data.length) {
            str.append(data[i]);
            if ((i + 1) % data.length != tail)//判断是否为队列中的最后一个元素
                str.append(", ");
        }
        str.append("] tail");
        return str.toString();
    }
}

使用接口Queue:

1
2
3
4
5
6
7
public interface Queue<E> {
    int getSize();//获取数据长度
    boolean isEmpty();//判断队列是否为空
    void enqueue(E e);//入队列
    E dequeue();//出队列
    E getFront();//获取队列头部元素
}

测试结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class Test {
    public static void main(String[] args) {
        LoopQueue<Integer> queue = new LoopQueue<>();
        for (int i = 0; i < 11; i++) {
            queue.enqueue(i);
            System.out.println(queue);
        }

        for (int i = 0; i < 11; i++) {
            queue.dequeue();
            System.out.println(queue);
        }
    }
}
输出结果:
LoopQueue: size = 1 , capacity = 10
 front [0] tail
LoopQueue: size = 2 , capacity = 10
 front [0, 1] tail
LoopQueue: size = 3 , capacity = 10
 front [0, 1, 2] tail
LoopQueue: size = 4 , capacity = 10
 front [0, 1, 2, 3] tail
LoopQueue: size = 5 , capacity = 10
 front [0, 1, 2, 3, 4] tail
LoopQueue: size = 6 , capacity = 10
 front [0, 1, 2, 3, 4, 5] tail
LoopQueue: size = 7 , capacity = 10
 front [0, 1, 2, 3, 4, 5, 6] tail
LoopQueue: size = 8 , capacity = 10
 front [0, 1, 2, 3, 4, 5, 6, 7] tail
LoopQueue: size = 9 , capacity = 10
 front [0, 1, 2, 3, 4, 5, 6, 7, 8] tail
LoopQueue: size = 10 , capacity = 10
 front [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] tail
LoopQueue: size = 11 , capacity = 20
 front [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] tail
LoopQueue: size = 10 , capacity = 20
 front [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] tail
LoopQueue: size = 9 , capacity = 20
 front [2, 3, 4, 5, 6, 7, 8, 9, 10] tail
LoopQueue: size = 8 , capacity = 20
 front [3, 4, 5, 6, 7, 8, 9, 10] tail
LoopQueue: size = 7 , capacity = 20
 front [4, 5, 6, 7, 8, 9, 10] tail
LoopQueue: size = 6 , capacity = 20
 front [5, 6, 7, 8, 9, 10] tail
LoopQueue: size = 5 , capacity = 20
 front [6, 7, 8, 9, 10] tail
LoopQueue: size = 4 , capacity = 10
 front [7, 8, 9, 10] tail
LoopQueue: size = 3 , capacity = 10
 front [8, 9, 10] tail
LoopQueue: size = 2 , capacity = 10
 front [9, 10] tail
LoopQueue: size = 1 , capacity = 5
 front [10] tail
LoopQueue: size = 0 , capacity = 2
 front [] tail

谢谢你请我吃糖果

支付宝
微信
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值