堆的插入删除实现和优化

来源:互联网 发布:淘宝商品怎么分类 编辑:程序博客网 时间:2024/05/16 08:51

堆的插入的时候实在树的最下面插入。例如

           97                /          \          95          69       /    \      /    \    65    67    26    26  / \   / \   / \   / \ 10 65 67               

在该树中,插入一个新的数据的时候,是要在第四层67的右边插入假如插入的数据是96.那么此时不满足最大堆(最小堆)那么96比67大,所以96和67交换位置。96也比95大,所以96再次和95交换。此时96不必它的父节点97大,所以当前就是它应该存在的位置,最后得到新树

         97                /          \          96          69       /    \      /    \    65    95    26    26  / \   / \   / \   / \ 10 65 67  67   
import java.util.*;import java.lang.*;// 在堆的有关操作中,需要比较堆中元素的大小,所以Item需要extends Comparablepublic class MaxHeap<Item extends Comparable> {    protected Item[] data;    protected int count;    protected int capacity;    // 构造函数, 构造一个空堆, 可容纳capacity个元素    public MaxHeap(int capacity){        data = (Item[])new Comparable[capacity+1];        count = 0;        this.capacity = capacity;    }    // 返回堆中的元素个数    public int size(){        return count;    }    // 返回一个布尔值, 表示堆中是否为空    public boolean isEmpty(){        return count == 0;    }    // 像最大堆中插入一个新的元素 item    public void insert(Item item){        assert count + 1 <= capacity;        data[count+1] = item;        count ++;        shiftUp(count);    }    // 交换堆中索引为i和j的两个元素    private void swap(int i, int j){        Item t = data[i];        data[i] = data[j];        data[j] = t;    }    //********************    //* 最大堆核心辅助函数    //********************    private void shiftUp(int k){        while( k > 1 && data[k/2].compareTo(data[k]) < 0 ){            swap(k, k/2);            k /= 2;        }    }    // 测试 MaxHeap    public static void main(String[] args) {        MaxHeap<Integer> maxHeap = new MaxHeap<Integer>(100);        int N = 50; // 堆中元素个数        int M = 100; // 堆中元素取值范围[0, M)        for( int i = 0 ; i < N ; i ++ )            maxHeap.insert( new Integer((int)(Math.random() * M)) );        System.out.println(maxHeap.size());    }}

辅助类,用于打印出树的样子
也就是这样

The max heap size is: 31Data in the max heap: 98 81 97 74 78 80 53 50 63 68 61 56 71 37 47 1 45 33 56 6 62 48 17 9 51 1 31 0 2 12 44                        98                                  /                      \                      81                      97                /          \            /          \          74          78          80          53       /    \      /    \      /    \      /    \    50    63    68    61    56    71    37    47  / \   / \   / \   / \   / \   / \   / \   / \ 1  45 33 56 6  62 48 17 9  51 1  31 0   2 12 44
// 我们的PrintableMaxHeap只能处理整数信息,所以继承的是MaxHeap<Comparable<Integer>>public class PrintableMaxHeap extends MaxHeap<Comparable<Integer>>{    public PrintableMaxHeap(int capacity){        super(capacity);    }    // 以树状打印整个堆结构    public void treePrint(){        if( size() >= 100 ){            System.out.println("This print function can only work for less than 100 integer");            return;        }        System.out.println("The max heap size is: " + size());        System.out.println("Data in the max heap: ");        for( int i = 1 ; i <= size() ; i ++ ){            // 我们的print函数要求堆中的所有整数在[0, 100)的范围内            assert (Integer)data[i] >= 0 && (Integer)data[i] < 100;            System.out.print(data[i] + " ");        }        System.out.println();        System.out.println();        int n = size();        int maxLevel = 0;        int numberPerLevel = 1;        while( n > 0 ){            maxLevel += 1;            n -= numberPerLevel;            numberPerLevel *= 2;        }        int maxLevelNumber = (int)Math.pow(2, maxLevel-1);        int curTreeMaxLevelNumber = maxLevelNumber;        int index = 1;        for( int level = 0 ; level < maxLevel ; level ++ ){            String line1 = new String(new char[maxLevelNumber*3-1]).replace('\0', ' ');            int curLevelNumber = Math.min(count-(int)Math.pow(2,level)+1,(int)Math.pow(2,level));            boolean isLeft = true;            for( int indexCurLevel = 0 ; indexCurLevel < curLevelNumber ; index ++ , indexCurLevel ++ ){                line1 = putNumberInLine( (Integer)data[index] , line1 , indexCurLevel , curTreeMaxLevelNumber*3-1 , isLeft );                isLeft = !isLeft;            }            System.out.println(line1);            if( level == maxLevel - 1 )                break;            String line2 = new String(new char[maxLevelNumber*3-1]).replace('\0', ' ');            for( int indexCurLevel = 0 ; indexCurLevel < curLevelNumber ; indexCurLevel ++ )                line2 = putBranchInLine( line2 , indexCurLevel , curTreeMaxLevelNumber*3-1 );            System.out.println(line2);            curTreeMaxLevelNumber /= 2;        }    }    private String putNumberInLine( Integer num, String line, int indexCurLevel, int curTreeWidth, boolean isLeft){        int subTreeWidth = (curTreeWidth - 1) / 2;        int offset = indexCurLevel * (curTreeWidth+1) + subTreeWidth;        assert offset + 1 < line.length();        if( num >= 10 )            line = line.substring(0, offset+0) + num.toString()                    + line.substring(offset+2);        else{            if( isLeft)                line = line.substring(0, offset+0) + num.toString()                        + line.substring(offset+1);            else                line = line.substring(0, offset+1) + num.toString()                        + line.substring(offset+2);        }        return line;    }    private String putBranchInLine( String line, int indexCurLevel, int curTreeWidth){        int subTreeWidth = (curTreeWidth - 1) / 2;        int subSubTreeWidth = (subTreeWidth - 1) / 2;        int offsetLeft = indexCurLevel * (curTreeWidth+1) + subSubTreeWidth;        assert offsetLeft + 1 < line.length();        int offsetRight = indexCurLevel * (curTreeWidth+1) + subTreeWidth + 1 + subSubTreeWidth;        assert offsetRight < line.length();        line = line.substring(0, offsetLeft+1) + "/" + line.substring(offsetLeft+2);        line = line.substring(0, offsetRight) + "\\" + line.substring(offsetRight+1);        return line;    }    // 测试 PrintableMaxHeap    public static void main(String[] args) {        PrintableMaxHeap maxHeap = new PrintableMaxHeap(100);        int N = 31; // 堆中元素个数        int M = 100; // 堆中元素取值范围[0, M)        for( int i = 0 ; i < N ; i ++ )            maxHeap.insert( new Integer((int)(Math.random() * M)) );        maxHeap.treePrint();    }}

