惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
酷 壳 – CoolShell
酷 壳 – CoolShell
WordPress大学
WordPress大学
小众软件
小众软件
博客园 - 司徒正美
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Jina AI
Jina AI
Hugging Face - Blog
Hugging Face - Blog
博客园 - Franky
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
量子位
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
雷峰网
雷峰网
云风的 BLOG
云风的 BLOG
M
MIT News - Artificial intelligence
F
Fortinet All Blogs
T
Tailwind CSS Blog
Martin Fowler
Martin Fowler
I
InfoQ
The GitHub Blog
The GitHub Blog
有赞技术团队
有赞技术团队
The Cloudflare Blog
罗磊的独立博客

风萧古道 - 勤学苦练,年复一年

AI 编程时代,想象力成了最被奖励的能力 游戏服务器开发经验(五)应对复杂需求 沉浸式体验东汉末年生活 - 《真三国无双 起源》玩后感 怒其不争!致2025年HLTV的Top18-NiKo Linux家用服务器维护指南 游戏服务器开发经验(四)避免写Bug的习惯、技巧和心态 游戏服务器开发经验(三)线上维护 游戏服务器开发经验(二)避免内存泄露 游戏服务器开发经验(一)道具防刷 35岁找不到工作,绝对不会是软件开发人员的结局 用爱发电项目开发两个月的心得体会 以魏延“子午谷奇谋”讨论软件需求可行性问题 MQTT协议中可变长度的具体计算方式(有计算过程解析) 关于游戏服务器配置表功能的探讨 Java并发编程中上锁的几种方式 如何用C++分割一个字符串? CSAPP第二章-信息的表示与处理 我的自我介绍 Windows XP虚拟机中文版无需激活下载 Java TreeSet的一些用法和特性 Linux C++ Socket实战 传统软件服务器与游戏服务器架构区别 独立个人项目开发心得 - 任务切分、挑战性、实用性和半途而废 使用Python实现简单UDP Ping 使用Python开发一个简单的web服务器 Kotlin手动实现一个最简单的哈希表 搭建Spark实战环境(3台linux虚拟机集群)(一)样板机的搭建 Springboot操作MongoDB,包括增改查及复杂操作 Unison在Linux下的安装与使用 Java实现类似WINSCP访问远程Linux服务器,执行命令、上传文件、下载文件
Kotlin实现二叉堆、大顶堆、优先级队列
JonathanLin · 2021-10-14 · via 风萧古道 - 勤学苦练,年复一年

参考了

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
    }
}