Skip to content

Commit

Permalink
Update 2024-02-29-java源码分析.md
Browse files Browse the repository at this point in the history
  • Loading branch information
nooblong committed Feb 29, 2024
1 parent 56d45dd commit 207e949
Showing 1 changed file with 149 additions and 0 deletions.
149 changes: 149 additions & 0 deletions _posts/2024-02-29-java源码分析.md
Original file line number Diff line number Diff line change
Expand Up @@ -1702,3 +1702,152 @@ Sn = n - log₂(n + 1)
所以,**Delete(i)**可以在O(log **N**)内完成,前提是我们已知序号**i**

### add、offer

```java
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
modCount++;
// i为size,i就为数组末尾空的index
int i = size;
if (i >= queue.length)
grow(i + 1);
siftUp(i, e);
size = i + 1;
return true;
}
private void siftUp(int k, E x) {
if (comparator != null)
// 原理一样,只是使用属性comparator去比较
siftUpUsingComparator(k, x, queue, comparator);
else
siftUpComparable(k, x, queue);
}
// k – 要填补的位置 x – 要插入的项目
private static <T> void siftUpComparable(int k, T x, Object[] es) {
Comparable<? super T> key = (Comparable<? super T>) x;
while (k > 0) {
// 为什么是k>0,当k=1,为根节点,右移一位就是0,同时不需要再上移了。
// 最小堆,除2舍弃小数,得到父节点(左子节点不用舍弃小数,右边的要)
int parent = (k - 1) >>> 1;
// 获得父节点的元素,如果要插入的大于父节点,则复合最小堆性质,直接赋值
Object e = es[parent];
if (key.compareTo((T) e) >= 0)
break;
// 不符合,将插入位置赋值为父节点,下一步将父节点的位置和要插入的元素参与比较
es[k] = e;
k = parent;
}
es[k] = key;
}
private void grow(int minCapacity) {
// 数组复制,从头填充
int oldCapacity = queue.length;
// Double size if small; else grow by 50%
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
oldCapacity < 64 ? oldCapacity + 2 : oldCapacity >> 1
/* preferred growth */);
queue = Arrays.copyOf(queue, newCapacity);
}
```

#### peek、element()都是直接返回数组[0]的元素,一个返回null报错,根据小顶堆的性质,堆顶那个元素就是全局最小的那个

#### Remove、poll

```java
public E poll() {
final Object[] es;
final E result;

if ((result = (E) ((es = queue)[0])) != null) {
modCount++;
final int n;
// 取出最后一个元素x
final E x = (E) es[(n = --size)];
// 最后一个元素的位置设为null
es[n] = null;
if (n > 0) {
// 队列不止1个元素
final Comparator<? super E> cmp;
if ((cmp = comparator) == null)
// 在位置0处插入x,n为元素取出后的剩余容量(--size)
siftDownComparable(0, x, es, n);
else
siftDownUsingComparator(0, x, es, n, cmp);
}
}
return result;
}
private static <T> void siftDownComparable(int k, T x, Object[] es, int n) {
// assert n > 0;
Comparable<? super T> key = (Comparable<? super T>)x;
int half = n >>> 1; // loop while a non-leaf
while (k < half) {
// k>=half说明已经遍历到了叶子节点
int child = (k << 1) + 1; // 假设左节点是最小的
Object c = es[child];
int right = child + 1;
if (right < n &&
// 如果左节点大于右节点
((Comparable<? super T>) c).compareTo((T) es[right]) > 0)
// 那就操作右节点
c = es[child = right];
// 如果要插入的比要操作的小,那就符合最小堆
if (key.compareTo((T) c) <= 0)
break;
// 交换
es[k] = c;
k = child;
}
es[k] = key;
}
```

#### remove(Object o)

```java
public boolean remove(Object o) {
int i = indexOf(o);
if (i == -1)
return false;
else {
removeAt(i);
return true;
}
}
private int indexOf(Object o) {
if (o != null) {
final Object[] es = queue;
for (int i = 0, n = size; i < n; i++)
// 从头找,嗯找
if (o.equals(es[i]))
return i;
}
return -1;
}
E removeAt(int i) {
//从队列中删除第 i 个元素。通常,此方法会保留最多 i-1(含)的元素,不受影响。在这种情况下,它返回 null。有时,为了保持堆不变性,它必须将列表中较晚的元素与早于 i 的元素交换。在这种情况下,此方法返回之前位于列表末尾且现在位于 i 之前某个位置的元素。 iterator.remove 使用这个事实来避免丢失遍历元素。
// 返回的不是被remove的!!!
// assert i >= 0 && i < size;
final Object[] es = queue;
modCount++;
int s = --size;
if (s == i) // removed last element
// 删除的是最后一个元素。直接删除即可,不需要调整
es[i] = null;
else {
// 删除的不是最后一个元素,从删除点开始以最后一个元素为参照调用一次siftDown()即可
E moved = (E) es[s];// 将最后一个元素拿出来(moved)
es[s] = null;// 最后的位置设为空
siftDown(i, moved);// 在i(要取出的元素的位置)插入moved,然后向下调整
if (es[i] == moved) {// 如果向下调整后移动的元素仍然比其父节点小
siftUp(i, moved);// 则需要通过向上调整操作将该元素移至正确的位置。
if (es[i] != moved)// 如果移动过,返回位于列表末尾且现在位于 i 之前某个位置的元素
return moved;
}
}
return null;
}
```

0 comments on commit 207e949

Please sign in to comment.