มีคิวขนาดคงที่ซึ่งจะลบองค์ประกอบที่มากเกินไปหรือไม่?


128

ฉันต้องการคิวที่มีขนาดคงที่ เมื่อฉันเพิ่มองค์ประกอบและคิวเต็มมันควรจะลบองค์ประกอบที่เก่าที่สุดโดยอัตโนมัติ

มีการนำไปใช้งานสำหรับสิ่งนี้ใน Java หรือไม่?


1
วิธีการเกี่ยวกับstackoverflow.com/a/6058025/1392882
มิเกล

คำตอบ:


19

ไม่มีการนำไปใช้งานในภาษา Java และรันไทม์ คิวทั้งหมดขยายAbstractQueueและเอกสารระบุชัดเจนว่าการเพิ่มองค์ประกอบในคิวแบบเต็มจะลงท้ายด้วยข้อยกเว้นเสมอ จะเป็นการดีที่สุด (และค่อนข้างง่าย) ที่จะรวม Queue ไว้ในคลาสของคุณเองเพื่อให้มีฟังก์ชันที่คุณต้องการ

อีกครั้งเนื่องจากคิวทั้งหมดเป็นลูกของ AbstractQueue เพียงใช้สิ่งนั้นเป็นประเภทข้อมูลภายในของคุณและคุณควรมีการใช้งานที่ยืดหยุ่นในแทบจะไม่มีเวลา :-)

UPDATE:

ตามที่ระบุไว้ด้านล่างมีการใช้งานแบบเปิดอยู่สองแบบ (คำตอบนี้ค่อนข้างเก่าคน!) ดูรายละเอียดคำตอบนี้


4
ใช้ Queue แทน AbstractQueue ... อาจมีคิวที่ใช้อินเทอร์เฟซ แต่ไม่ขยายคลาสนามธรรม
TofuBeer

1
ใน Python คุณสามารถใช้ a collection.dequeกับไฟล์maxlen.
Jonas Gröger

2
อัปเดตตอนนี้มีสองคลาสดังกล่าว ไม่จำเป็นต้องเขียนของคุณเอง ดูคำตอบของฉันในหน้านี้
Basil Bourque

108

ที่จริงแล้วLinkedHashMapทำในสิ่งที่คุณต้องการ คุณต้องลบล้างremoveEldestEntryเมธอด

ตัวอย่างสำหรับคิวที่มีองค์ประกอบสูงสุด 10 รายการ:

  queue = new LinkedHashMap<Integer, String>()
  {
     @Override
     protected boolean removeEldestEntry(Map.Entry<Integer, String> eldest)
     {
        return this.size() > 10;   
     }
  };

ถ้า "removeEldestEntry" คืนค่าเป็นจริงรายการที่เก่าที่สุดจะถูกลบออกจากแผนที่


7
สิ่งนี้ไม่ได้ทำในสิ่งที่คิวทำฉันจะดึงข้อมูลใหม่ล่าสุดได้อย่างไร วัตถุ?
Alex

69

ใช่สอง

จากคำถามที่ซ้ำกันของฉันเองกับคำตอบที่ถูกต้องนี้ฉันได้เรียนรู้สองข้อ:


ฉันใช้ประโยชน์จากฝรั่งEvictingQueueได้ผลดี

เพื่อสร้างอินสแตนซ์การEvictingQueueโทรด้วยวิธีโรงงานแบบคงที่createและระบุขนาดสูงสุดของคุณ

EvictingQueue< Person > people = com.google.common.collect.EvictingQueue.create( 100 ) ;  // Set maximum size to 100. 

... และถ้าคุณไม่สามารถใช้ Commons Collection 4.0 ได้ CircularFifoBuffer จะคล้ายกับ CircularFifoQueue ใน v 3.0
Sridhar Sarnobat

CircularFifoQueueลิงค์ตายใช้แทนcommons.apache.org/proper/commons-collections/apidocs/org/…
user7294900

@ user7294900 ขอบคุณลิงค์คงที่ FYI Stack Overflow ขอเชิญคุณทำการแก้ไขดังกล่าวโดยตรงกับคำตอบด้วยตัวคุณเอง ทุกคนสามารถแก้ไขได้ไม่ใช่เฉพาะผู้เขียนต้นฉบับ Stack Overflow มีจุดมุ่งหมายเพื่อให้เหมือนกับ Wikipedia ในเรื่องนั้น
Basil Bourque

@BasilBourque ใช่ แต่การแก้ไขดังกล่าวอาจถูกปฏิเสธได้แม้กระทั่งฉันเมื่อเปลี่ยนลิงก์มันเป็นพื้นที่สีเทา
user7294900

18

ฉันเพิ่งใช้คิวขนาดคงที่ด้วยวิธีนี้:

public class LimitedSizeQueue<K> extends ArrayList<K> {

    private int maxSize;

