二叉树—堆

1.二叉树的存储

一种存储是顺序存储结构,另一种是链式存储结构。顺序存储结构仅适用于完全二叉树的存储,就是把完全二叉树从上到下、从左到右的顺序存储到一块连续的存储空间中,(可以理解为以层序遍历的顺序存储),其一般存储在一维数组中。

 

树是一种非线性结构,为了存储树,不仅需要存储树中各个结点本身的数据信息,还要能唯一地反映树中各个结点之间的逻辑关系。双亲表示法是树的一种顺序存储结构,这种表示法是用一维数组来存储树的相关信息,将树中的结点按照从上到下,从左到右的顺序存放在一个一维数组中,每个元素中存放一个结点的信息,包括该点本身的信息、该点双亲的位置,也就是双亲的下标。

二叉树的存储可以用一维数组实现,即将完全二叉树上标号为i的结点元素存储在一维数组下标为i的元素中。按照层序的方式把值平铺在数组中,关注数组下标的变化可以推导出:

已知双亲结点下标:left=2*parent+1;right=2*parent+2。

已知孩子结点下标:parent=(child-1)/2 取整。

2.堆

(1)堆的定义

堆通常是一个可以看做一棵完全二叉树的数组对象。可以说堆在逻辑上是一棵完全二叉树,在物理上是一维数组。

(2)堆的性质

  • 堆总是一棵完全二叉树。
  • 将根结点最大的堆叫做最大堆,根节点最小的堆叫做最小堆

满足任意位置的值>=它的左右孩子的值,为大堆;满足任意位置的值<=它的左右孩子的值,为小堆。

所以堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。

  • 常见堆有二叉堆等。
  • 堆是非线性结构,相当于一维数组,有两个直接后继。

(3)堆的基本功能

找最值

(4)堆的操作

堆化(向上调整、向下调整)

堆化的前提:在整个堆中,除了要调整的位置之外,其余位置都已经满足堆的性质。

向上调整:让调整的结点与其孩子结点进行比较

向上调整:让调整的结点与其父亲结点进行比较

堆化思路:<以大堆为例>

  • 如果要调整的位置是叶子节点,调整结束。
  • 找到两个孩子中最大的一个孩子。(3种情况)只有左孩子;左右都有左孩子大;左右都有右孩子大
  • 比较最大孩子的值和要调整位置的值,如果满足堆的性质了,调整结束,否则,交换两个值,继续调整原来最大孩子的下标位置。

建堆(任意数组转成堆)

建堆思路:从最后一个非叶子节点(最后一个节点的双亲节点),向下调整

最后一个非叶子节点:(size-2)/2

最后一个叶子节点:size-1

(5)堆的应用

  • 优先级队列问题
  • TopK问题
  • 利用堆的特性做堆排序

代码实现:

import java.util.Arrays;

public class Heaps {//Heaps堆
    /**
     * 前提:除了index和它的孩子外,其他位置已经满足堆的性质了
     * 经过向下调整(堆化),最终完全成为一个堆
     * 时间复杂度是O(log(n))
     * @param array 被看作堆的数组
     * @param size 数组中被看作堆的值的个数
     * @param index 要调整位置的下标
     */
    //堆化为大堆
    //堆化(向下调整)
    public static void heapify(int[] array,int size,int index){
        while(true){
            int left = 2 * index + 1;
            if (left >= size) {
                return;
            }
            int max = left;
            //找出孩子结点中最大的结点下标
            if (left + 1 < size && array[left + 1] > array[left]) {//找最大
                max = left + 1;
            }
            //比较该根结点与最大的孩子结点的大小,如果孩子结点大,则换位置
            if (array[index] >= array[max]) {//比较
                return;
            }
            swap(array,index, max);//交换
            index = max;
        }
    }
    //堆化(向上调整)
    public static void adjustUp(int[] array,int index){
        //向上调整到下标为0的位置就不调整了
        if(index==0) {
            return;
        }
            int parent=(index-1)/2;
            //与父亲结点相比较
            //如果父亲结点的值小,就交换位置,否则就不调整
            if(array[index]>array[parent]){
                return;
            }
            swap(array,index,parent);
            index=parent;
        }

    public static void swap(int[]array,int i,int j){
        int t = array[i];
        array[i] = array[j];
        array[j] = t;
    }
    //【建堆】
    public static void createHeap(int[]array,int size){
        for(int i=(size-2)/2;i>=0;i--){
            heapify(array,size,i);

        }
    }
    public static void main(String[] args){
      int[]array={-1,8,4,6,7,2,3,1,0};
        System.out.println("堆化");
       heapify(array,array.length,0);
       System.out.println(Arrays.toString(array));
        adjustUp(array,0);
        System.out.println(Arrays.toString(array));
       System.out.println("建堆");
       createHeap(array,array.length);
       System.out.println(Arrays.toString(array));
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值