前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >最小堆与索引堆

最小堆与索引堆

作者头像
算法之名
发布于 2020-10-26 08:29:29
发布于 2020-10-26 08:29:29
94300
代码可运行
举报
文章被收录于专栏:算法之名算法之名
运行总次数:0
代码可运行

我们先来完成一个最小堆,采用JDK的ArrayList作为底层数据结构。关于堆的概念请参考数据结构整理 中最大堆的部分

接口

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface Heap<T> {
    int getSize();
    boolean isEmpty();
    void add(T t);

    /**
     * 取出最大元素(最大堆)或最小元素(最小堆)
     * @return
     */
    T extract();

    /**
     * 查看最大元素(最大堆)或最小元素(最小堆)
     * @return
     */
    T findHeap();

    /**
     * 取出堆中最大元素(最大堆)或最小元素(最小堆)
     * 并且替换成元素t
     * @param t
     * @return
     */
    T replace(T t);
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class MinHeap<T extends Comparable<T>> implements Heap<T> {
    private List<T> data;

    public MinHeap(int capcity) {
        data = new ArrayList<>(capcity);
    }

    public MinHeap() {
        data = new ArrayList<>();
    }

    /**
     * 将一个数组转化为最小堆
     * @param arr
     */
    public MinHeap(T[] arr) {
        data = new ArrayList<>();
        data.addAll(Arrays.asList(arr));
        for (int i = parent(getSize() - 1); i >= 0; i--) {
            shiftDown(i);
        }
    }

    @Override
    public int getSize() {
        return data.size();
    }

    @Override
    public boolean isEmpty() {
        return data.isEmpty();
    }

    @Override
    public void add(T t) {
        data.add(t);
        shiftUp(getSize() - 1);
    }

    @Override
    public T extract() {
        T ret = findHeap();
        data.set(0,data.get(getSize() - 1));
        data.set(getSize() - 1,ret);
        data.remove(getSize() - 1);
        shiftDown(0);
        return ret;
    }

    @Override
    public T findHeap() {
        if (isEmpty()) {
            throw new IllegalArgumentException("堆为空,不能做此操作");
        }
        return data.get(0);
    }

    @Override
    public T replace(T t) {
        T ret = findHeap();
        data.set(0,t);
        shiftDown(0);
        return ret;
    }

    /**
     * 获取父节点的索引
     * @param index
     * @return
     */
    private int parent(int index) {
        if (index == 0) {
            throw new IllegalArgumentException("索引0没有父节点");
        }
        return (index - 1) / 2;
    }

    private int leftChild(int index) {
        return index * 2 + 1;
    }

    private int rightChild(int index) {
        return index * 2 + 2;
    }

    private void shiftUp(int index) {
        //如果当前节点不是根节点
        //且父节点的值比当前节点的值要大
        while (index > 0 &&
                data.get(parent(index)).compareTo(data.get(index)) > 0) {
            //交换父节点和当前节点的值
            //并把当前节点的索引改为父节点的索引
            swap(parent(index),index);
            index = parent(index);
        }
    }

    private void shiftDown(int index) {
        while (leftChild(index) < getSize()) {
            int left = leftChild(index);
            int right = left + 1;
            int min = left;
            //比较左右孩子的值哪个更小
            if (right < getSize()
                    && data.get(right).compareTo(data.get(left)) < 0) {
                min = rightChild(index);
            }
            //如果父节点的值比左右孩子的最小值还要小,略过
            if (data.get(index).compareTo(data.get(min)) <= 0) {
                break;
            }
            //将父节点的值与左右孩子的最小值交换
            //并将父节点的索引改为左右孩子最小值的索引
            swap(index,min);
            index = min;
        }
    }

    private void swap(int x,int y) {
        if (x < 0 || x >= getSize() || y < 0 || y >= getSize()) {
            throw new IllegalArgumentException("索引非法");
        }
        T temp = data.get(x);
        data.set(x,data.get(y));
        data.set(y,temp);
    }
}

测试

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class MinHeapMain {
    public static void main(String[] args) {
        int n = 1000000;
        Heap<Integer> minHeap = new MinHeap<>();
        Random random = new Random();
        for (int i = 0;i < n;i++) {
            minHeap.add(random.nextInt(Integer.MAX_VALUE));
        }
        int[] arr = new int[n];
        for (int i = 0;i < n;i++) {
            arr[i] = minHeap.extract();
        }
        for (int i = 1;i < n;i++) {
            if (arr[i - 1] > arr[i]) {
                throw new IllegalArgumentException("出错");
            }
        }
        System.out.println("测试最小堆完成");
    }
}

运行结果

测试最小堆完成

顺便完成一下堆排序

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class HeapSort<T extends Comparable<T>> implements MSTResult<T>{
    private List<T> res = new ArrayList<>();

    public HeapSort(T arr[]) {
        Heap<T> heap = new MinHeap<>(arr);
        for (int i = 0; i < arr.length; i++) {
            res.add(heap.extract());
        }
    }

    @Override
    public List<T> result() {
        return res;
    }

    public static void main(String[] args) {
        int n = 10;
        Integer[] arr = new Integer[n];
        Random random = new Random();
        for (int i = 0; i < n; i++) {
            arr[i] = random.nextInt(n * 1000);
        }
        MSTResult<Integer> heapSort = new HeapSort<>(arr);
        System.out.println(heapSort.result());
    }
}

运行结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[1404, 1897, 2300, 2614, 3043, 4590, 6088, 6256, 9538, 9910]

索引堆是一种更高级的数据结构

索引堆是为了防止swap()交换大型数据带来的低效率,所以只交换索引。所以成员变量上比最大(小)堆多了一个存储索引的集合indexes。

接口

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface IndexHeap<T> {
    int getSize();
    boolean isEmpty();
    void add(int index,T t);
    void add(T t);

    /**
     * 取出最大元素(最大堆)或最小元素(最小堆)
     * @return
     */
    T extract();

    /**
     * 取出最大元素(最大堆)或最小元素(最小堆)的索引
     * @return
     */
    int extractIndex();

    /**
     * 获取一个索引的元素
     * @param index
     * @return
     */
    T get(int index);

    /**
     * 修改一个索引的元素为新的元素
     * @param index
     * @param t
     */
    void change(int index,T t);

    /**
     * 查看最大元素(最大堆)或最小元素(最小堆)
     * @return
     */
    T findHeap();
}

实现类

最小索引堆实现类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Getter
public class IndexMinHeap<T extends Comparable<T>> implements IndexHeap<T> {
    private List<T> data;
    private List<Integer> indexes;

    public IndexMinHeap(int capcity) {
        data = new ArrayList<>(capcity);
        indexes = new ArrayList<>(capcity);
    }

    public IndexMinHeap() {
        data = new ArrayList<>();
        indexes = new ArrayList<>();
    }

    public IndexMinHeap(T[] arr) {
        this(arr.length);
        data.addAll(Arrays.asList(arr));
        for (int i = 0; i < data.size(); i++) {
            indexes.add(i);
        }
        for (int i = parent(getSize() - 1); i >= 0; i--) {
            shiftDown(i);
        }
    }

    @Override
    public int getSize() {
        return indexes.size();
    }

    @Override
    public boolean isEmpty() {
        return indexes.isEmpty();
    }

    @Override
    public void add(int index,T t) {
        data.add(index,t);
        indexes.add(index);
        shiftUp(getSize() - 1);
    }

    @Override
    public void add(T t) {
        int index = data.size();
        data.add(t);
        indexes.add(index);
        shiftUp(getSize() - 1);
    }

    @Override
    public T extract() {
        T ret = findHeap();
        swap(0,getSize() - 1);
        indexes.remove(getSize() - 1);
        shiftDown(0);
        return ret;
    }

    @Override
    public int extractIndex() {
        int ret = indexes.get(0);
        swap(0,getSize() - 1);
        indexes.remove(getSize() - 1);
        shiftDown(0);
        return ret;
    }

    @Override
    public T get(int index) {
        if (!indexes.contains(index)) {
            throw new IllegalArgumentException("索引不存在");
        }
        return data.get(index);
    }

    @Override
    public void change(int index, T t) {
        data.set(index,t);
        for (int i = 0; i < getSize(); i++) {
            if (indexes.get(i) == index) {
                shiftUp(i);
                shiftDown(i);
            }
        }
    }

    @Override
    public T findHeap() {
        if (isEmpty()) {
            throw new IllegalArgumentException("堆为空,不能做此操作");
        }
        return data.get(indexes.get(0));
    }

    /**
     * 获取父节点的索引
     * @param index
     * @return
     */
    private int parent(int index) {
        if (index == 0) {
            throw new IllegalArgumentException("索引0没有父节点");
        }
        return (index - 1) / 2;
    }

    private int leftChild(int index) {
        return index * 2 + 1;
    }

    private int rightChild(int index) {
        return index * 2 + 2;
    }

    private void shiftUp(int index) {
        //如果当前节点不是根节点
        //且父节点的值比当前节点的值要大
        while (index > 0 &&
                data.get(indexes.get(parent(index))).compareTo(data.get(indexes.get(index))) > 0) {
            //交换父节点和当前节点的值
            //并把当前节点的索引改为父节点的索引
            swap(parent(index),index);
            index = parent(index);
        }
    }

    private void shiftDown(int index) {
        while (leftChild(index) < getSize()) {
            int left = leftChild(index);
            int right = left + 1;
            int min = left;
            //比较左右孩子的值哪个更小
            if (right < getSize()
                    && data.get(indexes.get(right)).compareTo(data.get(indexes.get(left))) < 0) {
                min = rightChild(index);
            }

            //如果父节点的值比左右孩子的最小值还要小,略过
            if (data.get(indexes.get(index)).compareTo(data.get(indexes.get(min))) <= 0) {
                break;
            }
            //将父节点的值与左右孩子的最小值交换
            //并将父节点的索引改为左右孩子最小值的索引
            swap(index, min);
            index = min;
        }
    }

    private void swap(int x,int y) {
        if (x < 0 || x >= getSize() || y < 0 || y >= getSize()) {
            throw new IllegalArgumentException("索引非法");
        }
        int temp = indexes.get(x);
        indexes.set(x,indexes.get(y));
        indexes.set(y,temp);
    }
}

测试

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class IndexMinHeapMain {
    public static void main(String[] args) {
        int n = 10;
        IndexHeap<Integer> minHeap = new IndexMinHeap<>(n);
        Random random = new Random();
        for (int i = 0;i < n;i++) {
            minHeap.add(random.nextInt(n * 1000));
        }
        System.out.println(((IndexMinHeap)minHeap).getData());
        Integer[] arr = new Integer[n];
        for (int i = 0; i < n; i++) {
            arr[i] = minHeap.extract();
        }
        for (int i = 1;i < n;i++) {
            if (arr[i - 1] > arr[i]) {
                throw new IllegalArgumentException("出错");
            }
        }
        for (int i = 0; i < n; i++) {
            System.out.print(arr[i] + " ");
        }
        Integer[] arr1 = new Integer[n];
        for (int i = 0; i < n; i++) {
            arr1[i] = random.nextInt(n * 1000);
        }
        System.out.println();
        System.out.println("测试最小堆完成");
        IndexHeap<Integer> minHeap1 = new IndexMinHeap<>(arr1);
        System.out.println(((IndexMinHeap)minHeap1).getData());
        System.out.println(((IndexMinHeap)minHeap1).getIndexes());
        Integer[] arr2 = new Integer[n];
        for (int i = 0; i < n; i++) {
            arr2[i] = minHeap1.extract();
        }
        for (int i = 0; i < n; i++) {
            System.out.print(arr2[i] + " ");
        }
    }
}

运行结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[8126, 6448, 4014, 1574, 2933, 3193, 5137, 6246, 9873, 7044]
1574 2933 3193 4014 5137 6246 6448 7044 8126 9873 
测试最小堆完成
[2412, 2996, 3523, 7162, 9881, 8777, 8733, 865, 3719, 4991]
[7, 0, 2, 1, 9, 5, 6, 3, 8, 4]
865 2412 2996 3523 3719 4991 7162 8733 8777 9881 

索引堆的优化

在之前的代码中,我们可以看到

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Override
    public void change(int index, T t) {
        data.set(index,t);
        for (int i = 0; i < getSize(); i++) {
            if (indexes.get(i) == index) {
                shiftUp(i);
                shiftDown(i);
            }
        }
    }

在索引集合中确定这个元素的索引的时候,它的时间复杂度是O(n)级别的,以及下面的这段代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Override
    public T get(int index) {
        if (!indexes.contains(index)) {
            throw new IllegalArgumentException("索引不存在");
        }
        return data.get(index);
    }

在判定索引是否存在的时候,它也是一个O(n)级别的时间复杂度,如果集合中元素较多的时候,它就会比较耗时,现在我们引入一个反向索引reverse来优化这个O(n)的时间复杂度的问题。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Getter
public class IndexMinHeap<T extends Comparable<T>> implements IndexHeap<T> {
    //存储数据
    private List<T> data;
    //存储数据的索引
    private List<Integer> indexes;
    //存储数据索引的反向索引
    private List<Integer> reverse;

    public IndexMinHeap(int capcity) {
        data = new ArrayList<>(capcity);
        indexes = new ArrayList<>(capcity);
        reverse = new ArrayList<>(capcity);
    }

    public IndexMinHeap() {
        data = new ArrayList<>();
        indexes = new ArrayList<>();
        reverse = new ArrayList<>();
    }

    public IndexMinHeap(T[] arr) {
        this(arr.length);
        data.addAll(Arrays.asList(arr));
        for (int i = 0; i < data.size(); i++) {
            indexes.add(i);
            reverse.add(i);
        }
        for (int i = parent(getSize() - 1); i >= 0; i--) {
            shiftDown(i);
        }
    }

    @Override
    public int getSize() {
        return indexes.size();
    }

    @Override
    public boolean isEmpty() {
        return indexes.isEmpty();
    }

    @Override
    public void add(int index,T t) {
        data.add(index,t);
        indexes.add(index);
        reverse.add(index);
        shiftUp(getSize() - 1);
    }

    @Override
    public void add(T t) {
        int index = data.size();
        data.add(t);
        indexes.add(index);
        reverse.add(index);
        shiftUp(getSize() - 1);
    }

    @Override
    public T extract() {
        T ret = findHeap();
        swap(0,getSize() - 1);
        reverse.set(indexes.get(0),0);
        reverse.set(indexes.get(getSize() - 1),-1);
        indexes.remove(getSize() - 1);
        shiftDown(0);
        return ret;
    }

    @Override
    public int extractIndex() {
        int ret = indexes.get(0);
        swap(0,getSize() - 1);
        reverse.set(indexes.get(0),0);
        reverse.set(indexes.get(getSize() - 1),-1);
        indexes.remove(getSize() - 1);
        shiftDown(0);
        return ret;
    }

    @Override
    public T get(int index) {
        if (index >= getSize() || reverse.get(index) == -1) {
            throw new IllegalArgumentException("索引不存在");
        }
        return data.get(index);
    }

    @Override
    public void change(int index, T t) {
        if (index >= getSize() || reverse.get(index) == -1) {
            throw new IllegalArgumentException("索引不存在");
        }
        data.set(index,t);
        int revIndex = reverse.get(index);
        shiftUp(revIndex);
        shiftDown(revIndex);
    }

    @Override
    public T findHeap() {
        if (isEmpty()) {
            throw new IllegalArgumentException("堆为空,不能做此操作");
        }
        return data.get(indexes.get(0));
    }

    /**
     * 获取父节点的索引
     * @param index
     * @return
     */
    private int parent(int index) {
        if (index == 0) {
            throw new IllegalArgumentException("索引0没有父节点");
        }
        return (index - 1) / 2;
    }

    private int leftChild(int index) {
        return index * 2 + 1;
    }

    private int rightChild(int index) {
        return index * 2 + 2;
    }

    private void shiftUp(int index) {
        //如果当前节点不是根节点
        //且父节点的值比当前节点的值要大
        while (index > 0 &&
                data.get(indexes.get(parent(index))).compareTo(data.get(indexes.get(index))) > 0) {
            //交换父节点和当前节点的值
            //并把当前节点的索引改为父节点的索引
            swap(parent(index),index);
            reverse.set(indexes.get(parent(index)),parent(index));
            reverse.set(indexes.get(index),index);
            index = parent(index);
        }
    }

    private void shiftDown(int index) {
        while (leftChild(index) < getSize()) {
            int left = leftChild(index);
            int right = left + 1;
            int min = left;
            //比较左右孩子的值哪个更小
            if (right < getSize()
                    && data.get(indexes.get(right)).compareTo(data.get(indexes.get(left))) < 0) {
                min = rightChild(index);
            }

            //如果父节点的值比左右孩子的最小值还要小,略过
            if (data.get(indexes.get(index)).compareTo(data.get(indexes.get(min))) <= 0) {
                break;
            }
            //将父节点的值与左右孩子的最小值交换
            //并将父节点的索引改为左右孩子最小值的索引
            swap(index, min);
            reverse.set(indexes.get(index),index);
            reverse.set(indexes.get(min),min);
            index = min;
        }
    }

    private void swap(int x,int y) {
        if (x < 0 || x >= getSize() || y < 0 || y >= getSize()) {
            throw new IllegalArgumentException("索引非法");
        }
        int temp = indexes.get(x);
        indexes.set(x,indexes.get(y));
        indexes.set(y,temp);
    }
}

测试

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class IndexMinHeapMain {
    public static void main(String[] args) {
        int n = 10;
        IndexHeap<Integer> minHeap = new IndexMinHeap<>(n);
        Random random = new Random();
        for (int i = 0;i < n;i++) {
            minHeap.add(random.nextInt(n * 1000));
        }
        System.out.println(((IndexMinHeap)minHeap).getData());
        Integer[] arr = new Integer[n];
        for (int i = 0; i < n; i++) {
            arr[i] = minHeap.extract();
        }
        for (int i = 1;i < n;i++) {
            if (arr[i - 1] > arr[i]) {
                throw new IllegalArgumentException("出错");
            }
        }
        for (int i = 0; i < n; i++) {
            System.out.print(arr[i] + " ");
        }
        Integer[] arr1 = new Integer[n];
        for (int i = 0; i < n; i++) {
            arr1[i] = random.nextInt(n * 1000);
        }
        System.out.println();
        System.out.println("测试最小堆完成");
        IndexHeap<Integer> minHeap1 = new IndexMinHeap<>(arr1);
        System.out.println(((IndexMinHeap)minHeap1).getData());
        System.out.println(((IndexMinHeap)minHeap1).getIndexes());
        minHeap1.extract();
        n--;
        System.out.println(minHeap1.get(8));
        minHeap1.change(3,9527);
        Integer[] arr2 = new Integer[n];
        for (int i = 0; i < n; i++) {
            arr2[i] = minHeap1.extract();
        }
        for (int i = 0; i < n; i++) {
            System.out.print(arr2[i] + " ");
        }
    }
}

运行结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[8524, 2544, 8147, 772, 4659, 3962, 6716, 9758, 9358, 3574]
772 2544 3574 3962 4659 6716 8147 8524 9358 9758 
测试最小堆完成
[6826, 3071, 8097, 5773, 6960, 9057, 6823, 8796, 7924, 3244]
[1, 9, 6, 3, 0, 5, 2, 7, 8, 4]
7924
3244 6823 6826 6960 7924 8097 8796 9057 9527 

现在我们以数组为底层数据结构来重写该最小索引堆

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Getter
public class ArrayIndexMinHeap<T extends Comparable<T>> implements IndexHeap<T> {
    private T[] data;
    private int[] indexes;
    private int count;
    private int capacity;
    private int[] reverse;

    @SuppressWarnings("unchecked")
    public ArrayIndexMinHeap(int capacity) {
        this.capacity = capacity;
        data = (T[]) new Comparable[capacity + 1];
        indexes = new int[capacity + 1];
        reverse = new int[capacity + 1];
        Arrays.fill(reverse,0);
        count = 0;
    }

    public ArrayIndexMinHeap(T[] arr) {
        this(arr.length);
        for (int i = 0; i < arr.length; i++) {
            data[i + 1] = arr[i];
            indexes[i + 1] = i + 1;
            reverse[i + 1] = i + 1;
            count++;
        }
        for (int i = parent(count); i >= 1; i--) {
            shiftDown(i);
        }
    }

    /**
     * 获取父节点的索引
     * @param index
     * @return
     */
    private int parent(int index) {
        if (index == 1) {
            throw new IllegalArgumentException("索引1没有父节点");
        }
        return index / 2;
    }

    private int leftChild(int index) {
        return index * 2;
    }

    private int rightChild(int index) {
        return index * 2 + 1;
    }

    private void swap(int x,int y) {
        if (x < 1 || x > count || y < 1 || y > count) {
            throw new IllegalArgumentException("索引非法");
        }
        int temp = indexes[x];
        indexes[x] = indexes[y];
        indexes[y] = temp;
    }

    private void shiftUp(int index) {
        //如果当前节点不是根节点
        //且父节点的值比当前节点的值要大
        while (index > 1 &&
                data[indexes[parent(index)]].compareTo(data[indexes[index]]) > 0) {
            //交换父节点和当前节点的值
            //并把当前节点的索引改为父节点的索引
            swap(parent(index),index);
            reverse[indexes[parent(index)]] = parent(index);
            reverse[indexes[index]] = index;
            index = parent(index);
        }
    }

    private void shiftDown(int index) {
        while (leftChild(index) <= count) {
            int left = leftChild(index);
            int right = left + 1;
            int min = left;
            //比较左右孩子的值哪个更小
            if (right <= count
                    && data[indexes[right]].compareTo(data[indexes[left]]) < 0) {
                min = rightChild(index);
            }

            //如果父节点的值比左右孩子的最小值还要小,略过
            if (data[indexes[index]].compareTo(data[indexes[min]]) <= 0) {
                break;
            }
            //将父节点的值与左右孩子的最小值交换
            //并将父节点的索引改为左右孩子最小值的索引
            swap(index, min);
            reverse[indexes[index]] = index;
            reverse[indexes[min]] = min;
            index = min;
        }
    }

    private boolean contain(int index) {
        return reverse[index + 1] == 0;
    }

    @Override
    public int getSize() {
        return count;
    }

    @Override
    public boolean isEmpty() {
        return count == 0;
    }

    @Override
    public void add(int index, T t) {
        if (count + 1 > capacity) {
            throw new IllegalArgumentException("数组越界");
        }
        if (index + 1 < 1 || index + 1 > capacity) {
            throw new IllegalArgumentException("数组越界");
        }
        index++;
        data[index] = t;
        indexes[count + 1] = index;
        reverse[index] = count + 1;
        count++;
        shiftUp(count);
    }

    @Override
    public void add(T t) {
        throw new RuntimeException("不提供该方法");
    }

    @Override
    public T extract() {
        T ret = findHeap();
        swap(1,count);
        reverse[indexes[1]] = 1;
        reverse[indexes[count]] = 0;
        count--;
        shiftDown(1);
        return ret;
    }

    @Override
    public int extractIndex() {
        if (isEmpty()) {
            throw new IllegalArgumentException("堆为空,不能做此操作");
        }
        int ret = indexes[1] - 1;
        swap(1,count);
        reverse[indexes[1]] = 1;
        reverse[indexes[count]] = 0;
        count--;
        shiftDown(1);
        return ret;
    }

    @Override
    public T get(int index) {
        if (contain(index)) {
            throw new IllegalArgumentException("索引不存在");
        }
        return data[index + 1];
    }

    @Override
    public void change(int index, T t) {
        if (contain(index)) {
            throw new IllegalArgumentException("索引不存在");
        }
        index++;
        data[index] = t;
        int revIndex = reverse[index];
        shiftUp(revIndex);
        shiftDown(revIndex);
    }

    @Override
    public T findHeap() {
        if (isEmpty()) {
            throw new IllegalArgumentException("堆为空,不能做此操作");
        }
        return data[indexes[1]];
    }
}

测试

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class IndexMinHeapMain {
    public static void main(String[] args) {
        int n = 10;
        IndexHeap<Integer> minHeap = new ArrayIndexMinHeap<>(n);
        Random random = new Random();
        for (int i = 0;i < n;i++) {
            minHeap.add(i,random.nextInt(n * 1000));
        }
        Stream.of(((ArrayIndexMinHeap)minHeap).getData())
                .filter(data -> data != null)
                .forEach(data -> System.out.print(data + " "));
        System.out.println("");
        Integer[] arr = new Integer[n];
        for (int i = 0; i < n; i++) {
            arr[i] = minHeap.extract();
        }
        for (int i = 1; i < n; i++) {
            if (arr[i - 1] > arr[i]) {
                throw new IllegalArgumentException("出错");
            }
        }
        for (int i = 0; i < n; i++) {
            System.out.print(arr[i] + " ");
        }
        Integer[] arr1 = new Integer[n];
        for (int i = 0; i < n; i++) {
            arr1[i] = random.nextInt(n * 1000);
        }
        System.out.println();
        System.out.println("测试最小堆完成");
        IndexHeap<Integer> minHeap1 = new ArrayIndexMinHeap<>(arr1);
        Stream.of(((ArrayIndexMinHeap)minHeap1).getData())
                .filter(data -> data != null)
                .forEach(data -> System.out.print(data + " "));
        System.out.println();
        for (int i = 1; i <= minHeap1.getSize(); i++) {
            System.out.print(((ArrayIndexMinHeap)minHeap1).getIndexes()[i] + " ");
        }
        System.out.println();
        minHeap1.extract();
        n--;
        Stream.of(((ArrayIndexMinHeap)minHeap1).getData())
                .filter(data -> data != null)
                .forEach(data -> System.out.print(data + " "));
        System.out.println();
        for (int i = 1; i <= minHeap1.getSize(); i++) {
            System.out.print(((ArrayIndexMinHeap)minHeap1).getIndexes()[i] + " ");
        }
        System.out.println();
        for (int i = 1; i <= minHeap1.getSize(); i++) {
            System.out.print(((ArrayIndexMinHeap)minHeap1).getReverse()[i] + " ");
        }
        System.out.println();
        System.out.println(minHeap1.get(8));
        minHeap1.change(3,9527);
        Integer[] arr2 = new Integer[n];
        for (int i = 0; i < n; i++) {
            arr2[i] = minHeap1.extract();
        }
        for (int i = 0; i < n; i++) {
            System.out.print(arr2[i] + " ");
        }
    }
}

运行结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
9003 7873 1421 7191 8573 799 471 2359 5132 6041 
471 799 1421 2359 5132 6041 7191 7873 8573 9003 
测试最小堆完成
3438 4971 9353 8743 2528 8294 4976 8498 7307 7161 
5 1 7 9 2 6 3 8 4 10 
3438 4971 9353 8743 2528 8294 4976 8498 7307 7161 
1 2 7 9 10 6 3 8 4 
1 2 7 9 0 6 3 8 4 
7307
3438 4971 4976 7161 7307 8294 8498 9353 9527 
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
[腾讯云大数据]神盾首创非对称联邦学习,深度保障数据隐私
导语:在过去的几年中,我们见证了大数据及人工智能技术的飞速发展,许多机构却依旧苦于数据数量少、质量低等难题而无法将前沿理论商业化落地。助力像石油般宝贵的数据突破隐私保护的条框限制并实现其价值的流通,对相关产业的发展起着至关重要的作用。在上一篇文章中,我们简要介绍了腾讯“神盾-联邦计算”平台的诞生背景和数据安全与隐私保护技术亮点。这次,我们着重选取本产品首推的“非对称联邦学习” (Asymmetrical Federated Learning, AFL) 范式进行介绍。该范式旨在全面保护数据集的样本ID、特征和标签的隐私安全,彻底解除在不平衡的 (unbalanced) 联邦计算系统中,中小企业对敏感用户ID泄露问题的担忧。
Narutoguo
2020/08/03
1.4K1
神盾首创非对称联邦学习,深度保障数据隐私
导语:在过去的几年中,我们见证了大数据及人工智能技术的飞速发展,许多机构却依旧苦于数据数量少、质量低等难题而无法将前沿理论商业化落地。助力像石油般宝贵的数据突破隐私保护的条框限制并实现其价值的流通,对相关产业的发展起着至关重要的作用。在上一篇文章中,我们简要介绍了腾讯“神盾-联邦计算”平台的诞生背景和数据安全与隐私保护技术亮点。这次,我们着重选取本产品首推的“非对称联邦学习” (Asymmetrical Federated Learning, AFL) 范式进行介绍。该范式旨在全面保护数据集的样本ID、特征和标签的隐私安全,彻底解除在不平衡的 (unbalanced) 联邦计算系统中,中小企业对敏感用户ID泄露问题的担忧。
腾讯云大数据
2021/01/07
7470
神盾首创非对称联邦学习,深度保障数据隐私
快速上手联邦学习——腾讯自研联邦学习平台PowerFL实战
导语:近10年,机器学习在人工智能领域迅猛发展,其中一个关键的推动燃料就是人类社会积累的大量数据。然而,尽管数据规模在总体上快速增长,绝大部分数据却分散在各个公司或部门内,导致数据被严重隔离和碎片化;也正因为此,各个组织间有很强的数据合作意愿,可是基于数据隐私和安全的考量,要在合规的情况下实现数据合作面临着诸多挑战。 基于上述原因形成的数据孤岛正严重阻碍着各方协同数据共同构建人工智能模型,也因此迫切需要一种新的机制来解决上述问题。联邦学习应运而生,通过这一新兴技术,可以在确保用户隐私和数据安全的前提下,各
腾讯大数据
2020/10/26
3.9K0
当联邦学习保护数据隐私,如何保证其自身的安全性?
联邦学习(Federated Learning)是一种由多方参与的联合计算技术,多方在不泄漏各自隐私数据的前提下,完成模型的训练与推理。
机器之心
2021/06/08
8390
RSPapers | 基于隐私保护的推荐系统论文合集
近年来,推荐系统已经成为许多社交/购物/新闻平台中必不可少的组件。一方面,推荐系统为了更好的捕捉和建模用户的行为习惯以及历史偏好,需要大量收集用户和物品的属性信息以及二者的交互记录。另一方面,大量的用户行为记录以及用户私有属性信息虽然使得模型能够掌握用户的行为模式,但也不可避免的造成了用户敏感信息以及隐私问题的担忧。所以如何在保证用户隐私前提下挖掘数据价值是目前大数据背景下值得研究的课题。
张小磊
2021/03/16
9620
RSPapers | 基于隐私保护的推荐系统论文合集
解密Angel PowerFL联邦学习平台中的纵向GBDT算法
导语:  GBDT(或XGBoost)算法是一种十分流行的树集成学习算法,不但是数据科学竞赛的常胜工具,在工业界的具体业务场景也有广泛的落地场景。然而,近年来用户隐私数据保护条例逐渐完善,“数据孤岛”逐渐形成,不但数据难以收集,不同公司或团队之间的数据也难以共享,这直接影响着机器学习模型的效果。为了应对这个问题,联邦学习技术逐渐进入人们的视线。本文聚焦腾讯自研的联邦学习平台Angel PowerFL中纵向联邦GBDT算法实现,介绍纵向联邦GBDT算法的原理和流程,并讲解相关的优化技术。 梯度提升决策树算法
腾讯大数据
2020/09/09
4.3K0
笔记︱联邦学习与隐私计算的案例集锦(一)
Federated Learning - 联邦学习 参考文献: 小白也能通俗易懂的联邦学习! 关于联邦学习建模过程中算法交互内容的研究
悟乙己
2022/06/06
4K1
笔记︱联邦学习与隐私计算的案例集锦(一)
腾讯云安全隐私计算产品获“2020年度大数据行业创新产品”奖
3月30日,由工信部部属单位中国工信出版传媒集团主办的第七届中国国际大数据大会在京召开,大会公布了“2020年度中国国际大数据大会行业评选”结果,腾讯云安全隐私计算产品凭借对大数据行业的深入解读,以及在数据安全、隐私保护等领域的出众能力和突破性成就,荣获“2020年度大数据行业创新产品”奖。 如今,在数字经济时代,大数据已成为全球数字经济发展的新动能,在各行各业智能化转型和高质量发展中都发挥着重要的作用和价值。与此同时,数据孤岛、数据隐私安全等问题又在一定程度上捆缚着企业发展的“手脚”,导致企业之间
腾讯云大数据
2021/04/06
4050
MICCAI论文精选:如何用联邦学习解决医学影像数据隐私问题?
雷锋网AI掘金志消息,日前,英伟达与伦敦国王学院以及一家法国初创公司Owkin合作,在新成立的伦敦医学影像与人工智能中心中应用了联邦学习技术。
AI掘金志
2019/10/30
1.6K0
MICCAI论文精选:如何用联邦学习解决医学影像数据隐私问题?
联邦学习 OR 迁移学习?No,我们需要联邦迁移学习
海量训练数据是现代机器学习算法、人工智能技术在各个领域中应用获得成功的重要条件。例如,计算机视觉和电子商务推荐系统中的 AI 算法都依赖于大规模的标记良好的数据集才能获得较好的处理效果,如 ImageNet 等。然而在一些应用领域中,例如医学领域、经济学领域以及一些政务信息化领域中,海量的可用训练数据往往是非常有限的。存在这些问题的主要原因:一是,针对机器学习算法的数据标注任务需要专业的知识和经验才能完成,这种预处理任务的成本非常高,往往无法获得机器学习所需要的足够的标注数据。二是,各个行业对数据隐私和数据安全的保护越来越强,在一定程度上也限制了对训练数据的共享,也就进一步加剧了可用的标注数据缺乏的问题。
机器之心
2020/11/20
1.1K0
联邦学习 OR 迁移学习?No,我们需要联邦迁移学习
腾讯 AngelFL 联邦学习平台揭秘
作者:AI前线 数据里蕴含着价值。在人工智能时代,机器学习尤其深度学习模型的获得需要大量的训练数据作为前提。但是在很多业务场景中,模型的训练数据往往分散在各个不同的业务团队、部门、甚至是不同的公司内的。由于用户隐私,这些数据无法直接使用,形成了所谓的“数据孤岛”。近两年,联邦学习技术 (Federated Learning)迅速发展,为跨团队数据合作,打破“数据孤岛”提供了新的解决思路,并开始从理论研究迈向批量应用的落地阶段。本文系统的介绍了联邦学习的发展历程以及业界情况,并重点介绍了TEG数据平台
腾讯技术工程官方号
2020/03/19
3.7K0
腾讯云安全隐私计算通过 CFCA 评测,再获国家级认可
‍ 2021年10月19日,中国金融认证中心(CFCA)正式公布了首批多方安全计算金融应用测评通过名单,腾讯云安全隐私计算在安全性、性能等多方面都以优秀的测试表现一路通关,成为国内最先获得该国家级认可的安全多方计算产品。 大数据及人工智能经过多年的飞速发展,数据已成为各企业最重要的资产及核心竞争力,受到国家高度重视,2019年10月,党的十九届四中全会首次将数据增列为一种生产要素,数据作为我国第五大生产要素,将为数字经济体系中技术创新、需求挖掘、效率提升提供重要动能。但随之而来的法律法规和信任问题收紧
腾讯云大数据
2021/10/21
8750
腾讯云参编的隐私计算报告发布,加快释放数据要素潜能
近日,北京金融科技产业联盟发布《隐私计算技术金融应用研究报告》。该报告分析了隐私计算的关键技术,介绍了隐私计算相关的政策和法律法规,梳理了隐私计算技术在金融业应用情况及面临的问题,并从标准化建设、行业政策引导、技术发展等方面给出建议。
bengbengsu
2022/04/27
8160
腾讯云参编的隐私计算报告发布,加快释放数据要素潜能
训练大模型缺少高质量数据?我们找到了一种新的解决方案
数据,作为决定机器学习模型性能的三大要素之一,正在成为制约大模型发展的瓶颈。正所谓「Garbage in, garbage out」[1],无论你的算法多么优秀,你的计算资源多么强大,模型的质量都直接取决于你用来训练模型的数据。
机器之心
2023/09/08
1.4K0
训练大模型缺少高质量数据?我们找到了一种新的解决方案
联邦学习,究竟能为大数据行业带来何种可能?
没有哪一项技术像人工智能一样,绵延数十年,引领数次风口。从60年前的达特茅斯会议到深蓝国际象棋再到AlphaGo,人工智能一直在持续着迭代、创新。联邦学习,就是人工智能与大数据行业一个新兴的技术,它的出现,有望解决数据孤岛的难题。
TVP官方团队
2020/04/08
1.4K0
一文梳理隐私计算/联邦学习推荐系统研究进展
推荐系统,对于我们来说并不陌生,它已经无时无刻不方便着我们的生活、学习、工作等方方面面,并且已经成为许多社交/购物/新闻平台中必不可少的组件。近些年来学术界以及工业界的研究者们已经对其进行了大量研究并提出了许多经典有效的推荐模型,比如UserCF、ItemCF、MF、FM、BPR、Item2vec、NCF、DIN等等。
炼丹笔记
2021/10/14
1.5K0
释放数据融合价值!腾讯Angel PowerFL荣获2021数博会“领先科技成果奖”
导读 / Introduction 5月26日-28日,在2021中国国际大数据产业博览会上,凭借对前沿趋势的把握和技术领先性,腾讯大数据-天工平台上的Angel PowerFL安全联合计算技术,荣获“领先科技成果奖——新技术”奖项。 数博会是全球首个以大数据为主题的博览会,由国家发展和改革委员会、工业和信息化部、国家互联网信息办公室和贵州省人民政府共同主办。作为数博会上的“重头戏”, “领先科技成果奖”是目前为止国家科学技术奖励办备案的唯一以博览会名义设奖和唯一以大数据为主题的专业奖项。 作为腾讯
腾讯大数据
2021/06/02
8930
联邦计算:不暴露真实数据如何完成合作建模?
导语:在金融场景下,银行等机构有强烈愿望和其他数据拥有方合作建模,但出于商业和合规方面的考虑,又不愿共享核心数据,导致行业内大规模数据共享迟迟无法推动。本文将从经典警匪影片情节出发,从技术角度探讨如何解决这一困境,希望与大家一同交流。
腾讯云大数据
2021/01/07
1.3K0
联邦计算:不暴露真实数据如何完成合作建模?
联邦计算:不暴露真实数据如何完成合作建模?
导语:在金融场景下,银行等机构有强烈愿望和其他数据拥有方合作建模,但出于商业和合规方面的考虑,又不愿共享核心数据,导致行业内大规模数据共享迟迟无法推动。本文将从经典警匪影片情节出发,从技术角度探讨如何解决这一困境,希望与大家一同交流。
Narutoguo
2020/09/25
2.9K0
联邦学习在腾讯微视广告投放中的实践
分享人:宋凯 博士 整理者:林宜蓁 导读: 本文从广告主的角度,分享联邦学习实践的经验跟思考。 先介绍业务与技术选型背景:团队项目为用户增长及成本控制,方式为广告渠道投放,投放目标分为拉新、拉活两类。 拉新时,微视侧端内用户特征稀疏,而广告平台积累大量信息,但仅有有限性的oCPX标准化数据回传。 拉活时,微视侧具备用户行为序列等宝贵画像数据,与广告平台特征有互补性,但又无法直接粗暴的与广告平台共享数据。 所以,希望微视侧能与广告平台侧利用双方数据,实现收益共赢,但保证数据的安全不出域。在这种背景下我
腾讯大数据
2021/09/06
2.5K0
推荐阅读
相关推荐
[腾讯云大数据]神盾首创非对称联邦学习,深度保障数据隐私
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档