    public LimitedSizeQueue(int size){
        this.maxSize = size;
    }

    public boolean add(K k){
        boolean r = super.add(k);
        if (size() > maxSize){
            removeRange(0, size() - maxSize);
        }
        return r;
    }

    public K getYoungest() {
        return get(size() - 1);
    }

    public K getOldest() {
        return get(0);
    }
}

1
มันควรจะเป็นremoveRange(0, size() - maxSize)
Ahmed Hegazy

@AhmedHegazy removeRange (0, size () - maxSize - 1) ถูกต้อง
Ashish Doneriya

ฉันเห็นด้วยกับ Amhed ข้างต้น ลบ - 1 มิฉะนั้นที่ความจุสูงสุดคุณจะจบลงด้วยอาร์เรย์ที่มีขนาด maxSize + 1 เนื่องจากเรากำลังพูดถึง 0 ตาม ตัวอย่างเช่น ถ้า maxSize = 50 เมื่อเพิ่มออบเจ็กต์ใหม่สูตร removeRange ในโพสต์ต้นฉบับจะเป็น 51 - 50 - 1 = 0 (เช่นไม่มีอะไรลบออก)
Etep

8

นี่คือสิ่งที่ฉันทำกับการQueueห่อด้วยLinkedListขนาดคงที่ซึ่งฉันให้ไว้ที่นี่คือ 2;

public static Queue<String> pageQueue;

pageQueue = new LinkedList<String>(){
            private static final long serialVersionUID = -6707803882461262867L;

            public boolean add(String object) {
                boolean result;
                if(this.size() < 2)
                    result = super.add(object);
                else
                {
                    super.removeFirst();
                    result = super.add(object);
                }
                return result;
            }
        };


....
TMarket.pageQueue.add("ScreenOne");
....
TMarket.pageQueue.add("ScreenTwo");
.....

4

ฉันคิดว่าสิ่งที่คุณกำลังอธิบายคือคิววงกลม นี่คือตัวอย่างและที่นี่เป็นที่ดีขึ้นอย่างใดอย่างหนึ่ง


4

คลาสนี้ทำงานโดยใช้องค์ประกอบแทนการสืบทอด (คำตอบอื่น ๆ ที่นี่) ซึ่งจะลบความเป็นไปได้ของผลข้างเคียงบางอย่าง (ตามที่ Josh Bloch กล่าวไว้ใน Essential Java) การตัดแต่งของ LinkedList พื้นฐานเกิดขึ้นกับวิธีการ add, addAll และ offer

import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;

public class LimitedQueue<T> implements Queue<T>, Iterable<T> {

    private final int limit;
    private final LinkedList<T> list = new LinkedList<T>();

    public LimitedQueue(int limit) {
        this.limit = limit;
    }

    private boolean trim() {
        boolean changed = list.size() > limit;
        while (list.size() > limit) {
            list.remove();
        }
        return changed;
    }

    @Override
    public boolean add(T o) {
        boolean changed = list.add(o);
        boolean trimmed = trim();
        return changed || trimmed;
    }

    @Override
    public int size() {
        return list.size();
    }

    @Override
    public boolean isEmpty() {
        return list.isEmpty();
    }

    @Override
    public boolean contains(Object o) {
        return list.contains(o);
    }

    @Override
    public Iterator<T> iterator() {
        return list.iterator();
    }

    @Override
    public Object[] toArray() {
        return list.toArray();
    }

    @Override
    public <T> T[] toArray(T[] a) {
        return list.toArray(a);
    }

    @Override
    public boolean remove(Object o) {
        return list.remove(o);
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        return list.containsAll(c);
    }

    @Override
    public boolean addAll(Collection<? extends T> c) {
        boolean changed = list.addAll(c);
        boolean trimmed = trim();
        return changed || trimmed;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        return list.removeAll(c);
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        return list.retainAll(c);
    }

    @Override
    public void clear() {
        list.clear();
    }

    @Override
    public boolean offer(T e) {
        boolean changed = list.offer(e);
        boolean trimmed = trim();
        return changed || trimmed;
    }

    @Override
    public T remove() {
        return list.remove();
    }

    @Override
    public T poll() {
        return list.poll();
    }

    @Override
    public T element() {
        return list.element();
    }

    @Override
    public T peek() {
        return list.peek();
    }
}

3
public class CircularQueue<E> extends LinkedList<E> {
    private int capacity = 10;

    public CircularQueue(int capacity){
        this.capacity = capacity;
    }

    @Override
    public boolean add(E e) {
        if(size() >= capacity)
            removeFirst();
        return super.add(e);
    }
}

การใช้งานและผลการทดสอบ:

public static void main(String[] args) {
    CircularQueue<String> queue = new CircularQueue<>(3);
    queue.add("a");
    queue.add("b");
    queue.add("c");
    System.out.println(queue.toString());   //[a, b, c]

    String first = queue.pollFirst();       //a
    System.out.println(queue.toString());   //[b,c]

    queue.add("d");
    queue.add("e");
    queue.add("f");
    System.out.println(queue.toString());   //[d, e, f]
}

