堆排序思想及代码实现

堆排序思想及代码实现

前言

对于一个数组,如果要实现数组中元素从小到大进行排序,此时这种需求就可以利用堆排序进行实现。本文讲解如果利用堆排序实现数组元素从小到大进行排序。

一、实现步骤

1.构造堆;
2.得到堆顶元素,这个值就是最大值;
3.交换堆顶元素和数组中的最后一个元素,此时所有元素中的最大元素已经放到合适的位置;
4.对堆进行调整,重新让除了最后一个元素的剩余元素中的最大值放到堆顶;
5.重复2~4这个步骤,直到堆中剩一个元素为止。

二、构造堆

1.由数组构造堆的思路一

堆的构造,最直观的想法就是另外再创建一个和新数组,然后从左往右遍历原数组,每得到一个元素后,添加到新数组中,并通过上浮,对堆进行调整,最后新的数组就是一个堆。

2.由数组构造堆的思路二

上述的方式虽然很直观,也很简单,但是我们可以用更聪明一点的办法完成它。创建一个新数组,把原数组的数据拷贝到新数组的1~length处,再从新数组长度的一半处开始往1索引处扫描(从右往左),然后对扫描到的每一个元素做下沉调整即可。
为什么是一半处?
因为堆的特性,前一半都是非叶子节点,后一半都是叶子节点,而叶子节点不能再下沉。

  • 一次由数组构造堆的过程
    堆排序思想及代码实现
    堆排序思想及代码实现
    堆排序思想及代码实现

3.思路二的具体代码实现

//根据原数组source,构造出堆heap
    private static void createHeap(Comparable[] source, Comparable[] heap)
    {
        //1.拷贝source数组到heap数组中(heap[0]元素不用),此时heap一个无序的堆
        System.arraycopy(source,0,heap,1,source.length);
        //2.对前一半元素使用下沉算法,使得heap成为真正有序的堆
        for (int i = (heap.length-1)/2; i >0 ; i--) {
            sink(heap,i,heap.length-1);
        }
    }

    //在heap堆中,对target处的元素做下沉,范围是0~range。
    private static void sink(Comparable[] heap, int target, int range)
    {
        //如果target位置结点的左子树存在,则循环遍历,将target位置结点与其左右子结点中较大的进行比较,若target位置处的结点小于较大的子结点,则交互
        while (2*target<=range)
        {
            int maxIndex;//左右结点中较大结点的索引
            //如果右结点存在,则比较左右子结点中较大的结点
            if (2*target+1<=range)
            {
                if (less(heap,2*target,2*target+1))
                {
                    maxIndex=2*target+1;
                }
                else
                    maxIndex=2*target;
            }
            //如果右结点不存在,则较大子结点就是左节点
            else
            {
                maxIndex=2*target;
            }

            //比较当前节点与较大子结点的大小,如果当前结点较小,则交换,否则,结束循环
            if(!less(heap,target,maxIndex))
            {
                break;
            }

            exch(heap,target,maxIndex);

            target=maxIndex;//继续下一次循环
        }
    }

    //判断heap堆中索引i处的元素是否小于索引j处的元素
    private static boolean less(Comparable[] heap, int i, int j)
    {
        return heap[i].compareTo(heap[j])<0;
    }
    //交换heap堆中i索引和j索引处的值
    private static void exch(Comparable[] heap, int i, int j)
    {
        Comparable temp=heap[i];
        heap[i]=heap[j];
        heap[j]=temp;
    }

三、堆排序

1.堆排序思路

对构造好的堆,我们只需要做类似于堆的删除操作,就可以完成排序。
1.将堆顶元素和堆中最后一个元素交换位置;
2.通过对堆顶元素下沉调整堆,把最大的元素放到堆顶(此时最后一个元素不参与堆的调整,因为最大的数据已经到了数组的最右边)
3.重复1~2步骤,直到堆中剩最后一个元素。
堆排序思想及代码实现
堆排序思想及代码实现
堆排序思想及代码实现
堆排序思想及代码实现

2.堆排序思路代码实现

 //对source数组中的数据从小到大排序
    public static void sort(Comparable[] source)
    {
        Comparable[] heap = new Comparable[source.length + 1];
        //创建堆
        createHeap(source,heap);
        int maxIndex = heap.length-1;
        //通过循环不断交互索引1和最大索引处的元素,并下沉元素1,排除最大索引处的结点
        while (maxIndex!=1)
        {
            exch(heap,1,maxIndex);
            maxIndex--;
            sink(heap,1,maxIndex);
        }
        //将堆数组拷贝到source数组
        System.arraycopy(heap,1,source,0,source.length);
    }

四、堆排序测试

//堆排序测试
public class HeapSortTest {
    public static void main(String[] args) {
        String[] arr = {"S","O","R","T","E","X","A","M","P","L","E"};
        HeapSort.sort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

堆排序思想及代码实现

上一篇:LeetCode——264. 丑数 II(Java)


下一篇:(五)内存管理