1. 冒泡排序
定义
重复地走访要排序的数列,一次比较两个元素,如果他们的顺序有变化就交换过来。冒泡排序是一种稳定排序,值相等的元素不会打乱原本的顺序。由于该排序算法每一轮都有遍历所有的元素,总共遍历(元素数量-1)轮,所以平均时间复杂度是O(n^2)。
实现步骤
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个的大小;
- 对每一个相邻元素做同样的工作,从开始第一队到结尾的最后一对。这步做完后,最后的元素会是最大的数;
- 针对所有的元素重复以上的步骤,除了最后一个;
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
实现代码
const bubbleSort = function (arr) {
// 控制行数
for (let i = 0; i < arr.length - 1; i++) {
// 是否排序,默认已经排序
let isSort = true;
for (let j = 0; j < arr.length - 1 - i; j++) {
// 如果当前值比后一个大,就进行两两交换大小
if (arr[j] > arr[j + 1]) {
// 利用数组解构进行交换
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]
// 设置排序标志为未排序
isSort = false
}
}
// 如果已经排序完了,就中断循环
if (isSort) {
break;
}
}
return arr;
}
复制代码
2. 插入排序
定义
不断地将尚未排好序的数插入到已经排好序的部分。平均时间复杂度是O(n^2)
实现步骤
- 将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列;
- 从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。
实现代码
const insertSort = function(arr) {
// 设置第一项是已经排好序的,开始变量之后的元素
for(let i = 1; i < arr.length; i++) {
let preIndex = i - 1;
const current = arr[i]
// 遍历前面已经排好序的数组,从后往前遍历
while(preIndex >= 0 && arr[preIndex] > current) {
arr[preIndex + 1] = arr[preIndex]
preIndex--
}
// 设置要插入的数组位置值
arr[preIndex+1] = current
}
return arr
}
复制代码
冒泡排序是找到最大或最小值依次放在右边;插入排序是找到最大或最小值依次放在左边
3. 选择排序
定义
每次找出最小的元素依次最前面
实现步骤
- 首先在未排序的数组中找出最小的元素,放在数组的第一个元素位置;
- 再从剩余的位置中继续寻找最小的元素,然后放在已排序的末尾位置;
- 重复第2个步骤,直到所有的元素均排序完成。
实现代码
const selectSort = function(arr) {
// 已排序末尾位置记录
let pos = 0;
// 已排序数组循环
while(pos < arr.length - 1) {
// 存放本次循环当前最小元素的索引
let index = pos
// 循环未排序数组
for(let i = pos + 1; i < arr.length; i++ ) {
if (arr[i] < arr[index]) {
// 存储本轮最小元素的索引
index = i
}
}
// 数组结构方式交换位置
[arr[pos], arr[index]] = [arr[index], arr[pos]]
// 更新下次已排序位置
pos += 1
}
return arr
}
复制代码
4. 快速排序
定义
采用了分治的思想,把原始数组筛选成较大和较小的两个子数组,然后递归地排序两个子数组
实现步骤
- 从数组中挑选一个元素,作为基准元素;
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边);
- 递归地把小于基准值元素的子数列和大于基准值元素的子数列排序。
实现代码
const quickSort = function(arr){
// 终止条件
if (arr.length < 2) {
return arr.slice()
}
// 基准值
let pivot = arr[Math.floor(Math.random() * arr.length)]
let left = [], mid = [], right = [];
for (let i = 0; i < arr.length; i++) {
const value = arr[i]
// 比基准值小的放在左边
if (value < pivot) {
left.push(value)
} else if (value === pivot) {
mid.push(value)
} else {
// 比基准值大的放在右边
right.push(value)
}
}
// 继续递归的找出左边和右边数组中排序值
return quickSort(left).concat(mid, quickSort(right))
}
复制代码
5. 归并排序
定义
把数组从中间划分成两个子数组;一直递归地把子数组划分成更小的子数组,直到子数组里面只有一个元素。
实现步骤
- 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
- 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
- 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
- 重复步骤 3 直到某一指针达到序列尾;
- 将另一序列剩下的所有元素直接复制到合并序列尾。
实现代码
function mergeSort(arr) { // 采用自上而下的递归方法
var len = arr.length;
if(len < 2) {
return arr;
}
// 取中间位置
var middle = Math.floor(len / 2),
// 划分两个数组
left = arr.slice(0, middle),
right = arr.slice(middle);
// 递归划分数组,然后合并数组
return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right)
{
var result = [];
while (left.length && right.length) {
if (left[0] <= right[0]) {
result.push(left.shift());
} else {
result.push(right.shift());
}
}
while (left.length)
result.push(left.shift());
while (right.length)
result.push(right.shift());
return result;
}
复制代码