【问题标题】:How to implement a generic PriorityQueue with basic methods in java?java - 如何使用java中的基本方法实现通用PriorityQueue?
【发布时间】:2016-05-07 14:55:14
【问题描述】:

我需要在不使用 Java.Util 形式的 PriorityQueue 的情况下实现自定义优先级队列...我有三个基本方法:插入、删除和清除。所有操作必须在恒定时间 O (log n) 内完成。我怎样才能做到这一点?我应该为这些操作使用什么算法?最后,我应该使用什么类型的容器来保存通用值?

这是我到目前为止所做的......

public class PriorityQueue<E extends Comparable<? super E>> implements Comparable {
    private Stack<E> queue = new Stack<>();
    private int size;


    public PriorityQueue(int size) {
        this.size = size;
    }

    public PriorityQueue() {
        size = 50000;
    }

    public void insert(E value) {
        if (value == null) {
            throw new NullPointerException();
        }
        //how can I insert a value and what container should I use ?

    }

    public void remove() {
        //remove largest
    }

    public int compareTo(Object o) {
        if (o != null && o instanceof PriorityQueue) {
            PriorityQueue anotherQueue = (PriorityQueue) o;
            return this.size - anotherQueue.size;
        } else {
            throw new ClassCastException();
        }
    }
}

不多.. 但我们将不胜感激!

【问题讨论】:

  • O (log N) 不是常数时间。 O(1) 是常数时间。您无法在恒定时间内实现这一点,但 O(Log N) 是内置库实现的。我假设你已经阅读了内置库,因为它有源代码和文档......你真的需要实现 Comparable 吗?为什么要使用未排序的集合,即 Stack 作为底层结构?
  • PriorityQueue 在内部使用heap
  • 堆栈不是一个好主意,也许 arrayList 会更好?但是我在操作算法方面遇到了问题......
  • 为什么不直接查看现有的PriorityQueue 类源代码并类似地实现它?
  • 您的元素必须是Comparable,但优先级队列本身不需要!

标签: java algorithm generics priority-queue constant-time


【解决方案1】:

我看到您的“删除”操作占用了最大的元素。似乎“最大堆”适合您的目的。

https://en.wikipedia.org/wiki/Heap_(data_structure)

【讨论】:

  • 各位审稿人:这答案。如果没有链接,它仍然有意义。
【解决方案2】:

这里我使用了一个 maxHeap 来将元素排序,这个堆是使用数组实现的。

max_size 是数组的大小,size 是当前存储在数组中的元素数。

  • offer() - 在叶子位置插入元素并调用 shifUp() 方法。
  • poll() - 为此返回数组的第一个元素。然后用它的一个叶子替换数组的第一个元素。然后在第一个元素上调用 shiftDown() 方法。数组中的第一个元素将始终具有最高优先级。
  • peek() - 这里我们只返回数组的第一个元素。我们不会删除它。

在泛型数组的情况下,我无法实现另外两种方法。如果它是一个整数数组,就不会有问题。 这两种方法是——

  • remove(E e) - 从队列中删除一个元素。为此,我需要 将 e 的优先级更改为无穷大,然后调用 shiftUp() 方法 e.之后,我只需要调用 poll() 方法即可。

但我无法找到如何将通用元素的优先级更改为无穷大。如果它是一个整数,我会用 Integer.MAX_VALUE 替换后备数组中的元素。

  • replace(E e1, E e2) - 在这里,我只需要删除元素 e1 并插入元素 e2。由于此方法调用 remove() 方法,我 无法实现。

_

import java.util.Comparator;

public class PriorityQueueUsingHeap<E>
{

    private int size;

    private Object H[];

    public PriorityQueueUsingHeap(int max_size)
    {
        H = new Object[max_size];
    }

    private Comparator<E> comparator;

    public PriorityQueueUsingHeap(int max_size, Comparator<E> comparator)
    {
        this.comparator = comparator;
        H = new Object[max_size];
    }

    private E parent(int i)
    {
        return (E) H[(i - 1) / 2];
    }

    private E left(int i)
    {
        return (E) H[2 * i + 1];
    }

    private E right(int i)
    {
        return (E) H[2 * i + 2];
    }

    private boolean greaterThanOrEqualTo(E e1, E e2) // return e1>=e2
    {
        if (comparator != null)
        {
            return comparator.compare(e1, e2) >= 0;
        }

        else
        {
            return ((Comparable<E>) e1).compareTo(e2) >= 0;
        }
    }

    private boolean lessThan(E e1, E e2) // return e1<e2
    {
        if (comparator != null)
        {
            return comparator.compare(e1, e2) < 0;
        }

        else
        {
            return ((Comparable<E>) e1).compareTo(e2) < 0;
        }
    }

