• 堆与优先队列


      我们经常提到的数据结构大顶堆指的是二叉堆,它是一颗堆有序的完全二叉树(非叶子结点层都是满的,最后一层从右向左只能空缺右结点)。其中根节点是所有结点中最大,并且每个父节点都大于其两个子节点(堆有序)。完全二叉树底层是用数组实现的,所以它只是逻辑上的一个概念。下图是一个大顶堆的例子:

      那么给定一个数组怎么建立大顶堆呢?我们用下面代码来说明,建立堆的时间复杂度为O(n)。

     1 //建立大顶堆
     2 public void creatHeap(int[] arr) { 
     3     for (int i=0; i<arr.length; i++) { 
     4         heapInsert(arr, i);
     5     }
     6 }
     7 /**
     8      * 某一个元素进堆,元素上浮的过程
     9      * @param arr
    10      * @param index
    11      */
    12 public void heapInsert(int[] arr, int index) {
    13     //当前元素大于父节点时,交换
    14     while (arr[index] > arr[(index - 1) / 2]) {
    15         swap(arr, index, (index - 1) / 2);
    16         // 来到父节点位置继续比较
    17         index = (index - 1) / 2;
    18     }
    19 }
    20 
    21 public void swap(int[] arr, int m, int n) {
    22     int temp = arr[m];
    23     arr[m] = arr[n];
    24     arr[n] = temp;
    25 }

         如果说堆中某个元素变小了,我们可以使用heapify来调整元素的位置,使得堆仍然是大顶堆,heapify实际上是当前元素下沉的过程,具体代码如下:

     1 /**
     2      * 元素下沉过程
     3      * @param arr 
     4      * @param index 当前变小的元素
     5      * @param heapSize 堆的大小,小于等于数组的大小  
     6      */
     7 public void heapify(int[] arr, int index, int heapSize) {
     8     //左右孩子结点的索引,数组的索引从0开始
     9     int left = 2 * index + 1;
    10     int right = left + 1;
    11 12     while (left < heapSize) {
    13         //从左右孩子中选出大的
    14         int largest = right < heapSize && arr[right] > arr[left] ? right : left; 
    15         //和index比较
    16         largest = arr[largest] > arr[index] ? largest : index; 
    17         //当前变小的元素任然比左右孩子结点大,结束循环 
    18         if (largest == index) break;
    19         //交换
    20         swap(arr, largest, index);
    21         //更新index位置,来到largest的位置
    22         index = largest; 
    23         //重置left位置,继续向下比较
    24         left = 2 * index + 1;
    25     }
    26 }

      优先队列本质还是一个队列,只不过队列里的元素有优先级,优先级高的元素先出队列。在Java中优先队列有两种实现,一种是大顶堆,另外一种是小顶堆。以大顶堆为例:当队首元素弹出时,优先队列会自动调整剩下的元素,使其仍是一个大顶堆,时间复杂度为O(nlogn)。具体实现过程就利用了我们上面的heapify方法,同样给出代码说明:

     1 public void heapSort(int[] arr) {
     2         int len = arr.length;
     3         //交换首尾元素,使得弹出的元素在堆中失效,但仍在数组中
     4         swap(arr, 0, --len);
     5         //不断地进行heapify操作
     6         while (len > 0) {
     7             heapify(arr, 0, len);
     8             swap(arr, 0, --len);
     9         }
    10 }

      优先队列可以应用于系统的任务调度,优先级高的任务先执行,低的在队列中等候;图的搜索算法中也会用到优先队列,感兴趣的童鞋可以阅读《算法》第四版具体学习。

      参考资料:左程云算法初级班

           《算法》第四版

  • 相关阅读:
    [leetcode]Remove Nth Node From End of List @ Python
    [leetcode]Swap Nodes in Pairs @ Python
    [leetcode]Linked List Cycle II @ Python
    [leetcode]Linked List Cycle @ Python
    [leetcode]LRU Cache @ Python
    [leetcode]Reorder List @ Python
    [leetcode]Insertion Sort List @ Python
    [leetcode]Sort List @ Python
    [leetcode]3Sum Closest @ Python
    [elk]elasticsearch实现冷热数据分离
  • 原文地址:https://www.cnblogs.com/fly-bryant/p/13088735.html
Copyright © 2020-2023  润新知