快速排序
-
快速排序是公认速度最快的算法之一。
-
快速排序的基本思路:
- 确定一个支点(pivot),通常选择数组的中间值
- 将所有小于支点的值放在左侧(升序,反之则降序),将所有大于支点的值放在右侧
- 重复以上过程,直到所有排序完成
-
具体做法(升序为例):
- 确定支点(pivot):用数组的长度除以 2 ,并向下取整,获取中间值,得到支点的索引,通过索引获取支点的值。
- 准备用于存放小于和大于支点的元素的空数组,比如left和right
- 获得不包含支点的数组,建立指针,指向新数组第一个元素
- 指针的当前值与支点比较,小于支点则放入left,大于则放入right,指针指向下一个当前值
- 对left和right重复以上操作
- 依次连接三个数组(left、支点、right)并返回,排序完成
-
JS实现(递归实现):
let quickSort = array => { if(array.length < 2) { return array } else { let left = [] let right = [] let index = Math.floor(array.length / 2) /* splice函数的三个注意点: 1. 函数的返回值是被截取的值 2. 函数的返回值总是一个数组 3. 函数的执行会影响原数组 */ let pivot = array.splice(index, 1)[0] for (let i = 0; i < array.length; i++) { array[i] < pivot ? left.push(array[i]) : right.push(array[i]) } return quickSort(left).concat([pivot], quickSort(right)) } }
选择排序
-
选择排序的基本思路:
- (升序)每次找出数组内的最小值,放在数组最前面
-
具体做法(升序):
- 定义获取最小值索引的函数
- 通过最小值索引函数获得最小值和最小值的索引号,通过索引号截取不包含最小值的数组
- 重复以上,获得所有最小值数组([最小值] + [其他])
- 依次连接所有数组(concat),排序完成
-
JS实现(递归实现)
let minIndex = array => {
let index = 0;
if (array.length < 2) { return index }
for (let i = 0; i < array.length; i++) {
index = array[index] < array[i] ? index : i
}
return index
}
let chooseSort = array => {
if (array.length < 2) { return array }
let index = minIndex(array)
let min = array[index]
// 注意splice的返回值
array.splice(index, 1)
return [min].concat(chooseSort(array))
}
归并排序
-
也叫做合并排序,效率较高,是一种广泛使用的排序算法
-
基本思路:
- 将两个已经排序的数组进行两两合并,这要比从头开始排序来的快。将数组拆分,分成n个只有一个元素的数组,然后不断地两两合并,直到全部排序完成。
-
具体做法(升序):
- 将数组切片,左边为从开始到中间,右边为从中间到结束,不断重复,直到每个数组只有一个值
- 设定指针,分别指向两端当前第一个值。
- 对指针两端两两比较,将符合条件的值取出,放在前面,不断重复
- 合并比较完的数组
-
JS实现(递归实现)
let merge = (left, right) => {
if (left.length === 0) { return right }
if (right.length === 0) { return left }
return left[0] < right[0] ? [left[0]].concat(merge(left.slice(1), right)) : [right[0]].concat(merge(left, right.slice(1)))
}
let mergeSort = array => {
if (array.length < 2) { return array }
let left = array.splice(0, array.length / 2)
let right = array.splice(array.lengt / 2)
return merge(mergeSort(left), mergeSort(right))
}
计数排序
-
基本思路:
- 使用哈希表,将每一个数组元素以 key: value 的形式置入哈希表,并找出key的最大值 max,key 为数组元素,value 为出现的次数,以 max 为最大次数遍历哈希表,遍历过程中将在哈希表中出现的 max 的值置入数组,完成排序。计数排序比以上排序都要快,因为它只遍历数组一遍。但需要额外使用哈希表,是典型的用空间换时间。
-
具体做法:
- 定义哈希表 hash、最大值 max,初始值为 0、和用于完成排序的空数组。
- 遍历数组,将每个元素作为 key,元素出现的次数作为 value,置入哈希表,同时找出最大值 max
- 以 max 的值为最大次数遍历哈希表,如果 max 的当前值,等于哈希表的 key,将 max 的当前值,置入数组 value 次
- 完成排序,返回排序完成的数组
-
JS实现
let countSort = array => {
let hash = {}
let max = 0
let result = []
for (let i = 0; i < array.length; i++) {
if(!hash[array[i]]) {
hash[array[i]] = 1
} else {
hash[array[i]]++
}
max = max > array[i] ? max : array[i]
}
// max的值在循环中是可以取到的
for (let i = 0; i <= max; i++) {
if (i in hash) {
for (let j = 0; j < hash[i]; j++) {
// 循环中的 i 的值,就是 hash 的 key
result.push(i)
}
}
}
return result
}