优先级队列简要分析与实现(Java)

目录

开场白

优先级队列的定义

无序数组实现方案

1. 准备工作

2. 判空 & 判满

3. 查找最大优先级元素对应索引

4. 删除指定索引处元素

5. 入队

6. 出队

7. 获取队首元素

final. 完整实现代码 & 单元测试

Java实现

C语言实现

有序数组实现

1. 准备工作

2. 判空 & 判满 & 出队 & 获取队首元素

3. 插入指定元素

4. 入队

final. 完整实现代码 & 单元测试

Java实现

C语言实现

堆实现

Java实现

总结


开场白

在前几篇文章中,我们从普通队列扩展到循环队列,再根据生活中的例子,又引出了双端队列,但以上的队列还是过于“死板”,即使是更加灵活的双端队列,仍然遵循着先进先出FIFO后进先出LIFO的特性。本文中我们将介绍另一种名为优先级队列的数据结构。说是队列,实际上从我个人角度看来,优先级队列已经在一定程度上打破了队列特性

“事有轻重,缓急有别”。当一个队列维护了一组事件的时候,如果只是按照先来后到(先来先服务,FCFS)的顺序进行事件的处理,往往是不符合实际的。实际上,不论在计算机处理事件的逻辑中还是在我们的日常生活中,我们往往会根据事件的轻重缓急来处理事件。例如在医院就诊这种关乎人身健康甚至生命安全的情况下,情况越严重的患者,医院往往会优先救治;又如很多排队窗口上标识着”军人优先“等字样,都体现着不能仅从先来后到这一层面处理问题。

优先级队列的定义

优先级队列(Priority Queue) 是一种抽象数据类型(ADT),它允许队列中维护的元素按优先级排序,优先级最高的元素会优先被处理。所以不难看出,对于获取队首元素方法和删除元素方法,操作对象都是队列中优先级最高的元素。

优先级队列的实现方案有很多种,最简单的是使用无序数组模拟实现,每次可以使用线性查找获取到数组中优先级最高的元素,届时可以对此元素进行处理;其次可以使用有序数组模拟实现,即优先级队列中存储的元素序列本身有序,在插入元素操作中使用适当的算法找到一个合适的位置,即一个不会破坏数组有序的位置,插入元素即可,我们此时规定数组中最后一个存储的元素是数组中优先级最高的元素,这是因为我们在优先级队列的背景下执行出队操作时要将队列中优先级最高的元素出队,若将优先级最高的元素置于队首,需要让当前元素的所有后继统一前移一位,这是比较耗时的操作;除了以上两种数组模拟的实现方案,还可以使用堆(Heap)进行实现,这也是在很多算法书籍和文章中直接将优先级队列称为堆的原因之一。后续我们会专门更新一篇有关堆的文章,敬请期待。

无序数组实现方案

1. 准备工作

通过前文的理论分析,我们不难发现,数组中除了需要存储元素本身,还要存储元素的优先级,我们不妨自定义一个接口 ,接口中有一个抽象方法  用于返回当前元素的优先级。在之后的实现中需要让表示队列元素的实现类实现此接口,并重写获取当前元素优先级的方法 

public interface Priority {
    int priority();
}

之后我们自定义一个实现了  接口的实现类 ,用于表示优先级队列中存储的元素数据类型,类中有两个属性  和 ,分别表示当前元素的值与优先级,优先级由用户自行定义。我们提供一个全参数构造方法用于创建指定值和指定优先级的存储对象,为了方便展示,我们也重写了  方法。

public class Entry implements Priority {

    private final String value;
    private final int priority;

    public Entry(String value, int priority) {
        this.value = value;
        this.priority = priority;
    }

    @Override
    public int priority() {
        return this.priority;
    }

    @Override
    public String toString() {
        return "(" + value + " priority = " + priority + ")";
    }
}

