Skip to content

Commit de13b81

Browse files
committed
add bucket sort and binary search
1 parent e714cc2 commit de13b81

File tree

5 files changed

+195
-12
lines changed

5 files changed

+195
-12
lines changed

typescript/12_sorts/MergeSort.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* 归并排序
3+
* 稳定排序,稳定的O(nlgn)时间复杂度
4+
* O(n)的空间复杂度
5+
* 在小规模数据排序中很常用
6+
*/
7+
class MergeSort {
8+
public static mergeSort(array: number[]) {
9+
if (!array || !array.length) return
10+
const length = array.length
11+
this.mergeSortInternally(array, 0, length - 1)
12+
}
13+
14+
static mergeSortInternally(array: number[], p: number, r: number) {
15+
if (p >= r) return
16+
// 严格按照中间值作切分点
17+
// js中除法需要做取整操作,不然结果有可能是小数
18+
const q = Math.floor(p + (r - p) / 2)
19+
this.mergeSortInternally(array, p, q)
20+
this.mergeSortInternally(array, q + 1, r)
21+
this.mergeArray(array, p, q, r)
22+
}
23+
24+
private static mergeArray(a: number[], p: number, q: number, r: number) {
25+
let i = p
26+
let j = q + 1
27+
let k = 0
28+
// 定义一个临时数组来存放排序的值
29+
const tmp: number[] = []
30+
while (i <= q && j <= r) {
31+
if (a[i] <= a[j]) {
32+
tmp[k++] = a[i++]
33+
} else {
34+
tmp[k++] = a[j++]
35+
}
36+
}
37+
// 判断哪个子数组中有剩余的数据
38+
let start = i
39+
let end = q
40+
if (j <= r) {
41+
start = j
42+
end = r
43+
}
44+
// 将剩余的数据拷贝到临时数组tmp
45+
while (start <= end) {
46+
tmp[k++] = a[start++]
47+
}
48+
49+
// 将tmp中的数组拷贝回a[p...r]
50+
for (i = 0; i <= r - p; i++) {
51+
a[p + i] = tmp[i]
52+
}
53+
}
54+
}
55+
56+
const test4 = [1, 3, 2, 3, 10, 9, 7, 6, 0, 12]
57+
MergeSort.mergeSort(test4)
58+
console.log(test4)

typescript/12_sorts/quickSort.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,19 @@
33
* 原地排序,空间复杂度O(1),比归并排序使用更广泛
44
* 平均复杂度基本接近O(nlg(n))
55
*/
6-
interface ArraySort {
7-
sort(array: number[]): void
8-
}
96

