• 算法总结系列之一:堆排序(Heap Sort)


        在软件设计相关领域,"堆(Heap)"的概念主要涉及到两个方面:

      • 一种数据结构, 逻辑上是一颗完全二叉树,存储上是一个数组对象(二叉堆).
      • 垃圾收集存储区,是软件系统可以编程的内存区域.

        本文所说的堆,指的是前者.另外, 这篇文章中堆中元素的值, 均以整型为例.

        堆排序的时间复杂度是O(nlgN),与快速排序达到相同的时间复杂度. 但是在实际应用中,我们往往采用快速排序而不是堆排序. 这是因为快速排序的一个好的实现,往往比堆排序具有更好的表现. 堆排序的主要用途,是在形成和处理优先级队列方面. 另外, 如果计算要求是类优先级队列(比如, 只要返回最大或者最小元素, 只有有限的插入要求等), 堆同样是很适合的数据结构.

    • 基础知识

        堆一般用数组表示,比如数组A. 数组的长度Length(A), 堆在数组中的元素个数HeapSize(A). 一般说来, HeapSize(A) <= Length(A), 因为数组A当中可能有一些元素不在堆中.

        假设节点I是数组A中下标为i的节点.

      • Parent(i) : return Floor(i/2);    //I的父节点下标.Floor(i)表示比i小的最大整数.
      • Left(i) : return 2*i;               //I的左子节点
      • Right(i) : return 2*i+1;           //I的右子节点

        含有n个元素的堆A的高度是: Floor(lgn)

    • 堆的基本操作
    • MaxHeapify( A, i ):

            保持堆的性质.假设数组A和下标i, 假定以Left(i)和Right(i)为根结点的左右两棵子树都已经是最大堆, 节点i的值可能小于其子节点. 调整节点i的位置.

        算法的C#实现:

    public void MaxHeapify( int[] A,  int heapSize, int i )
    {
    int left = 2*i;
    int right = 2*i+1;
    int larger = i;
    //compare with left child
    if ( left <= heapSize && A[left] > A[i])
    {
    larger = left;
    }

    //compare larger node with right child
    if ( right <= heapSize && A[right] > A[i])
    {
    larger = right;
    }

    //exchange i with the larger child
    if(larger != i )
    {
    int tmp = A[i];
    A[i] = A[larger];
    A[larger] = tmp;

    MaxHeapfy( A, heapSize, larger );
    }
    }

            时间复杂度与树的高度成正比, 为 O(lgn).

    • BuildMaxHeap( A ):

            从一个给定的数组建立最大堆.子数组A[ floor(n/2)+1 ....  ... n]中的元素都是树的叶节点(完全二叉树的基本性质) . 从索引 ceiling(n/2)开始一直到1, 对每一个元素都执行MaxHeapify, 最终得到一个最大堆.

    算法的C#实现:

    public void BuildMaxHeap( int[] A )
    {
    int heapSize = A.Length;
    for( int i = Math.Ceiling(heapSize/2); i >= 1; i --)
    {
    MaxHeapify( A, heapSize, i );
    }
    }
     
     
    时间复杂度依赖于MaxHeapify O(h) (h - 树的高度) ,BuildMaxHeap(A)的时间复杂度是O(n).
     
     
    • 堆排序 HeapSort( A ):

            堆排序算法的基本思想是, 将数组A创建为一个最大堆, 然后交换堆的根(最大元素)和最后一个叶节点x, 将x从堆中去掉形成新的堆A1, 然后重复以上动作,直到堆中只有一个节点.

    算法的C#实现:

    public void HeapSort( int[] A )
    {
    BuildMaxHeap(A);
    int HeapSize = A.Length;

    for(int i = HeapSize; i > 1; i--)
    {
    //assume the type of A is int[] for example
    int tmp = A[1];
    A[1] = A[i];
    A[i] = A[1];

    HeapSize -= 1; //cut off the sorted node.
    MaxHeapify( A, HeapSize, 1 ); // sort the A1 to a max heap
    	}
    }
     
    堆排序的时间复杂度是O(nlgn).
     
    • 优先级队列算法-增加某元素的值(优先级) : HeapIncreaseKey( A, i, key )
    增加某一个元素的优先级后(元素的值), 该元素应该向上移动,才能保持堆的性质.
    算法的C#实现:
    public void HeapIncreaseKey( int[] A, int index, int key )
    {
    if( key <= A[index])
    return;
    A[index] = key;
    while( index>1 && A[Parent(index)] < A[index]]
    {
    //prompt child node
    int tmp = A[index]:
    A[index]= A[Parent(index)];
    A[Parent(index)] = tmp;

    index = Parent(index);
    }
    }
     
    时间复杂度: O(lgn)
    • 优先级队列算法-插入一个元素: Insert( S, x ) 将x元素插入到优先级队列S中.
    主要思路是, 将堆的最后一个叶节点之后, 扩展一个为无穷小的新叶节点, 然后增大它的值为x的值
     
    算法的C#实现是:
    public void HeapInsert( int[] A, int key )
    {
    A.Length += 1;
    A[A.Length] = int.MinValue;

    HeapIncreasekey( A, A.Length, key );
    }
     
    时间复杂度O(lgn)

  • 相关阅读:
    jmeter实现multipart/form-data类型请求
    jmeter(正则提取器、json提取器)做接口关联
    windows使用ubuntu启动linux服务
    Jmeter+Ant+Jenkins环境搭建
    ubuntu网卡驱动的安装
    Ubuntu 挂载U盘
    Linux下安装jdk8步骤详述(转载)
    springboot项目:项目部署
    springboot项目:Redis缓存使用
    springboot项目:Redis分布式锁的使用(模拟秒杀系统)
  • 原文地址:https://www.cnblogs.com/sun/p/1225912.html
Copyright © 2020-2023  润新知