数据结构---堆

目录

堆的概念

向下调整

优先级队列---PriorityQueue

构造方法

add---增加元素

 扩容机制

向上调整

poll---删除元素

TOPK问题 

堆排序

 对象的比较


堆的概念

堆实现了树的顺序存储

大根堆:根结点大于孩子结点,并且左右子树都是大根堆

小根堆:根结点小于孩子结点,并且左右子树都是小根堆

已知父亲节点下标:parent,左孩子下标:2*parent+1,右孩子下标:2*parent+2

已知孩子结点下标:child,父亲结点下标:(child-1)/2

向下调整

class  Myheap {
    int[] elem=new int[20];
    int usedsize=0;

    public void init(int[] array) {
        for (int i = 0; i < array.length; i++) {
            elem[i] = array[i];
            usedsize++;
        }
        for (int parent = (usedsize - 2) / 2; parent >= 0; parent--) {
//得到最后一个子树的根节点
           shifedown(parent, usedsize);//将每个子树进行调整
        }
    }

    public void shifedown(int parent, int sz) {//每一棵树,调整结束的位置都是末尾
        //usedsize是长度
        int left = 2 * parent + 1;//左孩子下标
        //左孩子下标<右孩子下标
        while (left < sz) {
            if (left + 1 < sz) {//右孩子存在
                if (elem[left + 1] > elem[left])
                    left++;
            }//left是左右孩子最大值的下标
            if (elem[parent] < elem[left]) {//根结点转换为最大值
                int tmp = elem[parent];
                elem[parent] = elem[left];
                elem[left] = tmp;
                //   有可能调整好了,但是又破坏了子树,要继续调整子树
                parent = left;
                left = parent * 2 + 1;
            } else
                break;
        }
    }
   
}
public  class Heap {
    public static void main(String[] args) {
        Myheap myheap=new Myheap();
        int []array={8,7,0,21,87,32,18,9};
        myheap.init(array);
        for (int i = 0; i < myheap.usedsize ; i++) {
            System.out.print(myheap.elem[i]+" ");
        }
    }

时间复杂度:O(N)

每一层的结点个数*每一个结点调整的高度---》 Sn = n - log₂(n + 1)

优先级队列---PriorityQueue

 public static void main(String[] args) {
        PriorityQueue<Integer>priorityQueue=new PriorityQueue<>();//优先级队列
    }

构造方法

 也就是说:不传入大小时,默认空间11,传入大小>=1时,是传入大小

add---增加元素

 使用小堆存储

 扩容机制

向上调整

简单模拟实现大根堆的add方法(扩容没考虑)

调整一次:复杂度O(log2 N)

    public void offer(int x) {
        if (usedsize == 0) {
            elem[usedsize++] = x;
        } else {
            elem[usedsize++] = x;//开始调整
            int child = usedsize - 1;
            int parent = (child - 1) / 2;
            while (parent >= 0) {
                if (elem[parent] < elem[child]) {
                    int tmp = elem[parent];
                    elem[parent] = elem[child];
                    elem[child] = tmp;
                    child = parent;
                    parent = (child - 1) / 2;
                } else {
                    break;
                }
            }
        }
    }

poll---删除元素

删除完毕,剩下的元素仍然是小堆存储

大根堆删除的模拟实现 

    public void poll() {
        if (usedsize == 0)
            throw new RuntimeException("删除元素,优先级队列为空");
        else {
            elem[0] = elem[usedsize - 1];
            usedsize--;
           shifedown(0,usedsize);
        }
    }

TOPK问题 

例如:给定100个无序的数字,找到前10个最大的元素

    public static void main(String[] args) {
        PriorityQueue<Integer>priorityQueue=new PriorityQueue<>();
        int []array={1,3,2,4,5,2,3,2,4,8,9,0,98,78,76};
        int k=5;
        for(int i=0;i<k;i++){
            priorityQueue.add(array[i]);
        }
        for(int i=k;i<array.length;i++) {
            if(!priorityQueue.isEmpty()) {
                if (priorityQueue.peek() < array[i]) {
                    priorityQueue.poll();
                    priorityQueue.add(array[i]);
                }
            }
        }
        System.out.println(priorityQueue);
    }

 求前k个最大的元素:建立小根堆

 求前k个最小的元素:建立大根堆

 求第k个最大的元素:建立小根堆,顶点元素

 求第k个最小的元素:建立大根堆,顶点元素

堆排序

从小到大排:大根堆

从大到小排:小根堆

 建立小根堆,实现从大到小排

 public static void shifedown(int []elem,int parent, int sz) {//每一棵树,调整结束的位置都是末尾
        int left = 2 * parent + 1;//左孩子下标
        //左孩子下标<右孩子下标
        while (left < sz) {
            if (left + 1 < sz) {//右孩子存在
                if (elem[left + 1] < elem[left])
                    left++;
            }
            if (elem[parent] > elem[left]) {
                int tmp = elem[parent];
                elem[parent] = elem[left];
                elem[left] = tmp;
                //   有可能调整好了,但是又破坏了子树,要继续调整子树
                parent = left;
                left = parent * 2 + 1;
            } else
                break;
        }
    }

    public static void main(String[] args) {
        int []array={1,3,2,4,5,2,3,2,4,8,9,0,98,78,76};
        for (int i = (array.length-2)/2; i >=0 ; i--) {
            shifedown(array,i,array.length);
        }
        int end=array.length-1;
        for (int i=end;i>=0;i--){
            int tmp=array[0];
            array[0]=array[i];
            array[i]=tmp;
            shifedown(array,0,i);
        }
       for (int i=0;i<array.length;i++){
           System.out.print(array[i]+" ");
       }
    }

 对象的比较

class Person{
    int age;
    String name;

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }
}
public class Text {
    public static void main(String[] args) {
        PriorityQueue<Person>priorityQueue=new PriorityQueue<>();
        priorityQueue.add(new Person(30,"李四"));
        priorityQueue.add(new Person(14,"王五"));
        priorityQueue.add(new Person(34,"张三"));
        System.out.println(priorityQueue);
    }
}

 抛出异常

 指定小堆的比较方式

class Person{
    int age;
    String name;

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
class ComparatorAge implements Comparator<Person>{
    @Override
    public int compare(Person o1, Person o2) {
        return o1.age-o2.age;
    }
}
class ComparatorName implements Comparator<Person>{
    @Override
    public int compare(Person o1, Person o2) {
        return o1.name.compareTo(o2.name);
    }
}
public class Text {
    public static void main(String[] args) {
        PriorityQueue<Person>priorityQueue=new PriorityQueue<>(new ComparatorName());
        priorityQueue.add(new Person(30,"李四"));
        priorityQueue.add(new Person(14,"王五"));
        priorityQueue.add(new Person(34,"张三"));
        System.out.println(priorityQueue);
    }
  }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值