排序
- 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。排序算法,就是如何使得记录按照要求排列的方法。是《数据结构与算法》中最基本的算法之一。
- 我们常说的十大排序算法为:冒泡、选择、插入、希尔、归并、快速、堆、计数、桶、基数
- 推荐一个博客gavin103-JavaScript 算法
时间复杂度:
冒泡排序
- 冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<script>
// 冒泡排序:
// 原理:数组的每一项进行两两比较,如果前一项大于后一项就交换位置
// let ary = [12,23,11,34,10,9];
/*
第一轮比较(比较了5次-已经执行过的轮数)
12,23 [12,23,11,34,10,9]
23,11 [12,11,23,34,10,9]
23,34 [12,11,23,34,10,9]
34,10 [12,11,23,10,34,9]
34,9 [12,11,23,10,9,34]
第二轮(比较4次 ary.length-1-已经执行过的轮数)
12,11 [11,12,23,10,9,34]
12,23 [11,12,23,10,9,34]
23,10 [11,12,10,23,9,34]
23,9 [11,12,10,9,23,34]
第三轮(比较3次)
*/
// 每比较一轮就会产生一个最大值,当前数组一共六个值,比较五轮就会产生5个最大值,剩下的那个肯定是最小的(ary.length-1)
// 每轮比较的次数 (ary.length-1已经执行过的轮数)因为每次比较一轮就会产生一个最大值,最大值不需要参与比较
// let temp = null;
// let a = 12;
// let b = 13;
// temp = a; // 12
// a = b // 13
// b = temp // 12
let ary = [12, 23, 11, 34, 10, 9];
function bubbleSort(ary) {
//数组长度
let len = ary.length;
// 控制的比较的轮数
for (var i = 0; i < len - 1; i++) {
// 控制的是每一轮比较的次数
for (var j = 0; j < len - 1 - i; j++) {
// 如果前一项大于后一项就两两交换位置
if (ary[j] > ary[j + 1]) {
let temp = ary[j];
ary[j] = ary[j + 1];
ary[j + 1] = temp;
}
}
}
return ary;
}
console.log(bubbleSort(ary));
</script>
</body>
</html>
插入排序
- 插入排序的代码实现虽然没有冒泡排序和选择排序那么简单粗暴,但它的原理应该是最容易理解的了,因为只要打过扑克牌的人都应该能够秒懂。插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<script>
let ary = [12, 23, 11, 34, 56, 10];
//1.第一种
// function insert(ary) {
// let handAry = []; // 用来存放手里的牌
// handAry.push(ary[0]); // 抓了第一张牌
// // 这个循环就是抓牌
// for (var i = 1; i < ary.length; i++) {
// let item = ary[i] // 抓的每一张牌
// // 控制的是跟我手里的每一张牌去做比较(从右往左比较)
// for (var j = handAry.length - 1; j >= 0; j--) {
// let cur = handAry[j] // 手里的每一张牌
// // 如果抓的牌比手里的牌大了,就插入到这张牌的后面,并且停止比较
// if (item > cur) {
// handAry.splice(j + 1, 0, item);
// break;
// }
// // 如果能运行到这,证明抓的这张牌比我手里的牌都小,就直接放到数组的最前面
// if (j === 0) {
// handAry.unshift(item);
// }
// }
// }
// return handAry
// }
// console.log(insert(ary))
//2.第二种 推荐
function insertionSort(arr) {
//数组长度
let len = arr.length;
let preIndex, current;
for (let i = 1; i < len; i++) {
preIndex = i - 1;
current = arr[i];
while (preIndex >= 0 && arr[preIndex] > current) {
arr[preIndex + 1] = arr[preIndex]; // [10,11, 12, 23, 45, 23];
preIndex--;
}
arr[preIndex + 1] = current;
}
return arr;
}
console.log(insertionSort(ary));
</script>
</body>
</html>
快速排序
- 快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。
- 快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。
let ary = [12,11,23,21,10,56];
function quick(ary) {
// 4、如果数组中的length小于等于1,那就结束递归,把原数组return出去
if (ary.length <= 1) {
return ary
}
// 1、获取中间的一项作为基准(并且把原数组中的那一项删除)
let middleIndex = Math.floor(ary.length / 2) // 拿到中间项的索引
let middleValue = ary.splice(middleIndex, 1)[0];
// 2、创建两个数组,循环数组的每一项和基准做比较,如果每一项小于基准,就放到左边数组,反之放右边
let leftAry = [];
let rightAry = [];
for (var i = 0; i < ary.length; i++) {
if (ary[i] < middleValue) {
leftAry.push(ary[i])
} else {
rightAry.push(ary[i])
}
}
// 3、不断重复1和2步骤(递归)
return quick(leftAry).concat(middleValue, quick(rightAry))
}
console.log(quick(ary))
选择排序
- 选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n²) 的时间复杂度。所以用到它的时候,数据规模越小越好。
let arr=[555,398,4,546,235,234,12,3,26,555,454,654,2,3,45,645,65,3245];
function selectionSort(arr){
var len=arr.length;
var minIndex,temp;
for(var i=0;i<len-1;i++){
minIndex=i
for(var j=i+1;j<len;j++){
if(arr[minIndex]>arr[j]){
minIndex=j;
}
}
temp=arr[minIndex];
arr[minIndex]=arr[i];
arr[i]=temp
}
return arr
}
console.log(selectionSort(arr));
计数排序
- 计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。