数据结构--堆

一.实现堆

/**
 * @author 2902996750
 * @version 1.0
 * @date 2022/10/9 10:48
 * 堆的3大特性:
 *     1.用数组实现的完全二叉树(除最后一层,其他层必须是满的,最后一层,可以不是满的,但必须左边是满的)
 *     2.如果一个节点对应索引是 k ,那么它的父节点对应索引就是 k/2 ,它的左子节点就是 2k ,右子节点就是 2k+1;
 *     3.堆和二叉树的区别在于堆的每个节点大于等于子节点,而二叉树的节点的左节点会小于该节点,右节点会大于该节点。
 */
public class Heap<T extends Comparable<T>> {
    /**
     * 存储元素的数组
     */
    private T[] items;
    /**
     * 记录堆中元素的个数
     */
    private int anInt;

    public Heap(int n) {
        this.items= (T[]) new Comparable[n+1];
        this.anInt=0;
    }

    /**
     * 判断索引i处的元素是否大于索引j处的值
     * @param i
     * @param j
     * @return
     */
    private boolean less(int i, int j){
        return items[i].compareTo(items[j])>0;
    }

    /**
     * 交换堆中索引i处和索引j处的值
     * @param i
     * @param j
     */
    public void exchange(int i, int j){
        T temp=items[i];
        items[i]=items[j];
        items[j]=temp;
    }

    /**
     * 删除堆中最大元素,并返回这个最大元素
     * 拿最后一个元素与最大的元素进行交换,然后对堆进行下沉算法,重新构建堆
     * @return
     */
    public T delMax(){
        if (items[1]!=null){
            T t=items[1];
            /*
              anInt 不能与 items.length 进行替换。
              items长度为10但是里面存放东西可能没有10个,可能有好多null,不然会空指针异常
             */
            exchange(1,anInt);
            items[anInt]=null;
            anInt--;
            sink(1);
            return t;
        }
        return null;
    }

    /**
     * 往堆中插入一个元素
     * @param t
     */
    public void insert(T t){
       items[++anInt]=t;
       swim(anInt);
    }

    /**
     * 使用上浮算法,使索引k处的值出现在正确的位置
     * @param k
     */
    public void swim(int k){
        while (k>1){
            if(less(k,k/2)){
                exchange(k,k/2);
                k=k/2;
            }
        }
    }

    /**
     * 使用下沉算法,使索引k处的值出现在正确的位置
     * @param k
     */
    public void sink(int k){
        while (2*k<=anInt){
            //max 记录左右节点哪个大
            int max;
            if (2*k+1<=anInt){
                int i = items[2 * k].compareTo(items[2 * k + 1]);
                if (i>0){
                    max=2*k;
                }else {
                    max=2*k+1;
                }
            }else {
                max=2*k;
            }
            //比较当前节点和最大值哪个大
            if (less(k,max)){
                break;
            }else{
                exchange(k,max);
                k=max;
            }
        }
    }
}

二.测试

/**
 * @author 2902996750
 * @version 1.0
 * @date 2022/10/9 14:40
 */
public class Test {
    public static void main(String[] args) {
        Heap<String> stringHeap = new Heap<>(10);
        stringHeap.insert("a");
        stringHeap.insert("b");
        stringHeap.insert("c");
        stringHeap.insert("d");
        stringHeap.insert("e");
        stringHeap.insert("f");
        stringHeap.insert("g");
        String result = stringHeap.delMax();
        while (result != null){
            System.out.print(result);
            result = stringHeap.delMax();
        }
    }
}

三.堆排序

1.实现堆排序

package 堆排序;

/**
 * @author 2902996750
 * @version 1.0
 * @date 2022/10/9 15:15
 */
public class HeapSort<T extends Comparable<T>> {

    /**
     * 对source数组从小到大排序
     * @param source
     */
    public static void sort(Comparable[] source){
        //构建堆存放数据的堆数组
        Comparable[] heaps = new Comparable[source.length + 1];
        createHeap(source,heaps);
        //将最大元素与heaps的最后一个元素替换,然后对heaps重新进行下沉操作,保证堆的完整性(注意此时替换到最后一个位置的最大值不参加堆下沉操作)
        //这里减 1 是因为数组长度减1就是最后一个元素所在索引
        int size=heaps.length-1;
        while (size!=1){
            exchange(heaps,1,size);
            size--;
            sink(heaps,1,size);
        }
        //在这里执行完循环之后就会出现最大值从小到大排列在heap数组中
        System.arraycopy(heaps,1,source,0,source.length);
    }

    /**
     * 根据原数组构造出堆
     * @param comparable
     * @param heap
     */
    public static void createHeap(Comparable[] comparable,Comparable[] heap){
        //把source中的元素拷贝到heap
        System.arraycopy(comparable,0,heap,1,comparable.length);
        //对堆中元素做下沉操作(从长度一半开始做下沉操作)
        for (int i = heap.length/2; i >0 ; i--) {
            sink(heap,i, heap.length-1);
        }
    }

    /**
     * 判断堆中索引i处是否大于索引j处的值
     * @param comparable
     * @param i
     * @param j
     * @return
     */
    public static boolean less(Comparable[] comparable,int i,int j){
        return comparable[i].compareTo(comparable[j])>0;
    }

    /**
     * 交换堆中索引i处和j处的值
     * @param comparable
     * @param i
     * @param j
     */
    public static void exchange(Comparable[] comparable,int i,int j){
        Comparable temp=comparable[j];
        comparable[j]=comparable[i];
        comparable[i]=temp;
    }

    /**
     * 在comparable堆中.对i处元素下沉,范围是0到j
     * @param comparable 对堆顺序错乱的数组进行重新排序
     * @param i 要下沉的节点
     * @param j 参加堆排序的最大节点
     */
    public static void sink(Comparable[] comparable,int i,int j){
        while (2*i<=j){
            //max 记录左右节点哪个大
            int max;
            if (2*i+1<=j){
                int compare = comparable[2 * i].compareTo(comparable[2 * i + 1]);
                if (compare>0){
                    max=2*i;
                }else {
                    max=2*i+1;
                }
            }else {
                max=2*i;
            }
            //比较当前节点和最大值哪个大
            if (less(comparable,i,max)){
                break;
            }else{
                exchange(comparable,i,max);
                i=max;
            }
        }
    }
}

2.测试类

package 堆排序;

import java.util.Arrays;

/**
 * @author 2902996750
 * @version 1.0
 * @date 2022/10/9 16:12
 */
public class Test {
    public static void main(String[] args) {
        //待排序数组
        String[] ars={"s","o","r","t","e","x","a","m","n","p","l","e",};
        //通过heapsort进行排序
        HeapSort.sort(ars);
        //打印排序后数据中的元素
        System.out.println(Arrays.toString(ars));
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值