10-
class QuickSort implements ArraySort {
11-
sort(array: number[]): void {
7+
export class QuickSort {
8+
static sort(array: number[]): void {
129
this.sortInternally(array, 0, array.length - 1)
1310
}
14-
15-
private sortInternally(array: number[], p: number, r: number) {
11+
private static sortInternally(array: number[], p: number, r: number) {
1612
if (p >= r) return
1713
// 获取分界点
1814
const q: number = this.partition(array, p, r)
1915
this.sortInternally(array, p, q - 1)
2016
this.sortInternally(array, q + 1, r)
2117
}
22-
23-
private partition(array: number[], p: number, r: number): number {
18+
private static partition(array: number[], p: number, r: number): number {
2419
/**
2520
* 参考值pivot,小于pivot的放在左边,大于pivot的在右边,最后再把分界点的值和它做交换
2621
* 这样返回的index一定是值在中间的下标
@@ -39,14 +34,13 @@ class QuickSort implements ArraySort {
3934
return index - 1
4035
}
4136

42-
private swap(array: number[], p: number, q: number) {
37+
private static swap(array: number[], p: number, q: number) {
4338
const temp = array[p]
4439
array[p] = array[q]
4540
array[q] = temp
4641
}
4742
}
4843

4944
const testSort = [1, 3, 2, 3, 10, 9, 7, 6, 0, -12]
50-
const quickSort: ArraySort = new QuickSort()
51-
quickSort.sort(testSort)
45+
QuickSort.sort(testSort)
5246
console.log(testSort)

typescript/13_sorts/BucketSort.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* 桶排序对数据的要求比较高
3+
* 首先要知道数据的范围
4+
* 然后根据范围将数据分到小范围的桶中
5+
* 每个桶采用快速排序
6+
* 当桶的数量接近数据量大小的时候,时间复杂度为O(n)
7+
*/
8+
import { QuickSort } from '../12_sorts/quickSort'
9+
10+
class BucketSort {
11+
static sort(array: number[], bucketSize: number = 5) {
12+
const length = array.length
13+
if (length === 0) return array
14+
// 首先要确定数据的范围
15+
let min = array[0]
16+
let max = array[0]
17+
for (let i = 0; i < length; i++) {
18+
if (array[i] < min) {
19+
min = array[i]
20+
} else if (array[i] > max) {
21+
max = array[i]
22+
}
23+
}
24+
25+
// 初始化桶,确定桶的数量
26+
// 因为不能保证正好被整除,需要+1 存放剩余的元素
27+
const bucketCount = Math.floor((max - min) / bucketSize) + 1
28+
// 桶是个二维数组
29+
const buckets = new Array(bucketCount)
30+
for (let i = 0; i < bucketCount; i++) {
31+
buckets[i] = []
32+
}
33+
34+
// 利用映射函数将数据分配到各个桶中
35+
// 这个时间复杂度为O(n)
36+
for (let i = 0; i < length; i++) {
37+
buckets[Math.floor((array[i]-min) / bucketSize)].push(array[i])
38+
}
39+
array.length = 0 // 返回数组
40+
for (let i = 0; i < bucketCount; i++) {
41+
// 每个桶里根据具体情况排序,使用插入排序或者快速排序等等
42+
QuickSort.sort(buckets[i])
43+
for (let j = 0; j < buckets[i].length; j++) {
44+
array.push(buckets[i][j]);
45+
}
46+
}
47+
}
48+
}
49+
50+
const bucketTest = [1, 3, 2, 3, 10, 9, 7, 6, 0, -12]
51+
BucketSort.sort(bucketTest)
52+
console.log(bucketTest)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* 计数排序
3+
* 也是线性时间复杂度,和桶排序非常类似
4+
* 适用于值范围较小的大数据排序
5+
* 注意值范围需要不小于0,不然需要将数据预处理
6+
* 并非原地排序
7+
*/
8+
class CountingSort {
9+
static sort(array: number[]) {
10+
const length = array.length
11+
12+
// 找到这个数组的最大值
13+
let max = array[0]
14+
array.forEach((item) => {
15+
if (item > max) {
16+
max = item
17+
}
18+
})
19+
20+
// 初始化值范围数组
21+
const countArray = new Array(max + 1).fill(0, 0, max + 1)
22+
// 先计算每个元素的出现个数
23+
for (let i = 0; i < length; i++) {
24+
countArray[array[i]] = countArray[array[i]] + 1
25+
}
26+
// 计算元素的累计出现个数
27+
for (let i = 1; i <= max; i++) {
28+
countArray[i] = countArray[i - 1] + countArray[i]
29+
}
30+
31+
// 接下来开始计数排序了
32+
// 空间还是要申请
33+
const sortedArray = []
34+
// 倒序遍历能够达到稳定排序的作用
35+
for (let i = length - 1; i >= 0; i--) {
36+
// -1是为了填补sortedArray在0的位置,因为countArray在0的位置中一定么有值
37+
const index = countArray[array[i]] - 1
38+
sortedArray[index] = array[i]
39+
countArray[array[i]]--
40+
}
41+
for (let i = 0; i < length; i++) {
42+
array[i] = sortedArray[i]
43+
}
44+
}
45+
}
46+
47+
48+
const testSort2 = [1, 3, 2, 3, 10, 9, 7, 6, 0]
49+
CountingSort.sort(testSort2)
50+
console.log(testSort2)
51+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* 二分查找适合于连续内存的数组查找
3+
* 并且是已经排好序的数组
4+
* 时间复杂度只有log(n)
5+
*/
6+
class BinarySearch {
7+
static bSearch(array: number[], target: number) {
8+
if (!array || array.length === 0) return -1
9+
const length = array.length
10+
let low = 0
11+
let high = length - 1
12+
while (low <= high) {
13+
// 一定是整数,这边的移位运算优先级低于+,-运算符,需要加括号
14+
const mid = low + ((high - low) >> 1)
15+
if (array[mid] === target) {
16+
return mid
17+
} else if (array[mid] > target) {
18+
high = mid - 1
19+
} else {
20+
low = mid + 1
21+
}
22+
}
23+
return -1
24+
}
25+
}
26+
27+
const testBinarySearch = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
28+
console.log(BinarySearch.bSearch(testBinarySearch, 10))

0 commit comments

Comments
 (0)