堆排序算法Java面向对象实现

堆排序算法介绍

堆是一种重要的数据结构,为一棵完全二叉树, 底层如果用数组存储数据的话,假设某个元素为序号为i(Java数组从0开始,i为0到n-1),如果它有左子树,那么左子树的位置是2i+1,如果有右子树,右子树的位置是2i+2,如果有父节点,父节点的位置是(n-1)/2取整。分为最大堆和最小堆,最大堆的任意子树根节点不小于任意子结点,最小堆的根节点不大于任意子结点。所谓堆排序就是利用堆这种数据结构来对数组排序,我们使用的是最大堆。处理的思想和冒泡排序,选择排序非常的类似,一层层封顶,只是最大元素的选取使用了最大堆。最大堆的最大元素一定在第0位置,构建好堆之后,交换0位置元素与顶即可。堆排序为原位排序(空间小), 且最坏运行时间是O(nlgn),是渐进最优的比较排序算法。

实现思路

堆排序简单来说可以概括为三个步骤:
1.根据数据建立无序的堆
2.对堆按大顶堆或小顶堆调整。大顶堆即是满足树中根节点的值始终大于孩子节点的值,局部也满足这个条件,小顶堆相反。
3.每一次调整过后再顶部得到这些数据的最大值或最小值,出堆,并把最后一个节点放到顶部,以此循环,直到堆里的数据全部给出。

具体代码

堆排序类

public class HeapSort<T extends Comparable<T>> {

    private List<T> sub;// 排序资源列表

    private Integer listLength = 0;// 元素个数

    private Integer nodeNum = 0;// 堆中节点个数

    private Node top;// 顶节点

    private Node end;// 最后一个节点

    private Node end2;// 倒数第二个节点

    private List<T> result = new ArrayList<T>();//排序结果

    public HeapSort(List<T> srcList) {
        this.nodeNum = 1;
        this.top = new Node((T)srcList.get(0), 1, 1);// 顶节点默认层数为1,编号为1
        this.sub = srcList.subList(1, srcList.size());
        this.listLength = srcList.size();
        this.end = null;
        createHeap(this.top);
    }

    // 创建堆
    private void createHeap(Node h) {
        if (sub == null || sub.size() <= 0) {
            return;
        }
        // 添加左孩子
        createLeftChild(h);
        // 添加右孩子
        createRightChild(h);
        return;
    }

    // 创建左孩子
    private void createLeftChild(Node h) {
        if (h.getLeft() != null) {
            return;
        }
        if (listLength >= h.getNum().intValue() * 2) {// 可以有左孩子
            nodeNum++;
            Node leftChild = new Node((T)sub.get(0), h.getFloor() + 1, h.getNum() * 2);
            h.setLeft(leftChild);
            leftChild.setParent(h);
            if (leftChild.getNum() == listLength) {// 最后一个节点
                end = leftChild;
            }
            sub = sub.subList(1, sub.size());
            createHeap(leftChild);
        }else{
            end = h;
        }
        return;
    }

    // 创建右孩子
    private void createRightChild(Node h) {
        if (h.getRight() != null) {
            return;
        }
        if (listLength >= h.getNum().intValue() * 2 + 1) {// 可以有右孩子
            nodeNum++;
            Node rightChild = new Node((T)sub.get(0), h.getFloor() + 1, h.getNum() * 2 + 1);
            h.setRight(rightChild);
            rightChild.setParent(h);
            if (rightChild.getNum() == listLength) {// 最后一个节点
                end = rightChild;
            }
            sub = sub.subList(1, sub.size());
            createHeap(rightChild);
        }
        return;
    }