我们自定义一个名为  的类,用于实现无序数组的方案,此类实现了我们先前定义的  接口,虽然优先级队列在一定程度上打破了队列特性,但是终究来说还是队列。需要提前指出的是,此类定义了泛型 ,其中的      是一种泛型约束(Generic Constraint),规定了泛型  的上界,在此背景下就是规定泛型  可以是任意实现了  接口的类。

public class DisorderArrayPriorityQueue<E extends Priority> implements Queue<E>{}

类中我们定义一个用于存放元素的数组及一个表示优先级队列中存储元素数量的变量。

    private Priority[] array;
    private int size;

同时我们提供一个传入表示优先级队列规模  的构造方法。

    public DisorderArrayPriorityQueue(int capacity) {
        array = new Priority[capacity];
    }

2. 判空 & 判满

与先前循环队列判空判满实现方案相同,使用  变量与数组长度进行判断即可,不再赘述。

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean isFull() {
        return size == array.length;
    }

3. 查找最大优先级元素对应索引

我们先前提到,每次的出队元素都是当前队列中优先级最高的元素,我们不妨实现一个私有化的工具方法来做此工作。在无序数组实现优先级队列的背景下,我们无法通过特别高效的查找算法来获取到数组中优先级最高的元素,那么只能使用最朴素的线性查找(顺序查找)算法来实现。使用循环遍历判断即可,学习了相关程序设计基础课程的读者一定不陌生,这里直接给出实现代码。

    private int findMaxPriIndex() {
        int index = 0;
        for (int i = 1; i < size; i ++)
            if (array[i].priority() > array[index].priority())
                index = i;
        return index;
    }

4. 删除指定索引处元素

诶,串台了?队列怎么会出现这种方法?如果出现此疑问,那么一定是我在前文对无序数组的理论分析没有说清楚,那么我们再来一遍。此时数组中的元素是无序的,而当我们执行出队操作时需要将数组中优先级最高的元素出队,此时只能通过查找到数组中最高优先级元素对应的下标,然后再删除才行。对于数组中删除指定索引处元素这一操作,各位读者一定也不陌生,只需要将此索引之后的所有元素前移一位即可。但是还没结束,我们最后还需要更新表示队列中存储元素数量的  变量。

    private E remove(int index) {
        E element = (E) array[index];
        for (int i = index; i < size - 1; i ++)
            array[i] = array[i + 1];
        size --;
        return element;
    }

5. 入队

在入队之前需要判断当前队列是否已满,如果已满,返回 ;否则,执行入队逻辑。实际上, 变量的另一层含义是优先级队列的队尾指针,换句话说, 的当前值表示待插入元素的存储位置。所以在入队时,直接在数组的  位置存储元素,随后更新  变量即可。

    @Override
    public boolean offer(E value) {
        if (isFull())
            return false;
        array[size ++] = value;
        return true;
    }

6. 出队

首先需要判断队列是否为空,如果为空,直接返回 ,否则执行出队逻辑。由于我们先前已经实现了查找最大优先级元素对应索引删除指定索引处元素的私有化工具方法,结合两个工具方法,很容易的就实现了此功能。

    @Override
    public E pull() {
        if (isEmpty())
            return null;
        return remove(findMaxPriIndex());
    }

7. 获取队首元素

依旧,需要判断当前队列是否为空,如果为空,直接返回 ,否则执行获取队首元素逻辑。队首元素,即队列中优先级最高的元素,结合我们先前实现的两个私有化工具方法,很容易实现功能。

    @Override
    public E peek() {
        if (isEmpty())
            return null;
        return (E) array[findMaxPriIndex()];
    }

final. 完整实现代码 & 单元测试

Java实现

/**<h3>无序数组实现优先级队列</h3>
 * @Author Arrebol
 * @Date 2025/1/20 19:33
 * @Project datastructure_algorithm
 * @Description:
 */
@SuppressWarnings("all")
public class DisorderArrayPriorityQueue<E extends Priority> implements Queue<E> {

    private Priority[] array;
    private int size;

    public DisorderArrayPriorityQueue(int capacity) {
        array = new Priority[capacity];
    }

