zoukankan      html  css  js  c++  java
  • 手写数据结构-基于动态数组实现的二叉堆

    1.堆基础

    二叉堆的定义:

    1.二叉堆是一个完全二叉树结构。完全二叉树不一定是一个满二叉树。完全二叉树左节点必须是满的,右节点为可以为空。把元素一层一层的从左往右依次排列。

    2.当满足该节点的左右孩子节点都小于该节点时,称为最大堆。反之,当该节点的左右孩子节点大于该节点时,称为最小堆。

    2.手动实现最大堆及复杂度分析

    package com.tc.javabase.datastructure.tree.heap;
    
    import com.tc.javabase.datastructure.array.ArrayList;
    
    public class MaxHeap<E extends Comparable<E>> {
    
        private ArrayList<E> data;
    
        public MaxHeap(int capacity){
            data = new ArrayList<>(capacity);
        }
    
        public MaxHeap(){
            data = new ArrayList<>();
        }
    
        public MaxHeap(E[] arr){
            data = new ArrayList<>(arr);
            if(arr.length != 1){
                for(int i = parent(arr.length - 1) ; i >= 0 ; i --)
                    siftDown(i);
            }
        }
    
        // 返回堆中的元素个数
        public int size(){
            return data.getSize();
        }
    
        // 返回一个布尔值, 表示堆中是否为空
        public boolean isEmpty(){
            return data.isEmpty();
        }
    
        // 返回完全二叉树的数组表示中,一个索引所表示的元素的父亲节点的索引
        private int parent(int index){
            if(index == 0)
                throw new IllegalArgumentException("index-0 doesn't have parent.");
            return (index - 1) / 2;
        }
    
        // 返回完全二叉树的数组表示中,一个索引所表示的元素的左孩子节点的索引
        private int leftChild(int index){
            return index * 2 + 1;
        }
    
        // 返回完全二叉树的数组表示中,一个索引所表示的元素的右孩子节点的索引
        private int rightChild(int index){
            return index * 2 + 2;
        }
    
        // 向堆中添加元素
        public void add(E e){
            data.addLast(e);
            siftUp(data.getSize() - 1);
        }
    
        private void siftUp(int k){
    
            while(k > 0 && data.get(parent(k)).compareTo(data.get(k)) < 0 ){
                data.swap(k, parent(k));
                k = parent(k);
            }
        }
    
        // 看堆中的最大元素
        public E findMax(){
            if(data.getSize() == 0)
                throw new IllegalArgumentException("Can not findMax when heap is empty.");
            return data.get(0);
        }
    
        // 取出堆中最大元素
        public E extractMax(){
    
            E ret = findMax();
    
            data.swap(0, data.getSize() - 1);
            data.removeLast();
            siftDown(0);
    
            return ret;
        }
    
        private void siftDown(int k){
    
            while(leftChild(k) < data.getSize()){
                int j = leftChild(k); // 在此轮循环中,data[k]和data[j]交换位置
                if( j + 1 < data.getSize() &&
                        data.get(j + 1).compareTo(data.get(j)) > 0 )
                    j ++;
                // data[j] 是 leftChild 和 rightChild 中的最大值
    
                if(data.get(k).compareTo(data.get(j)) >= 0 )
                    break;
    
                data.swap(k, j);
                k = j;
            }
        }
    
        // 取出堆中的最大元素,并且替换成元素e
        public E replace(E e){
    
            E ret = findMax();
            data.set(0, e);
            siftDown(0);
            return ret;
        }
    }
    

    Sift Up(上浮):当我们往堆中添加了个元素的时候,在堆的最后添加一个元素,再将该元素进行上浮操作,即和它的父节点一直进行比较,若比它的父节点大则交换位置,否则不动。

    Sift Down(下沉):当我们取出堆中最大的元素时,首先将根元素和最尾端的元素进行交换位置,然后删掉最尾端的元素,然后再将此时的顶端元素进行下层操作,即将该元素和它的左右孩子中的最大的一个进行比较,若比它小则交换位置否则不动 。

    问题:考虑给你一个没有顺序的数组,然后用给排成一个二叉最大堆的结构

    若直接将该数组扫描一遍,然后依次进行add操作则时间复杂度为nLog(n),那么有没有更好的方法?

    Heapify(堆排序):即将依次从最后一个非叶子节点到根节点依次做Sift Down操作,此时的时间复杂度为O(n)。

  • 相关阅读:
    使用某些 DOCTYPE 时会导致 document.body.scrollTop 失效
    VB.NET 笔记1
    知识管理系统Data Solution研发日记之一 场景设计与需求列出
    知识管理系统Data Solution研发日记之五 网页下载,转换,导入
    折腾了这么多年的.NET开发,也只学会了这么几招 软件开发不是生活的全部,但是好的生活全靠它了
    分享制作精良的知识管理系统 博客园博客备份程序 Site Rebuild
    知识管理系统Data Solution研发日记之四 片段式数据解决方案
    知识管理系统Data Solution研发日记之二 应用程序系列
    知识管理系统Data Solution研发日记之七 源代码与解决方案
    知识管理系统Data Solution研发日记之三 文档解决方案
  • 原文地址:https://www.cnblogs.com/tc971121/p/13443774.html
Copyright © 2011-2022 走看看