麻蛋,原来是最小堆呀! 数据结构不熟害死人呀! 看来待复习复习数据结构了
在lucene源码中对多个段合并的时候,会先将多个段放到一个PriorityQueue中,不要被这个名字迷惑,这个PriorityQueue和JDK的PriorityQueue是完全两个类,而且底层实现也完全不一样,lucene的队列并不是数据结构里学的先进先出的结构,lucene的这个PriorityQueue(org.apache.lucene.util.PriorityQueue)只满足部分有序,为什么要这样设计? 可能是为了性能。那哪部分有序? 这个需要了解基础的操作put和pop的实现,PriorityQueue底层也是一个Object数组,对该队列的操作主要是两个:
PUT:
put操作就是往队列里新增一个元素,当put时候是把新增的元素放到Object数字的最后一个位置上,在PriorityQueue中有个size变量用于存储当前Object数字存储的真实元素有多少个,每次put时候就是把size++然后存到size的位置上,存完以后内部会再执行一个upHeap的操作,这个操作就是将新增的这个元素调整到合适的位置,为什么叫upHeap,是因为新增的元素在数组的最后一个位置上,调整的方向是从后往前,找到这个新增的元素大小合适的地方,排序的规则是由lessThan方法决定,这个由使用PriorityQueue的地方实现该方法。具体的找的逻辑类似二分查找,每次都查找折半位置处的元素是否大于新添加的元素,比如一个size=32的数组,折半查找过程是 32 / 2 = 16、16 / 2 = 8 、8 / 2 = 4、4 / 2 = 2 、 2 / 2 = 1,从前往后依次查找位置 16、8、4、2、1处的元素是否大于新添加的元素(Object[size]),如果不大于,则停止后续的查找,这就解释了上面说的局部有序的问题,这个局部不确定,根据添加的元素有关系,但是基本保证了小的值在前,大的在后。
POP:
pop操作就是把队列头的数据取出,取出后会将最后一个元素放到第一位,然后再执行downHeap的操作,这个操作和upHeap差不多,只是方向是从前往后,不断折半找到一个第一个位数大的元素,找到就调换位置,没有找到就结束