    private boolean lessThanOrEqualTo(E e1, E e2) // return e1<=e2
    {
        if (comparator != null)
        {
            return comparator.compare(e1, e2) <= 0;
        }

        else
        {
            return ((Comparable<E>) e1).compareTo(e2) <= 0;
        }
    }

    private boolean greaterThan(E e1, E e2) // return e1>e2
    {
        if (comparator != null)
        {
            return comparator.compare(e1, e2) > 0;
        }

        else
        {
            return ((Comparable<E>) e1).compareTo(e2) > 0;
        }
    }

    private void swap(int i1, int i2)
    {
        E temp = get(i1);
        H[i1] = H[i2];
        H[i2] = temp;
    }

    private E get(int i)
    {
        return (E) H[i];
    }

    private void shiftUp(int i)
    {
        while (i > 0 & greaterThanOrEqualTo(get(i), parent(i)))
        {
            swap(i, (i - 1) / 2);
            i = (i - 1) / 2;
        }
    }

    private void shiftDown(int i)
    {
        int max_index = i;

        if ((2 * i + 1) <= size-1 && lessThan(get(max_index), left(i)))
            max_index = 2 * i + 1;

        if (((2 * i + 2) <= size-1) && (lessThan(get(max_index), right(i))))
            max_index = 2 * i + 2;

        if (i != max_index)
        {
            swap(i, max_index);
            shiftDown(max_index);
        }
    }

    public void offer(E data)
    {
        if(size == H.length)
            System.out.println("Queue is full");

        else
        {
            H[size] = (E) data;
            shiftUp(size);
            size++;
        }

    }

    public E peek()
    {
        return get(0);
    }

    public E poll()
    {
        if(size==0)
        {
            System.out.println("Queue is empty");
            return null;
        }
        else
        {
            E result = get(0);

            H[0] = H[size-1];
            size--;
            shiftDown(0);
            return result;
        }
    }

    public E remove(E e)
    {
        // Logic
        return e;
    }

    public void replace(E e1, E e2)
    {
        offer(e2);
        remove(e1);
    }

}

这是相同的主类 -

public class Main_PriorityQueueUsingHeap
{

    public static void main(String[] args)
    {

        PriorityQueueUsingHeap<Integer> q1 = new PriorityQueueUsingHeap<>(10);

        for (int i = 0; i < 5; i++)
        {
            q1.offer(i);
        }

        for (int i = 0; i < 5; i++)
        {
            System.out.print(q1.poll() + " ");
        }
        System.out.println();

        PriorityQueueUsingHeap<String> q2 = new PriorityQueueUsingHeap<>(10);

        q2.offer("Jatin");
        q2.offer("Ashvini");
        q2.offer("Ram");
        q2.offer("Mahesh");
        q2.offer("Kamal");

        for (int i = 0; i < 5; i++)
        {
            System.out.print(q2.poll() + " ");
        }
        System.out.println();

        PriorityQueueUsingHeap<String> q3 = new PriorityQueueUsingHeap<>(10, 
                (s1, s2) -> {
            return (s1.length() != s2.length()) ? s1.length() - s2.length() : s1.compareTo(s2);
        });

        q3.offer("Jatin");
        q3.offer("Ashvini");
        q3.offer("Ram");
        q3.offer("Mahesh");
        q3.offer("Kamal");

        for (int i = 0; i < 5; i++)
        {
            System.out.print(q3.poll() + " ");
        }
        System.out.println();

        PriorityQueueUsingHeap<Integer> q4 = new PriorityQueueUsingHeap<>(10);

        q4.offer(12);
        q4.offer(2);
        q4.offer(42);
        q4.offer(62);
        q4.offer(12);


        for (int i = 0; i < 5; i++)
        {
            System.out.print(q4.poll() + " ");
        }

    }

}

这是输出 -

4 3 2 1 0 
Ram Mahesh Kamal Jatin Ashvini 
Ashvini Mahesh Kamal Jatin Ram 
62 42 12 12 2 

主类的解释 - 我创建了 4 个优先级队列并执行了以下操作:

  • q1:整数的通用队列。将整数 0 到 4 相加,然后逐个轮询元素。输出显示它们中的每一个都是按优先级降序排列的(数字越大,优先级越高)。
  • q2:没有给出比较器的字符串的通用队列。因此,将根据 Comparable 接口中的 compareTo(E e) 方法比较两个字符串。输出按字典顺序排序。
  • q3 :带有比较器的字符串的通用队列。此比较器比较两个字符串的长度,如果它们相同,则按字典顺序对字符串进行排序。
  • q4:整数的通用队列。添加了一些随机数,并在逐个轮询时,所有这些都按优先级降序排列。由于没有通过比较器,因此优先级是根据 compareTo(E e) 方法决定的。

【讨论】:

    猜你喜欢
    • 2014-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-28
    • 1970-01-01
    • 1970-01-01
    • 2020-09-02
    • 1970-01-01
    相关资源
    最近更新 更多