    @Override
    public boolean offer(E value) {
        if (isFull())
            return false;
        array[size ++] = value;
        return true;
    }

    @Override
    public E pull() {
        if (isEmpty())
            return null;
        return remove(findMaxPriIndex());
    }

    @Override
    public E peek() {
        if (isEmpty())
            return null;
        return (E) array[findMaxPriIndex()];
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean isFull() {
        return size == array.length;
    }

    private int findMaxPriIndex() {
        int index = 0;
        for (int i = 1; i < size; i ++)
            if (array[i].priority() > array[index].priority())
                index = i;
        return index;
    }

    private E remove(int index) {
        E element = (E) array[index];
        for (int i = index; i < size - 1; i ++)
            array[i] = array[i + 1];
        size --;
        return element;
    }
}
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class DisorderArrayPriorityQueueTest {

    private DisorderArrayPriorityQueue<MyPriorityElement> queue;

    @BeforeEach
    void setUp() {
        queue = new DisorderArrayPriorityQueue<>(5);
    }

    @Test
    void testOfferAndPeek() {
        assertTrue(queue.offer(new MyPriorityElement(3)));
        assertEquals(3, queue.peek().priority());

        assertTrue(queue.offer(new MyPriorityElement(5)));
        assertEquals(5, queue.peek().priority());

        assertTrue(queue.offer(new MyPriorityElement(1)));
        assertEquals(5, queue.peek().priority());
    }

    @Test
    void testPull() {
        queue.offer(new MyPriorityElement(3));
        queue.offer(new MyPriorityElement(5));
        queue.offer(new MyPriorityElement(1));

        assertEquals(5, queue.pull().priority());
        assertEquals(3, queue.pull().priority());
        assertEquals(1, queue.pull().priority());
        assertNull(queue.pull());
    }

    @Test
    void testIsEmpty() {
        assertTrue(queue.isEmpty());

        queue.offer(new MyPriorityElement(2));
        assertFalse(queue.isEmpty());

        queue.pull();
        assertTrue(queue.isEmpty());
    }

    @Test
    void testIsFull() {
        assertFalse(queue.isFull());

        queue.offer(new MyPriorityElement(1));
        queue.offer(new MyPriorityElement(2));
        queue.offer(new MyPriorityElement(3));
        queue.offer(new MyPriorityElement(4));
        queue.offer(new MyPriorityElement(5));

        assertTrue(queue.isFull());

        queue.pull();
        assertFalse(queue.isFull());
    }

    @Test
    void testOfferWhenFull() {
        for (int i = 0; i < 5; i++) {
            queue.offer(new MyPriorityElement(i));
        }

        assertTrue(queue.isFull());
        assertFalse(queue.offer(new MyPriorityElement(6)));
    }

    @Test
    void testPriorityOrder() {
        queue.offer(new MyPriorityElement(2));
        queue.offer(new MyPriorityElement(5));
        queue.offer(new MyPriorityElement(1));
        queue.offer(new MyPriorityElement(4));

        assertEquals(5, queue.pull().priority());
        assertEquals(4, queue.pull().priority());
        assertEquals(2, queue.pull().priority());
        assertEquals(1, queue.pull().priority());
    }

    static class MyPriorityElement implements Priority {
        private final int pri;

        public MyPriorityElement(int pri) {
            this.pri = pri;
        }

        @Override
        public int priority() {
            return pri;
        }
    }
}

C语言实现

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef struct {
    int (*priority)(void*);
} Priority;

typedef struct {
    void* data;
    Priority* priority;
} QueueElement;

typedef struct {
    QueueElement* array;
    int capacity;
    int size;
} DisorderArrayPriorityQueue;

DisorderArrayPriorityQueue* createQueue(int capacity) {
    DisorderArrayPriorityQueue* queue = (DisorderArrayPriorityQueue*)malloc(sizeof(DisorderArrayPriorityQueue));
    queue->array = (QueueElement*)malloc(capacity * sizeof(QueueElement));
    queue->capacity = capacity;
    queue->size = 0;
    return queue;
}

bool isEmpty(DisorderArrayPriorityQueue* queue) {
    return queue->size == 0;
}

bool isFull(DisorderArrayPriorityQueue* queue) {
    return queue->size == queue->capacity;
}

bool offer(DisorderArrayPriorityQueue* queue, void* data, Priority* priority) {
    if (isFull(queue)) {
        return false;
    }
    queue->array[queue->size].data = data;
    queue->array[queue->size].priority = priority;
    queue->size++;
    return true;
}

int findMaxPriIndex(DisorderArrayPriorityQueue* queue) {
    int index = 0;
    for (int i = 1; i < queue->size; i++) {
        if (queue->array[i].priority->priority(queue->array[i].data) >
            queue->array[index].priority->priority(queue->array[index].data)) {
            index = i;
        }
    }
    return index;
}

void* removeAt(DisorderArrayPriorityQueue* queue, int index) {
    void* element = queue->array[index].data;
    for (int i = index; i < queue->size - 1; i++) {
        queue->array[i] = queue->array[i + 1];
    }
    queue->size--;
    return element;
}

void* pull(DisorderArrayPriorityQueue* queue) {
    if (isEmpty(queue)) {
        return NULL;
    }
    int index = findMaxPriIndex(queue);
    return removeAt(queue, index);
}

void* peek(DisorderArrayPriorityQueue* queue) {
    if (isEmpty(queue)) {
        return NULL;
    }
    int index = findMaxPriIndex(queue);
    return queue->array[index].data;
}

typedef struct {
    int pri;
} MyPriorityElement;

int myPriorityFunction(void* data) {
    MyPriorityElement* element = (MyPriorityElement*)data;
    return element->pri;
}

Priority MyPriorityInterface = {myPriorityFunction};

int main() {
    DisorderArrayPriorityQueue* queue = createQueue(5);

    MyPriorityElement e1 = {3};
    MyPriorityElement e2 = {5};
    MyPriorityElement e3 = {1};

    offer(queue, &e1, &MyPriorityInterface);
    printf("Peek: %d\n", ((MyPriorityElement*)peek(queue))->pri);

    offer(queue, &e2, &MyPriorityInterface);
    printf("Peek: %d\n", ((MyPriorityElement*)peek(queue))->pri);

    offer(queue, &e3, &MyPriorityInterface);
    printf("Peek: %d\n", ((MyPriorityElement*)peek(queue))->pri);

    printf("Pull: %d\n", ((MyPriorityElement*)pull(queue))->pri);
    printf("Pull: %d\n", ((MyPriorityElement*)pull(queue))->pri);
    printf("Pull: %d\n", ((MyPriorityElement*)pull(queue))->pri);

    printf("Pull from empty queue: %s\n", pull(queue) == NULL ? "NULL" : "NOT NULL");

    MyPriorityElement e4 = {2};
    MyPriorityElement e5 = {4};
    MyPriorityElement e6 = {6};

    offer(queue, &e1, &MyPriorityInterface);
    offer(queue, &e2, &MyPriorityInterface);
    offer(queue, &e3, &MyPriorityInterface);
    offer(queue, &e4, &MyPriorityInterface);
    offer(queue, &e5, &MyPriorityInterface);

    printf("Is full: %s\n", isFull(queue) ? "true" : "false");
    printf("Offer to full queue: %s\n", offer(queue, &e6, &MyPriorityInterface) ? "true" : "false");

    free(queue->array);
    free(queue);

    return 0;
}

有序数组实现

除了使用无序数组模拟实现优先级队列,我们还可以通过维护一个有序数组实现。需要提前指出的是,我们并不是通过不断执行排序算法来维护数组有序性的,而是寻找一个合适的位置插入元素来保证有序性。与无序数组相比,判空、判满、出队以及获取队首元素的实现思路是一致的,我们在后续的分析中将不再赘述这些操作。

1. 准备工作

我们自定义一个名为  的类来实现基于有序数组的优先级队列,依旧需要定义真正存储队列元素的数组  和表示当前队列存储元素数量的  变量,同时提供传入队列规模参数  的构造方法。

