-
Notifications
You must be signed in to change notification settings - Fork 13.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add JavaScript and TypeScript code of bucket sort, counting sort and …
…radix sort (Chapter of Sorting) (#451) * Add JavaScript and TypeScript code of bucket sort (Chapter of Sorting) * Add JavaScript and TypeScript code of counting sort (Chapter of Sorting) * Add JavaScript and TypeScript code of radix sort (Chapter of Sorting)
- Loading branch information
1 parent
3872f94
commit 56243cc
Showing
6 changed files
with
354 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/** | ||
* File: bucket_sort.js | ||
* Created Time: 2023-04-08 | ||
* Author: Justin (xiefahit@gmail.com) | ||
*/ | ||
|
||
/* 桶排序 */ | ||
function bucketSort(nums) { | ||
// 初始化 k = n/2 个桶,预期向每个桶分配 2 个元素 | ||
const k = nums.length / 2; | ||
const buckets = []; | ||
for (let i = 0; i < k; i++) { | ||
buckets.push([]); | ||
} | ||
// 1. 将数组元素分配到各个桶中 | ||
for (const num of nums) { | ||
// 输入数据范围 [0, 1),使用 num * k 映射到索引范围 [0, k-1] | ||
const i = Math.floor(num * k); | ||
// 将 num 添加进桶 i | ||
buckets[i].push(num); | ||
} | ||
// 2. 对各个桶执行排序 | ||
for (const bucket of buckets) { | ||
// 使用内置排序函数,也可以替换成其它排序算法 | ||
bucket.sort((a, b) => a - b); | ||
} | ||
// 3. 遍历桶合并结果 | ||
let i = 0; | ||
for (const bucket of buckets) { | ||
for (const num of bucket) { | ||
nums[i++] = num; | ||
} | ||
} | ||
} | ||
|
||
/* Driver Code */ | ||
const nums = [0.49, 0.96, 0.82, 0.09, 0.57, 0.43, 0.91, 0.75, 0.15, 0.37]; | ||
bucketSort(nums); | ||
console.log('桶排序完成后 nums =', nums); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/** | ||
* File: coutning_sort.js | ||
* Created Time: 2023-04-08 | ||
* Author: Justin (xiefahit@gmail.com) | ||
*/ | ||
|
||
/* 计数排序 */ | ||
// 简单实现,无法用于排序对象 | ||
function countingSortNaive(nums) { | ||
// 1. 统计数组最大元素 m | ||
let m = 0; | ||
for (const num of nums) { | ||
m = Math.max(m, num); | ||
} | ||
// 2. 统计各数字的出现次数 | ||
// counter[num] 代表 num 的出现次数 | ||
const counter = new Array(m + 1).fill(0); | ||
for (const num of nums) { | ||
counter[num]++; | ||
} | ||
// 3. 遍历 counter ,将各元素填入原数组 nums | ||
let i = 0; | ||
for (let num = 0; num < m + 1; num++) { | ||
for (let j = 0; j < counter[num]; j++, i++) { | ||
nums[i] = num; | ||
} | ||
} | ||
} | ||
|
||
/* 计数排序 */ | ||
// 完整实现,可排序对象,并且是稳定排序 | ||
function countingSort(nums) { | ||
// 1. 统计数组最大元素 m | ||
let m = 0; | ||
for (const num of nums) { | ||
m = Math.max(m, num); | ||
} | ||
// 2. 统计各数字的出现次数 | ||
// counter[num] 代表 num 的出现次数 | ||
const counter = new Array(m + 1).fill(0); | ||
for (const num of nums) { | ||
counter[num]++; | ||
} | ||
// 3. 求 counter 的前缀和,将“出现次数”转换为“尾索引” | ||
// 即 counter[num]-1 是 num 在 res 中最后一次出现的索引 | ||
for (let i = 0; i < m; i++) { | ||
counter[i + 1] += counter[i]; | ||
} | ||
// 4. 倒序遍历 nums ,将各元素填入结果数组 res | ||
// 初始化数组 res 用于记录结果 | ||
const n = nums.length; | ||
const res = new Array(n); | ||
for (let i = n - 1; i >= 0; i--) { | ||
const num = nums[i]; | ||
res[counter[num] - 1] = num; // 将 num 放置到对应索引处 | ||
counter[num]--; // 令前缀和自减 1 ,得到下次放置 num 的索引 | ||
} | ||
// 使用结果数组 res 覆盖原数组 nums | ||
for (let i = 0; i < n; i++) { | ||
nums[i] = res[i]; | ||
} | ||
} | ||
|
||
/* Driver Code */ | ||
const nums = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4]; | ||
countingSortNaive(nums); | ||
console.log('计数排序(无法排序对象)完成后 nums =', nums); | ||
|
||
const nums1 = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4]; | ||
countingSort(nums1); | ||
console.log('计数排序完成后 nums1 =', nums1); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/** | ||
* File: radix_sort.js | ||
* Created Time: 2023-04-08 | ||
* Author: Justin (xiefahit@gmail.com) | ||
*/ | ||
|
||
/* 获取元素 num 的第 k 位,其中 exp = 10^(k-1) */ | ||
function digit(num, exp) { | ||
// 传入 exp 而非 k 可以避免在此重复执行昂贵的次方计算 | ||
return Math.floor(num / exp) % 10; | ||
} | ||
|
||
/* 计数排序(根据 nums 第 k 位排序) */ | ||
function countingSortDigit(nums, exp) { | ||
// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶 | ||
const counter = new Array(10).fill(0); | ||
const n = nums.length; | ||
// 统计 0~9 各数字的出现次数 | ||
for (let i = 0; i < n; i++) { | ||
const d = digit(nums[i], exp); // 获取 nums[i] 第 k 位,记为 d | ||
counter[d]++; // 统计数字 d 的出现次数 | ||
} | ||
// 求前缀和,将“出现个数”转换为“数组索引” | ||
for (let i = 1; i < 10; i++) { | ||
counter[i] += counter[i - 1]; | ||
} | ||
// 倒序遍历,根据桶内统计结果,将各元素填入 res | ||
const res = new Array(n).fill(0); | ||
for (let i = n - 1; i >= 0; i--) { | ||
const d = digit(nums[i], exp); | ||
const j = counter[d] - 1; // 获取 d 在数组中的索引 j | ||
res[j] = nums[i]; // 将当前元素填入索引 j | ||
counter[d]--; // 将 d 的数量减 1 | ||
} | ||
// 使用结果覆盖原数组 nums | ||
for (let i = 0; i < n; i++) { | ||
nums[i] = res[i]; | ||
} | ||
} | ||
|
||
/* 基数排序 */ | ||
function radixSort(nums) { | ||
// 获取数组的最大元素,用于判断最大位数 | ||
let m = Number.MIN_VALUE; | ||
for (const num of nums) { | ||
if (num > m) { | ||
m = num; | ||
} | ||
} | ||
// 按照从低位到高位的顺序遍历 | ||
for (let exp = 1; exp <= m; exp *= 10) { | ||
// 对数组元素的第 k 位执行计数排序 | ||
// k = 1 -> exp = 1 | ||
// k = 2 -> exp = 10 | ||
// 即 exp = 10^(k-1) | ||
countingSortDigit(nums, exp); | ||
} | ||
} | ||
|
||
/* Driver Code */ | ||
const nums = [10546151, 35663510, 42865989, 34862445, 81883077, | ||
88906420, 72429244, 30524779, 82060337, 63832996]; | ||
radixSort(nums); | ||
console.log('基数排序完成后 nums =', nums); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/** | ||
* File: bucket_sort.ts | ||
* Created Time: 2023-04-08 | ||
* Author: Justin (xiefahit@gmail.com) | ||
*/ | ||
|
||
/* 桶排序 */ | ||
function bucketSort(nums: number[]): void { | ||
// 初始化 k = n/2 个桶,预期向每个桶分配 2 个元素 | ||
const k = nums.length / 2; | ||
const buckets: number[][] = []; | ||
for (let i = 0; i < k; i++) { | ||
buckets.push([]); | ||
} | ||
// 1. 将数组元素分配到各个桶中 | ||
for (const num of nums) { | ||
// 输入数据范围 [0, 1),使用 num * k 映射到索引范围 [0, k-1] | ||
const i = Math.floor(num * k); | ||
// 将 num 添加进桶 i | ||
buckets[i].push(num); | ||
} | ||
// 2. 对各个桶执行排序 | ||
for (const bucket of buckets) { | ||
// 使用内置排序函数,也可以替换成其它排序算法 | ||
bucket.sort((a, b) => a - b); | ||
} | ||
// 3. 遍历桶合并结果 | ||
let i = 0; | ||
for (const bucket of buckets) { | ||
for (const num of bucket) { | ||
nums[i++] = num; | ||
} | ||
} | ||
} | ||
|
||
/* Driver Code */ | ||
const nums = [0.49, 0.96, 0.82, 0.09, 0.57, 0.43, 0.91, 0.75, 0.15, 0.37]; | ||
bucketSort(nums); | ||
console.log('桶排序完成后 nums =', nums); | ||
|
||
export {}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/** | ||
* File: coutning_sort.ts | ||
* Created Time: 2023-04-08 | ||
* Author: Justin (xiefahit@gmail.com) | ||
*/ | ||
|
||
/* 计数排序 */ | ||
// 简单实现,无法用于排序对象 | ||
function countingSortNaive(nums: number[]): void { | ||
// 1. 统计数组最大元素 m | ||
let m = 0; | ||
for (const num of nums) { | ||
m = Math.max(m, num); | ||
} | ||
// 2. 统计各数字的出现次数 | ||
// counter[num] 代表 num 的出现次数 | ||
const counter: number[] = new Array<number>(m + 1).fill(0); | ||
for (const num of nums) { | ||
counter[num]++; | ||
} | ||
// 3. 遍历 counter ,将各元素填入原数组 nums | ||
let i = 0; | ||
for (let num = 0; num < m + 1; num++) { | ||
for (let j = 0; j < counter[num]; j++, i++) { | ||
nums[i] = num; | ||
} | ||
} | ||
} | ||
|
||
/* 计数排序 */ | ||
// 完整实现,可排序对象,并且是稳定排序 | ||
function countingSort(nums: number[]): void { | ||
// 1. 统计数组最大元素 m | ||
let m = 0; | ||
for (const num of nums) { | ||
m = Math.max(m, num); | ||
} | ||
// 2. 统计各数字的出现次数 | ||
// counter[num] 代表 num 的出现次数 | ||
const counter: number[] = new Array<number>(m + 1).fill(0); | ||
for (const num of nums) { | ||
counter[num]++; | ||
} | ||
// 3. 求 counter 的前缀和,将“出现次数”转换为“尾索引” | ||
// 即 counter[num]-1 是 num 在 res 中最后一次出现的索引 | ||
for (let i = 0; i < m; i++) { | ||
counter[i + 1] += counter[i]; | ||
} | ||
// 4. 倒序遍历 nums ,将各元素填入结果数组 res | ||
// 初始化数组 res 用于记录结果 | ||
const n = nums.length; | ||
const res: number[] = new Array<number>(n); | ||
for (let i = n - 1; i >= 0; i--) { | ||
const num = nums[i]; | ||
res[counter[num] - 1] = num; // 将 num 放置到对应索引处 | ||
counter[num]--; // 令前缀和自减 1 ,得到下次放置 num 的索引 | ||
} | ||
// 使用结果数组 res 覆盖原数组 nums | ||
for (let i = 0; i < n; i++) { | ||
nums[i] = res[i]; | ||
} | ||
} | ||
|
||
/* Driver Code */ | ||
const nums = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4]; | ||
countingSortNaive(nums); | ||
console.log('计数排序(无法排序对象)完成后 nums =', nums); | ||
|
||
const nums1 = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4]; | ||
countingSort(nums1); | ||
console.log('计数排序完成后 nums1 =', nums1); | ||
|
||
export {}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/** | ||
* File: radix_sort.ts | ||
* Created Time: 2023-04-08 | ||
* Author: Justin (xiefahit@gmail.com) | ||
*/ | ||
|
||
/* 获取元素 num 的第 k 位,其中 exp = 10^(k-1) */ | ||
function digit(num: number, exp: number): number { | ||
// 传入 exp 而非 k 可以避免在此重复执行昂贵的次方计算 | ||
return Math.floor(num / exp) % 10; | ||
} | ||
|
||
/* 计数排序(根据 nums 第 k 位排序) */ | ||
function countingSortDigit(nums: number[], exp: number): void { | ||
// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶 | ||
const counter = new Array(10).fill(0); | ||
const n = nums.length; | ||
// 统计 0~9 各数字的出现次数 | ||
for (let i = 0; i < n; i++) { | ||
const d = digit(nums[i], exp); // 获取 nums[i] 第 k 位,记为 d | ||
counter[d]++; // 统计数字 d 的出现次数 | ||
} | ||
// 求前缀和,将“出现个数”转换为“数组索引” | ||
for (let i = 1; i < 10; i++) { | ||
counter[i] += counter[i - 1]; | ||
} | ||
// 倒序遍历,根据桶内统计结果,将各元素填入 res | ||
const res = new Array(n).fill(0); | ||
for (let i = n - 1; i >= 0; i--) { | ||
const d = digit(nums[i], exp); | ||
const j = counter[d] - 1; // 获取 d 在数组中的索引 j | ||
res[j] = nums[i]; // 将当前元素填入索引 j | ||
counter[d]--; // 将 d 的数量减 1 | ||
} | ||
// 使用结果覆盖原数组 nums | ||
for (let i = 0; i < n; i++) { | ||
nums[i] = res[i]; | ||
} | ||
} | ||
|
||
/* 基数排序 */ | ||
function radixSort(nums: number[]): void { | ||
// 获取数组的最大元素,用于判断最大位数 | ||
let m = Number.MIN_VALUE; | ||
for (const num of nums) { | ||
if (num > m) { | ||
m = num; | ||
} | ||
} | ||
// 按照从低位到高位的顺序遍历 | ||
for (let exp = 1; exp <= m; exp *= 10) { | ||
// 对数组元素的第 k 位执行计数排序 | ||
// k = 1 -> exp = 1 | ||
// k = 2 -> exp = 10 | ||
// 即 exp = 10^(k-1) | ||
countingSortDigit(nums, exp); | ||
} | ||
} | ||
|
||
/* Driver Code */ | ||
const nums = [10546151, 35663510, 42865989, 34862445, 81883077, | ||
88906420, 72429244, 30524779, 82060337, 63832996]; | ||
radixSort(nums); | ||
console.log('基数排序完成后 nums =', nums); | ||
|
||
export {}; |