diff --git a/codes/kotlin/chapter_hashing/array_hash_map.kt b/codes/kotlin/chapter_hashing/array_hash_map.kt new file mode 100644 index 000000000..489667f2b --- /dev/null +++ b/codes/kotlin/chapter_hashing/array_hash_map.kt @@ -0,0 +1,130 @@ +/** + * File: array_hash_map.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_hashing + +/* 键值对 */ +class Pair( + var key: Int, + var value: String +) + +/* 基于数组实现的哈希表 */ +class ArrayHashMap { + private val buckets = arrayOfNulls(100) + + /* 构造方法 */ + init { + // 初始化数组,包含 100 个桶 + for (i in 0..<100) { + buckets[i] = null + } + } + + /* 哈希函数 */ + fun hashFunc(key: Int): Int { + val index = key % 100 + return index + } + + /* 查询操作 */ + fun get(key: Int): String? { + val index = hashFunc(key) + val pair = buckets[index] ?: return null + return pair.value + } + + /* 添加操作 */ + fun put(key: Int, value: String) { + val pair = Pair(key, value) + val index = hashFunc(key) + buckets[index] = pair + } + + /* 删除操作 */ + fun remove(key: Int) { + val index = hashFunc(key) + // 置为 null ,代表删除 + buckets[index] = null + } + + /* 获取所有键值对 */ + fun pairSet(): MutableList { + val pairSet = ArrayList() + for (pair in buckets) { + if (pair != null) pairSet.add(pair) + } + return pairSet + } + + /* 获取所有键 */ + fun keySet(): MutableList { + val keySet = ArrayList() + for (pair in buckets) { + if (pair != null) keySet.add(pair.key) + } + return keySet + } + + /* 获取所有值 */ + fun valueSet(): MutableList { + val valueSet = ArrayList() + for (pair in buckets) { + pair?.let { valueSet.add(it.value) } + } + return valueSet + } + + /* 打印哈希表 */ + fun print() { + for (kv in pairSet()) { + val key = kv.key + val value = kv.value + println("${key}->${value}") + } + } +} + +/* Driver Code */ +fun main() { + /* 初始化哈希表 */ + val map = ArrayHashMap() + + /* 添加操作 */ + // 在哈希表中添加键值对 (key, value) + map.put(12836, "小哈") + map.put(15937, "小啰") + map.put(16750, "小算") + map.put(13276, "小法") + map.put(10583, "小鸭") + println("\n添加完成后,哈希表为\nKey -> Value") + map.print() + + /* 查询操作 */ + // 向哈希表中输入键 key ,得到值 value + val name: String? = map.get(15937) + println("\n输入学号 15937 ,查询到姓名 $name") + + /* 删除操作 */ + // 在哈希表中删除键值对 (key, value) + map.remove(10583) + println("\n删除 10583 后,哈希表为\nKey -> Value") + map.print() + + /* 遍历哈希表 */ + println("\n遍历键值对 Key->Value") + for (kv in map.pairSet()) { + println("${kv.key} -> ${kv.value}") + } + println("\n单独遍历键 Key") + for (key in map.keySet()) { + println(key) + } + println("\n单独遍历值 Value") + for (value in map.valueSet()) { + println(value) + } +} diff --git a/codes/kotlin/chapter_hashing/built_in_hash.kt b/codes/kotlin/chapter_hashing/built_in_hash.kt new file mode 100644 index 000000000..948268800 --- /dev/null +++ b/codes/kotlin/chapter_hashing/built_in_hash.kt @@ -0,0 +1,36 @@ +/** + * File: built_in_hash.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_hashing + +import utils.ListNode + +/* Driver Code */ +fun main() { + val num = 3 + val hashNum = Integer.hashCode(num) + println("整数 $num 的哈希值为 $hashNum") + + val bol = true + val hashBol = Boolean.hashCode() + println("布尔量 $bol 的哈希值为 $hashBol") + + val dec = 3.14159 + val hashDec = java.lang.Double.hashCode(dec) + println("小数 $dec 的哈希值为 $hashDec") + + val str = "Hello 算法" + val hashStr = str.hashCode() + println("字符串 $str 的哈希值为 $hashStr") + + val arr = arrayOf(12836, "小哈") + val hashTup = arr.contentHashCode() + println("数组 ${arr.contentToString()} 的哈希值为 ${hashTup}") + + val obj = ListNode(0) + val hashObj = obj.hashCode() + println("节点对象 $obj 的哈希值为 $hashObj") +} \ No newline at end of file diff --git a/codes/kotlin/chapter_hashing/hash_map.kt b/codes/kotlin/chapter_hashing/hash_map.kt new file mode 100644 index 000000000..ffc468fee --- /dev/null +++ b/codes/kotlin/chapter_hashing/hash_map.kt @@ -0,0 +1,50 @@ +/** + * File: hash_map.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_hashing + +import utils.printHashMap + +/* Driver Code */ +fun main() { + /* 初始化哈希表 */ + val map: MutableMap = HashMap() + + /* 添加操作 */ + // 在哈希表中添加键值对 (key, value) + map[12836] = "小哈" + map[15937] = "小啰" + map[16750] = "小算" + map[13276] = "小法" + map[10583] = "小鸭" + println("\n添加完成后,哈希表为\nKey -> Value") + printHashMap(map) + + /* 查询操作 */ + // 向哈希表中输入键 key ,得到值 value + val name = map[15937] + println("\n输入学号 15937 ,查询到姓名 $name") + + /* 删除操作 */ + // 在哈希表中删除键值对 (key, value) + map.remove(10583) + println("\n删除 10583 后,哈希表为\nKey -> Value") + printHashMap(map) + + /* 遍历哈希表 */ + println("\n遍历键值对 Key->Value") + for ((key, value) in map) { + println("$key -> $value") + } + println("\n单独遍历键 Key") + for (key in map.keys) { + println(key) + } + println("\n单独遍历值 Value") + for (value in map.values) { + println(value) + } +} \ No newline at end of file diff --git a/codes/kotlin/chapter_hashing/hash_map_chaining.kt b/codes/kotlin/chapter_hashing/hash_map_chaining.kt new file mode 100644 index 000000000..205db6df5 --- /dev/null +++ b/codes/kotlin/chapter_hashing/hash_map_chaining.kt @@ -0,0 +1,145 @@ +/** + * File: hash_map_chaining.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_hashing + +/* 链式地址哈希表 */ +class HashMapChaining() { + var size: Int // 键值对数量 + var capacity: Int // 哈希表容量 + val loadThres: Double // 触发扩容的负载因子阈值 + val extendRatio: Int // 扩容倍数 + var buckets: MutableList> // 桶数组 + + /* 构造方法 */ + init { + size = 0 + capacity = 4 + loadThres = 2.0 / 3.0 + extendRatio = 2 + buckets = ArrayList(capacity) + for (i in 0.. loadThres) { + extend() + } + val index = hashFunc(key) + val bucket = buckets[index] + // 遍历桶,若遇到指定 key ,则更新对应 val 并返回 + for (pair in bucket) { + if (pair.key == key) { + pair.value = value + return + } + } + // 若无该 key ,则将键值对添加至尾部 + val pair = Pair(key, value) + bucket.add(pair) + size++ + } + + /* 删除操作 */ + fun remove(key: Int) { + val index = hashFunc(key) + val bucket = buckets[index] + // 遍历桶,从中删除键值对 + for (pair in bucket) { + if (pair.key == key) { + bucket.remove(pair) + size-- + break + } + } + } + + /* 扩容哈希表 */ + fun extend() { + // 暂存原哈希表 + val bucketsTmp = buckets + // 初始化扩容后的新哈希表 + capacity *= extendRatio + // mutablelist 无固定大小 + buckets = mutableListOf() + for (i in 0..() + for (pair in bucket) { + val k = pair.key + val v = pair.value + res.add("$k -> $v") + } + println(res) + } + } +} + +/* Driver Code */ +fun main() { + /* 初始化哈希表 */ + val map = HashMapChaining() + + /* 添加操作 */ + // 在哈希表中添加键值对 (key, value) + map.put(12836, "小哈") + map.put(15937, "小啰") + map.put(16750, "小算") + map.put(13276, "小法") + map.put(10583, "小鸭") + println("\n添加完成后,哈希表为\nKey -> Value") + map.print() + + /* 查询操作 */ + // 向哈希表中输入键 key ,得到值 value + val name = map.get(13276) + println("\n输入学号 13276 ,查询到姓名 $name") + + /* 删除操作 */ + // 在哈希表中删除键值对 (key, value) + map.remove(12836) + println("\n删除 12836 后,哈希表为\nKey -> Value") + map.print() +} diff --git a/codes/kotlin/chapter_hashing/hash_map_open_addressing.kt b/codes/kotlin/chapter_hashing/hash_map_open_addressing.kt new file mode 100644 index 000000000..58a3c2d76 --- /dev/null +++ b/codes/kotlin/chapter_hashing/hash_map_open_addressing.kt @@ -0,0 +1,156 @@ +/** + * File: hash_map_open_addressing.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_hashing + +/* 开放寻址哈希表 */ +class HashMapOpenAddressing { + private var size: Int = 0 // 键值对数量 + private var capacity = 4 // 哈希表容量 + private val loadThres: Double = 2.0 / 3.0 // 触发扩容的负载因子阈值 + private val extendRatio = 2 // 扩容倍数 + private var buckets: Array // 桶数组 + private val TOMBSTONE = Pair(-1, "-1") // 删除标记 + + /* 构造方法 */ + init { + buckets = arrayOfNulls(capacity) + } + + /* 哈希函数 */ + fun hashFunc(key: Int): Int { + return key % capacity + } + + /* 负载因子 */ + fun loadFactor(): Double { + return (size / capacity).toDouble() + } + + /* 搜索 key 对应的桶索引 */ + fun findBucket(key: Int): Int { + var index = hashFunc(key) + var firstTombstone = -1 + // 线性探测,当遇到空桶时跳出 + while (buckets[index] != null) { + // 若遇到 key ,返回对应的桶索引 + if (buckets[index]?.key == key) { + // 若之前遇到了删除标记,则将键值对移动至该索引处 + if (firstTombstone != -1) { + buckets[firstTombstone] = buckets[index] + buckets[index] = TOMBSTONE + return firstTombstone // 返回移动后的桶索引 + } + return index // 返回桶索引 + } + // 记录遇到的首个删除标记 + if (firstTombstone == -1 && buckets[index] == TOMBSTONE) { + firstTombstone = index + } + // 计算桶索引,越过尾部则返回头部 + index = (index + 1) % capacity + } + // 若 key 不存在,则返回添加点的索引 + return if (firstTombstone == -1) index else firstTombstone + } + + /* 查询操作 */ + fun get(key: Int): String? { + // 搜索 key 对应的桶索引 + val index = findBucket(key) + // 若找到键值对,则返回对应 val + if (buckets[index] != null && buckets[index] != TOMBSTONE) { + return buckets[index]?.value + } + // 若键值对不存在,则返回 null + return null + } + + /* 添加操作 */ + fun put(key: Int, value: String) { + // 当负载因子超过阈值时,执行扩容 + if (loadFactor() > loadThres) { + extend() + } + // 搜索 key 对应的桶索引 + val index = findBucket(key) + // 若找到键值对,则覆盖 val 并返回 + if (buckets[index] != null && buckets[index] != TOMBSTONE) { + buckets[index]!!.value = value + return + } + // 若键值对不存在,则添加该键值对 + buckets[index] = Pair(key, value) + size++ + } + + /* 删除操作 */ + fun remove(key: Int) { + // 搜索 key 对应的桶索引 + val index = findBucket(key) + // 若找到键值对,则用删除标记覆盖它 + if (buckets[index] != null && buckets[index] != TOMBSTONE) { + buckets[index] = TOMBSTONE + size-- + } + } + + /* 扩容哈希表 */ + fun extend() { + // 暂存原哈希表 + val bucketsTmp = buckets + // 初始化扩容后的新哈希表 + capacity *= extendRatio + buckets = arrayOfNulls(capacity) + size = 0 + // 将键值对从原哈希表搬运至新哈希表 + for (pair in bucketsTmp) { + if (pair != null && pair != TOMBSTONE) { + put(pair.key, pair.value) + } + } + } + + /* 打印哈希表 */ + fun print() { + for (pair in buckets) { + if (pair == null) { + println("null") + } else if (pair == TOMBSTONE) { + println("TOMESTOME") + } else { + println("${pair.key} -> ${pair.value}") + } + } + } +} + +/* Driver Code */ +fun main() { + // 初始化哈希表 + val hashmap = HashMapOpenAddressing() + + // 添加操作 + // 在哈希表中添加键值对 (key, val) + hashmap.put(12836, "小哈") + hashmap.put(15937, "小啰") + hashmap.put(16750, "小算") + hashmap.put(13276, "小法") + hashmap.put(10583, "小鸭") + println("\n添加完成后,哈希表为\nKey -> Value") + hashmap.print() + + // 查询操作 + // 向哈希表中输入键 key ,得到值 val + val name = hashmap.get(13276) + println("\n输入学号 13276 ,查询到姓名 $name") + + // 删除操作 + // 在哈希表中删除键值对 (key, val) + hashmap.remove(16750) + println("\n删除 16750 后,哈希表为\nKey -> Value") + hashmap.print() +} \ No newline at end of file diff --git a/codes/kotlin/chapter_hashing/simple_hash.kt b/codes/kotlin/chapter_hashing/simple_hash.kt new file mode 100644 index 000000000..a4353361b --- /dev/null +++ b/codes/kotlin/chapter_hashing/simple_hash.kt @@ -0,0 +1,62 @@ +/** + * File: simple_hash.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_hashing + +const val MODULUS = 10_0000_0007 + +/* 加法哈希 */ +fun addHash(key: String): Int { + var hash = 0L + for (c in key.toCharArray()) { + hash = (hash + c.code) % MODULUS + } + return hash.toInt() +} + +/* 乘法哈希 */ +fun mulHash(key: String): Int { + var hash = 0L + for (c in key.toCharArray()) { + hash = (31 * hash + c.code) % MODULUS + } + return hash.toInt() +} + +/* 异或哈希 */ +fun xorHash(key: String): Int { + var hash = 0 + for (c in key.toCharArray()) { + hash = hash xor c.code + } + return hash and MODULUS +} + +/* 旋转哈希 */ +fun rotHash(key: String): Int { + var hash = 0L + for (c in key.toCharArray()) { + hash = ((hash shl 4) xor (hash shr 28) xor c.code.toLong()) % MODULUS + } + return hash.toInt() +} + +/* Driver Code */ +fun main() { + val key = "Hello 算法" + + var hash: Int = addHash(key) + println("加法哈希值为 $hash") + + hash = mulHash(key) + println("乘法哈希值为 $hash") + + hash = xorHash(key) + println("异或哈希值为 $hash") + + hash = rotHash(key) + println("旋转哈希值为 $hash") +} \ No newline at end of file