diff --git a/docs/chapter_hashing/hash_map.md b/docs/chapter_hashing/hash_map.md index e65eeefce..7167dd21f 100755 --- a/docs/chapter_hashing/hash_map.md +++ b/docs/chapter_hashing/hash_map.md @@ -1458,18 +1458,21 @@ index = hash(key) % capacity /* 基于数组实现的哈希表 */ typedef struct { - Pair *buckets[HASHTABLE_CAPACITY]; + Pair *buckets[MAX_SIZE]; } ArrayHashMap; /* 构造函数 */ ArrayHashMap *newArrayHashMap() { ArrayHashMap *hmap = malloc(sizeof(ArrayHashMap)); + for (int i=0; i < MAX_SIZE; i++) { + hmap->buckets[i] = NULL; + } return hmap; } /* 析构函数 */ void delArrayHashMap(ArrayHashMap *hmap) { - for (int i = 0; i < HASHTABLE_CAPACITY; i++) { + for (int i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { free(hmap->buckets[i]->val); free(hmap->buckets[i]); @@ -1503,13 +1506,13 @@ index = hash(key) % capacity int i = 0, index = 0; int total = 0; /* 统计有效键值对数量 */ - for (i = 0; i < HASHTABLE_CAPACITY; i++) { + for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { total++; } } entries = malloc(sizeof(Pair) * total); - for (i = 0; i < HASHTABLE_CAPACITY; i++) { + for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { entries[index].key = hmap->buckets[i]->key; entries[index].val = malloc(strlen(hmap->buckets[i]->val) + 1); @@ -1527,13 +1530,13 @@ index = hash(key) % capacity int i = 0, index = 0; int total = 0; /* 统计有效键值对数量 */ - for (i = 0; i < HASHTABLE_CAPACITY; i++) { + for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { total++; } } keys = malloc(total * sizeof(int)); - for (i = 0; i < HASHTABLE_CAPACITY; i++) { + for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { keys[index] = hmap->buckets[i]->key; index++; @@ -1549,13 +1552,13 @@ index = hash(key) % capacity int i = 0, index = 0; int total = 0; /* 统计有效键值对数量 */ - for (i = 0; i < HASHTABLE_CAPACITY; i++) { + for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { total++; } } vals = malloc(total * sizeof(char *)); - for (i = 0; i < HASHTABLE_CAPACITY; i++) { + for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { vals[index] = hmap->buckets[i]->val; index++; diff --git a/docs/chapter_searching/binary_search.md b/docs/chapter_searching/binary_search.md index be5d33fad..ed755432b 100755 --- a/docs/chapter_searching/binary_search.md +++ b/docs/chapter_searching/binary_search.md @@ -339,7 +339,27 @@ comments: true === "Ruby" ```ruby title="binary_search.rb" - [class]{}-[func]{binary_search} + ### 二分查找(双闭区间) ### + def binary_search(nums, target) + # 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素 + i, j = 0, nums.length - 1 + + # 循环,当搜索区间为空时跳出(当 i > j 时为空) + while i <= j + # 理论上 Ruby 的数字可以无限大(取决于内存大小),无须考虑大数越界问题 + m = (i + j) / 2 # 计算中点索引 m + + if nums[m] < target + i = m + 1 # 此情况说明 target 在区间 [m+1, j] 中 + elsif nums[m] > target + j = m - 1 # 此情况说明 target 在区间 [i, m-1] 中 + else + return m # 找到目标元素,返回其索引 + end + end + + -1 # 未找到目标元素,返回 -1 + end ``` === "Zig" @@ -667,7 +687,27 @@ comments: true === "Ruby" ```ruby title="binary_search.rb" - [class]{}-[func]{binary_search_lcro} + ### 二分查找(左闭右开区间) ### + def binary_search_lcro(nums, target) + # 初始化左闭右开区间 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1 + i, j = 0, nums.length + + # 循环,当搜索区间为空时跳出(当 i = j 时为空) + while i < j + # 计算中点索引 m + m = (i + j) / 2 + + if nums[m] < target + i = m + 1 # 此情况说明 target 在区间 [m+1, j) 中 + elsif nums[m] > target + j = m - 1 # 此情况说明 target 在区间 [i, m) 中 + else + return m # 找到目标元素,返回其索引 + end + end + + -1 # 未找到目标元素,返回 -1 + end ``` === "Zig" diff --git a/docs/chapter_searching/binary_search_edge.md b/docs/chapter_searching/binary_search_edge.md index 8cd9c96c5..7213e300a 100644 --- a/docs/chapter_searching/binary_search_edge.md +++ b/docs/chapter_searching/binary_search_edge.md @@ -212,7 +212,16 @@ comments: true === "Ruby" ```ruby title="binary_search_edge.rb" - [class]{}-[func]{binary_search_left_edge} + ### 二分查找最左一个 target ### + def binary_search_left_edge(nums, target) + # 等价于查找 target 的插入点 + i = binary_search_insertion(nums, target) + + # 未找到 target ,返回 -1 + return -1 if i == nums.length || nums[i] != target + + i # 找到 target ,返回索引 i + end ``` === "Zig" @@ -461,7 +470,19 @@ comments: true === "Ruby" ```ruby title="binary_search_edge.rb" - [class]{}-[func]{binary_search_right_edge} + ### 二分查找最右一个 target ### + def binary_search_right_edge(nums, target) + # 转化为查找最左一个 target + 1 + i = binary_search_insertion(nums, target + 1) + + # j 指向最右一个 target ,i 指向首个大于 target 的元素 + j = i - 1 + + # 未找到 target ,返回 -1 + return -1 if j == -1 || nums[j] != target + + j # 找到 target ,返回索引 j + end ``` === "Zig" diff --git a/docs/chapter_searching/binary_search_insertion.md b/docs/chapter_searching/binary_search_insertion.md index 0d14a0eec..e8f466343 100644 --- a/docs/chapter_searching/binary_search_insertion.md +++ b/docs/chapter_searching/binary_search_insertion.md @@ -293,7 +293,26 @@ comments: true === "Ruby" ```ruby title="binary_search_insertion.rb" - [class]{}-[func]{binary_search_insertion_simple} + ### 二分查找插入点(无重复元素) ### + def binary_search_insertion_simple(nums, target) + # 初始化双闭区间 [0, n-1] + i, j = 0, nums.length - 1 + + while i <= j + # 计算中点索引 m + m = (i + j) / 2 + + if nums[m] < target + i = m + 1 # target 在区间 [m+1, j] 中 + elsif nums[m] > target + j = m - 1 # target 在区间 [i, m-1] 中 + else + return m # 找到 target ,返回插入点 m + end + end + + i # 未找到 target ,返回插入点 i + end ``` === "Zig" @@ -625,7 +644,26 @@ comments: true === "Ruby" ```ruby title="binary_search_insertion.rb" - [class]{}-[func]{binary_search_insertion} + ### 二分查找插入点(存在重复元素) ### + def binary_search_insertion(nums, target) + # 初始化双闭区间 [0, n-1] + i, j = 0, nums.length - 1 + + while i <= j + # 计算中点索引 m + m = (i + j) / 2 + + if nums[m] < target + i = m + 1 # target 在区间 [m+1, j] 中 + elsif nums[m] > target + j = m - 1 # target 在区间 [i, m-1] 中 + else + j = m - 1 # 首个小于 target 的元素在区间 [i, m-1] 中 + end + end + + i # 返回插入点 i + end ``` === "Zig" diff --git a/docs/chapter_searching/replace_linear_by_hashing.md b/docs/chapter_searching/replace_linear_by_hashing.md index a06d95962..3db51f347 100755 --- a/docs/chapter_searching/replace_linear_by_hashing.md +++ b/docs/chapter_searching/replace_linear_by_hashing.md @@ -228,7 +228,17 @@ comments: true === "Ruby" ```ruby title="two_sum.rb" - [class]{}-[func]{two_sum_brute_force} + ### 方法一:暴力枚举 ### + def two_sum_brute_force(nums, target) + # 两层循环,时间复杂度为 O(n^2) + for i in 0...(nums.length - 1) + for j in (i + 1)...nums.length + return [i, j] if nums[i] + nums[j] == target + end + end + + [] + end ``` === "Zig" @@ -531,7 +541,19 @@ comments: true === "Ruby" ```ruby title="two_sum.rb" - [class]{}-[func]{two_sum_hash_table} + ### 方法二:辅助哈希表 ### + def two_sum_hash_table(nums, target) + # 辅助哈希表,空间复杂度为 O(n) + dic = {} + # 单层循环,时间复杂度为 O(n) + for i in 0...nums.length + return [dic[target - nums[i]], i] if dic.has_key?(target - nums[i]) + + dic[nums[i]] = i + end + + [] + end ``` === "Zig" diff --git a/docs/chapter_sorting/bucket_sort.md b/docs/chapter_sorting/bucket_sort.md index fa030145b..4a9270947 100644 --- a/docs/chapter_sorting/bucket_sort.md +++ b/docs/chapter_sorting/bucket_sort.md @@ -340,51 +340,37 @@ comments: true ```c title="bucket_sort.c" /* 桶排序 */ - void bucketSort(float nums[], int size) { - // 初始化 k = n/2 个桶,预期向每个桶分配 2 个元素 - int k = size / 2; - float **buckets = calloc(k, sizeof(float *)); - for (int i = 0; i < k; i++) { - // 每个桶最多可以分配 size 个元素 - buckets[i] = calloc(size, sizeof(float)); + void bucketSort(float nums[], int n) { + int k = n / 2; // 初始化 k = n/2 个桶 + int *sizes = malloc(k * sizeof(int)); // 记录每个桶的大小 + float **buckets = malloc(k * sizeof(float *)); // 动态数组的数组(桶) + + for (int i = 0; i < k; ++i) { + // 为每个桶预分配足够的空间 + buckets[i] = (float *)malloc(n * sizeof(float)); + sizes[i] = 0; } // 1. 将数组元素分配到各个桶中 - for (int i = 0; i < size; i++) { - // 输入数据范围为 [0, 1),使用 num * k 映射到索引范围 [0, k-1] - int bucket_idx = nums[i] * k; - int j = 0; - // 如果桶中有数据且数据小于当前值 nums[i], 要将其放到当前桶的后面,相当于 cpp 中的 push_back - while (buckets[bucket_idx][j] > 0 && buckets[bucket_idx][j] < nums[i]) { - j++; - } - float temp = nums[i]; - while (j < size && buckets[bucket_idx][j] > 0) { - swap(&temp, &buckets[bucket_idx][j]); - j++; - } - buckets[bucket_idx][j] = temp; + for (int i = 0; i < n; ++i) { + int idx = (int)(nums[i] * k); + buckets[idx][sizes[idx]++] = nums[i]; } // 2. 对各个桶执行排序 - for (int i = 0; i < k; i++) { - qsort(buckets[i], size, sizeof(float), compare_float); + for (int i = 0; i < k; ++i) { + qsort(buckets[i], sizes[i], sizeof(float), compare); } - // 3. 遍历桶合并结果 - for (int i = 0, j = 0; j < k; j++) { - for (int l = 0; l < size; l++) { - if (buckets[j][l] > 0) { - nums[i++] = buckets[j][l]; - } + // 3. 合并排序后的桶 + int idx = 0; + for (int i = 0; i < k; ++i) { + for (int j = 0; j < sizes[i]; ++j) { + nums[idx++] = buckets[i][j]; } - } - - // 释放上述分配的内存 - for (int i = 0; i < k; i++) { + // 释放内存 free(buckets[i]); } - free(buckets); } ``` diff --git a/docs/chapter_sorting/insertion_sort.md b/docs/chapter_sorting/insertion_sort.md index 40ed3d4ed..1dee1b995 100755 --- a/docs/chapter_sorting/insertion_sort.md +++ b/docs/chapter_sorting/insertion_sort.md @@ -253,7 +253,21 @@ comments: true === "Ruby" ```ruby title="insertion_sort.rb" - [class]{}-[func]{insertion_sort} + ### 插入排序 ### + def insertion_sort(nums) + n = nums.length + # 外循环:已排序区间为 [0, i-1] + for i in 1...n + base = nums[i] + j = i - 1 + # 内循环:将 base 插入到已排序区间 [0, i-1] 中的正确位置 + while j >= 0 && nums[j] > base + nums[j + 1] = nums[j] # 将 nums[j] 向右移动一位 + j -= 1 + end + nums[j + 1] = base # 将 base 赋值到正确位置 + end + end ``` === "Zig" diff --git a/en/docs/chapter_hashing/hash_map.md b/en/docs/chapter_hashing/hash_map.md index 922eb15c2..0937369d7 100755 --- a/en/docs/chapter_hashing/hash_map.md +++ b/en/docs/chapter_hashing/hash_map.md @@ -1417,18 +1417,21 @@ The following code implements a simple hash table. Here, we encapsulate `key` an /* 基于数组实现的哈希表 */ typedef struct { - Pair *buckets[HASHTABLE_CAPACITY]; + Pair *buckets[MAX_SIZE]; } ArrayHashMap; /* 构造函数 */ ArrayHashMap *newArrayHashMap() { ArrayHashMap *hmap = malloc(sizeof(ArrayHashMap)); + for (int i=0; i < MAX_SIZE; i++) { + hmap->buckets[i] = NULL; + } return hmap; } /* 析构函数 */ void delArrayHashMap(ArrayHashMap *hmap) { - for (int i = 0; i < HASHTABLE_CAPACITY; i++) { + for (int i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { free(hmap->buckets[i]->val); free(hmap->buckets[i]); @@ -1462,13 +1465,13 @@ The following code implements a simple hash table. Here, we encapsulate `key` an int i = 0, index = 0; int total = 0; /* 统计有效键值对数量 */ - for (i = 0; i < HASHTABLE_CAPACITY; i++) { + for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { total++; } } entries = malloc(sizeof(Pair) * total); - for (i = 0; i < HASHTABLE_CAPACITY; i++) { + for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { entries[index].key = hmap->buckets[i]->key; entries[index].val = malloc(strlen(hmap->buckets[i]->val) + 1); @@ -1486,13 +1489,13 @@ The following code implements a simple hash table. Here, we encapsulate `key` an int i = 0, index = 0; int total = 0; /* 统计有效键值对数量 */ - for (i = 0; i < HASHTABLE_CAPACITY; i++) { + for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { total++; } } keys = malloc(total * sizeof(int)); - for (i = 0; i < HASHTABLE_CAPACITY; i++) { + for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { keys[index] = hmap->buckets[i]->key; index++; @@ -1508,13 +1511,13 @@ The following code implements a simple hash table. Here, we encapsulate `key` an int i = 0, index = 0; int total = 0; /* 统计有效键值对数量 */ - for (i = 0; i < HASHTABLE_CAPACITY; i++) { + for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { total++; } } vals = malloc(total * sizeof(char *)); - for (i = 0; i < HASHTABLE_CAPACITY; i++) { + for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { vals[index] = hmap->buckets[i]->val; index++; diff --git a/zh-Hant/docs/chapter_hashing/hash_map.md b/zh-Hant/docs/chapter_hashing/hash_map.md index 77c69317f..9c7aea2d1 100755 --- a/zh-Hant/docs/chapter_hashing/hash_map.md +++ b/zh-Hant/docs/chapter_hashing/hash_map.md @@ -1458,18 +1458,21 @@ index = hash(key) % capacity /* 基於陣列實現的雜湊表 */ typedef struct { - Pair *buckets[HASHTABLE_CAPACITY]; + Pair *buckets[MAX_SIZE]; } ArrayHashMap; /* 建構子 */ ArrayHashMap *newArrayHashMap() { ArrayHashMap *hmap = malloc(sizeof(ArrayHashMap)); + for (int i = 0; i < MAX_SIZE; i++) { + hmap->buckets[i] = NULL; + } return hmap; } /* 析構函式 */ void delArrayHashMap(ArrayHashMap *hmap) { - for (int i = 0; i < HASHTABLE_CAPACITY; i++) { + for (int i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { free(hmap->buckets[i]->val); free(hmap->buckets[i]); @@ -1503,13 +1506,13 @@ index = hash(key) % capacity int i = 0, index = 0; int total = 0; /* 統計有效鍵值對數量 */ - for (i = 0; i < HASHTABLE_CAPACITY; i++) { + for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { total++; } } entries = malloc(sizeof(Pair) * total); - for (i = 0; i < HASHTABLE_CAPACITY; i++) { + for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { entries[index].key = hmap->buckets[i]->key; entries[index].val = malloc(strlen(hmap->buckets[i]->val) + 1); @@ -1527,13 +1530,13 @@ index = hash(key) % capacity int i = 0, index = 0; int total = 0; /* 統計有效鍵值對數量 */ - for (i = 0; i < HASHTABLE_CAPACITY; i++) { + for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { total++; } } keys = malloc(total * sizeof(int)); - for (i = 0; i < HASHTABLE_CAPACITY; i++) { + for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { keys[index] = hmap->buckets[i]->key; index++; @@ -1549,13 +1552,13 @@ index = hash(key) % capacity int i = 0, index = 0; int total = 0; /* 統計有效鍵值對數量 */ - for (i = 0; i < HASHTABLE_CAPACITY; i++) { + for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { total++; } } vals = malloc(total * sizeof(char *)); - for (i = 0; i < HASHTABLE_CAPACITY; i++) { + for (i = 0; i < MAX_SIZE; i++) { if (hmap->buckets[i] != NULL) { vals[index] = hmap->buckets[i]->val; index++; diff --git a/zh-Hant/docs/chapter_sorting/bucket_sort.md b/zh-Hant/docs/chapter_sorting/bucket_sort.md index bd49cc67f..d7c4eea25 100644 --- a/zh-Hant/docs/chapter_sorting/bucket_sort.md +++ b/zh-Hant/docs/chapter_sorting/bucket_sort.md @@ -340,51 +340,37 @@ comments: true ```c title="bucket_sort.c" /* 桶排序 */ - void bucketSort(float nums[], int size) { - // 初始化 k = n/2 個桶,預期向每個桶分配 2 個元素 - int k = size / 2; - float **buckets = calloc(k, sizeof(float *)); - for (int i = 0; i < k; i++) { - // 每個桶最多可以分配 size 個元素 - buckets[i] = calloc(size, sizeof(float)); + void bucketSort(float nums[], int n) { + int k = n / 2; // 初始化 k = n/2 個桶 + int *sizes = malloc(k * sizeof(int)); // 記錄每個桶的大小 + float **buckets = malloc(k * sizeof(float *)); // 動態陣列的陣列(桶) + + for (int i = 0; i < k; ++i) { + // 為每個桶預分配足夠的空間 + buckets[i] = (float *)malloc(n * sizeof(float)); + sizes[i] = 0; } // 1. 將陣列元素分配到各個桶中 - for (int i = 0; i < size; i++) { - // 輸入資料範圍為 [0, 1),使用 num * k 對映到索引範圍 [0, k-1] - int bucket_idx = nums[i] * k; - int j = 0; - // 如果桶中有資料且資料小於當前值 nums[i], 要將其放到當前桶的後面,相當於 cpp 中的 push_back - while (buckets[bucket_idx][j] > 0 && buckets[bucket_idx][j] < nums[i]) { - j++; - } - float temp = nums[i]; - while (j < size && buckets[bucket_idx][j] > 0) { - swap(&temp, &buckets[bucket_idx][j]); - j++; - } - buckets[bucket_idx][j] = temp; + for (int i = 0; i < n; ++i) { + int idx = (int)(nums[i] * k); + buckets[idx][sizes[idx]++] = nums[i]; } // 2. 對各個桶執行排序 - for (int i = 0; i < k; i++) { - qsort(buckets[i], size, sizeof(float), compare_float); + for (int i = 0; i < k; ++i) { + qsort(buckets[i], sizes[i], sizeof(float), compare); } - // 3. 走訪桶合併結果 - for (int i = 0, j = 0; j < k; j++) { - for (int l = 0; l < size; l++) { - if (buckets[j][l] > 0) { - nums[i++] = buckets[j][l]; - } + // 3. 合併排序後的桶 + int idx = 0; + for (int i = 0; i < k; ++i) { + for (int j = 0; j < sizes[i]; ++j) { + nums[idx++] = buckets[i][j]; } - } - - // 釋放上述分配的記憶體 - for (int i = 0; i < k; i++) { + // 釋放記憶體 free(buckets[i]); } - free(buckets); } ```