开局之前

感觉堆这种数据结构很重要,因为优先队列中用到了这种结构
topk也用到了这种结构

什么样的树才是堆呢?

  1. 堆是一个完全二叉树

除了最后一层,其余的都是满的,而且最后一层必须靠左对齐

  1. 堆中每个节点都要>=或<= 子树中每个节点的值

    对于每个节点的值都大于等于子树中每个节点值的堆,我们叫做“大顶堆”。对于每个节点的值都小于等于子树中每个节点值的堆,我们叫做“小顶堆”。

    所以使用topk的时候 我们都用的是小顶堆,因为堆顶是最小的,只要删除了堆顶元素就可以了

堆化

因为堆化是沿着二叉树的路径走的,所以时间复杂度和高度有关 树的高度不会超过
28 | 堆和堆排序:为什么说堆排序没有快速排序快? - 图1 所以时间复杂度是log2n

从下往上

可以理解为把一个元素插入到最尾部,然后使用节点之间的位置关系,来调整堆

  1. public static void main(String[] args) {
  2. /*
  3. int arr[] = {5, 98, 78, 15, 32, 2, 46};
  4. heapSort(arr, arr.length);
  5. System.out.println(Arrays.toString(arr));;
  6. */
  7. Heap heap = new Heap(10);
  8. heap.insert(1);
  9. heap.insert(2);
  10. heap.insert(3);
  11. heap.insert(4);
  12. heap.insert(5);
  13. System.out.println(1);
  14. }
  15. public static class Heap {
  16. private int[] a; // 数组,从下标1开始存储数据
  17. private int n; // 堆可以存储的最大数据个数
  18. private int count; // 堆中已经存储的数据个数
  19. public Heap(int capacity) {
  20. a = new int[capacity + 1];
  21. n = capacity;
  22. count = 0;
  23. }
  24. public void insert(int data) {
  25. if (count >= n) return; // 堆满了
  26. ++count;
  27. a[count] = data;
  28. int i = count;
  29. while (i/2 > 0 && a[i] > a[i/2]) { // 自下往上堆化
  30. swap(a, i, i/2); // swap()函数作用:交换下标为i和i/2的两个元素
  31. i = i/2;
  32. }
  33. }
  34. private static void swap(int[] a, int i, int j) {
  35. int temp = a[i];
  36. a[i] = a[j];
  37. a[j] = temp;
  38. }
  39. public static void main(String[] args) {
  40. int[] arr = {1,2,3,4};
  41. swap(arr,0,1);
  42. System.out.println();
  43. }
  44. }

从上往下

image.png