Java数据结构之堆和优先队列(3)

向堆中添加一个元素,在堆的内部要进行一个上浮的操作,保证用数组实现的二叉堆还符合我们最大堆的性质(父节点的值大于两个子节点的值)。

Java数据结构之堆和优先队列

82大于他的父节点60,两个结点交换位置,82还大于他的父结点80,两个节点交换位置。80小于现在的父结点90,结束交换。这个操作很多人称为上浮操作(个人认为名称贴切)上浮操作完成。

Java数据结构之堆和优先队列

用代码实现我们刚才的操作,已经知道他父结点的位置(公式),交换两个人的位置就变得很简单,MaxHeap添加函数。

//堆中添加元素 public void add(E e) { data.addLast(e); siftUp(data.getSize() - 1); } //上浮操作 private void siftUp(int i) { while (i > 0 && data.get(parent(i)).compareTo(data.get(i)) < 0) { //交换位置 data.swap(i,parent(i));
       i = parent(i) } }

Array类,添加交换位置的函数

public void swap(int i,int j) { if (i < 0 || i >= size || j < 0 || j > size) { throw new IllegalArgumentException("索引越界"); } E t = data[i]; data[i] = data[j]; data[j] = t; }

有添加就有取出,取出堆中元素其实很简单,因为最大堆决定了只取堆顶元素(数组的第一个元素),直接取出即可。困难的是如何维护二叉堆的性质不变。

取出堆顶元素后

Java数据结构之堆和优先队列

取出堆顶元素,剩下两个子树,将两颗子树糅合成一个二叉堆,现在直接将60这个元素作为堆顶,就满足了完全二叉树的性质但并不符合最大堆性质。

Java数据结构之堆和优先队列

和上浮的操作相反,现在我们要进行下沉的操作,60的左右孩子都比60来得大,要选择左右孩子最大的那个数进行交换,82和60进行交换,80比60来得大,交换他们的位置,10比60来得小,符合二叉堆的性质。交换结束。

Java数据结构之堆和优先队列

用代码描述刚才取出的操作。

MaxHeap类

//堆中最大元素 public E findMax() { if (data.getSize() == 0) { throw new IllegalArgumentException("堆为空,无法查看值"); } return data.get(0); } //取出堆顶元素 public E extractMax() { E ret = findMax(); data.swap(0,data.getSize() - 1); data.removeLast(); siftDown(0); return ret; } //下沉操作 private void siftDown(int i) { //比较到他左右孩子那个比他大进行交换操作 while (leftChild(i) < data.getSize()) { int j = leftChild(i); if (j + 1 < data.getSize() && data.get(j + 1).compareTo(data.get(j)) > 0) //右节点 { j = rightChild(i); } if (data.get(i).compareTo(data.get(j)) >= 0) { break; } data.swap(i,j); i = j; } }

现在我们堆结构基本完成,简单测试一下

Main类

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/dac0739a28da389db9e2cc4e1132777c.html