From de13b81887ff04064c978d30c46707398e671e2a Mon Sep 17 00:00:00 2001 From: xuzhiwei Date: Sat, 8 Jun 2019 18:01:58 +0900 Subject: [PATCH] add bucket sort and binary search --- typescript/12_sorts/MergeSort.ts | 58 ++++++++++++++++++++++ typescript/12_sorts/quickSort.ts | 18 +++---- typescript/13_sorts/BucketSort.ts | 52 +++++++++++++++++++ typescript/13_sorts/CountingSort.ts | 51 +++++++++++++++++++ typescript/14_binarysearch/BinarySearch.ts | 28 +++++++++++ 5 files changed, 195 insertions(+), 12 deletions(-) create mode 100644 typescript/12_sorts/MergeSort.ts create mode 100644 typescript/13_sorts/BucketSort.ts create mode 100644 typescript/13_sorts/CountingSort.ts create mode 100644 typescript/14_binarysearch/BinarySearch.ts diff --git a/typescript/12_sorts/MergeSort.ts b/typescript/12_sorts/MergeSort.ts new file mode 100644 index 0000000..a466e19 --- /dev/null +++ b/typescript/12_sorts/MergeSort.ts @@ -0,0 +1,58 @@ +/** + * 归并排序 + * 稳定排序,稳定的O(nlgn)时间复杂度 + * O(n)的空间复杂度 + * 在小规模数据排序中很常用 + */ +class MergeSort { + public static mergeSort(array: number[]) { + if (!array || !array.length) return + const length = array.length + this.mergeSortInternally(array, 0, length - 1) + } + + static mergeSortInternally(array: number[], p: number, r: number) { + if (p >= r) return + // 严格按照中间值作切分点 + // js中除法需要做取整操作,不然结果有可能是小数 + const q = Math.floor(p + (r - p) / 2) + this.mergeSortInternally(array, p, q) + this.mergeSortInternally(array, q + 1, r) + this.mergeArray(array, p, q, r) + } + + private static mergeArray(a: number[], p: number, q: number, r: number) { + let i = p + let j = q + 1 + let k = 0 + // 定义一个临时数组来存放排序的值 + const tmp: number[] = [] + while (i <= q && j <= r) { + if (a[i] <= a[j]) { + tmp[k++] = a[i++] + } else { + tmp[k++] = a[j++] + } + } + // 判断哪个子数组中有剩余的数据 + let start = i + let end = q + if (j <= r) { + start = j + end = r + } + // 将剩余的数据拷贝到临时数组tmp + while (start <= end) { + tmp[k++] = a[start++] + } + + // 将tmp中的数组拷贝回a[p...r] + for (i = 0; i <= r - p; i++) { + a[p + i] = tmp[i] + } + } +} + +const test4 = [1, 3, 2, 3, 10, 9, 7, 6, 0, 12] +MergeSort.mergeSort(test4) +console.log(test4) diff --git a/typescript/12_sorts/quickSort.ts b/typescript/12_sorts/quickSort.ts index ae22c62..c1963f8 100644 --- a/typescript/12_sorts/quickSort.ts +++ b/typescript/12_sorts/quickSort.ts @@ -3,24 +3,19 @@ * 原地排序,空间复杂度O(1),比归并排序使用更广泛 * 平均复杂度基本接近O(nlg(n)) */ -interface ArraySort { - sort(array: number[]): void -} -class QuickSort implements ArraySort { - sort(array: number[]): void { +export class QuickSort { + static sort(array: number[]): void { this.sortInternally(array, 0, array.length - 1) } - - private sortInternally(array: number[], p: number, r: number) { + private static sortInternally(array: number[], p: number, r: number) { if (p >= r) return // 获取分界点 const q: number = this.partition(array, p, r) this.sortInternally(array, p, q - 1) this.sortInternally(array, q + 1, r) } - - private partition(array: number[], p: number, r: number): number { + private static partition(array: number[], p: number, r: number): number { /** * 参考值pivot,小于pivot的放在左边,大于pivot的在右边,最后再把分界点的值和它做交换 * 这样返回的index一定是值在中间的下标 @@ -39,7 +34,7 @@ class QuickSort implements ArraySort { return index - 1 } - private swap(array: number[], p: number, q: number) { + private static swap(array: number[], p: number, q: number) { const temp = array[p] array[p] = array[q] array[q] = temp @@ -47,6 +42,5 @@ class QuickSort implements ArraySort { } const testSort = [1, 3, 2, 3, 10, 9, 7, 6, 0, -12] -const quickSort: ArraySort = new QuickSort() -quickSort.sort(testSort) +QuickSort.sort(testSort) console.log(testSort) diff --git a/typescript/13_sorts/BucketSort.ts b/typescript/13_sorts/BucketSort.ts new file mode 100644 index 0000000..c7004a2 --- /dev/null +++ b/typescript/13_sorts/BucketSort.ts @@ -0,0 +1,52 @@ +/** + * 桶排序对数据的要求比较高 + * 首先要知道数据的范围 + * 然后根据范围将数据分到小范围的桶中 + * 每个桶采用快速排序 + * 当桶的数量接近数据量大小的时候,时间复杂度为O(n) + */ +import { QuickSort } from '../12_sorts/quickSort' + +class BucketSort { + static sort(array: number[], bucketSize: number = 5) { + const length = array.length + if (length === 0) return array + // 首先要确定数据的范围 + let min = array[0] + let max = array[0] + for (let i = 0; i < length; i++) { + if (array[i] < min) { + min = array[i] + } else if (array[i] > max) { + max = array[i] + } + } + + // 初始化桶,确定桶的数量 + // 因为不能保证正好被整除,需要+1 存放剩余的元素 + const bucketCount = Math.floor((max - min) / bucketSize) + 1 + // 桶是个二维数组 + const buckets = new Array(bucketCount) + for (let i = 0; i < bucketCount; i++) { + buckets[i] = [] + } + + // 利用映射函数将数据分配到各个桶中 + // 这个时间复杂度为O(n) + for (let i = 0; i < length; i++) { + buckets[Math.floor((array[i]-min) / bucketSize)].push(array[i]) + } + array.length = 0 // 返回数组 + for (let i = 0; i < bucketCount; i++) { + // 每个桶里根据具体情况排序,使用插入排序或者快速排序等等 + QuickSort.sort(buckets[i]) + for (let j = 0; j < buckets[i].length; j++) { + array.push(buckets[i][j]); + } + } + } +} + +const bucketTest = [1, 3, 2, 3, 10, 9, 7, 6, 0, -12] +BucketSort.sort(bucketTest) +console.log(bucketTest) diff --git a/typescript/13_sorts/CountingSort.ts b/typescript/13_sorts/CountingSort.ts new file mode 100644 index 0000000..ba8ea3e --- /dev/null +++ b/typescript/13_sorts/CountingSort.ts @@ -0,0 +1,51 @@ +/** + * 计数排序 + * 也是线性时间复杂度,和桶排序非常类似 + * 适用于值范围较小的大数据排序 + * 注意值范围需要不小于0,不然需要将数据预处理 + * 并非原地排序 + */ +class CountingSort { + static sort(array: number[]) { + const length = array.length + + // 找到这个数组的最大值 + let max = array[0] + array.forEach((item) => { + if (item > max) { + max = item + } + }) + + // 初始化值范围数组 + const countArray = new Array(max + 1).fill(0, 0, max + 1) + // 先计算每个元素的出现个数 + for (let i = 0; i < length; i++) { + countArray[array[i]] = countArray[array[i]] + 1 + } + // 计算元素的累计出现个数 + for (let i = 1; i <= max; i++) { + countArray[i] = countArray[i - 1] + countArray[i] + } + + // 接下来开始计数排序了 + // 空间还是要申请 + const sortedArray = [] + // 倒序遍历能够达到稳定排序的作用 + for (let i = length - 1; i >= 0; i--) { + // -1是为了填补sortedArray在0的位置,因为countArray在0的位置中一定么有值 + const index = countArray[array[i]] - 1 + sortedArray[index] = array[i] + countArray[array[i]]-- + } + for (let i = 0; i < length; i++) { + array[i] = sortedArray[i] + } + } +} + + +const testSort2 = [1, 3, 2, 3, 10, 9, 7, 6, 0] +CountingSort.sort(testSort2) +console.log(testSort2) + diff --git a/typescript/14_binarysearch/BinarySearch.ts b/typescript/14_binarysearch/BinarySearch.ts new file mode 100644 index 0000000..cda4877 --- /dev/null +++ b/typescript/14_binarysearch/BinarySearch.ts @@ -0,0 +1,28 @@ +/** + * 二分查找适合于连续内存的数组查找 + * 并且是已经排好序的数组 + * 时间复杂度只有log(n) + */ +class BinarySearch { + static bSearch(array: number[], target: number) { + if (!array || array.length === 0) return -1 + const length = array.length + let low = 0 + let high = length - 1 + while (low <= high) { + // 一定是整数,这边的移位运算优先级低于+,-运算符,需要加括号 + const mid = low + ((high - low) >> 1) + if (array[mid] === target) { + return mid + } else if (array[mid] > target) { + high = mid - 1 + } else { + low = mid + 1 + } + } + return -1 + } +} + +const testBinarySearch = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +console.log(BinarySearch.bSearch(testBinarySearch, 10))