    /**
     * 调整大顶堆,并且返回最顶端的值
     * @param h 根节点
     * @return
     */
    private T adjustMaxHeap(Node h) {
        // 通过迭代遍历根节点和孩子节点,调整为根节点最大
        if (h == null) {
            return null;
        }
        if(nodeNum==1){
            return (T) top.getValue();
        }
        if (h.getNum().equals(nodeNum - 1)) {// 调整堆的时候添加上倒数第二个节点的引用,以便删除最后一个节点后将end指向此节点
            end2 = h;
        }
        T top = (T) h.getValue();
        // 调整左孩子
        T maxLeft = adjustMaxHeap(h.getLeft());
        // 调整右孩子
        T maxRight = adjustMaxHeap(h.getRight());
        if (maxLeft == null && maxRight == null) {// 没有左右孩子
            return (T) h.getValue();
        } else if (maxLeft == null && maxRight != null) {// 没有左孩子
            if (maxRight.compareTo(top)>0) {
                h.setValue(maxRight);
                h.getRight().setValue(top);
            }
        } else if (maxLeft != null && maxRight == null) {// 没有右孩子
            if (maxLeft.compareTo(top)>0) {
                h.setValue(maxLeft);
                h.getLeft().setValue(top);
            }
        } else {// 有左右孩子
            if (maxLeft.compareTo(top)>0 || maxRight.compareTo(top)>0) {
                if (maxLeft.compareTo(maxRight)>=0) {// 左孩子最大
                    h.setValue(maxLeft);
                    h.getLeft().setValue(top);
                } else {// 右孩子最大
                    h.setValue(maxRight);
                    h.getRight().setValue(top);
                }
            }
        }
        return (T) h.getValue();
    }

    /**
     * 堆排序方法(大顶堆)
     * @param srcList
     * @return
     */
    public List<T> sort() {
        // 循环调整堆
        while (floorMoreOne()) {
            T max = adjustMaxHeap(top);
            //stack.push(max);
            result.add((T) max);
            top.setValue(end.getValue());
            Node parent = end.getParent();
            if (end.getParent() == null) {
                break;
            }
            if (parent.getLeft() != null && parent.getLeft().getNum().intValue() == end.getNum().intValue()) {
                parent.setLeft(null);
            }
            if (parent.getRight() != null && parent.getRight().getNum().intValue() == end.getNum().intValue()) {
                parent.setRight(null);
            }
            nodeNum--;
            end = end2;
            // end指向倒数第二个节点
        }
        result.add((T) top.getValue());
        return result;
    }

    // 判断堆的层数是否大于一
    private boolean floorMoreOne() {
        if (top.getLeft() != null || top.getRight() != null) {
            return true;
        }
        return false;
    }
}

节点类

public class Node<T> {

    private T value;// 节点的值

    private Integer floor;// 节点所在层

    private Integer num;// 节点编号

    private Node parent;// 父节点

    private Node left;// 左孩子

    private Node right;// 右孩子

    public Node() {
    }

    public Node(T value) {
        super();
        this.value = value;
    }

    public Node(T value, Integer floor) {
        super();
        this.value = value;
        this.floor = floor;
    }

    public Node(T value, Integer floor, Integer num) {
        super();
        this.value = value;
        this.floor = floor;
        this.num = num;
    }

    public Node<T> getLeft() {
        return left;
    }

    public Integer getNum() {
        return num;
    }

    public void setLeft(Node leftChild) {
        this.left = leftChild;
    }

    public void setRight(Node rightChild) {
        this.right = rightChild;
    }

    public void setParent(Node h) {
        this.parent = h;
    }

    public int getFloor() {
        return floor;
    }

    public T getValue() {
        return value;
    }

    public Node getRight() {
        return right;
    }

    public void setValue(T value) {
        this.value = value;
    }

    public Node getParent() {
        return parent;
    }
}

这个实现中用到了泛型,可以对多种类型排序,只需要实现comparable接口并实现了compareTo方法。

测试代码

public void test01(){
        @SuppressWarnings("unchecked")
        int j=0;
        String[] strs = new String[1000];
        while(j<strs.length){
            int len = (int) Math.floor(Math.random()*10+1);
            byte[] bytes = new byte[len];
            for(int k=0;k<len;k++){
                bytes[k] = (byte) Math.floor(Math.random()*26+65);
            }
            strs[j] = new String(bytes);
            j++;
        }
        HeapSort<String> sort = new HeapSort<String>((List<String>)Arrays.asList(strs));
        List<String> list1 = sort.sort();
        for(String o:list1){
            if(list1.indexOf(o)%10==0){
                System.out.println(o.toString()+" ");
            }else{
                System.out.print(o.toString()+" ");
            }
        }
    }

测试结果

这个实例是纯java面向对象的实现,相比较原生面向过程的实现处理速度回慢,占用资源也多,进攻学习用。如果有什么问题,希望道友们慷慨指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值