返回

JavaScript中的堆[heap]数据结构

前端

堆的概念

堆是一种特殊的树形数据结构,其中每个节点的值都大于或等于其子节点的值。堆通常用于实现优先队列,其中优先级最高的元素位于堆的顶部。堆的典型操作包括插入、删除和查找。

堆的实现

在JavaScript中,堆可以通过数组来实现。堆的数组表示法中,每个元素都存储一个值,并且该值大于或等于其子节点的值。堆的数组表示法如下图所示:

[
  10,
  8, 15,
  3, 9, 12,
  2, 5, 7, 11
]

堆的操作

堆的主要操作包括插入、删除和查找。插入操作将一个新的元素插入堆中,删除操作从堆中删除一个元素,查找操作找到堆中的某个元素。

插入操作

插入操作将一个新的元素插入堆中。插入操作首先将新元素添加到堆的末尾,然后将新元素向上移动,直到新元素的值大于或等于其父节点的值。插入操作的时间复杂度为O(log n),其中n是堆中的元素数量。

删除操作

删除操作从堆中删除一个元素。删除操作首先将堆顶元素与堆的最后一个元素交换,然后将堆的最后一个元素删除。然后,将堆顶元素向下移动,直到堆顶元素的值大于或等于其子节点的值。删除操作的时间复杂度为O(log n),其中n是堆中的元素数量。

查找操作

查找操作找到堆中的某个元素。查找操作从堆顶元素开始,然后向下移动,直到找到要查找的元素。查找操作的时间复杂度为O(log n),其中n是堆中的元素数量。

堆的应用

堆在计算机科学中有很多应用,包括排序、查找、插入和删除。

排序

堆可以用于对数组进行排序。堆排序是一种非递归的排序算法,其时间复杂度为O(n log n),其中n是数组中的元素数量。堆排序的实现如下:

function heapSort(array) {
  // 构建堆
  for (let i = Math.floor(array.length / 2) - 1; i >= 0; i--) {
    heapify(array, i, array.length);
  }

  // 排序
  for (let i = array.length - 1; i > 0; i--) {
    // 将堆顶元素与最后一个元素交换
    [array[0], array[i]] = [array[i], array[0]];

    // 调整堆
    heapify(array, 0, i);
  }

  return array;
}

function heapify(array, i, n) {
  // 左子节点的索引
  let left = 2 * i + 1;

  // 右子节点的索引
  let right = 2 * i + 2;

  // 最大元素的索引
  let largest = i;

  // 如果左子节点的值大于父节点的值,则将最大元素的索引更新为左子节点的索引
  if (left < n && array[left] > array[i]) {
    largest = left;
  }

  // 如果右子节点的值大于最大元素的值,则将最大元素的索引更新为右子节点的索引
  if (right < n && array[right] > array[largest]) {
    largest = right;
  }

  // 如果最大元素的索引不是父节点的索引,则将父节点的值与最大元素的值交换,并递归地调整堆
  if (largest !== i) {
    [array[i], array[largest]] = [array[largest], array[i]];
    heapify(array, largest, n);
  }
}

查找

堆可以用于查找数组中的某个元素。查找操作从堆顶元素开始,然后向下移动,直到找到要查找的元素。查找操作的时间复杂度为O(log n),其中n是数组中的元素数量。

插入

堆可以用于向数组中插入一个新的元素。插入操作首先将新元素添加到堆的末尾,然后将新元素向上移动,直到新元素的值大于或等于其父节点的值。插入操作的时间复杂度为O(log n),其中n是数组中的元素数量。

删除

堆可以用于从数组中删除一个元素。删除操作首先将堆顶元素与堆的最后一个元素交换,然后将堆的最后一个元素删除。然后,将堆顶元素向下移动,直到堆顶元素的值大于或等于其子节点的值。删除操作的时间复杂度为O(log n),其中n是数组中的元素数量。

总结

堆是一种树形数据结构,其中每个节点的值都大于或等于其子节点的值。堆在计算机科学中有很多应用,包括排序、查找、插入和删除。堆的实现可以通过数组来实现,其时间复杂度为O(log n)。