• 堆及堆排序


    --------------------------------------------------------------------------------------------------------------------------------------------------------------

    2018年8月30日补充:

    看了普林斯顿算法中关于堆的实现,感觉更加形象生动,补充如下:

    //下面的结点往上游,游到一个合适的位置
    void swim(int k)
    {
      while(k > 1 && less(k/2,k))
      {
          exch(k/2,k);
          k/=2;
      }
    }
    
    
    //上面的结点往下沉 沉到一个合适的位置
    void sink(int k)
    {
       while(2*k <= N)
       {
         int j=2*k;
         if(j<N && less(j,j+1)) j++;  //选出两个儿子中的较大值
         if(!less(k,j)) break;        //若找到了合适的位置就跳出
         exch(k,j);
         k = j;
       }
    }
    
    
    //删除最大元素
    Key delMax()
    {
      Key max = pq[1];   //从根结点得到最大的元素
      exch(1,N--);       //将其和最后一个结点交换
      pq[N+1] = NULL;    //防止对象游离
      sink(1);           //恢复堆的有序性
      return max;
    }
    
    void stack_sort(int a[], int N)
    {
       for(int k=N/2; k>=1; k--)
       {
           sink(a,k,N);   //将初始的数组排成堆
       }
    
       while(N > 1)
       {
          exch(a,1,N--);  //将max排到最后面
          sink(a,1,N);    //重新恢复有序性
       }
    }

    堆排序是我们所知的唯一能够同时最优地利用空间和时间的方法------在最坏的情况下也能保证使用2NlgN次比较和恒定的额外空间

    //最大堆
    typedef struct Heap* MaxHeap;
    struct Heap
    {
       ElementType *Elements;  //存储数组
       int Size;   //当前堆中元素个数
       int Capacity;   //堆的容量
    };
    
    
    //创建一个最大堆
    MaxHeap CreateMaxHeap(int MaxSize)
    {
        MaxHeap H = malloc(sizeof(struct Heap));
        H->Elements = malloc(sizeof(ElementType) * MaxSize);
        H->Size = 0;
        H->Capacity = MaxSize;
    
        H->Elements[0] = MaxData;  //哨兵
        return H;
    }
    
    //
    int isFull(MaxHeap H)
    {
        return (H->Size == H->Capacity);
    }
    
    //在堆中插入一个元素
    int Insert(MaxHeap H,ElementType X)
    {
        if(isFull(H))
        {
            printf("space error");
            return 0;
        }
    
        i = ++H->Size;
        for(;H->Elements[i/2] < X;i/=2)
            H->Elements[i] = H->Elements[i/2]; 
    
        H->Elements[i] = X;
        return 1;
    }
    
    //
    int isEmpty(MaxHeap H)
    {
        return (H->Size == 0);
    }
    
    
    //在最大堆中删除最大的元素,即根节点
    ElementType DeleteMax(MaxHeap H)
    {
        int Parent, Child;
        ElementType MaxItem;
    
        if(isEmpty(H)) 
        {
            printf("the tree is empty!")
            return 0;
        }
    
        MaxItem = H->Elements[1];
        
        ElementType Tmp = H->Elements[Size--];   //所要替代根节点的元素
        //现在给它找一个合适的位置
        for(Parent = 1; Parent * 2 <= H->Size/*判断是否存在左子结点*/; Parent = Child)
        {
            Child = 2*Parent;
    
            if((Child != H->Size)&&(H->Elements[Child] < H->Elements[Child+1]))
                Child++;     //判断左右两个结点哪个大,并使Child指向他
    
            if(temp >= H->Elements[Child]) break;  //如果找到了合适的位置就跳出
            else 
                H->Elements[Parent] = H->Elements[Child];  //没有找到,即左右两个节点中存在比Tmp大的,则将大的子结点向上移动
        }
    
        H->Elements[Parent] = Tmp;
        return MaxItem
    }
    
    
    //建造最大堆
    //PercDown:在H中以H->Elements[p]为根节点的子堆 将其排成最大堆
    void PercDown(MaxHeap H, int p)
    {
      int Parent,Child;
      ElementType X;
    
      X = H->Elements[p];
      for(Parent = p; Parent*2 <= H->Size; Parent = Child)
      {
          Child = Parent*2;
    
          if((Child != H->Size)&&(H->Elements[Child] < H->Elements[Child+1]))
                Child++;     //判断左右两个结点哪个大,并使Child指向他
    
        if(X >= H->Elements[Child]) break;  //如果找到了合适的位置就跳出
        else 
           H->Elements[Parent] = H->Elements[Child];  //没有找到,即左右两个节点中存在比Tmp大的,则将大的子结点向上移动
      }
      H->Elements[Parent] = X;
    }
    
    
    //建造最大堆
    void BuildHeap(MaxHeap H)
    {
       int i;
    
       for(i = H->Size/2; i>0; i--)
       {
             PercDown(H,i);
       }
    }
    
    
    //堆排序
    //注意,堆排序中没有了哨兵
    void Swap(ElementType *a, ElementType *b)
    {
        ElementType t = *a;
        *a = *b;
        *b = t;
    }
    
    void PercDown(ElementType a[], int p, int N)
    {
       int Parent,Child;
       ElementType X;
    
       X = a[p];
       for(Parent = p; (Parent*2+1)<N;Parent = Child)
       {
             Child = Parent*2 + 1;
    
             if(((Child+1)!=N) && a[Child] < a[Child+1])
                 Child++;
    
             if(X >= a[Child]) break;
             else
                 a[Parent] = a[Child];
       }
       a[Parent] = X;
    }
    
    
    void HeapSort(ElementType a[], int N)
    {
        int i;
        for(i = N/2-1;i>=0;i--)
        {
           PercDown(a,i,N);
        }
    
        for(i=N-1;i>0;i--)
        {
            Swap(&a[0],&a[i]);
            PercDown(a,0,i);
        }
    }

     复杂度分析:O(nlogn):第一个for循环,初始化堆,为O(n),第二个for循环为O(nlogn);

    稳定性分析:不稳定

  • 相关阅读:
    webpack 性能优化
    Bert模型实现垃圾邮件分类
    基于SKLearn的SVM模型垃圾邮件分类——代码实现及优化
    sklearn中,数据集划分函数 StratifiedShuffleSplit.split() 使用踩坑
    mysql5.7安装教程【转载】
    Postman 使用小技巧/指南
    如何知道 window 的 load 事件已经触发
    前端常用库 CDN
    使用 rollup 打包可按需加载的 NPM 包
    webpack 4 快速搭建
  • 原文地址:https://www.cnblogs.com/dzy521/p/9401357.html
Copyright © 2020-2023  润新知