Có một hàng đợi có kích thước cố định mà loại bỏ các yếu tố quá mức?


127

Tôi cần một hàng đợi với kích thước cố định. Khi tôi thêm một phần tử và hàng đợi đã đầy, nó sẽ tự động xóa phần tử cũ nhất.

Có một triển khai hiện có cho điều này trong Java không?


Câu trả lời:


19

Không có triển khai hiện có trong Ngôn ngữ Java và Thời gian chạy. Tất cả các hàng đợi mở rộng AbstractQueue và tài liệu của nó nêu rõ rằng việc thêm một phần tử vào hàng đợi đầy đủ luôn kết thúc bằng một ngoại lệ. Sẽ là tốt nhất (và khá đơn giản) để bọc Hàng đợi vào một lớp của riêng bạn để có chức năng bạn cần.

Một lần nữa, vì tất cả các hàng đợi là con của AbstractQueue, chỉ cần sử dụng nó làm kiểu dữ liệu nội bộ của bạn và bạn sẽ có một triển khai linh hoạt chạy trong hầu như không có thời gian :-)

CẬP NHẬT:

Như được phác thảo dưới đây, có hai triển khai mở có sẵn (câu trả lời này khá cũ, folks!), Xem câu trả lời này để biết chi tiết.


4
Sử dụng Hàng đợi thay vì Tóm tắt ... có thể có hàng đợi triển khai giao diện nhưng không mở rộng lớp trừu tượng.
TofuBeer

1
Trong Python bạn có thể sử dụng một collection.dequevới chỉ định maxlen.
Jonas Gröger

2
CẬP NHẬT Hiện có hai lớp như vậy có sẵn. Không cần phải viết của riêng bạn. Xem câu trả lời của tôi trên trang này.
Basil Bourque

107

Trên thực tế LinkedHashMap thực hiện chính xác những gì bạn muốn. Bạn cần ghi đè removeEldestEntryphương thức.

Ví dụ cho hàng đợi có tối đa 10 phần tử:

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

Nếu "removeEldestEntry" trả về đúng, mục nhập lớn nhất sẽ bị xóa khỏi bản đồ.


7
điều này thực sự không làm những gì một hàng đợi làm, làm thế nào tôi có thể lấy ra cái mới nhất. vật?
Alex

69

Vâng, hai

Từ câu hỏi trùng lặp của riêng tôi với câu trả lời đúng này , tôi đã học được hai:


Tôi đã sử dụng năng suất của ổi EvictingQueue, hoạt động tốt.

Để khởi tạo một EvictingQueuecuộc gọi phương thức tĩnh nhà máy createvà chỉ định kích thước tối đa của bạn.

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

... Và nếu bạn không thể sử dụng Bộ sưu tập Commons 4.0 thì thì trònFifoBuffer dường như tương tự như Thông tưFifoQueue trong phiên bản 3.0.
Sridhar Sarnobat

CircularFifoQueueliên kết đã chết, sử dụng thay vì commons.apache.org/proper/commons-collections/apidocs/org/
triệt

@ user7294900 Cảm ơn, liên kết đã được sửa. FYI, Stack Overflow mời bạn thực hiện các chỉnh sửa như vậy trực tiếp để tự trả lời. Bất cứ ai cũng có thể chỉnh sửa, không chỉ là tác giả gốc. Stack Overflow được dự định giống với Wikipedia hơn về vấn đề đó.
Basil Bourque

@BasilBourque có, nhưng những chỉnh sửa như vậy có thể bị từ chối ngay cả khi tôi thay đổi liên kết đó là một khu vực màu xám
user7294900

18

Tôi chỉ thực hiện một hàng đợi kích thước cố định theo cách này:

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
Nó nên làremoveRange(0, size() - maxSize)
Ahmed Hegazy

@AhmedHegazy removeRange (0, size () - maxSize - 1) là chính xác
Ashish Doneriya

Tôi đồng ý với Amhed ở trên. Xóa - 1. Nếu không, với công suất tối đa, bạn sẽ kết thúc với một mảng có kích thước tối đa + 1 vì chúng ta đang nói về 0 dựa trên. Ví dụ. Nếu maxSize = 50 thì khi thêm một đối tượng mới, công thức removeRange trong bài viết gốc sẽ là 51 - 50 - 1 = 0 (nghĩa là không có gì bị xóa).
Etep

