zoukankan      html  css  js  c++  java
  • 排序---堆排序

    堆排序

    堆的概念

      堆中某个节点的值总是大于等于其子节点的值,并且堆是一颗完全二叉树。

      堆可以用数组来表示,这是因为堆是完全二叉树,而完全二叉树很容易存储在数组中,位置看k的节点的父节点位置为(k-1)/2,而它的两个子节点的位置分别为2k+1和2k+2。

    上浮和下沉

      在堆中,当一个节点比父节点大,那么需要交换这两个节点。交换后可能比它新的父节点还大,因此需要不断的进行比较和交换操作,把这种操作称为上浮。

      类似的,当一个节点比子节点小,也需要不断的向下进行比较和交换,把这种操作称为下沉。一个节点如果有两个子节点,应当与两个子节点中最大的那个节点进行交换。

    堆排序

      把最大元素和当前堆中数组的最后一个元素交换位置,并且不删除它,那么就可以得到一个从头到尾的递增序列,这就是堆排序。

    1.构建大顶堆

      无序数组建立堆最直接的方法就是从左到右遍历数组进行上浮操作。

    2.交换堆顶元素和最后一个元素

      交换之后需要对堆顶元素进行下沉操作,重新保持大顶堆状态。

    代码实现:

    public class Sort{
        public static void heapSort(int[]arr){
            if(arr==null||arr.length==0)
                return;
            for(int i=0;i<arr.length;i++){
                heapInsert(arr,i);  //插入元素构成大顶堆
            }
            int size=arr.length; //堆的大小
            swap(arr,0,--size);//将堆顶元素和最后一个元素交换,堆的大小减1
            while(size>0){//调整当前堆,使其变成大顶堆,下沉过程
                heapify(arr,0,size);
                swap(arr,0,--size);//将堆顶元素和堆里最后一个元素交换,然后堆的大小减1。
            }
            
        }
        public static void heapInsert(int[]arr,int i){
            while(arr[i]>arr[(i-1)/2]){//当前节点大于其父节点,上浮
                swap(arr,i,(i-1)/2);
                i=(i-1)/2;   
            }
        }
        public static void heapify(int []arr,int index,int size){
            int left=2*index+1; //左孩子坐标
            while(left<size){
                int largest=left+1<size&&arr[left]>arr[left+1]?left:left+1;
                largest=arr[largest]>arr[index]?largest:index;
                if(largest==index){
                    break;//如果三个数中最大值还是父节点,那么就退出,不用下沉
                }
                swap(arr,largest,index);
                index=largest; //和前面相同的操作,迭代往下沉,直到越界
                left=index*2+1;
            }
        }
        public static void swap(int[]arr,int index,int largest){
            arr[index]=arr[index]^arr[largest];
            arr[largest]=arr[index]^arr[largest];
            arr[index]=arr[index]^arr[largest];
        }
    }
    

      一个堆的高度为logN,因此在堆中插入元素和删除最大元素的复杂度都为logN。

      对于堆排序,由于要对N个节点进行下沉操作,所以复杂度为O(NlogN)。

      堆排序是原地排序,没有利用额外的空间。

  • 相关阅读:
    C#检查数组是否重复——HashSet
    C#动态生成控件,并添加事件处理,获取控件值并保存
    .net接口交互
    SQL Server 表建Trigger
    SQL Server 表建Trigger
    SQL语句修改not in 变为not exists
    奋战杭电ACM(DAY11)1017
    奋战杭电ACM(DAY11)1016
    奋战杭电ACM(DAY10)1015
    奋战杭电ACM(DAY9)1014
  • 原文地址:https://www.cnblogs.com/yjxyy/p/11103731.html
Copyright © 2011-2022 走看看