0

ดูเหมือนรายการธรรมดาที่วิธีการเพิ่มมีส่วนย่อยเพิ่มเติมซึ่งจะตัดทอนรายการหากยาวเกินไป

หากง่ายเกินไปคุณอาจต้องแก้ไขคำอธิบายปัญหาของคุณ


จริงๆแล้วเขาจะต้องลบองค์ประกอบแรก (เช่นแรกสุด) การตัดทอนจะลบองค์ประกอบสุดท้าย ยังคงใช้งานได้จริงกับ LinkedList
MAK


0

ยังไม่ชัดเจนว่าคุณมีข้อกำหนดใดบ้างที่ทำให้คุณต้องถามคำถามนี้ หากคุณต้องการโครงสร้างข้อมูลขนาดคงที่คุณอาจต้องการดูนโยบายการแคชที่แตกต่างกัน อย่างไรก็ตามเนื่องจากคุณมีคิวการคาดเดาที่ดีที่สุดของฉันคือคุณกำลังมองหาฟังก์ชันการทำงานของเราเตอร์บางประเภท ในกรณีนั้นฉันจะใช้วงแหวนบัฟเฟอร์: อาร์เรย์ที่มีดัชนีตัวแรกและตัวสุดท้าย เมื่อใดก็ตามที่มีการเพิ่มองค์ประกอบคุณเพียงแค่เพิ่มดัชนีองค์ประกอบสุดท้ายและเมื่อนำองค์ประกอบออกให้เพิ่มดัชนีองค์ประกอบแรก ในทั้งสองกรณีการเพิ่มจะดำเนินการโมดูโลขนาดอาร์เรย์และตรวจสอบให้แน่ใจว่าได้เพิ่มดัชนีอื่นเมื่อจำเป็นนั่นคือเมื่อคิวเต็มหรือว่างเปล่า

นอกจากนี้หากเป็นแอปพลิเคชันประเภทเราเตอร์คุณอาจต้องการทดลองใช้อัลกอริทึมเช่น Random Early Dropping (RED) ซึ่งจะดร็อปองค์ประกอบจากคิวแบบสุ่มก่อนที่มันจะเต็ม ในบางกรณีพบว่า RED มีประสิทธิภาพโดยรวมดีกว่าวิธีง่ายๆในการปล่อยให้คิวเต็มก่อนที่จะวาง


0

จริงๆแล้วคุณสามารถเขียน im ของคุณเองตาม LinkedList มันค่อนข้างตรงไปตรงมาเพียงแค่ลบล้างวิธีการเพิ่มและให้เจ้าหน้าที่


0

ฉันคิดว่าคำตอบที่ตรงกันที่สุดมาจากคำถามอื่น ๆนี้

Apache commons คอลเลกชัน 4 มีCircularFifoQueueซึ่งเป็นสิ่งที่คุณกำลังมองหา อ้างถึง javadoc:

CircularFifoQueue เป็นคิวแรกเข้าก่อนออกโดยมีขนาดคงที่ซึ่งจะแทนที่องค์ประกอบที่เก่าที่สุดหากเต็ม


0

วิธีง่ายๆด้านล่างคือคิวของ "String"

LinkedHashMap<Integer, String> queue;
int queueKeysCounter;

queue.put(queueKeysCounter++, "My String");
queueKeysCounter %= QUEUE_SIZE;

โปรดทราบว่าสิ่งนี้จะไม่คงลำดับของรายการในคิว แต่จะแทนที่รายการที่เก่าที่สุด


0

ตามคำแนะนำใน OOPs ว่าเราควรชอบComposition มากกว่า Inheritance

นี่คือทางออกของฉันโดยคำนึงถึงสิ่งนั้น

package com.choiceview;

import java.util.ArrayDeque;

class Ideone {
    public static void main(String[] args) {
        LimitedArrayDeque<Integer> q = new LimitedArrayDeque<>(3);
        q.add(1);
        q.add(2);
        q.add(3);
        System.out.println(q);

        q.add(4);
        // First entry ie 1 got pushed out
        System.out.println(q);
    }
}

class LimitedArrayDeque<T> {

    private int maxSize;
    private ArrayDeque<T> queue;

    private LimitedArrayDeque() {

    }

    public LimitedArrayDeque(int maxSize) {
        this.maxSize = maxSize;
        queue = new ArrayDeque<T>(maxSize);
    }

    public void add(T t) {
        if (queue.size() == maxSize) {
            queue.removeFirst();
        }
        queue.add(t);
    }

    public boolean remove(T t) {
        return queue.remove(t);
    }

    public boolean contains(T t) {
        return queue.contains(t);
    }

    @Override
    public String toString() {
        return queue.toString();
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.