排序算法将一串数组(一个列表)中的元素(整数,数字,字符串等)按某种顺序(增大,减小,字典顺序等)重新排列。
有很多种不同的排序算法,每一种都有各自的优势和限制。
这里主要分享常见的冒泡排序、选择排序、插入排序、归并排序和快速排序的简单实现。
所有的代码都可以直接复制进行测试~
冒泡排序
冒泡排序是排序算法中最简单的一个,但从运行时间的角度来说,冒泡排序是最差的一个。
冒泡排序会比较所有相邻的两个项,如果第一个比第二个大,就将它们交换。元素项向上移动至正确的顺序,像起跑升至表面。故而称之为冒泡排序。
简单实现
<script>
function bubbleSort(arr) {
let len = arr.length
// 外循环 有n个数字就比较n-1轮
for (let i = 0; i < len-1; i++) {
// 从内循环减去从外循环中已跑过的次数,优化不必要的比较
for (let j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
// 使用ES6语法交换数组元素
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
}
}
}
return arr
}
// 测试一下结果
let arr1 = [3, 5, 2, 6, 1]
console.log(bubbleSort(arr1))
</script>
选择排序
选择排序是一种原址比较排序算法。思路是找到数据结构中最小值放在第一位、再找到第二小的值放在第二位……以此类推。
简单实现
<script>
function selectionSort(arr) {
// 定义所需变量
let len = arr.length
// 当前正在寻找的最小值索引
let indexMin
// 从第一位开始寻找最小值,需要找 n-1 轮
for (let i = 0; i < len - 1; i++) {
// 当前要找的第i小的数字
indexMin = i
// 将最小值位置的值与后面的值对比(所以要找到最后一个) 找出后面最小值的索引值
for (let j = i; j < len; j++) {
if (arr[indexMin] > arr[j]) { indexMin = j }
}
// 如果现在占坑(正在寻找的位置)的值不是最小的,那就与最小值交换
if (i !== indexMin) {
[arr[i], arr[indexMin]] = [arr[indexMin], arr[i]]
}
}
return arr
}
// 测试一下
let arr1 = [2, 7, 3, 1, 5]
console.log(selectionSort(arr1))
</script>
插入排序
插入排序就像我们平时打扑克牌排手牌一样,先假定第一张牌已经拿到手了,然后抽牌,与第一张牌进行比较——是插在第一张前面还是放在第二张的位置,以此类推构件最后的排序数组。在数组长度较小时,插入排序性能优于冒泡排序和选择排序。
简单实现
<script>
function insertSort(arr) {
let len = arr.length
// 代表需要被排序的值(抽到的牌)
let temp
// 从第二项开始比,所以i=1。需要比到最后一个,所以 i < len。
for (let i = 1; i < len; i++) {
// 存放当前的索引和值
let j = i
let temp = arr[i];
// 比较当前值和前一个值 如果前一个值大就把他往后挪 直到找到位置或索引值为0
while (j > 0 && arr[j - 1] > temp) {
arr[j] = arr[j - 1]
j--
}
// 把当前值插入应该在的地方
arr[j] = temp
}
return arr
}
// 测试一下
let arr1 = [4, 1, 5, 2, 6]
console.log(insertSort(arr1))
</script>
归并排序
归并排序是一种分而治之的算法。思想是将原始数组切分成较小的数组,直到每个小数组只有一个位置,接着将小数组排序并归并为一个大数组。用到了递归的思想。
简单实现
<script>
function merge(left, right) {
console.log(left, right)
// 存放结果的数组
let result = []
let il = 0
let ir = 0
// 迭代接收到的数组
while (il < left.length && ir < right.length) {
// 比较两个数组的项哪个小,将小的数组先添加到结果数组中并递增控制变量
if (left[il] < right[ir]) {
result.push(left[il++])
} else {
result.push(right[ir++])
}
}
// 将剩余项添加至结果数组
while (il < left.length) {
result.push(left[il++])
}
while (ir < right.length) {
result.push(right[ir++])
}
return result
}
function mergeSort(arr) {
// 递归的停止条件 如果数组长度为 1,则返回这个数组
if (arr.length == 1) return arr
// 将数组递归拆分成小数组,并在归并过程中进行排序
let mid = Math.floor(arr.length / 2)
let left = mergeSort(arr.slice(0, mid))
let right = mergeSort(arr.slice(mid, arr.length))
return merge(left, right)
}
var arr1 = [3, 7, 2, 8, 1]
console.log(mergeSort(arr1))
</script>
快速排序
快速排序也许是最常用的算法了。和归并排序一样,快速排序也用到了分而治之的方法,同样用到了递归。
简单实现
<script>
// 找一个基准点 通过比较分为左右两个数组 然后递归进行比较
function quickSort(arr) {
if (arr.length == 0) return [];
let cIndex = Math.floor(arr.length / 2)
// 重要 要把c分出来
let c = arr.splice(cIndex, 1)
let l = []
let r = []
for (let i = 0; i < arr.length; i++) {
if (arr[i] < c) {
l.push(arr[i]);
} else {
r.push(arr[i])
}
}
return quickSort(l).concat(c, quickSort(r))
}
let arr1 = [2, 5, 2, 6, 1, 7]
console.log(quickSort(arr1));
</script>