Skip to content

Commit

Permalink
add bucket sort and binary search
Browse files Browse the repository at this point in the history
  • Loading branch information
jsrdxzw committed Jun 8, 2019
1 parent e714cc2 commit de13b81
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 12 deletions.
58 changes: 58 additions & 0 deletions typescript/12_sorts/MergeSort.ts
Original file line number Diff line number Diff line change
@@ -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)
18 changes: 6 additions & 12 deletions typescript/12_sorts/quickSort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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一定是值在中间的下标
Expand All @@ -39,14 +34,13 @@ 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
}
}

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)
52 changes: 52 additions & 0 deletions typescript/13_sorts/BucketSort.ts
Original file line number Diff line number Diff line change
@@ -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)
51 changes: 51 additions & 0 deletions typescript/13_sorts/CountingSort.ts
Original file line number Diff line number Diff line change
@@ -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)

28 changes: 28 additions & 0 deletions typescript/14_binarysearch/BinarySearch.ts
Original file line number Diff line number Diff line change
@@ -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))

0 comments on commit de13b81

Please sign in to comment.