堆排序

什么是堆排序 (Heapsort)

堆排序(英语:Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

注意:对于堆的讲解,在另外一篇文章中有讲解,数据结构-堆.

堆排序的步骤

  1. 交换函数

交换函数:因为在构建堆和排序的过程中,需要多次交换元素的位置,所以写了一个交换数组两个位置的函数,在排序算法中,这个函数还是比较重要的,很多排序算法都有用到。

 /**
     * 交换两个位置的数据
     * @param arr
     * @param i
     * @param j
     */
    public  static  void  swap(int[] arr,int i ,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
  1. 堆化函数

堆化函数:主要就是针对于每一个子树,把根节点的值和两个子节点的值做比较,把最大的一个交换到根节点的位置,如果有交换,则需要处理以被交换位置的子节点作为根节点的子树(此处选用的是递归)。

     /**
     *  //堆化
     * @param arr
     * @param len
     */
    public  static void heapify(int[] arr,int index,int len){
        int left = 2 * index + 1;
        int right = 2 * index + 2;
        int max = index;
        //左边的大,交换左边的
        if(left < len && arr[left] > arr[max]){
            max = left;
        }
        //右节点,与左节点和根节点中较大的比较
        if(right < len && arr[right] > arr[max]){
            max = right;
        }
        //如果不相等,说明index位置不是最大的
       if(max != index){
           //左右子节点,与根节点交换
           swap(arr,index,max);
           //由于当前位置发生了调整,所以继续调整当前节点和其子节点
           heapify(arr,max,len);
       }
    }
  1. 构建堆

构建堆:就是把一个无序的数组,初步构建成一个大根堆,从数组的1/2的位置开始,为什么选用这个位置呢,是因为堆的性质:ki >= k2i +1 且 ki >= k2i + 2,所以最后一个元素的父节点,在(len - 1)/2位置。所以从这里开始,就可以覆盖所有的元素。

         //构建堆
    public  static  void buildHeap(int [] arr,int len){
        //这里从数组长度的一半位置,开始向前堆化
        for(int i = (len - 1)/2; i >= 0;i--){
            heapify(arr,i,len);
        }
    }

  1. 堆排序

    堆排序:循环整个数组,利用堆的性质进行排序,把构建好的大根堆(堆顶元素最大)的根位置与最后一元素交换,然后继续把剩余的元素构建成一个大根堆(堆顶元素最大),继续把堆顶的元素交换的倒数第二个位置.....以此类推,就把数组调整成了一个有序数组。

                     //堆排序
            for (int i = arr.length-1;i >= 0;i--){
                swap(arr,0,i);
                heapify(arr,0,i);
            }
    

结论

堆排序就是利用堆的堆顶位置是最小或者最大的性质,把构建好的大根堆或者小根堆,堆顶元素和后面位置的元素交换,以此把最大或者最小的元素交换到数组后方, 从而达到排序的效果。

注意:升序排序,需要构建大根堆,降序排序,需要构建小根堆。

完整的代码

import java.util.Arrays;
public class HeapSort {
    public static void main(String[] args) {
        int[] arr = {3,2,4,5,6,7,5,1,2,3,9,7};
        //构建堆
        buildHeap(arr,arr.length);
        //堆排序
        for (int i = arr.length-1;i >= 0;i--){
            swap(arr,0,i);
            heapify(arr,0,i);
        }
        // 打印排序后的数组
        System.out.println(Arrays.toString(arr));
    }

    //构建堆
    public  static  void buildHeap(int [] arr,int len){
        //这里从数组长度的一半位置,开始向前堆化
        for(int i = (len - 1)/2; i >= 0;i--){
            heapify(arr,i,len);
        }
    }

    /**
     *  //堆化
     * @param arr
     * @param len
     */
    public  static void heapify(int[] arr,int index,int len){
        int left = 2 * index + 1;
        int right = 2 * index + 2;
        int max = index;
        //左边的大,交换左边的
        if(left < len && arr[left] > arr[max]){
            max = left;
        }
        //右节点,与左节点和根节点中较大的比较
        if(right < len && arr[right] > arr[max]){
                max = right;
        }
        //如果不相等,说明index位置不是最大的
       if(Largest != index){
           //左右子节点,与根节点交换
           swap(arr,index,max);
           //由于当前位置发生了调整,所以继续调整当前节点和其子节点
           heapify(arr,max,len);
       }
    }

    /**
     * 交换两个位置的数据
     * @param arr
     * @param i
     * @param j
     */
    public  static  void  swap(int[] arr,int i ,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

输出结果

输入:{3,2,4,5,6,7,5,1,2,3,9,7}

输出:[1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 7, 9]

你可能感兴趣的:(堆排序)