大顶堆小顶堆笔记

大顶堆小顶堆笔记

堆是一颗完全二叉树

堆分为两类:
1、最大堆(大顶堆):堆的每个父节点都大于其孩子节点;
2、最小堆(小顶堆):堆的每个父节点都小于其孩子节点;

堆的存储:
一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2,i从0开始

堆排序:
堆的第一个元素要么是最大值(大顶堆),要么是最小值(小顶堆),这样在排序的时候(假设共n个节点),直接将第一个元素和最后一个元素进行交换,然后从第一个元素开始进行向下调整至第n-1个元素。所以,如果需要升序,就建一个大堆,需要降序,就建一个小堆。
堆排序的步骤分为三步:
1、建堆(升序建大堆,降序建小堆)
2、交换数据
3、向下调整

实现
注释基完整,网上得有一些问题,修改了没问题,测试过了(代码就是网上的)
重点在于元素交换操作

项目结构
在这里插入图片描述

MinHeap

package com.example.taco.minHeapTest;

import lombok.Data;

/**
 * 最小堆实现
 *
 * @author lh
 * @date 2022/01/13 20:52
 */
@Data
public class MinHeap {
    /**
     * 堆容器数组
     */
    private Node[] heapArray;

    /**
     * 堆最大大小
     */
    private int maxSize;

    /**
     * 堆当前大小
     */
    private int currentSize;

    /**
     * 构造最小堆
     *
     * @param maxSize
     */
    public MinHeap(int maxSize) {
        this.maxSize = maxSize;
        heapArray = new Node[maxSize];
        currentSize = 0;
    }

    /**
     * 自上而下扫描树,将节点换成两个子女中大的那一个
     *
     * @param start
     * @param endOfHeap
     */
    public void filterDown(int start, int endOfHeap) {
        /**
         *i当前节点
         */
        int i = start;
        /**
         * 左边孩子节点
         */
        int j = 2 * i + 1;

        Node temp = heapArray[i];
        //检查是否到达最后位置
        while (j <= endOfHeap) {
            //让j指向两子女中小的那一个
            if (j < endOfHeap && heapArray[j].getIDate() > heapArray[j + 1].getIDate()) {
                j++;
            }
            //如果子节点比当前点大则停止
            if (temp.getIDate() <= heapArray[j].getIDate()) {
                break;
            }
            //当前节点大,则交换i,j
            else {
                heapArray[i] = heapArray[j];
                i = j;
                j = 2 * j + 1;
            }
        }
        //回送,即是将函数入口的开始值放到最后的位置,即底部位置
        heapArray[i] = temp;
    }

    /**
     * 自下而上的调整:从节点start开始到0为止,自下而上比较,如果子女的值小于双亲节点的值则互相交换
     *
     * @param start
     */
    public void filterUp(int start) {
        /**
         *j 当前节点
         */
        int j = start;
        /**
         * i 当前节点的双亲节点
         */
        int i = (j - 1) / 2;
        /**
         * Node 暂存当前节点
         */
        Node temp = heapArray[j];
        //沿着双亲节点直达根节点
        while (j > 0) {
            //双亲节点值小,不调整
            if (heapArray[i].getIDate() <= temp.getIDate()) {
                break;
            } else {
                heapArray[j] = heapArray[i];
                j = i;
                i = (i - 1) / 2;
            }
        }
        //回送,即是将函数入口的开始值放到最后的位置,即底部位置
        heapArray[j] = temp;
    }

    /**
     * 插入元素,根据当前关键字构建节点,自上而下扫瞄成功就插入,并且堆的大小加1
     *
     * @param key
     * @return
     */
    public boolean insert(int key) throws MinHeapException {
        /**
         * 为真则插入成功
         */
        boolean bool = true;
        //堆满插入失败
        if (isFull()) {
            bool = false;
            throw new MinHeapException("heap is full");
        } else {
            /**
             * 构建一个节点
             */
            Node newNode = new Node(key);
            //赋给最后的位置
            heapArray[currentSize] = newNode;
            //调整位置
            filterUp(currentSize);
            currentSize++;
        }
        return bool;
    }

    private boolean isFull() {
        return currentSize == maxSize;
    }

