• 堆排序(转)


    转载自:https://www.cnblogs.com/chengxiao/p/6129630.html

    堆排序

      堆排序是利用这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。首先简单了解下堆结构。

      堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。如下图:

    同时,我们对堆中的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子

    该数组从逻辑上讲就是一个堆结构,我们用简单的公式来描述一下堆的定义就是:

    大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]  

    小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]  

    ok,了解了这些定义。接下来,我们来看看堆排序的基本思想及基本步骤:

    堆排序的基本思想是:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了

    步骤一 构造初始堆。将给定无序序列构造成一个大顶堆(一般升序采用大顶堆,降序采用小顶堆)。

      a.假设给定无序序列结构如下

    2.此时我们从最后一个非叶子结点开始(叶结点自然不用调整,第一个非叶子结点 arr.length/2-1=5/2-1=1,也就是下面的6结点),从左至右,从下至上进行调整。

    4.找到第二个非叶节点4,由于[4,9,8]中9元素最大,4和9交换。

    这时,交换导致了子根[4,5,6]结构混乱,继续调整,[4,5,6]中6最大,交换4和6。

    此时,我们就将一个无需序列构造成了一个大顶堆。

    步骤二 将堆顶元素与末尾元素进行交换,使末尾元素最大。然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换。

    a.将堆顶元素9和末尾元素4进行交换

    b.重新调整结构,使其继续满足堆定义

    c.再将堆顶元素8与末尾元素5进行交换,得到第二大元素8.

    后续过程,继续进行调整,交换,如此反复进行,最终使得整个序列有序

    再简单总结下堆排序的基本思路:

      a.将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;

      b.将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;

      c.重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。

    function stackSort(arr){
      // 1.构建大顶堆
      for (let i=arr.length/2-1;i>=0;i--){
        // 从第一个非叶子结点开始,从右往左,从下往上调整
        adjustHeap(arr,i,arr.length);
      }
      // 2.交换首尾结点
      for (let k=arr.length-1;k>0;k--){
        swap(arr,0,k);
        adjustHeap(arr,0,k);
      }
      // return arr;
    }
    function swap(arr,i,j){
      let temp = arr[i];
      arr[i] = arr[j];
      arr[j] = temp;
    }
    // 调整大根堆
    function adjustHeap(arr,i,length){
      let temp = arr[i];
      for (let k=2*i+1;k<length;k=2*k+1) {
        if (k<length-1 && arr[k]<arr[k+1]){  // 左子结点小于右子节点,指向右子结点
          k++;
        }
        if (temp<arr[k]){ //如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
          arr[i] = arr[k];
          i = k;
        }else{
          break; //前一步操作,对顶元素改变了,从上到下,如果上面的没变,下面的就不需要动了
        }
      }
      arr[i] = temp;
    }
    
    var arr = [9,8,7,6,5,4,3,2,1,0];
    stackSort(arr);
    console.log(arr);

    堆排序是一种选择排序,整体主要由构建初始堆+交换堆顶元素和末尾元素并重建堆两部分组成。其中构建初始堆经推导复杂度为O(n),在交换并重建堆的过程中,需交换n-1次,而重建堆的过程中,根据完全二叉树的性质,[log2(n-1),log2(n-2)...1]逐步递减,近似为nlogn。所以堆排序时间复杂度一般认为就是O(nlogn)级。

  • 相关阅读:
    POJ 2828 Buy Tickets (线段树 单点更新 变形)
    HDU 1754 I Hate It (线段树 单点更新)
    HDU 1166 敌兵布阵 (线段树 单点更新)
    sdut 2934 人活着系列之平方数 (完全背包变形)
    Codeforces Round #259 (Div. 2) C
    poj 1724 ROADS (bfs+优先队列)
    hdu 4901 The Romantic Hero (dp)
    MemSQL Start[c]UP 2.0
    BestCoder Round #2 1001 (简单处理)
    tc 2014 college tour 250 500
  • 原文地址:https://www.cnblogs.com/ceceliahappycoding/p/10618082.html
Copyright © 2020-2023  润新知