优先级队列(堆)

目录

一、堆的性质

二、优先级队列的常用接口

三、PriorityQueue接口

1、使用PriorityQueue接口注意点

2、接口常用方法

3、改变接口的堆形式

4、Comparable接口与Comparator接口的区别

四、有关堆oj题目

1、一个普通序列建大根堆

2、一个普通序列建小根堆

3、大根堆中插入元素

4、小根堆中插入元素

5、大根堆中删除元素

6、小根堆中删除元素

7、大根堆排序--升序

8、小根堆排序--降序

9、max-top-k

10、min-top-k

一、堆的性质

1、堆总是一棵完全二叉树;

2、堆的所有元素按完全二叉树的顺序存储在一维数组中;

3、堆中某个结点的值总是小于父结点,其为根堆;

4、堆中某个结点的值总是大于父结点,其为根堆。

5、在数组中,若父结点下标为n,则左孩子为:2*n+1;右孩子为:2*n+2

二、优先级队列的常用接口

java集合框架提供了PriorityQueue和PriorityBlockIngQueue两种类型的优先级队列。PriorityQueue是线程不安全的,PriorityBlockIngQueue是线程安全的。

三、PriorityQueue接口

1、使用PriorityQueue接口注意点

①放置的元素必须能够比较大小,不能插入无法比较大小的对象;

②不能插入null对象;

③可以插入任意多个元素,内部可以自动扩容:数量<64,2倍扩容;数量>64,1.5倍扩容;数量>MAX_ARRAY_SIZE,按照MAX_ARRAY_SIZE来进行扩容;

④默认情况下是小堆,默认容量是11。

2、接口常用方法

3、改变接口的堆形式

①默认为小堆,改为大堆形式

②改为小堆形式

4、Comparable接口与Comparator接口的区别

相同点:都是用于实现自定义对象的比较。

①Comparable:在定义一个类时,可以直接实现该接口,重写compareTo方法。此时该类就可以直接比较大小了,一经定义,无法改变比较方式。

②Comparator:写一个比较器类实现了Comparator接口,重写compare方法。一个自定义类想比较大小,就可以直接用该比较器生成一个对象作为自定义类的参数。比较方式可以改变,选择不同的比较器。

四、有关堆oj题目

1、一个普通序列建大根堆

思路:从最后一个父结点开始,遍历完所有父结点,对每个父结点进行向下调整,直到没有孩子结点。

建堆的时间复杂度为:O(N)

import java.util.Arrays;

public class BigPriorityQueue {
    public static void buildPile(int[] a,int parent,int n){
        int child=2*parent+1;  //向下调整
        while(child<n){
            if(child+1<n&&a[child+1]>a[child]){
                child+=1;
            }
            if(a[child]>a[parent]){
                swap(a,parent,child);
                parent=child;
                child=2*parent+1;
            }else {
                break;
            }
        }
    }
    public static void swap(int[] array,int a,int b){
        int temp=array[a];
        array[a]=array[b];
        array[b]=temp;
    }

    public static void main(String[] args) {
        int[] a=new int[]{4,5,8,6,3,9,1};
        int n=a.length;
        int parent=(n-2)/2;
        for(int i=parent;i>=0;i--){  //遍历父结点
            buildPile(a,i,n);
        }
        System.out.println(Arrays.toString(a));
    }
}
2、一个普通序列建小根堆
import java.util.Arrays;

public class SmallPriorityQueue {
    public static void buildPile(int[] a,int parent,int n){
        int child=2*parent+1;  //向下调整
        while(child<n){
            if(child+1<n&&a[child+1]<a[child]){
                child+=1;
            }
            if(a[child]<a[parent]){
                swap(a,parent,child);
                parent=child;
                child=2*parent+1;
            }else {
                break;
            }
        }
    }
    public static void swap(int[] array,int a,int b){
        int temp=array[a];
        array[a]=array[b];
        array[b]=temp;
    }

    public static void main(String[] args) {
        int[] a=new int[]{4,5,8,6,3,9,1};
        int n=a.length;
        int parent=(n-2)/2;
        for(int i=parent;i>=0;i--){  //遍历父结点
            buildPile(a,i,n);
        }
        System.out.println(Arrays.toString(a));
    }
}

插入的时间复杂度为:O(logN)

3、大根堆中插入元素

思路:先将插入元素放在最后一个,只要不满足堆要求就向上调整,直到父结点为第一个父结点;若满足堆要求就结束。

import java.util.Arrays;

