zoukankan      html  css  js  c++  java
  • 大顶堆为例):

    • 首先根据序列构建一个完全二叉树
    • 在完全二叉树的基础上,从最后一个非叶结点开始调整:比较三个元素的大小–自己,它的左孩子,右孩子。分为三种情况: 
      • 自己最大,不用调整
      • 左孩子最大,交换该非叶结点与其左孩子的值,并考察以左孩子为根的子树是否满足大顶堆的要求,不满足递归向下处理
      • 右孩子最大,交换该非叶结点与其右孩子的值,并考察以右孩子为根的子树是否满足大顶堆的要求,不满足递归向下处理

    就这些基本要求,就可以解决这一类的手工计算问题。举个例子:

    比如:一组记录(5,11,7,2,3,17)利用大顶堆排序方法建立初始堆为?

    分析:首先建立完全二叉树。

    这里写图片描述

    再从最后一个非叶结点开始调整。

    第一次交换7,17的位置。

    这里写图片描述

    11不用调整。

    最后调整根结点。

    这里写图片描述

    此时把5换下去后,以5为根的子树不满足大顶堆的要求,因此再调整。

    这里写图片描述

    即最终的初始堆是:17,11,7,2,3,5.

    //实现最大堆(用数组来存放完全二叉树中的节点,从上到下,从左到右排序,按序存在数组,子节点的值小于等于父节点的值)
    public class Heap {
    private int[] data;
    private int count; //当前节点数
    private int capacity; //容量

    public Heap(int capacity) {
    this.data=new int[capacity+1]; //因为索引0不存节点,所以长度加一
    this.capacity=capacity;
    this.count=0;
    }
    //将一个无序数组构造成一个最大堆 相当于堆排序
    public Heap(int[] arr,int n){
    data=new int[n+1];
    capacity=n;
    for(int i=0;i<n;i++){
    data[i+1]=arr[i];
    }
    count=n;
    for(int i=count/2;i>=1;i--){ //i=count/2:i是最后一个叶子节点的父节点(最后一个非叶子节点)
    shiftDown(i);
    }
    }



    private void shiftUp(int i){
    while((i>1)&&(data[i/2]<data[i])){ //data[i/2]为当前节点的父节点
    swap(data,i,i/2);
    i=i/2; //更新索引
    }
    }

    private void shiftDown(int k){
    //第一次循环对最后一个非叶子节点循环
    while((2*k)<=count){ //有左子节点,2*k为当前非叶子节点的左孩子
    int j=2*k; //这轮循环,data[k]和data[j]交换位置
    if((j+1)<=count&&(data[j+1]>data[j])){ //有右子节点且右边的更大,j+1为右孩子下标
    j+=1;//右孩子下标
    }
    if(data[k]>=data[j]) //如果父节点大于等于子节点,则停止循环
    break;
    swap(data,k,j);
    k=j; //k被赋为当前位置,为下次循环做初始化
    }
    }
    public int size() {
    return count;
    }
    public boolean isEmpty(){
    return count==0;
    }
    public void insert(int a){
    assert((count+1)<=capacity); //防止数组越界
    data[count+1]=a; //从索引1开始存
    count++;
    shiftUp(count); //由于可能新添加的数违背最大堆的定义,所以要重排序
    }
    public int extractMax(){ //弹出最大值,即根节点
    assert(count>0);
    int ret=data[1];
    swap(data,1,count); //将最后数放到第一位置,保持完全二叉树的结构
    count--;
    shiftDown(1); //将第一个数移至合适位置,保持最大堆性质
    return ret;
    }

    public int[] getData() {
    return data;
    }

    public static void swap(int[] arr, int a, int b){
    int c=arr[a];
    arr[a]=arr[b];
    arr[b]=c;
    }
    public static void situheapsort(int[] arr,int n){ //原地堆排序(就是堆排序),从0开始存
    for(int i=(n-1)/2;i>=0;i--){ //i=(n-1)/2:i是最后一个叶子节点的父节点(最后一个非叶子节点)
    __shiftDown(arr,n,i); //将一个完全无序的数组arr构造成最大堆
    }
    for(int i=n-1;i>0;i--){
    swap(arr,0,i); //第一个即最大值与最后一个值交换
    __shiftDown(arr,i,0); //把第一个较小的值放在合适位置,此时的数组长度为n-1
    }
    }
    public static void __shiftDown(int[] arr,int n,int k){
    while((2*k+1)<n){ //有左子节点
    int j=2*k+1; //这轮循环,arr[k]和arr[j]交换位置
    if((j+1)<n&&(arr[j+1]>arr[j])){ //有右子节点且右边的更大
    j+=1;
    }
    if(arr[k]>=arr[j]) //如果父节点大于等于子节点,则停止循环
    break;
    swap(arr,k,j);
    k=j; //k被赋为当前位置,为下次循环做初始化
    }
    }
    public static void main(String[] args) {
    Heap heap=new Heap(100);
    System.out.print("插入的数为:");
    for(int i=0;i<30;i++){
    int rand=new Random().nextInt(100)+1;
    System.out.print(rand+" ");
    heap.insert(rand);
    }
    System.out.println();
    System.out.print("heap.extractMax():");
    while(!heap.isEmpty()){
    System.out.print(heap.extractMax()+" "); //从大到小输出
    }
    System.out.println();
    // System.out.println("*********************堆排序*********************************");
    // int arr[] = MAIN.geneateArrays(30);
    // situheapsort(arr,arr.length);
    // for(int i=0;i<arr.length;i++){
    // System.out.print(arr[i]+" ");
    // }
    }

    }
  • 相关阅读:
    关于springMVC转换json出现的异常
    jQuery实现,动态自动定位弹窗。JS分页,Ajax请求
    servlet为什么要配置web.xml
    Jmeter系列(4)- Jmeter 脚本录制
    后缀数组模板
    NOIP2016 玩脱记
    TERSUS无代码开发(笔记21)-流程执行顺序思考(转载)
    ===>===>===>特色思TERSUS常用功能整理
    TERSUS无代码开发(笔记20)-本地开发测试mysql数据库连接
    TERSUS无代码开发(笔记19)-mysql-connector-java-5.-bin.jar下载方法
  • 原文地址:https://www.cnblogs.com/kexianting/p/8612965.html
Copyright © 2011-2022 走看看