Apakah ada antrian berukuran tetap yang menghilangkan elemen berlebihan?

127

Saya perlu antrian dengan ukuran tetap. Ketika saya menambahkan elemen dan antrian penuh, itu akan secara otomatis menghapus elemen tertua.

Apakah ada implementasi yang sudah ada untuk ini di Jawa?

c0d3x
sumber
1
bagaimana dengan stackoverflow.com/a/6058025/1392882
Miguel

Jawaban:

19

Tidak ada implementasi yang ada di Bahasa Jawa dan Runtime. Semua Antrian memperpanjang AbstractQueue , dan dokumennya dengan jelas menyatakan bahwa menambahkan elemen ke antrian penuh selalu berakhir dengan pengecualian. Akan lebih baik (dan cukup sederhana) untuk membungkus Antrian ke dalam kelas Anda sendiri karena memiliki fungsi yang Anda butuhkan.

Sekali lagi, karena semua antrian adalah anak-anak dari AbstractQueue, cukup gunakan itu sebagai tipe data internal Anda dan Anda harus memiliki implementasi yang fleksibel berjalan dalam waktu yang hampir tidak ada :-)

MEMPERBARUI:

Seperti diuraikan di bawah ini, ada dua implementasi terbuka yang tersedia (jawaban ini cukup tua, kawan!), Lihat jawaban ini untuk perincian.

moritz
sumber
4
Gunakan Antrian alih-alih AbstractQueue ... mungkin ada antrian yang mengimplementasikan antarmuka tetapi tidak memperluas kelas abstrak.
TofuBeer
1
Dengan Python Anda bisa menggunakan collection.dequedengan yang ditentukan maxlen.
Jonas Gröger
2
PEMBARUAN Sekarang ada dua kelas yang tersedia. Tidak perlu menulis sendiri. Lihat jawaban saya di halaman ini.
Basil Bourque
108

Sebenarnya LinkedHashMap melakukan apa yang Anda inginkan. Anda perlu mengganti removeEldestEntrymetode.

Contoh untuk antrian dengan maksimal 10 elemen:

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

Jika "removeEldestEntry" mengembalikan true, entri tertua dihapus dari peta.

Mavrik
sumber
7
ini sebenarnya tidak melakukan apa yang dilakukan antrian, bagaimana saya dapat mengambil yang terbaru. obyek?
Alex
69

Ya dua

Dari pertanyaan rangkap saya sendiri dengan jawaban yang benar ini , saya belajar dua:


Saya memanfaatkan Jambu secara produktif EvictingQueue, bekerja dengan baik.

Untuk membuat instance EvictingQueuepanggilan metode pabrik statis createdan tentukan ukuran maksimum Anda.

EvictingQueue< Person > people = com.google.common.collect.EvictingQueue.create( 100 ) ;  // Set maximum size to 100. 
Basil Bourque
sumber
... dan jika Anda tidak dapat menggunakan Commons Collection 4.0 maka CircularFifoBuffer tampaknya mirip dengan CircularFifoQueue di v 3.0.
Sridhar Sarnobat
CircularFifoQueuetautan sudah mati, gunakan sebaliknya commons.apache.org/proper/commons-collections/apidocs/org/…
user7294900
@ user7294900 Terima kasih, tautan diperbaiki. FYI, Stack Overflow mengundang Anda untuk mengedit sendiri langsung ke Jawaban. Siapa pun dapat mengedit, bukan hanya penulis asli. Stack Overflow dimaksudkan untuk lebih menyukai Wikipedia dalam hal itu.
Basil Bourque
@ BasilBourque ya, tetapi pengeditan tersebut dapat ditolak bahkan oleh saya ketika mengubah tautan itu adalah wilayah abu - abu
user7294900
18

Saya baru saja menerapkan antrian ukuran tetap dengan cara ini:

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);
    }
}
Roar Skullestad
sumber
1
SeharusnyaremoveRange(0, size() - maxSize)
Ahmed Hegazy
@AhmedHegazy removeRange (0, size () - maxSize - 1) benar
Ashish Doneriya
Saya setuju dengan Amhed di atas. Hapus - 1. Jika tidak pada kapasitas maks Anda akan berakhir dengan array yang maxSize + 1 karena kita berbicara tentang 0 berbasis. Misalnya. Jika maxSize = 50 maka ketika menambahkan objek baru, formula removeRange dalam postingan asli akan menjadi 51 - 50 - 1 = 0 (mis. Tidak ada yang dihapus).
Etep
8

