CS61B project 1 笔记

本文介绍了Java中队列的两种常见实现方式:带哨兵的双向链表和循环数组。带哨兵链表利用sentinel节点简化头尾判断,循环数组利用位操作提升满队列判断效率并支持动态扩容。同时提到ArrayDeque在头部出队和尾部入队的高效性能,以及可能的缩容策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

队列这种数据结构的物理实现一般是两种,一种是链表,一种是数组。

1. 带哨兵的双向链表

使用一个sentinel来代替之前的head头指针,sentinel的item没有实际的意义,主要关注它的next和pre,初始的时候,链表只有一个sentinel节点,sentinel.next指向自己,sentinel.pre也指向自己。当添加了若干个节点之后,sentinel.next指向头节点,而sentinel.pre则指向尾节点;而同样的,这时头节点的pre不再是NULL而是指向sentinel,尾节点的next也不再是NULL,也是指向sentinel。

不需要标明队头和队尾,在操作的时候想清楚增加哪些指向和删除哪些指向即可。

2. 循环数组

nextLast到达尾端时通过取模可以回到初始位置,通过判断nextLast+1是否等于nextFirst来判断队列满。(其实还有一个空位置

入队操作

public void addLast(T item) {
    if (item == null)
        throw new NullPointerException();
    array[nextLast] = item;
    if ((nextLast = (nextLast + 1) & (elements.length - 1)) == nextFirst)
    doubleCapacity();
)

在构造的时候会让arry的长度为2的指数值,可以提高入队的效率,因为对于任意一个2的指数级的值减去1之后必然所有位全为1,例如:8-1之后为111,16-1之后1111。而对于nextLast来说,当nextLast+1小于等于array.length - 1,两者与完之后的结果还是nextLast+1,但是如果大于array.length - 1,两者与完之后就为0,回到初始位置。这种判断队列是否满的方式要远远比使用符号%直接取模高效。如果队列满,会调用扩充容量的方法。

private void doubleCapacity() {
    assert nextFirst== nextLast;
    int p = nextFirst;
    int n = array.length;
    int r = n - p; 
    int newCapacity = n << 1;
    if (newCapacity < 0)
        throw new IllegalStateException("Sorry");
    Object[] a = new Object[newCapacity];
    System.arraycopy(elements, p, a, 0, r);
    System.arraycopy(elements, 0, a, r, p);
    array = a;
    nextFirst= 0;
    nextLast = n;
}

n << 1就是乘2的动作。

出队操作

public T removeLast() {
    T x = pollLast(); // 调用pollLast方法
    if (x == null)
        throw new NoSuchElementException();
    return x;
}

public T pollLast() {
    int t = (nextLast- 1) & (elements.length - 1); // 尾索引 -1
    @SuppressWarnings("unchecked")
    T result = (T) array[t]; // 根据尾索引,得到尾元素
    if (result == null)
        return null;
    array[t] = null; // 尾元素置空
    nextLast= t;
    return result;
}

ArrayDeque的主要优势在于尾部添加元素,头部出队元素的效率是比较高的,内部使用位操作来判断队满条件,效率相对有所提高,并且该结构使用动态扩容,所以对队列长度也是没有限制的。

还应该加上缩容,比如当size小于length的四分之一时,减小数组长度

Q: I can’t get Java to create an array of generic objects!

A: Use the strange syntax we saw in January 30th’s lecture,
i.e. T[] a = (T[]) new Object[1000];. Here, T is a generic type, it’s a placeholder for other Object types like “String” or “Integer”.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值