排序算法之堆排序

堆排序比一般的排序算法略为复杂。

1.什么是二叉堆?

2.如何用数组描述一个二叉堆?

3.如果构建最大堆或最小堆

4.构建好最大堆或最小堆后,对堆的排序

堆的性质:(1)是棵完全二叉树;(2)某个节点的值总是大于或小于子节点(最大堆和最小堆)

算法过程:

1.构造最大堆或者最小堆(从小到大排序--->最大堆,从大到小排序--->最小堆)

2.然后把最上面的元素跟最末尾的元素互换,然后就不管最后一个,因为互换后,最后一个肯定是最大(/最小)值。

3.然后重新建造最大堆或者最小堆。再重复过程2,直到剩下最后一个元素。

1.什么是二叉堆?

二叉堆是完全二叉树或近似完全二叉树。而且任何父节点的键值都大于等于(或小于等于)任何一点子节点的兼职。

父节点键值大等于他的子节点的键值为最大堆,父节点键值小于等于他的子节点的键值为最小堆。

如下图,是一个二叉堆:

 

2.用数组描述一个二叉堆

如上面的二叉堆,用数组表示就是A[ 6 ] = {16,7,3,20,17,8};

这个方法跟描述树的方法是一样的。

 

3.构建最小堆(最大堆)

(以最大堆为例)

从堆 最后一个有叶子结点的结点 开始,设堆有 n 个元素,则该节点序号为:(n/2)-1,上图中该节点就是 3,也就是 A[ 6/2 -1 ] = A[2 ]

构建最大堆的过程:

原始堆。

先从 最后一个有叶子结点的结点(A[ 2 ]) 开始,8比3大,因此 位置互换。

然后到A[ 1 ] ,首先选出比较大的孩子结点,再跟父节点比,看哪个大。大的跟父节点换位置

然后到A[ 0 ].同上

 

把16换下来后,会发现红色圈的三个里面是 17 最大,因此把 17和 16的位置互换。

这就完成了最大堆了。可以开始排序

构成最大堆(or最小堆后):(又叫大根堆,小根堆)

def buildHeap(arr):  #建堆:建堆的目的是 先给数组中的数字建立一个规律,即父节点大于(or小于)子节点
    n = len(arr)
    for i in reversed(range(n // 2)):  #从最后一个非叶子结点开始
        heapify(arr,n,i)
    return arr

def heapify(arr,n,i):
    left = 2*i+1
    right = 2*i+2
    max_index = i
    if left<n and arr[left]>arr[i]: #arr[left]<arr[i]为建最小堆===》从大到小排序。
        max_index = left            #arr[left]>arr[i]为建最大堆===>从小到大排序
    if right<n and arr[right]>arr[max_index]:
        max_index = right
    if max_index!=i:
        arr[i],arr[max_index] = arr[max_index],arr[i]
        heapify(arr,n,max_index)

def heapSort(arr):
    arr = buildHeap(arr) #建堆
    n = len(arr)
    while n>0:
        arr[0],arr[n-1] = arr[n-1],arr[0]
        n-=1
        heapify(arr,n,0)  #再次堆化,把arr[0]的数值沉到堆的应有位置
    return arr
a = [0,1,6,5,2,7,8,2,99,12,3]
b = heapSort(a)
print(b) #[0, 1, 2, 2, 3, 5, 6, 7, 8, 12, 99]

时间复杂度:O(nlogn) 空间复杂度O(1)

Java版本:

public class HeapSort {
    public static void buildHeap(int[] arr,int n){
        for(int i=n/2 -1;i>=0;i--){
            heapify(arr,n,i);
        }
    }
    public static void heapify(int[] arr,int n,int i){
        int left = 2*i+1;
        int right = 2*i+2;
        int max_index = i;
        if(left<n && arr[left]>arr[max_index]){
            max_index = left;
        }
        if(right<n && arr[right]>arr[max_index]){
            max_index = right;
        }
        if(max_index!=i){
            int t = arr[i];
            arr[i] = arr[max_index];
            arr[max_index] = t;
            heapify(arr,n,max_index);
        }
    }

    public static void heapSort(int[] arr,int n){
        buildHeap(arr,n);
        while(n>0){
            int t = arr[0];
            arr[0] = arr[n-1];
            arr[n-1] = t;
            n--;
            heapify(arr,n,0);
        }
    }
    public static void main(String[] args) {
        int[] arr = {1,3,4,3,2,3,5,6,3,3,1,2};
        heapSort(arr,arr.length);
        System.out.println(arr);
    }
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值