关于findMax()函数的一个小小问题

来源:8-4 从堆中取出元素和Sift Down

DorJake

2019-05-06

感觉findMax()是不是应该私有的比较好,感觉有可能会破坏堆的结构。

比如用一个堆存放Student类

MaxHeap<Student> maxheap = MaxHeap<>();

之后往maxheap中放入Student对象

然后取出最大的Student对象,并且更改其年龄

Student s = maxheap.fandMax();
s.setYear(0);

假如student对象的大小比较就是和其year属性相关。

经过上述的操作之后这个大顶堆的结构就被破坏了,因为改变最大元素的属性之后并不会进行Shif Down操作。

解决方法我想的是定义两个函数,一个fianMax()是私有的和教程中一样。还有一个getMax()为公有的开放给外部调用,返回的是最大元素的克隆。不知道是不是有其它方法。

写回答

1回答

liuyubobobo

2019-05-07

大赞。


你的考虑是对的。但是,在Java中,无法通过访问限制的问题解决(C++中可以解决)。你的clone的方法是ok的,但是增大了开销。


事实上,Java标准库中的数据结构,有同样的问题。以PriorityQueue为例(底层就是堆),你可以实验如下代码:

// 创建一个学生类
public class Student implements Comparable<Student>{
    
    public String name;
    public int score;
    
    public Student(String name, int score){
        this.name = name;
        this.score = score;
    }
    
    // 学生类可以按照分数做比较
    @Override
    public int compareTo(Student another){
        return another.score - score;
    }
    
    @Override
    public String toString(){
        return this.name + " " + String.valueOf(this.score);
    }
}


然后,实验如下Main:

import java.util.PriorityQueue;

public class Main {
    public static void main(String[] args) {
        PriorityQueue<Student> pq = new PriorityQueue<>();
        pq.add(new Student("A", 60));
        pq.add(new Student("B", 100));
        pq.add(new Student("C", 80));
        
        // 打印优先队列的第一名,应该是B同学,100分嘛
        System.out.println(pq.peek()); 
        
        // 现在,把第一名取出来
        Student topStudent = pq.peek();
        
        // 他的成绩判错了,其实是15分,直接修改
        topStudent.score = 15;
        
        // 再打印优先队列的第一名,还是B同学。可却是15分
        System.out.println(pq.peek());
    }
}


所以,这个问题在Java语言中是一个设计困境。看你的取舍了。当前的设计,就是需要调用者保证不直接修改优先队列中的引用内容。这就好比用户调用数组元素,需要保障数组索引不越界;调用出栈或者出队操作,需要保障栈或者队不为空一样:)


继续加油!:)

5
0

玩转数据结构

动态数组/栈/队列/链表/BST/堆/线段树/Trie/并查集/AVL/红黑树…

6221 学习 · 1705 问题

查看课程