Inilah yang saya lakukan dengan Queuedibungkus LinkedList, Ini adalah ukuran tetap yang saya berikan di sini adalah 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");
.....
Berkay Turancı
sumber
4

Saya pikir apa yang Anda gambarkan adalah antrian melingkar. Berikut adalah contoh dan di sini adalah lebih baik satu


sumber
4

Kelas ini melakukan pekerjaan menggunakan komposisi alih-alih pewarisan (jawaban lain di sini) yang menghilangkan kemungkinan efek samping tertentu (seperti yang dicakup oleh Josh Bloch di Essential Java). Pemangkasan LinkedList yang mendasari terjadi pada metode add, addAll dan 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();
    }
}
Dave Moten
sumber
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);
    }
}

Penggunaan dan hasil tes:

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]
}
Leon
sumber
0

Kedengarannya seperti Daftar biasa di mana metode add berisi potongan tambahan yang memotong daftar jika terlalu lama.

Jika itu terlalu sederhana, maka Anda mungkin perlu mengedit deskripsi masalah Anda.

Thorbjørn Ravn Andersen
sumber
Sebenarnya, ia perlu menghapus elemen pertama (yaitu yang paling awal), memotong akan menghapus elemen terakhir. Masih praktis dengan LinkedList.
MAK
0

Lihat juga pertanyaan SO ini , atau ArrayBlockingQueue (hati-hati tentang pemblokiran, ini mungkin tidak diinginkan dalam kasus Anda).

Zoran Regvart
sumber
0

Tidak jelas persyaratan apa yang Anda miliki yang membuat Anda mengajukan pertanyaan ini. Jika Anda membutuhkan struktur data ukuran tetap, Anda mungkin juga ingin melihat kebijakan caching yang berbeda. Namun, karena Anda memiliki antrian, tebakan terbaik saya adalah Anda mencari beberapa jenis fungsi router. Dalam hal ini, saya akan menggunakan buffer cincin: array yang memiliki indeks pertama dan terakhir. Setiap kali elemen ditambahkan, Anda hanya menambah indeks elemen terakhir, dan ketika elemen dihapus, tambah indeks elemen pertama. Dalam kedua kasus, penambahan dilakukan modulo ukuran array, dan pastikan untuk menambah indeks lain saat diperlukan, yaitu, ketika antrian penuh atau kosong.

Selain itu, jika ini adalah aplikasi tipe router, Anda mungkin juga ingin bereksperimen dengan algoritma seperti Random Early Dropping (RED), yang menjatuhkan elemen dari antrian secara acak bahkan sebelum terisi. Dalam beberapa kasus, RED telah ditemukan memiliki kinerja keseluruhan yang lebih baik daripada metode sederhana yang memungkinkan antrian untuk diisi sebelum jatuh.

JaakkoK
sumber
0

Sebenarnya Anda dapat menulis impl Anda sendiri berdasarkan LinkedList, itu sangat mudah, hanya menimpa metode add dan melakukan staf.

Mike
sumber
0

Saya pikir jawaban yang paling cocok adalah dari pertanyaan lain ini .

Koleksi Apache commons 4 memiliki CircularFifoQueue yang merupakan apa yang Anda cari. Mengutip javadoc:

CircularFifoQueue adalah antrian masuk pertama keluar dengan ukuran tetap yang menggantikan elemen tertua jika penuh.

Diego
sumber
0

Solusi sederhana, di bawah ini adalah Antrian "String"

LinkedHashMap<Integer, String> queue;
int queueKeysCounter;

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

Perhatikan bahwa ini tidak akan mempertahankan Urutan item dalam Antrian, tetapi itu akan menggantikan entri tertua.

M. Usman Khan
sumber
0

Seperti yang disarankan dalam OOP bahwa kita harus lebih memilih Komposisi daripada Warisan

Di sini solusi saya mengingatnya.

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();
    }
}
Abhishek
sumber