目录
4、Comparable接口与Comparator接口的区别
一、堆的性质
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));
}
}