【java容器的刻意練習(xí)】【十四】ArrayDeque的源碼分析(二)

上一篇看了ArrayDeque的添加元素,這篇我們來看刪除元素是怎樣實現(xiàn)的。

    /**
     * @throws NoSuchElementException {@inheritDoc}
     */
    public E removeFirst() {
        E e = pollFirst();
        if (e == null)
            throw new NoSuchElementException();
        return e;
    }

原來removeFirst調(diào)用了pollFirst,我們來看看pollFirst

    public E pollFirst() {
        final Object[] es;
        final int h;
        E e = elementAt(es = elements, h = head);
        if (e != null) {
            es[h] = null;
            head = inc(h, es.length);
        }
        return e;
    }

調(diào)用了elementAtelements獲取了head位置的元素:

    static final <E> E elementAt(Object[] es, int i) {
        return (E) es[i];
    }

因為是數(shù)組,所以直接通過下標(biāo)訪問即可,時間復(fù)雜度O(1)。

然后將head元素置空,通過head = inc(h, es.length);將head位置加一。如果超過數(shù)組長度,根據(jù)循環(huán)數(shù)組的特點,變?yōu)閿?shù)組第0個下標(biāo)。

pollLast實現(xiàn)也是差不多的,就不多啰嗦了。

peekFirst、peekLast就更簡單了,直接通過elementAt通過數(shù)組下標(biāo)快速訪問元素即可:

    public E peekFirst() {
        return elementAt(elements, head);
    }

    public E peekLast() {
        final Object[] es;
        return elementAt(es = elements, dec(tail, es.length));
    }

由于是數(shù)組,所以極度不推薦刪除元素的,所以removeFirstOccurrenceremoveLastOccurrence這2個極度浪費性能操作能不用盡量不用。

    /**
     * Removes the first occurrence of the specified element in this
     * deque (when traversing the deque from head to tail).
     * If the deque does not contain the element, it is unchanged.
     * More formally, removes the first element {@code e} such that
     * {@code o.equals(e)} (if such an element exists).
     * Returns {@code true} if this deque contained the specified element
     * (or equivalently, if this deque changed as a result of the call).
     *
     * @param o element to be removed from this deque, if present
     * @return {@code true} if the deque contained the specified element
     */
    public boolean removeFirstOccurrence(Object o) {
        if (o != null) {
            final Object[] es = elements;
            for (int i = head, end = tail, to = (i <= end) ? end : es.length;
                 ; i = 0, to = end) {
                for (; i < to; i++)
                    if (o.equals(es[i])) {
                        delete(i);
                        return true;
                    }
                if (to == end) break;
            }
        }
        return false;
    }

這個removeFirstOccurrence就是刪除第一個找到的元素。如果雙端隊列不包含某個元素,那么就不會變。如果該元素被刪除,就會使得數(shù)組的元素向前或向后運動。 delete函數(shù)作者已經(jīng)優(yōu)化了算法,使得每次挪動最少的元素。

    /**
     * Removes the element at the specified position in the elements array.
     * This can result in forward or backwards motion of array elements.
     * We optimize for least element motion.
     *
     * <p>This method is called delete rather than remove to emphasize
     * that its semantics differ from those of {@link List#remove(int)}.
     *
     * @return true if elements near tail moved backwards
     */
    boolean delete(int i) {
        final Object[] es = elements;
        final int capacity = es.length;
        final int h, t;
        // number of elements before to-be-deleted elt
        final int front = sub(i, h = head, capacity);
        // number of elements after to-be-deleted elt
        final int back = sub(t = tail, i, capacity) - 1;
        if (front < back) {
            // move front elements forwards
            if (h <= i) {
                System.arraycopy(es, h, es, h + 1, front);
            } else { // Wrap around
                System.arraycopy(es, 0, es, 1, i);
                es[0] = es[capacity - 1];
                System.arraycopy(es, h, es, h + 1, front - (i + 1));
            }
            es[h] = null;
            head = inc(h, capacity);
            return false;
        } else {
            // move back elements backwards
            tail = dec(t, capacity);
            if (i <= tail) {
                System.arraycopy(es, i + 1, es, i, back);
            } else { // Wrap around
                System.arraycopy(es, i + 1, es, i, capacity - (i + 1));
                es[capacity - 1] = es[0];
                System.arraycopy(es, 1, es, 0, t - 1);
            }
            es[tail] = null;
            return true;
        }
    }

每刪除一個元素,都要挪動其他元素,非常劃不來。那如果用了ArrayDeque,但是迫不得已要刪除元素,怎么辦?我建議在保存的元素Object里面添加一個叫isDelete的boolean屬性。使用前先判斷isDelete即可。這就像居委大媽跟普通大媽區(qū)別,就是袖子上多一個紅袖標(biāo),大大寫著“居委”兩字。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容