堆排序(java)

宝宝记性很差,需要不断的强化才能有所记忆,所以。。。记录学习~~

堆是一种有序队列,普通的队列是先进先出,而堆是最小元素(最大元素)先出;
首先,堆必须是一棵完全二叉树,完全二叉树有一些性质可以很好的利用,如:
完全树(Complete Tree):从下图中看出,在第n层深度被填满之前,不会开始填第n+1层深度,还有一定是从左往右填满。
这里写图片描述

再来一棵完全三叉树:
这里写图片描述

这样有什么好处呢?好处就是能方便地把指针省略掉,用一个简单的数组来表示一棵树,如图:
这里写图片描述

那么下面介绍二叉堆:二叉堆是一种完全二叉树,其任意子树的左右节点(如果有的话)的键值一定比根节点大,上图其实就是一个二叉堆。
你一定发觉了,最小的一个元素就是数组第一个元素,那么二叉堆这种有序队列如何入队呢?看图:
这里写图片描述

假设要在这个二叉堆里入队一个单元,键值为2,那只需在数组末尾加入这个元素,然后尽可能把这个元素往上挪,直到挪不动,经过了这种复杂度为Ο(logn)的操作,二叉堆还是二叉堆。
那如何出队呢?也不难,看图:
这里写图片描述

出队一定是出数组的第一个元素,这么来第一个元素以前的位置就成了空位,我们需要把这个空位挪至叶子节点,然后把数组最后一个元素插入这个空位,把这个“空位”尽量往上挪。这种操作的复杂度也是Ο(logn),比Ο(n)强多了吧?
代码如下:(大致代码)

package com.luxia.datastructure;
import java.util.ArrayList;
import java.util.Comparator;
/**
 * 二叉堆(最小最大堆)
 * @author wangluxia
 *
 */
public class BinaryHeap<E extends Comparable<?>>{

// 用数组实现
private ArrayList<E> values;
private Boolean isMinHeap;
private Comparator<E> compatator;

public BinaryHeap(ArrayList<E> values,Boolean isMinHeap,Comparator<E> comparator){
    this.values=values;
    this.isMinHeap=isMinHeap;
    this.compatator=comparator;
}

/**
 * 是否为空
 * @return
 */
public Boolean isEmpty(){
    return values.isEmpty();
}

/**
 * 获得最大/最小的元素
 * @return
 */
public E get(){
    if(isEmpty()){
        return null;
    }else{
        return values.get(0);
    }
}

/**
 * 比较函数
 * @return
 */
public int compare(E a,E b){
    if(this.compatator!=null){
        // 使用自己提供的比较器进行比较
        return this.compatator.compare(a, b);
    }else{
        @SuppressWarnings("unchecked")
        Comparable<E> ca=Comparable.class.cast(a);
        return ca.compareTo(b);
    }
}

/**
 * 最小堆
 * 向上调整
 * 每个元素和父元素进行比较 如果比父元素小 则替换父元素
 */
public void minUp(int index){
    int tmp=index;
    E element=values.get(index);

    // tmp>0 则肯定存在父元素
    while(tmp > 0 && this.compare(element, values.get((tmp-1)/2))<0){
        int next=(tmp-1)/2;
        this.values.set(tmp,values.get(next));
        tmp=next;
    }
    this.values.set(tmp, element);
}

/**
 * 最大堆向上调整
 * @param index
 */
public void maxUp(int index){
    int tmp=index;
    E element=values.get(index);

    // tmp>0 则肯定存在父元素
    while(tmp > 0 && this.compare(element, values.get((tmp-1)/2))>0){
        int next=(tmp-1)/2;
        this.values.set(tmp,values.get(next));
        tmp=next;
    }
    this.values.set(tmp, element);
}

/**
 * 最小堆向下调整
 * @param index
 */
public void minDown(int index){
    int tmp=index;
    E element = this.values.get(tmp);

    while((tmp*2+1)<this.values.size()){
        int minChild=tmp*2+1;
        // 找到左右孩子的 小的那个 (如果存在右孩子时)
        if((tmp*2+2)<this.values.size() && this.compare(this.values.get(minChild), this.values.get(tmp*2+2))>0){
            minChild++;
        }

        if(this.compare(this.values.get(minChild), element)>=0){
            break;
        }

        this.values.set(tmp, this.values.get(minChild));
        tmp=minChild;
    }
    this.values.set(tmp, element);
}

/**
 * 最大堆向下调整
 * @param index
 */
public void maxDown(int index){
    int tmp=index;
    E element = this.values.get(tmp);

    while((tmp*2+1)<this.values.size()){
        int maxChild=tmp*2+1;
        // 找到左右孩子的 小的那个 (如果存在右孩子时)
        if((tmp*2+2)<this.values.size() && this.compare(this.values.get(maxChild), this.values.get(tmp*2+2))<0){
            maxChild++;
        }

        if(this.compare(this.values.get(maxChild), element)<=0){
            break;
        }

        this.values.set(tmp, this.values.get(maxChild));
        tmp=maxChild;
    }
    this.values.set(tmp, element);
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值