参考了

https://www.bilibili.com/video/BV11t4y1r79L

https://blog.csdn.net/qq_19782019/article/details/78301832

他们已经写的足够好了。我最近都在用Kotlin编程开发,我尝试用Kotlin实现了大顶堆,并且作为手动实现的优先级队列,通过了Leetcode 347

package main.kotlin

/**
 * 二叉堆(大顶堆、优先级队列)
 *
 * @Date 2021-10-14.
 * @author Johnathan Lin
 */
data class MaxHeap<T : Comparable<T>>(
  val arr: Array<T>,
  var size: Int
) {
  //将无序的数组构建一个二叉堆
  fun makeHeap() {
    for (i in (size - 1) downTo 0) {
      heapDown(i)
    }
  }

  //向二叉堆中加入元素
  fun addItem(value: T) {
    //TODO 添加的边界还未考虑
    val newIndex = size++
    arr[newIndex] = value
    heapUp(newIndex)
  }

  //移除堆顶元素
  fun removeItem(): T {
    //TODO 删除的边界还未考虑
    val removeValue = arr[0]
    val lastValue = arr[size - 1]
//    println("lastValue:$lastValue")
    arr[0] = lastValue
    size--
    heapDown(0)

    return removeValue
  }

  fun printHeap() {
    for (i in 0..(size - 1)) {
      print(arr[i].toString() + " ")
    }
    println()
  }

  private fun heapDown(p: Int) {
    var i = p
    while (i < size) {
      //和左右子节点(如果存在)比大小,如果自己是最大则结束,如果不是,则将自己这个位置换成最大的,然后再从被换的位置继续比
      val left = 2 * i + 1
      val right = 2 * i + 2
      var maxinum = i
      if (left < size && arr[maxinum] < arr[left]) {
        maxinum = left
      }
      if (right < size && arr[maxinum] < arr[right]) {
        maxinum = right
      }

      if (maxinum == i) {
        break
      }
//      println("交换i: $i ${arr[i]}, maxinum:$maxinum ${arr[maxinum]}")
      val tmp = arr[i]
      arr[i] = arr[maxinum]
      arr[maxinum] = tmp
      i = maxinum
    }
  }

  private fun heapUp(p: Int) {
    //从下往上不停地比较其父节点,比父节点大则交换
    var i = p
    while (i >= 0 && arr[i] > arr[(i - 1) / 2]) {
      val parentIndex = (i - 1) / 2
      val tmp = arr[i]
      arr[i] = arr[parentIndex]
      arr[parentIndex] = tmp
      i = parentIndex
    }
  }
}

//自己定义的类型,实现Comparable接口
data class Data(
  val name: String, //名字
  val weight: Int //权重
) : Comparable<Data> {
  override fun compareTo(other: Data): Int {
    return if (weight > other.weight) {
      1
    } else if (weight < other.weight) {
      -1
    } else {
      0
    }
  }

  override fun toString(): String {
    return "${name}-${weight}"
  }

}

fun main() {
  //TODO 这里由于Kotlin指定泛型Data为非空,所以要求对每个元素初始化,这步很浪费空间
  //TODO 如果改为Array<Data?> 则很多地方都要判断是否为空
  val arr: Array<Data> = Array(100) { i -> Data("null", i) }
  //测试数据
  arr[0] = Data("Kobe", 5)
  arr[1] = Data("James", 4)
  arr[2] = Data("Duncan", 6)
  arr[3] = Data("Garnett", 8)
  arr[4] = Data("Wall", 2)
  arr[5] = Data("Nash", 10)
  arr[6] = Data("Howard", 12)
  arr[7] = Data("Paul", 3)
  arr[8] = Data("Anthony", 7)
  arr[9] = Data("Yi", 11)
  println("构建二叉堆")
  val heap: MaxHeap<Data> = MaxHeap(arr, 10)
  //将无序的数组构建一个二叉堆
  heap.makeHeap()
  heap.printHeap()

  //加入一个元素,预计这个元素会到堆顶
  val added = Data("Gasol", 16)
  println("添加一个元素${added.toString()}")
  heap.addItem(added)
  heap.printHeap()

  val removed = heap.removeItem()
  println("移除了顶部元素${removed.toString()}")
  heap.printHeap()
  println("finish")

}

输出结果如下:

构建二叉堆
Howard-12 Yi-11 Nash-10 Garnett-8 James-4 Kobe-5 Duncan-6 Paul-3 Anthony-7 Wall-2 
添加一个元素Gasol-16
Gasol-16 Howard-12 Nash-10 Garnett-8 Yi-11 Kobe-5 Duncan-6 Paul-3 Anthony-7 Wall-2 James-4 
移除了顶部元素Gasol-16
Howard-12 Yi-11 Nash-10 Garnett-8 James-4 Kobe-5 Duncan-6 Paul-3 Anthony-7 Wall-2 
finish

Process finished with exit code 0

然后我将其进行修改,提交到LeetCode,通过,代码如下:

data class MaxHeap<T:Comparable<T>>(
  val arr:Array<T>,
  var size: Int
) {

  fun makeHeap() {
    for(i in (size - 1) downTo 0) {
      heapDown( i)
    }
  }

  fun heapDown(p: Int) {
    var i = p
    while(i < size) {
    //   if(i == 0) {
    //     println("i: $i, arr[i] = ${arr[i]}")
    //   }
      val left = 2 * i + 1
      val right = 2 * i + 2
      var maxinum = i
      if (left < size && arr[maxinum] < arr[left]) {
        maxinum = left
      }
      if (right < size && arr[maxinum] < arr[right]) {
        maxinum = right
      }

      if (maxinum == i) {
        break
      }
    //   println("交换i: $i ${arr[i]}, maxinum:$maxinum ${arr[maxinum]}")
      val tmp = arr[i]
      arr[i] = arr[maxinum]
      arr[maxinum] = tmp
      i = maxinum
    }
  }

  fun heapUp(p: Int) {
    var i = p
    while (i >= 0 && arr[i] > arr[(i-1)/2]) {
      val parentIndex = (i-1)/2
      val tmp = arr[i]
      arr[i] = arr[parentIndex]
      arr[parentIndex] = tmp
      i = parentIndex
    }
  }

  fun addItem(value: T) {
    val newIndex = size++
    arr[newIndex] = value
    heapUp(newIndex)
  }

  fun removeItem():T {
    val removeValue = arr[0]
    val lastValue = arr[size-1]
//    println("lastValue:$lastValue")
    arr[0] = lastValue
    size--
    heapDown(0)
    
    return removeValue
  }
}

data class Data(
  val value: Int,
  val num: Int
): Comparable<Data> {
  override fun compareTo(other: Data): Int {
    return if (num > other.num) {
      1
    } else if (num < other.num) {
      -1
    } else {
      0
    }
  }

  override fun toString(): String {
    return "${value}-${num}"
  }

}
class Solution {


    fun topKFrequent(nums: IntArray, k: Int): IntArray {
        val res = IntArray(k);
        val arr:Array<Data> = Array(nums.size)  {i -> Data(0, 0)}
        //  val arr: Array<Data> = Array(nums.size) { i -> Data(0, 0) }
        val maxHeap = MaxHeap(arr, 0)
        val map: HashMap<Int, Int> = hashMapOf()
        nums.forEach { it ->
            map[it] = map.getOrDefault(it, 0) + 1
        }
        map.forEach { key, value ->
            maxHeap.addItem(Data(key, value))
        }
        for(i in 1..k) {
            res[i-1] = maxHeap.removeItem().value
        }
        return res
    }
}