文章目录
- 基于无序数组实现
- 基于有序数组的实现
- 基于堆的实现
- 合并多个有序链表-力扣 23 题
基于无序数组实现
要点
- 入队保持顺序,在数组尾部插入即可
- 出队前找到优先级最高的出队,相当于一次选择排序
基于有序数组的实现
要点
- 入队后排好序,优先级最高的排列在尾部
- 出队只需删除尾部元素即可
基于堆的实现
堆是一种基于树的数据结构,通常用完全二叉树实现。堆的特性如下
- 在大顶堆中,任意节点 C 与它的父节点 P 符合 P . v a l u e ≥ C . v a l u e P.value \geq C.value P.value≥C.value
- 而小顶堆中,任意节点 C 与它的父节点 P 符合 P . v a l u e ≤ C . v a l u e P.value \leq C.value P.value≤C.value
- 最顶层的节点(没有父亲)称之为 root 根节点
完全二叉树可以使用数组来表示:
特征
- 如果从索引 0 开始存储节点数据
- 节点 i i i 的父节点为 f l o o r ( ( i − 1 ) / 2 ) floor((i-1)/2) floor((i−1)/2),当 i > 0 i>0 i>0 时
- 节点 i i i 的左子节点为 2 i + 1 2i+1 2i+1,右子节点为 2 i + 2 2i+2 2i+2,当然它们得 < s i z e < size <size
- 如果从索引 1 开始存储节点数据
- 节点 i i i 的父节点为 f l o o r ( i / 2 ) floor(i/2) floor(i/2),当 i > 1 i > 1 i>1 时
- 节点 i i i 的左子节点为 2 i 2i 2i,右子节点为 2 i + 1 2i+1 2i+1,同样得 < s i z e < size <size
用大顶锥实现优先级队列:
入队:将新元素加入队尾,然后不断比较其与父节点的优先级,若大于父节点优先级,则交换两节点,然后再比较新节点的父节点,直到找到小于父节点优先级
,或者当前节点(child)索引为0
,则找到。
public boolean offer(E offered) {
if (isFull()) {
return false;
}
int child = size++;//当前child指向数组最后一个元素,然后size++
int parent = (child - 1) / 2;
while (child > 0 && offered.priority() > array[parent].priority()) {
array[child] = array[parent];
child = parent;
parent = (child - 1) / 2;
}
array[child] = offered;
return true;
}
出队:将数组索引为0的元素与数组最后元素交换,交换后数组最后一个元素就是优先级最大的元素,将其出队,然后将数组为0位置元素逐步下潜,调整大顶锥,使其满足大顶锥定义。
public E poll() {
if (isEmpty()) {
return null;
}
swap(0, size - 1);
size--;
Priority e = array[size];
array[size] = null;
shiftDown(0);
return (E) e;
}
void shiftDown(int parent) {
int left = 2 * parent + 1;
int right = left + 1;
int max = parent;
if (left < size && array[left].priority() > array[max].priority()) {
max = left;
}
if (right < size && array[right].priority() > array[max].priority()) {
max = right;
}
if (max != parent) {
swap(max, parent);
shiftDown(max);
}
}
private void swap(int i, int j) {
Priority t = array[i];
array[i] = array[j];
array[j] = t;
}
合并多个有序链表-力扣 23 题
思路:小顶锥实现,k个链表创建有k个元素的小顶锥,用优先级队列实现(遍历lists,如果遍历到的不是空链表,将头节点加入到优先级队列中,)当队列不空时循环取出元素,取出的这个元素就是最小的元素,并将此元素加入到新的链表中,然后将当前这个最小的元素的next节点入队(当next节点存在的情况下),当优先级队列为空时表示已经将k个链表合并。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
Queue<ListNode> pq = new PriorityQueue<>((v1, v2)-> v1.val - v2.val);
for(ListNode node : lists){
if(node != null){
pq.offer(node);
}
}
ListNode sentinel = new ListNode(-1, null);
ListNode tail = sentinel;
while(!pq.isEmpty()){
ListNode minNode = pq.poll();
tail.next = minNode;
tail = minNode;
if(minNode.next != null){
pq.offer(minNode.next);
}
}
return sentinel.next;
}
}