堆结构与桶排序总结(附代码)

堆结构(Heap)、完全二叉树的概念

从左往右依次铺满的二叉树就是完全二叉树。

堆结构,通常我们有大根堆或者小根堆。以大根堆为例,它首先是一个完全二叉树,且每个叶子节点都比父节点的值,根节点是整个树中最大值。

用数组来表示一棵完全二叉树

假设数组为 arr 我们用 i 来代表数组的下标,数组中第i个数的值为arr[i]

下标为i的节点对应的 左节点 2i+1 右节点则是 2i+2

而 i 的父节点下标为 (i - 1)/2

arr[0]则作为这棵树的根节点。

如何从完全二叉树变成大根堆

利用数组来表示完全二叉树时候,我们就可以轻松通过下标关系来获取到父子节点。当然,在这之前先判断是否越界问题。

 

实现堆最重要的两个方法:heapify 以及 heapInsert

Heapify

可以理解为在一棵完全二叉树中(数组表示)对某个节点进行“堆化”,使得这个节点往下的2个子节点都比父节点小(大/如果是小根堆),形成一个局部的堆。如果heapify自子节点起开始作用,一直往上,则完成一系列动作后,这棵完全二叉树就是大(小)根堆了。

//对index为i的子树进行堆化处理 
void MaxHeapify(int i) { 
        int l = lChild(i); 
        int r = rChild(i); 
        int largest = i; 
        if (l < heapSize && arr[l] > arr[i]) 
            largest = l; 
        if (r < heapSize && arr[r] > arr[largest]) 
            largest = r; 
        if (largest != i) { 
            int temp = arr[i]; 
            arr[i] = arr[largest]; 
            arr[largest] = temp; 
            MaxHeapify(largest); 
        } 
    } 

heapInsert

维护当前堆状态,当从二叉树尾部插入一棵树时,heapInsert会在插入后向上比较如果大于当前父节点则向上交换,直到找不到大于它的或者以及时根节点了。这时,新加入的这个节点就没有打破堆结构。

一些性能上的数据

如何排序,复杂度问题

堆排序步骤:

  1. 给定一个数组,从中间(i/2 -1)开始往根节点依次进行局部的“堆化”(heapify),将这个完全二叉树(给定待排序 的数组)变成一个堆。

  2. 循环遍历堆大小,将根节点取出存到一个新同等大小的数组。每次取出根节点后,将最后一个节点放到根节点上,然后对根节点进行一次“堆化”(heapify)操作。整个遍历过后,便会获得一个排好序的数组。

堆数据结构时间复杂度:

访问最值 O(1),插入和删除 O(log n), 堆排序O(nlog n)

关于堆的应用

  1. 优先队列

  2. 堆排序

  3. 内存管理

  4. 一下关于图的算法问题

代码

附上简单的堆结构代码:

package algorithm.heap;

public class MaxHeap {

    private int[] heap;

    private int size;

    private int getParentPosition(int i){
        return (i - 1) >> 1;
    }

    private int getLeftPosition(int i){
        return 2 * i + 1;
    }

    private int getRightPosition(int i){
        return 2 * i + 2;
    }

    public MaxHeap() {
        heap = new int[16];
        size = 0;
    }

    private void headInsert(int num,int index){
        heap[index] = num;
        while (index != 0 && heap[getParentPosition(index)] < heap[index]){
            int pi = getParentPosition(index);
            swap(index,pi);
            index = pi;
        }
    }

    public void add(int num){
        if (++size >= heap.length) {
            int[] newHeap = new int[heap.length << 1];
            for (int i = 0; i < heap.length; i++) {
                newHeap[i] = heap[i];
            }
            heap = newHeap;
        }
        headInsert(num,size - 1);
    }

    /**
     * get maximum number
     * @return
     */
    public int get(){
        return heap[0];
    }

    /**
     * get and remove maximum number(root)
     * @return
     */
    public int pop(){
        int res = get();
        size--;
        int cur = 0;
        if (size > 0){
            heap[0] = heap[size];
            heapify(0);
        }
        return res;
    }

    private void heapify(int index){
        int l = getLeftPosition(index);
        int r = getRightPosition(index);
        while (r < size && heap[index] < Math.max(heap[l],heap[r])){
            index = heap[l] > heap[r] ? l : r;
            swap(index,getParentPosition(index));
            l = getLeftPosition(index);
            r = getRightPosition(index);
        }
        if (heap[l]>heap[index]){
            swap(l,index);
        }
    }

    private void swap(int i,int j){
        int temp = heap[i];
        heap[i] = heap[j];
        heap[j] = temp;

    }

    public int getSize(){
        return size;
    }

}

测试:

package algorithm.heap;

import java.util.PriorityQueue;

public class heapTest {


    public static void main(String[] args) {
        MaxHeap maxHeap = new MaxHeap();
        maxHeap.add(12);
        maxHeap.add(31);
        maxHeap.add(29);
        maxHeap.add(122);
        maxHeap.add(88);
        maxHeap.add(8);
        while (maxHeap.getSize() != 0){
            System.out.println(maxHeap.pop());
        }

        PriorityQueue<Integer> p = new PriorityQueue<>();
    }

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值