zoukankan      html  css  js  c++  java
  • 数据结构-最大堆、最小堆【手动实现】

    0,堆的简介

      数据结构中的堆是一种特殊的二叉树,不同于 Java 内存模型中的堆。

      堆必须符合以下两个条件:

    1. 是一棵完全二叉树。
    2. 任意一个节点的值都大于(或小于)左右子节点的值。

      从第一点可以知道,堆适合用数组来存储。

      第二点中,若父节点都大于等于左右子节点,则被称为大顶堆,反之则为小顶堆

    图-最大堆及其存储方式

      0.1节点的父、子节点关系

      一个节点【根节点除外】的父节点地址为其地址的二分之一,它的左子节点地址为其地址值的2倍,右子节点地址为其地址2倍加1。

       例如:现在有个节点的地址为3,其数值为5;那么它的父节点地址为3/2=1,父节点的数值为13;左子节点地址为3*2=6,左子节点数值为6;右子节点地址为3*2+1=7,这个最大堆中没有其右节点数据。

      0.2节点的存储、删除操作

      添加新元素的时候,一般先存放到数组的尾部,之后在通过向上重排序的操作,来进行堆化【满足堆数据结构的调整】

      删除元素时【一般默认删除第一个根节点】,现将数组的最后一个元素放到根节点的位置,之后通过向下重排序的操作,来进行堆化处理。

      

    1,堆的实现

       主要实现功能:①添加元素-add();②输出极值并清除-poll();③输出极值不清除-peek();

      上面的功能都是是显示的函数,隐形函数有:①扩容dilatate();②向上重排序reSortUp();③向下重排序reSortDown();

    package com.cnblogs.mufasa.Solution1;
    
    public class Heap {
        private static final int CAPACITY=16;
        private static final boolean TYPE=true;
    
        private static int[] nums;
        private int capacity=16;
        int size=0;
    
        private boolean type=true;//true由小到大,false由大到小
        public Heap(){
            this(CAPACITY);
        }
    
        public Heap(int capacity){
            this(capacity,TYPE);
        }
    
        public Heap(boolean type){
            this(CAPACITY,type);
        }
    
        public Heap(int capacity,boolean type){
            this.capacity=capacity;
            this.type=type;
            nums=new int[capacity];
        }
    
    
        //数据添加
        public void add(int num){
            if(size+1>=capacity){
                dilatate();
            }
            nums[size+1]=num;
            reSortUp(size+1);
            size++;
        }
    
        private void reSortUp(int index){
            if(type){//由小到大
                while (index!=1){
                    if(nums[index/2]>nums[index]){
                        int temp=nums[index];
                        nums[index]=nums[index/2];
                        nums[index/2]=temp;
                        index/=2;
                    }else if(nums[index/2]==nums[index]){
    //                    throw new IllegalArgumentException("数据结构-堆不接受重复数据输入");
                        break;
                    }else {
                        return;
                    }
                }
            }else {//由大到小
                while (index!=1){
                    if(nums[index/2]<nums[index]){
                        int temp=nums[index];
                        nums[index]=nums[index/2];
                        nums[index/2]=temp;
                        index/=2;
                    }else if(nums[index/2]==nums[index]){
    //                    throw new IllegalArgumentException("数据结构-堆不接受重复数据输入");
                        break;
                    }else {
                        return;
                    }
                }
            }
        }
    
        //数据输出,并且清楚该数据
        public int poll() throws Exception {
            if(size>0){
                int temp=nums[1];
                nums[1]=nums[size];
                reSortDown();
                size--;
                return temp;
            }else {
                throw new Exception("数据为空");
            }
        }
    
        private void reSortDown(){
            int index=1;
            int L,R;
            if(type){//由小到大
                while (index<size){
                    L=index*2;
                    R=L+1;
                    if(R<=size){
                        boolean flag=nums[L]<nums[R];
                        int min=(flag?nums[L]:nums[R]);
                        if(nums[index]>min){
                            if(flag){
                                int temp=nums[index];
                                nums[index]=nums[L];
                                nums[L]=temp;
                                index=L;
                            }else {
                                int temp=nums[index];
                                nums[index]=nums[R];
                                nums[R]=temp;
                                index=R;
                            }
                        }else {
                            return;
                        }
                    }else if(L<=size){
                        if(nums[index]>nums[L]){
                            int temp=nums[index];
                            nums[index]=nums[L];
                            nums[L]=temp;
                        }
                        return;
                    }else {
                        return;
                    }
                }
            }else {//由大到小
                while (index<size){
                    L=index*2;
                    R=L+1;
                    if(R<size){
                        boolean flag=nums[L]<nums[R];
                        int max=(flag?nums[R]:nums[L]);
                        if(nums[index]<max){
                            if(flag){
                                int temp=nums[index];
                                nums[index]=nums[R];
                                nums[R]=temp;
                                index=R;
                            }else {
                                int temp=nums[index];
                                nums[index]=nums[L];
                                nums[L]=temp;
                                index=L;
                            }
                        }else {
                            return;
                        }
                    }else if(L<size){
                        if(nums[index]<nums[L]){
                            int temp=nums[index];
                            nums[index]=nums[L];
                            nums[L]=temp;
                        }
                        return;
                    }else {
                        return;
                    }
                }
            }
        }
    
        //数据输出,不清除该数据
        public int peek() throws Exception {
            if(size>0){
                return nums[0];
            }else {
                throw new Exception("数据为空");
            }
        }
    
        //数据扩容,二倍扩容
        private void dilatate(){
            capacity=capacity<<1;
            int[] pre=new int[capacity];
            for(int i=1;i<=size;i++){
                pre[i]=nums[i];
            }
            nums=pre;
        }
    
    }
    
    class Client{
        public static void main(String[] args) throws Exception {
            Heap heap=new Heap(4,true);
    //        Heap heap=new Heap(4,false);
            heap.add(5);
            heap.add(3);
            heap.add(3);
            heap.add(7);
            heap.add(1);
            heap.add(0);
            heap.add(8);
            heap.add(8);
    
            int len=heap.size;
            for(int i=0;i<len;i++){
                System.out.print(heap.poll()+",");
            }
        }
    }
    /*
    0,1,3,5,7,8,
    8,7,5,3,1,0,
     */

    2,堆的应用

      3.1 堆排序

      利用堆这种数据结构,来进行数组排序,时间复杂度为O(nlogn)

      3.2 Java容器中的优先队列

      PriorityQueue<Integer> queue=new PriorityQueue<Integer>();

      3.3 求动态集合中位数

      有若干个数据,求其中位数,并且数据还在不断的输入【两个堆数据即可很好的解决问题,一个最大堆,一个最小堆】

      3.4 60百分位的数

      这个问题是上面的问题的扩展,本质上也是使用两个对数据结构即可。但是需要控制两个堆中元素个数的比例!

  • 相关阅读:
    C#随机数的使用
    英才评测 个人性格倾向 IT知识
    有点迷茫
    [转帖]2006年it人士必去的10个网站
    ASP.NET 中 Cookie 的基本知识
    Http请求方法
    Spherical Mercator
    Axure快速原型设计
    【转】Spring Insight 使用介绍
    DB2执行sql文件
  • 原文地址:https://www.cnblogs.com/Mufasa/p/11580751.html
Copyright © 2011-2022 走看看