删除

import java.util.*;import java.lang.*;// 在堆的有关操作中,需要比较堆中元素的大小,所以Item需要extends Comparablepublic class MaxHeap<Item extends Comparable> {    protected Item[] data;    protected int count;    protected int capacity;    // 构造函数, 构造一个空堆, 可容纳capacity个元素    public MaxHeap(int capacity){        data = (Item[])new Comparable[capacity+1];        count = 0;        this.capacity = capacity;    }    // 返回堆中的元素个数    public int size(){        return count;    }    // 返回一个布尔值, 表示堆中是否为空    public boolean isEmpty(){        return count == 0;    }    // 像最大堆中插入一个新的元素 item    public void insert(Item item){        assert count + 1 <= capacity;        data[count+1] = item;        count ++;        shiftUp(count);    }    // 从最大堆中取出堆顶元素, 即堆中所存储的最大数据    public Item extractMax(){        assert count > 0;        Item ret = data[1];        swap( 1 , count );        count --;        shiftDown(1);        return ret;    }    // 获取最大堆中的堆顶元素    public Item getMax(){        assert( count > 0 );        return data[1];    }    // 交换堆中索引为i和j的两个元素    private void swap(int i, int j){        Item t = data[i];        data[i] = data[j];        data[j] = t;    }    //********************    //* 最大堆核心辅助函数    //********************    private void shiftUp(int k){        while( k > 1 && data[k/2].compareTo(data[k]) < 0 ){            swap(k, k/2);            k /= 2;        }    }    private void shiftDown(int k){        while( 2*k <= count ){            int j = 2*k; // 在此轮循环中,data[k]和data[j]交换位置            if( j+1 <= count && data[j+1].compareTo(data[j]) > 0 )                j ++;            // data[j] 是 data[2*k]和data[2*k+1]中的最大值            if( data[k].compareTo(data[j]) >= 0 ) break;            swap(k, j);            k = j;        }    }    // 测试 MaxHeap    public static void main(String[] args) {        MaxHeap<Integer> maxHeap = new MaxHeap<Integer>(100);        int N = 100; // 堆中元素个数        int M = 100; // 堆中元素取值范围[0, M)        for( int i = 0 ; i < N ; i ++ )            maxHeap.insert( new Integer((int)(Math.random() * M)) );        Integer[] arr = new Integer[N];        // 将maxheap中的数据逐渐使用extractMax取出来        // 取出来的顺序应该是按照从大到小的顺序取出来的        for( int i = 0 ; i < N ; i ++ ){            arr[i] = maxHeap.extractMax();            System.out.print(arr[i] + " ");        }        System.out.println();        // 确保arr数组是从大到小排列的        for( int i = 1 ; i < N ; i ++ )            assert arr[i-1] >= arr[i];    }}