8

Đây là những gì tôi đã làm với Queuebọc LinkedList, Nó có kích thước cố định mà tôi đưa ra ở đây là 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

Tôi nghĩ những gì bạn đang mô tả là một hàng đợi tròn. Dưới đây là một ví dụ và đây là một tốt hơn một


4

Lớp này thực hiện công việc bằng cách sử dụng thành phần thay vì kế thừa (các câu trả lời khác ở đây) sẽ loại bỏ khả năng tác dụng phụ nhất định (như được Josh Bloch trình bày trong Essential Java). Việc cắt danh sách LinkedList cơ bản xảy ra trên các phương thức add, addAll và 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);
    }
}

Kết quả sử dụng và kiểm tra:

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

Âm thanh giống như một Danh sách thông thường trong đó phương thức add chứa một đoạn bổ sung sẽ cắt bớt danh sách nếu quá dài.

Nếu điều đó quá đơn giản, thì có lẽ bạn cần chỉnh sửa mô tả vấn đề của mình.


Trên thực tế, anh ta sẽ cần phải xóa phần tử đầu tiên (tức là sớm nhất), cắt bớt sẽ loại bỏ phần tử cuối cùng. Vẫn thực tế với LinkedList.
MAK


0

Nó không hoàn toàn rõ ràng những yêu cầu bạn có mà dẫn bạn đặt câu hỏi này. Nếu bạn cần một cấu trúc dữ liệu có kích thước cố định, bạn cũng có thể muốn xem xét các chính sách bộ đệm khác nhau. Tuy nhiên, vì bạn có một hàng đợi, tôi đoán tốt nhất là bạn đang tìm kiếm một số loại chức năng của bộ định tuyến. Trong trường hợp đó, tôi sẽ đi với bộ đệm vòng: một mảng có chỉ mục đầu tiên và cuối cùng. Bất cứ khi nào một phần tử được thêm vào, bạn chỉ cần tăng chỉ số phần tử cuối cùng và khi một phần tử được loại bỏ, hãy tăng chỉ số phần tử đầu tiên. Trong cả hai trường hợp, phép cộng được thực hiện theo kích thước mảng và đảm bảo tăng chỉ số khác khi cần, nghĩa là khi hàng đợi đầy hoặc trống.

Ngoài ra, nếu đó là một ứng dụng loại bộ định tuyến, bạn cũng có thể muốn thử nghiệm một thuật toán như Thả sớm ngẫu nhiên (ĐỎ), loại bỏ các yếu tố khỏi hàng đợi một cách ngẫu nhiên ngay cả trước khi nó được lấp đầy. Trong một số trường hợp, RED đã được tìm thấy có hiệu suất tổng thể tốt hơn so với phương pháp đơn giản cho phép hàng đợi lấp đầy trước khi thả.


0

Trên thực tế, bạn có thể viết hàm riêng của mình dựa trên LinkedList, nó khá đơn giản, chỉ cần ghi đè phương thức add và làm nhân viên.


0

Tôi nghĩ rằng câu trả lời phù hợp nhất là từ câu hỏi khác này .

Bộ sưu tập Apache commons 4 có một tròn trònFifoQueue , đó là những gì bạn đang tìm kiếm. Trích dẫn javadoc:

ThongFifoQueue là hàng đợi vào trước xuất trước với kích thước cố định thay thế phần tử cũ nhất của nó nếu đầy đủ.


0

Một giải pháp đơn giản, bên dưới là Hàng đợi của "Chuỗi"

LinkedHashMap<Integer, String> queue;
int queueKeysCounter;

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

Lưu ý rằng điều này sẽ không duy trì Thứ tự của các mục trong Hàng đợi, nhưng nó sẽ thay thế mục nhập cũ nhất.


0

Như đã khuyên trong các OOP rằng chúng ta nên ưu tiên Thành phần hơn Kế thừa

Đây là giải pháp của tôi giữ điều đó trong tâm trí.

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();
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.