    private E[] array;
    private int size;

    public OrderedArrayPriority(int capacity) {
        array = (E[]) new Priority[capacity];
    }

2. 判空 & 判满 & 出队 & 获取队首元素

与无序数组实现方案一致,这里直接给出对应代码实现。需要说明的是,在出队方法  中有 ,将队列中元素置空的意义在于可以帮助  垃圾回收器(Garbage Collector, GC)回收内存。

    @Override
    public E pull() {
        if (isEmpty())
            return null;
        E element = array[size - 1];
        array[--size] = null;
        return element;
    }

    @Override
    public E peek() {
        if (isEmpty())
            return null;
        return array[size - 1];
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean isFull() {
        return size == array.length;
    }

3. 插入指定元素

先前我们提到,数组的有序性是通过我们寻找合适位置插入元素实现的。具体实现方案就是,循环遍历当前数组,不断让当前遍历的元素向后移动,一旦发现当前遍历元素的优先级小于(或小于等于,取决于用户),那么此时的遍历下标  处就是待插入元素的合理插入位置,直接在此下标存储元素并更新  变量即可。

    private void insert(E value) {
        int i = size - 1;
        while (i >= 0 && array[i].priority() > value.priority()) {
            array[i + 1] = array[i];
            i--;
        }
        array[i + 1] = value;
        size++;
    }

4. 入队

在实现了上一个方法后,再实现入队操作就很容易了。当队列未满时,直接调用上面实现的私有工具方法即可。

    @Override
    public boolean offer(E value) {
        if (isFull())
            return false;
        insert(value);
        return true;
    }

final. 完整实现代码 & 单元测试

Java实现

/**
 * @Author Arrebol
 * @Date 2025/1/20 20:07
 * @Project datastructure_algorithm
 * @Description:
 */
@SuppressWarnings("all")
public class OrderedArrayPriority<E extends Priority> implements Queue<E> {

    private E[] array;
    private int size;

    public OrderedArrayPriority(int capacity) {
        array = (E[]) new Priority[capacity];
    }

    @Override
    public boolean offer(E value) {
        if (isFull())
            return false;
        insert(value);
        return true;
    }

    @Override
    public E pull() {
        if (isEmpty())
            return null;
        E element = array[size - 1];
        array[--size] = null;
        return element;
    }

    @Override
    public E peek() {
        if (isEmpty())
            return null;
        return array[size - 1];
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean isFull() {
        return size == array.length;
    }

    private void insert(E value) {
        int i = size - 1;
        while (i >= 0 && array[i].priority() > value.priority()) {
            array[i + 1] = array[i];
            i--;
        }
        array[i + 1] = value;
        size++;
    }
}
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class OrderedArrayPriorityTest {

    private OrderedArrayPriority<MyPriorityElement> queue;

    @BeforeEach
    void setUp() {
        queue = new OrderedArrayPriority<>(5);
    }

    @Test
    void testOfferAndPeek() {
        assertTrue(queue.offer(new MyPriorityElement(3)));
        assertEquals(3, queue.peek().priority());

        assertTrue(queue.offer(new MyPriorityElement(5)));
        assertEquals(5, queue.peek().priority());

        assertTrue(queue.offer(new MyPriorityElement(1)));
        assertEquals(5, queue.peek().priority());
    }

    @Test
    void testPull() {
        queue.offer(new MyPriorityElement(3));
        queue.offer(new MyPriorityElement(5));
        queue.offer(new MyPriorityElement(1));

        assertEquals(5, queue.pull().priority());
        assertEquals(3, queue.pull().priority());
        assertEquals(1, queue.pull().priority());
        assertNull(queue.pull());
    }

    @Test
    void testIsEmpty() {
        assertTrue(queue.isEmpty());

        queue.offer(new MyPriorityElement(2));
        assertFalse(queue.isEmpty());

        queue.pull();
        assertTrue(queue.isEmpty());
    }

    @Test
    void testIsFull() {
        assertFalse(queue.isFull());

        queue.offer(new MyPriorityElement(1));
        queue.offer(new MyPriorityElement(2));
        queue.offer(new MyPriorityElement(3));
        queue.offer(new MyPriorityElement(4));
        queue.offer(new MyPriorityElement(5));

        assertTrue(queue.isFull());

        queue.pull();
        assertFalse(queue.isFull());
    }

    @Test
    void testOfferWhenFull() {
        for (int i = 0; i < 5; i++) {
            queue.offer(new MyPriorityElement(i));
        }

        assertTrue(queue.isFull());
        assertFalse(queue.offer(new MyPriorityElement(6))); // 队列已满,offer 失败
    }

    @Test
    void testPriorityOrder() {
        queue.offer(new MyPriorityElement(2));
        queue.offer(new MyPriorityElement(5));
        queue.offer(new MyPriorityElement(1));
        queue.offer(new MyPriorityElement(4));

        assertEquals(5, queue.pull().priority());
        assertEquals(4, queue.pull().priority());
        assertEquals(2, queue.pull().priority());
        assertEquals(1, queue.pull().priority());
    }

    static class MyPriorityElement implements Priority {
        private final int pri;

        public MyPriorityElement(int pri) {
            this.pri = pri;
        }

        @Override
        public int priority() {
            return pri;
        }
    }
}

C语言实现

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int priority;
} Priority;

typedef struct {
    Priority** array;
    int size;
    int capacity;
} OrderedArrayPriority;

OrderedArrayPriority* createOrderedArrayPriority(int capacity) {
    OrderedArrayPriority* queue = (OrderedArrayPriority*)malloc(sizeof(OrderedArrayPriority));
    queue->array = (Priority**)malloc(capacity * sizeof(Priority*));
    queue->size = 0;
    queue->capacity = capacity;
    return queue;
}

int isEmpty(OrderedArrayPriority* queue) {
    return queue->size == 0;
}

int isFull(OrderedArrayPriority* queue) {
    return queue->size == queue->capacity;
}

void insert(OrderedArrayPriority* queue, Priority* value) {
    int i = queue->size - 1;
    while (i >= 0 && queue->array[i]->priority > value->priority) {
        queue->array[i + 1] = queue->array[i];
        i--;
    }
    queue->array[i + 1] = value;
    queue->size++;
}

int offer(OrderedArrayPriority* queue, Priority* value) {
    if (isFull(queue)) {
        return 0;
    }
    insert(queue, value);
    return 1;
}

Priority* pull(OrderedArrayPriority* queue) {
    if (isEmpty(queue)) {
        return NULL;
    }
    Priority* element = queue->array[queue->size - 1];
    queue->array[--queue->size] = NULL;
    return element;
}

Priority* peek(OrderedArrayPriority* queue) {
    if (isEmpty(queue)) {
        return NULL;
    }
    return queue->array[queue->size - 1];
}

typedef struct {
    Priority base;
    int pri;
} MyPriorityElement;

MyPriorityElement* createMyPriorityElement(int pri) {
    MyPriorityElement* element = (MyPriorityElement*)malloc(sizeof(MyPriorityElement));
    element->base.priority = pri;
    element->pri = pri;
    return element;
}

int main() {
    OrderedArrayPriority* queue = createOrderedArrayPriority(5);

    MyPriorityElement* element1 = createMyPriorityElement(3);
    MyPriorityElement* element2 = createMyPriorityElement(5);
    MyPriorityElement* element3 = createMyPriorityElement(1);

    printf("Test offer and peek:\n");
    printf("%d\n", offer(queue, (Priority*)element1));
    printf("%d\n", peek(queue)->priority);
    printf("%d\n", offer(queue, (Priority*)element2));
    printf("%d\n", peek(queue)->priority);
    printf("%d\n", offer(queue, (Priority*)element3));
    printf("%d\n", peek(queue)->priority);

    printf("Test pull:\n");
    printf("%d\n", pull(queue)->priority);
    printf("%d\n", pull(queue)->priority);
    printf("%d\n", pull(queue)->priority);
    printf("%p\n", pull(queue));

    printf("Test isEmpty:\n");
    printf("%d\n", isEmpty(queue));
    offer(queue, (Priority*)createMyPriorityElement(2));
    printf("%d\n", isEmpty(queue));
    pull(queue);
    printf("%d\n", isEmpty(queue));

    printf("Test isFull:\n");
    printf("%d\n", isFull(queue));
    offer(queue, (Priority*)createMyPriorityElement(1));
    offer(queue, (Priority*)createMyPriorityElement(2));
    offer(queue, (Priority*)createMyPriorityElement(3));
    offer(queue, (Priority*)createMyPriorityElement(4));
    offer(queue, (Priority*)createMyPriorityElement(5));
    printf("%d\n", isFull(queue));
    pull(queue);
    printf("%d\n", isFull(queue));

    printf("Test offer when full:\n");
    printf("%d\n", offer(queue, (Priority*)createMyPriorityElement(6)));

    printf("Test priority order:\n");
    offer(queue, (Priority*)createMyPriorityElement(2));
    offer(queue, (Priority*)createMyPriorityElement(5));
    offer(queue, (Priority*)createMyPriorityElement(1));
    offer(queue, (Priority*)createMyPriorityElement(4));
    printf("%d\n", pull(queue)->priority);
    printf("%d\n", pull(queue)->priority);
    printf("%d\n", pull(queue)->priority);
    printf("%d\n", pull(queue)->priority);

    free(queue->array);
    free(queue);

    return 0;
}

堆实现

这里我们直接给出对应实现代码,后续会发布”堆的简要分析与实现“一文,届时再展开说明。

Java实现

/**
 * <h3>基于数组模拟大顶堆实现优先级队列</h3>
 *
 * @Author Arrebol
 * @Date 2025/1/21 0:24
 * @Project algorithm
 * @Description:
 */
@SuppressWarnings("all")
public class PriorityQueue3<E extends Priority> implements Queue<E> {

    Priority[] array;
    int size;

    public PriorityQueue3(int capacity) {
        array = new Priority[capacity];
    }

    @Override
    public boolean offer(E offerd) {
        if (isFull())
            return false;
        int child = size++;
        int parent = (child - 1) / 2;
        while (child > 0 && offerd.priority() > array[parent].priority()) {
            array[child] = array[parent];
            child = parent;
            parent = (child - 1) / 2;
        }
        array[child] = offerd;
        return true;
    }

    @Override
    public E pull() {
        if (isEmpty())
            return null;
        swap(0, size - 1);
        size --;
        E e = (E) array[size];
        dive(0);
        return e;
    }

    @Override
    public E peek() {
        if (isEmpty())
            return null;
        return (E) array[0];
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean isFull() {
        return size == array.length;
    }

    private int selectMax() {
        int i = 0;
        for (int j = 1; j < size; j++) {
            if (array[j].priority() > array[i].priority())
                i = j;
        }
        return i;
    }

    private void remove(int index) {
        if (index < size - 1) {
            for (int i = index; i < size - 1; i++)
                array[i] = array[i + 1];
        }
        size--;
    }

    private void swap(int i, int j) {
        Priority tenp = array[i];
        array[i] = array[j];
        array[j] = tenp;
    }

    private void dive(int parent) {
        int lchild = 2 * parent + 1;
        int rchild = lchild + 1;
        int max = parent;
        if (lchild < size && array[lchild].priority() > array[max].priority()) {
            max = lchild;
        }
        if (rchild < size && array[rchild].priority() > array[max].priority()) {
            max = rchild;
        }
        if (max != parent) {
            swap(max, parent);
            dive(max);
        }
    }
}

总结

“最重要的事情永远不应该被最不重要的事情所左右。”    —— 约翰·洛克菲勒

这也许就是优先级队列的意义吧... ...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值