public class BigPriorityQueue {
    public static int[] add(int[] a, int num, int n) {
        int[] b = Arrays.copyOf(a, n + 1);
        b[n] = num;
        int child1 = n;
        while (child1 > 0) {
            int parent = (child1 - 1) / 2;
            if (b[child1] > b[parent]) {
                swap(b, child1, parent);
                child1 = parent;
            } else {
                break;
            }
        }
        return b;
    }
    public static void swap(int[] array,int a,int b){
        int temp=array[a];
        array[a]=array[b];
        array[b]=temp;
    }

    public static void main(String[] args) {
        int[] a=new int[]{9,6,8,5,3,4,1};
        int n = a.length;
        int[] b = add(a, 7, n);
        System.out.println(Arrays.toString(b));
    }
}
4、小根堆中插入元素
import java.util.Arrays;

public class SmallPriorityQueue {
    public static int[] add(int[] a, int num, int n) {
        int[] b = Arrays.copyOf(a, n + 1);  
        b[n] = num;
        int child1 = n;
        while (child1 > 0) {
            int parent = (child1 - 1) / 2;
            if (b[child1] < b[parent]) {
                swap(b, child1, parent);
                child1 = parent;         //向上调整
            } else {
                break;
            }
        }
        return b;
    }
    public static void swap(int[] array, int a, int b) {
        int temp = array[a];
        array[a] = array[b];
        array[b] = temp;
    }
    public static void main(String[] args) {
        int[] a = new int[]{1, 3, 4, 6, 5, 9, 8};
        int n = a.length;
        int[] b = add(a, 0, n);
        System.out.println(Arrays.toString(b));
    }
}
5、大根堆中删除元素

思路:删除堆顶元素,和最后一个位置交换,然后前n-1个元素以第一个父结点建堆。

删除的时间复杂度为:O(logN)

import java.util.Arrays;

public class BigPriorityQueue {
    public static int[] delete(int[] a, int n) {
        a[0] = a[n - 1];
        int[] b = Arrays.copyOf(a, n - 1);
        buildPile(b, 0, n - 1);
        return b;
    }
    public static void swap(int[] array, int a, int b) {
        int temp = array[a];
        array[a] = array[b];
        array[b] = temp;
    }
    public static void buildPile(int[] a, int parent, int n) {
        int child = 2 * parent + 1;  //向下调整
        while (child < n) {
            if (child + 1 < n && a[child + 1] > a[child]) {
                child += 1;
            }
            if (a[child] > a[parent]) {
                swap(a, parent, child);
                parent = child;
                child = 2 * parent + 1;
            } else {
                break;
            }
        }
    }
    public static void main(String[] args) {
        int[] a = new int[]{9, 6, 8, 5, 3, 4, 1};
        int n = a.length;
        int[] b = delete(a, n);
        System.out.println(Arrays.toString(b));
    }
}
6、小根堆中删除元素
public class SmallPriorityQueue {
    public static void buildPile(int[] a, int parent, int n) {
        int child = 2 * parent + 1;  //向下调整
        while (child < n) {
            if (child + 1 < n && a[child + 1] < a[child]) {
                child += 1;
            }
            if (a[child] < a[parent]) {
                swap(a, parent, child);
                parent = child;
                child = 2 * parent + 1;
            } else {
                break;
            }
        }
    }
    public static void swap(int[] array, int a, int b) {
        int temp = array[a];
        array[a] = array[b];
        array[b] = temp;
    }
    public static int[] delete(int[] a, int n) {
        a[0] = a[n - 1];
        int[] b = Arrays.copyOf(a, n - 1);
        buildPile(b, 0, n - 1);
        return b;
    }
    public static void main(String[] args) {
        int[] a = new int[]{1, 3, 4, 6, 5, 9, 8};
        int n = a.length;
        int[] b = delete(a, n);
        System.out.println(Arrays.toString(b));
    }
}
7、大根堆排序--升序

思路:将堆顶元素放在最后一个,前n-1个元素以第一个父结点建堆,接着交换......直到要交换的元素下标为0。

