Java 堆排序

堆排序,我想了好几天,最后还是参考了一下别人的博客,看了许多的解释,不过还是下面这些最好理解:

http://www.ixywy.com/zsjz/2564.html (这篇的不是博客)

http://blog.csdn.net/zdp072/article/details/44227317 (csdn博客)

好了,代码如下:

package com.vgbh;

/*
 * 堆排序
 */

public class heapSorting {

    /*
    堆排序算法思想:
    堆排序,顾名思义,就是基于堆。

    因此先来介绍一下堆的概念:
    堆分为最大堆和最小堆,其实就是:完全二叉树或近似完全二叉树。
    二叉树的特点:
    1.最大堆要求节点的元素都要大于其孩子。
    2.最小堆要求节点元素都小于其左右孩子。
    有了上面的定义,我们可以得知,处于最大堆的根节点的元素一定是这个堆中的最大值。
    其实我们的堆排序算法就是抓住了堆的这一特点,每次都取堆顶的元素,将其放在序列最后面,然后将剩余的元素重新调整为最大堆,依次类推,最终得到排序的序列。

    本质上讲,堆排序是一种选择排序,每次都选择堆中最大的元素进行排序。只不过堆排序选择元素的方法更为先进,时间复杂度更低,效率更高。
     */

    /*
    步骤:
    1 首先从第一个非叶子节点开始,比较当前节点和其孩子节点,将最大的元素放在当前节点,交换当前节点和最大节点元素。
    2 将当前元素前面所有的元素都进行1的过程,这样就生成了最大堆
    3 将堆顶元素和最后一个元素交换,列表长度减1。由此无序区减1,有序区加1
    4 剩余元素重新调整建堆
    5 继续3和4,直到所有元素都完成排序
    */

    /*
    时间复杂度:
    堆排序的平均时间复杂度为O(nlogn),接近于最坏的时间复杂度。
    在最好情况下,时间复杂度为O(1).
     */

    /*
    算法总结:
    堆排序时间复杂度:O(nlogn)
    堆排序对原始记录的排序状态并不敏感,其在性能上要远远好过于冒泡、简单选择、直接插入排序。
     */

    private static int n = 10 ;//数组长度
    private static int[] arr = new int[n] ;//数组

    static PublicOut pc = null ;//定义外部对象

    public static int count = 0;//运行次数

    public static void main(String[] args) {

        pc = new PublicOut();
        pc.data(arr, n);
        pc.prin(arr, n);

        heapSorting hs = new heapSorting();
        hs.heap(arr);

        pc.prin(arr, n);

        //System.out.println("最后共运行" + count + "次。");

    }

    //数据结构的p281有详细的运算过程     详解:http://www.ixywy.com/zsjz/2564.html

    //堆排序
    public void heap (int[] arr) {
        //将数组转化为大堆
        for (int i=arr.length / 2; i>=0; i--) {
            buildHeap(arr,i,arr.length);
        }

        //将最小值与最大值交换,并调整二叉树
        for (int i=arr.length - 1; i>0; i--) {
            swap(arr, 0, i);//将父元素和当前未经排序子序列的最后一个记录交换
            buildHeap(arr, 0, i);//交换之后,重新比对二叉树,不符合则要调整。
        }

    }

    /*
     * 创建堆
     * arr:数组
     * x:需要构建堆的根节点的序号
     * y:数组长度
     */
    public void buildHeap (int[] arr,int x,int y) {
        count++;
        int child ;
        int father ;
        for (father = arr[x]; leftChild(x) < y; x = child) {
            child = leftChild(x);

            //如果左子树小于右子树,则需要比较右子树和父节点
            if (child != y-1 && arr[child] < arr[child+1]) {
                child++;//自增可以指向父节点
            }

            //如果父节点小于孩子节点,则需要交换
            if (father < arr[child]) {
                arr[x] = arr[child];
            } else {
                break;//大堆未被破坏,不需要调整
            }
        }
        arr[x] = father;

    }

    //交换元素
    public void swap (int[] arr,int x,int y) {
        int tmp = arr[x];
        arr[x] = arr[y];
        arr[y] = tmp;
    }

    //获取左孩子结点
    public int leftChild (int i) {
        return 2 * i + 1;
    }

}

如果关于堆排序还有不会的,可以发邮件到我的邮箱。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

vgbh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值