    /**
     * 按某种格式输出堆
     */
    public void displayHeap() {
        System.out.println("heapArray:");
        for (int i = 0; i < currentSize; i++) {
            if (heapArray[i] != null) {
                System.out.println(heapArray[i].getIDate() + " ");
            } else {
                System.out.println("-- ");
            }
        }
        System.out.println();
        //输出堆
        int nBlanks = 32;
        int itemsPerRow = 1;
        int column = 0;
        int j = 0;
        String dots = ".........................";
        System.out.println(dots + dots);

        while (currentSize > 0) {
            if (column == 0) {
                for (int k = 0; k < nBlanks; k++) {
                    System.out.print(" ");
                }
            }
            System.out.print(heapArray[j].getIDate());
            if (++j == currentSize) {
                break;
            }

            if (++column == itemsPerRow) {
                nBlanks /= 2;
                itemsPerRow *= 2;
                column = 0;
                System.out.println();
            } else {
                for (int k = 0; k < nBlanks * 2 - 2; k++) {
                    System.out.print(" ");
                }
            }
        }
        System.out.println("\n" + dots + dots);
    }

    public boolean isEmpty() {
        return currentSize == 0;
    }

    /**
     * 删除最小元素,重新建立根节点
     */
    public Node removeMin() throws MinHeapException {
        if (isEmpty()) {
            throw new MinHeapException("minHeap is empty");
        }
        /**
         * 删除的节点
         */
        Node root = heapArray[0];
        //最后的节点移到最小的位置
        heapArray[0] = heapArray[currentSize - 1];
        currentSize--;
        //将最小的位置的元素下沉
        filterDown(0, currentSize - 1);
        return root;
    }

    public void makeEmpty() {
        currentSize = 0;
    }
}

MinHeapApp

package com.example.taco.minHeapTest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 最小堆测试
 *
 * @author lh
 * @date 2022/01/13 20:01
 */
public class MinHeapApp {

    public static void main(String[] args) throws IOException, MinHeapException {
        int value1, value2;
        MinHeap hp = new MinHeap(31);
        boolean success;
        hp.insert(23);
        hp.insert(34);
        hp.insert(3);
        hp.insert(2233);
        hp.insert(234);
        hp.insert(21);
        hp.insert(25);
        hp.insert(25);
        hp.insert(63);
        while (true) {
            System.out.println("enter first letter of ");
            System.out.println("show,insert,remove:");
            int choice = getChar();
            switch (choice) {
                case 's':
                    hp.displayHeap();
                    break;
                case 'i':
                    System.out.println("enter value to insert:");
                    value1 = getInt();
                    success = hp.insert(value1);
                    if (!success) {
                        System.out.println("can't insert;heap is full");
                    }
                    break;
                case 'r':
                    if (!hp.isEmpty()) {
                        hp.removeMin();
                    } else {
                        System.out.println("can't remove;heap is empty");
                    }
                    break;
                default:
                    System.out.println("invalid enter\n ");
            }
        }
    }

    /**
     * 获得控制台输入字符
     *
     * @return
     * @throws IOException
     */
    private static char getChar() throws IOException {
        return getString().charAt(0);
    }

    /**
     * 获得控制台输入流
     *
     * @return
     * @throws IOException
     */
    private static String getString() throws IOException {
        return new BufferedReader(new InputStreamReader(System.in)).readLine();
    }

    /**
     * 获得控制台输入的整形
     *
     * @return
     * @throws IOException
     * @throws NumberFormatException
     */
    public static int getInt() throws IOException, NumberFormatException {
        return Integer.parseInt(getString());
    }
}

MinHeapException

package com.example.taco.minHeapTest;

/**
 * @author lh
 * @date 2022/01/14 0:14
 */
public class MinHeapException extends Exception{
    private static final long serialVersionUID=1L;

    public MinHeapException() {
        super("MinHeapException");
    }

    public MinHeapException(String message) {
        super(message);
    }
}

Node

package com.example.taco.minHeapTest;

import lombok.Data;

/**
 * 堆结点
 * @author lh
 * @date 2022/01/14 14:13
 */
@Data
public class Node {
    /**
     * 数据
     */
    private int iDate;
    public Node(int iDate){
        super();
        this.iDate=iDate;
    }
}

输出堆

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸟程序员李老板专业码代码三十年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值