发布时间:2025-06-24 18:07:15 作者:北方职教升学中心 阅读量:980
删除和取出堆定元素、判断堆是否为空等。 // 否则,返回 false,表示堆中至少有一个元素。
堆的这些性质使得堆顶元素(根节点)在最大堆中是最大值,在最小堆中是最小值。
(1)插入操作
插入操作其实就是我们在创建堆中的逐个插入元素的操作,这里再让我们回顾一下:
// 插入元素的方法 public void offer(int val) { // 如果堆已满,扩展数组容量为原来的两倍 if (isFull()) { elem = Arrays.copyOf(elem, 2 * elem.length); } // 将新元素放入数组的最后一位 elem[usedSize++] = val; // 进行上浮操作,保持堆的性质 shiftUp(usedSize - 1); } // 检查堆是否已满 private boolean isFull() { return usedSize == elem.length; } // 向上调整算法,将新插入的元素移动到正确位置 private void shiftUp(int child) { int parent = (child - 1) / 2; // 当child不为根节点,并且父节点的值小于子节点的值时,进行交换 while (parent >= 0) { if (elem[parent] < elem[child]) { swap(parent, child); child = parent; parent = (child - 1) / 2; } else { break; } } }
(2)删除操作
删除操作的核心思想为:将栈顶的元素和数组最后一个元素进行交换之后,删除最后一个元素,之后再对堆进行整理(整理为最小堆或最大堆)
public void poll() { // 将根节点(索引0)与堆的最后一个节点交换位置 swap(0, usedSize - 1); // 移除堆的最后一个节点(原根节点),减少堆的大小 usedSize--; // 从根节点开始进行下沉调整,恢复堆的性质 shiftDown(0, usedSize);}private void swap(int pos1, int pos2) { // 交换堆中两个指定位置的元素 int temp = elem[pos1]; elem[pos1] = elem[pos2]; elem[pos2] = temp;}private void shiftDown(int root, int len) { int child = 2 * root + 1; // 计算左孩子的索引 while (child < len) { // 如果右孩子存在且大于左孩子,则选择右孩子 if (child + 1 < len && elem[child] < elem[child + 1]) { child++; } // 如果选中的孩子节点大于当前根节点,则交换并继续下沉 if (elem[child] > elem[root]) { swap(child, root); root = child; // 更新根节点为刚刚下沉的孩子节点 child = 2 * root + 1; // 更新孩子节点的索引 } else { break; // 当前根节点已经大于或等于所有孩子节点,结束下沉 } }}
(3)返回堆顶元素
其核心思想为:将堆中的首元素返回
public boolean isEmpty() { // 检查堆是否为空 // 如果堆的大小为0,则返回true,表示堆为空;否则返回false return usedSize == 0;}public int peekHeap() { // 查看堆顶元素 if (isEmpty()) { // 如果堆为空,则抛出异常 throw new NullElementException("优先队列中没有元素!!!"); } // 返回堆顶元素(根节点) return elem[0];}
(4)判断堆是否为空
其核心思想为:数组中有没有元素
public boolean isEmpty() { // 如果 usedSize(堆的当前大小)等于0,说明堆中没有元素,返回 true。逐个插入元素的方法相对简单,但批量建堆的方法效率更高。现在让我们详细介绍这些操作的实现方法。(读者若有兴趣可以自行了解!) 堆的定义
——堆是一种特殊的完全二叉树,满足以下两个条件:
完全二叉树:
除了最后一层,其他层的节点都是满的,并且最后一层的节点从左到右连续排列。
以上就是本篇文章的全部内容了~~~