CS61B笔记 | Heaps and Priority Queues

  1. 数据结构决定了如何组织、存储数据,而算法则定义了如何高效地操作这些数据。
  2. 不同的数据结构适合不同类型的算法,反之,特定的算法往往需要特定的数据结构来实现其效率。
  3. 数据结构是算法的基础,而算法则是对数据结构的操作过程。

问题引申

我需要这样一个抽象数据结构:Priority Queues(优先级队列),它将具有以下基本功能:

  • 添加
  • 获取最小元素
  • 删除最小元素
  • 获取元素个数
/** (Min) Priority Queue: Allowing tracking and removal of the

  * smallest item in a priority queue. */
public interface MinPQ<Item> {

/** Adds the item to the priority queue. */

public void add(Item x);

/** Returns the smallest item in the priority queue. */

public Item getSmallest();

/** Removes the smallest item from the priority queue. */

public Item removeSmallest();

/** Returns the size of the priority queue. */

public int size();

}

现在假如有10w个物理粒子,我们需要找出其中10个最大的,如何在最少的内存和时间开销下去找到它们呢?

  • 我们可以每次只保存10个粒子,当出现第11个粒子的时候,就removeSmallest(),使得队列中粒子数上限一直为10。循环执行即可找到10w个物理粒子中10个最大的粒子。

现在,考虑如何去实现...

一些糟糕的实现

Ordered Array Bushy BST Hash Table Heap
add Θ(N) Θ(log N) Θ(1)
getSmallest Θ(1) Θ(log N) Θ(N)
removeSmallest Θ(N) Θ(log N) Θ(N)
Caveats Dups tough
  1. 有序数组,添加和删除都需要Θ(N)的时间复杂度,开销太大,不考虑。
  2. 二分搜索树,添加删除查找元素都只需要Θ(log N)时间,但是注意二分搜索树很难有重复项,一开始我们就没有考虑往里面添加重复元素。如果使用BST来实现我们的需求,可能需要大量额外操作,也不考虑。
  3. 哈希表,添加和查找元素需要常数时间,看起来不错。但是在哈希表中如何找到最小元素呢?哈希表中的东西没有真正的顺序,如果要找最小元素需要遍历每一个桶,这并不好玩,所以还是不考虑。

Heap

我想用一个快速而优雅地处理重复项的实现来填充Heap这一列

  • 使用的新数据结构叫做 二叉最小堆,它仍然是一个二叉树,但是基本属性有所不同。
  • 根节点是最小值,每个节点的值小于或等于子节点的值,所有元素尽量往左边靠拢。
  • 如果要添加元素,先添加到合适的叶子节点,保证整棵树的茂盛,然后向上swimming,遇到大于自己的就交换,直到找到合适的位置。
  • 如果删除根节点,将根节点替换为堆中最后一个项目,也就是尽可能靠右的底层。然后再向下寻找是否有子节点比自己还小,交换,直到找到合适的位置。

具体代码可以用数组实现,类似于不相交集。也可以类似于之前作业里写过的BST。

Ordered Array Bushy BST Hash Table Heap
add Θ(N) Θ(log N) Θ(1) Θ(log N)
getSmallest Θ(1) Θ(log N) Θ(N) Θ(1)
removeSmallest Θ(N) Θ(log N) Θ(N) Θ(log N)
Caveats Dups tough

堆对重复项非常擅长!

目前学习的所有数据结构,都有一些共同点:

  • 用户可以添加新项目到项目堆中。(数据结构要做的就是保持项目堆的有序性)
  • 应该有某个操作可以让用户从项目堆中取出项目。(通过有序性,这样做可以是高效的)
    所以我们花了很长时间,以不同并且创造性的方式来解决的都是搜索问题,非常酷!

以上几种数据结构是CS61B的核心部分,之后开始学习图。

posted @ 2024-09-10 17:57  Merakii  阅读(31)  评论(0)    收藏  举报