import java.util.Arrays;
public class BigPriorityQueue {
    public static void sort(int[] a, int n) {  //升序
        for (int i = n - 1; i > 0; i--) {
            swap(a, 0, i);
            buildPile(a, 0, --n);
        }
    }
    public static void buildPile(int[] a, int parent, int n) {
        int child = 2 * parent + 1;  //向下调整
        while (child < n) {
            if (child + 1 < n && a[child + 1] > a[child]) {
                child += 1;
            }
            if (a[child] > a[parent]) {
                swap(a, parent, child);
                parent = child;
                child = 2 * parent + 1;
            } else {
                break;
            }
        }
    }
    public static void swap(int[] array, int a, int b) {
        int temp = array[a];
        array[a] = array[b];
        array[b] = temp;
    }
    public static void main(String[] args) {
        int[] a = new int[]{9, 6, 8, 5, 3, 4, 1};
        int n = a.length;
        sort(a, n);
        System.out.println(Arrays.toString(a));
    }
}
8、小根堆排序--降序
import java.util.Arrays;
public class SmallPriorityQueue {
    public static void sort(int[] a, int n) {  //降序
        for (int i = n - 1; i > 0; i--) {
            swap(a, 0, i);
            buildPile(a, 0, --n);
        }
    }
    public static void buildPile(int[] a, int parent, int n) {
        int child = 2 * parent + 1;  //向下调整
        while (child < n) {
            if (child + 1 < n && a[child + 1] < a[child]) {
                child += 1;
            }
            if (a[child] < a[parent]) {
                swap(a, parent, child);
                parent = child;
                child = 2 * parent + 1;
            } else {
                break;
            }
        }
    }
    public static void swap(int[] array, int a, int b) {
        int temp = array[a];
        array[a] = array[b];
        array[b] = temp;
    }
    public static void main(String[] args) {
        int[] a = new int[]{1, 3, 4, 6, 5, 9, 8};
        int n = a.length;
        sort(a, n);
        System.out.println(Arrays.toString(a));
    }
}
9、max-top-k

思路:利用小根堆找出前k个最大的值。先将数组前k个元素建成小根堆,遍历数组后的数,只要比堆顶元素大,就和堆顶交换,前k个元素以第一个父结点建堆.....直到遍历完数组。可以不断筛选出较小值。

import java.util.Arrays;
public class SmallPriorityQueue {
    public static int[] maxTopK(int[] a, int n, int k) {
        if (k <= 0 || k > n) {
            return null;
        }
        if (k == n) {
            return a;
        }
        int[] b = Arrays.copyOf(a, k);
        if (k >= 2) {  //前k个建堆
            int parent = (k - 2) / 2;
            for (int i = parent; i >= 0; i--) {
                buildPile(b, i, k);
            }
        }
        for (int j = k; j < n; j++) {
            if (a[j] >= b[0]) {  //将元素小的筛选掉
                b[0] = a[j];
                buildPile(b, 0, k);
            }
        }
        return b;
    }
    public static void buildPile(int[] a, int parent, int n) {
        int child = 2 * parent + 1;  //向下调整
        while (child < n) {
            if (child + 1 < n && a[child + 1] < a[child]) {
                child += 1;
            }
            if (a[child] < a[parent]) {
                swap(a, parent, child);
                parent = child;
                child = 2 * parent + 1;
            } else {
                break;
            }
        }
    }
    public static void main(String[] args) {
        int[] a = new int[]{1, 3, 4, 6, 5, 9, 8};
        int n = a.length;
        int[] b = maxTopK(a, n, 3);
        System.out.println(Arrays.toString(b));
    }
}
10、min-top-k

思路:利用大根堆找出前k个最小的值。先将数组前k个元素建成大根堆,遍历数组后的数,只要比堆顶元素小,就和堆顶交换,前k个元素以第一个父结点建堆.....直到遍历完数组。可以不断筛选出较大值。

import java.util.Arrays;
public class BigPriorityQueue {
    public static int[] minTopK(int[] a, int n, int k) {
        if (k <= 0 || k > n) {
            return null;
        }
        if (k == n) {
            return a;
        }
        int[] b = Arrays.copyOf(a, k);
        if (k >= 2) {  //前k个建堆
            int parent = (k - 2) / 2;
            for (int i = parent; i >= 0; i--) {
                buildPile(b, i, k);
            }
        }
        for (int j = k; j < n; j++) {
            if (a[j] <= b[0]) {  //将元素大的筛选掉
                b[0] = a[j];
                buildPile(b, 0, k);
            }
        }
        return b;
    }
    public static void buildPile(int[] a, int parent, int n) {
        int child = 2 * parent + 1;  //向下调整
        while (child < n) {
            if (child + 1 < n && a[child + 1] > a[child]) {
                child += 1;
            }
            if (a[child] > a[parent]) {
                swap(a, parent, child);
                parent = child;
                child = 2 * parent + 1;
            } else {
                break;
            }
        }
    }
    public static void main(String[] args) {
        int[] a = new int[]{9, 6, 8, 5, 3, 4, 1};
        int n = a.length;
        int[] b = minTopK(a, n, 3);
        System.out.println(Arrays.toString(b));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ambition…

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值