知识体系第二遍回顾补充--②冒泡算法
注: 时间复杂度: 完成一个程序所需要的时间;
一套图 搞懂“时间复杂度”:O(1): 常量; O(logn): 对数; O(n):线性; O(n^2):指数型;
空间复杂度: 完成一个程序所需要的内存/变量;
标准:数组内部数字的升序排列;
| 思想 | 空间复杂度 | ||
| 循环比较O(n^2) | O(n^2) | 冒泡排序:你比我小,我就要和你换,大值往上 | 选择排序:你比我小,我就要和你换,小值往下 |
| 分而治之O(nlogn) | O(logn) | 快速排序:取基值,左小右大,递归调,concat连 | 归并排序:一直中分,用slice,合并比较终用shift |
| 无序插有序O(n^2) | O(1) | 插入排序:你比我大,你就后移,找到最后一个大值,插入 | 二分法排序:找到第一个大值,大值自身及后面都后移,插入 |
| arr.sort((a,b)=>a-b) |
1.冒泡排序: 两两比较,如果前一个比后一个大,则互换位置,每次循环比较后,最后一个永远是最大的,下一轮比较,它就不参与了。
口诀:一层减1,二层减i减1
时间复杂度:(n-1)*(n-i-1)=n^2
点击查看代码
function sort(array){
for(var i = 0; i < array.length - 1; i++){
for(var j = 0; j<array.length - i -1; j++){ //最后一个不参与排序
if(array[j] > array[j+1]){
var smap = array[j]; //把大值赋值给一个变量
array[j] = array[j+1]; //把小值前移
array[j+1] = smap; //把大值后移
}
}
}
return array;
}
一共比较了 1 + 2 + 3 + ... + (array.length-1) 次比较。
2. 快速排序: 取基准,左小右大,做递归;两个坑儿要记牢,长度小(于)1要返回,splice截取后要取[0]; (20210627总结)
arr.splice(index,num,items); 返回被截取的数组
Math.floor(num); 对浮点数向下取整。
时间复杂度:O(nlogn)
点击查看代码
function quickSort(array){
if(array.length <= 1){// 避免进入递归死循环,此行必加
return array;
}
//var middleIndex = Math.floor(array.length / 2);
//var middle = array.splice(middleIndex,1)[0]; //获得中间数值
// 20210615 新写法
var middle = array.splice(0,1)[0];// 直接截取第一个得了,并且用splice函数截取出原数组,简单直接,因为怎么都是顺序一遍
var left = [];
var right = [];
for(var i = 0; i < array.length; i++){
if(array[i] < middle){
left.push(array[i]); //把小于中间数的放到左边的数组里
}eles{
right.push(array[i]); //把大于中间数的放到右边的数组里面
}
}
return quickSort(left).concat([middle],quickSort(right)); //进行递归调用
}
3. 插入排序: 设定有序数列和无序数列,把无序数列中的项插入到有序数列中,在有序数列的内循环中采取移动赋值的方式达到目的。
适合小数据量排序(<1000)
时间复杂度:O(n^2)
空间复杂度:O(1)
点击查看代码
// 插入排序,无序数列依次插入有序数列
function insertSort(array = []){
for(let i = 1;i < array.length; i++){// 默认第一项已经排好序了
let temp = array[i];// 无序数列第一项
let j = i - 1;
while(j>=0 && array[j] > temp){// (从后往前扫描)比我大,你就后移
array[j+1] = array[j];
j--;
}
// 找到自己位置了,我就插入
array[j+1] = temp;
}
return array;
}
4. 二分法排序:在插入排序的基础上进行的优化,在已排序数列中,找到第一个比待插入项大的值
点击查看代码
// 二分算法:在插入排序的基础上进行的优化,在已排序数列中,找到第一个比待插入项大的值
function binaryInsertSort(arr = []){
for(let i = 1;i < arr.length;i++){
let temp = arr[i];
let left = 0;
let right = i-1;
// 1. 二分法找第一个大值的位置
while(left<=right){
// 中间值
let middle = parseInt( (right+left)/2 );
if(temp < arr[middle]){// 数组元素值
right = middle - 1;
}else {
left = middle + 1;
}
}
// 2. 整体后移,从当前项的前一项开始,依次后移
for(let j = i - 1;j >= left;j--){
arr[j+1] = arr[j];
}
// 3. 找到位置,插入
arr[left] = temp;
}
return arr;
}
5. 选择排序: 把未排序列表中最小(大)的数,排在首位,再把剩余未排序列表中最小(大)的数,排在排序列表的后面,依据索引来排序。
前面的是最小的,和冒泡排序的逻辑是相反的,是把未排序中最小的往前移。
点击查看代码
// 选择排序:把未排序中的最小值往前移
function selectionSort(arr = []){
for(let i = 0;i < arr.length;i++){
let minIndex = i;// 初始化的最小值
let temp = arr[i];// 1. 暂存变量
for(let j = i+1;j < arr.length;j++){
if(arr[j] < arr[minIndex]){// 2. 既然你比我小,我就要把最小的称号给你喽
minIndex = j;
}
}
// 3. 最终找到了未排序中的最小值的索引,那就替换吧
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
return arr;
}
6. 归并排序:分而治之的思想;
时间复杂度:O(nlogn)
和快速排序很像
点击查看代码
// 归并排序:分而治之的思想
function mergeSort(arr = []){
// 1. 先分解
function sort(arr = []){
if(arr.length <= 1){ return arr } // 分到不能再分为止
let mid = Math.floor(arr.length/2);
let left = arr.slice(0,mid);
let right = arr.slice(mid);
return merge(sort(left),sort(right));
}
// 2. 再合并
function merge(left = [],right = []){
let temp = [];
while(left.length && right.length){// 直到某个数组为空为止,while挺好用
if(left[0] < right[0]){
temp.push(left.shift());// 关键一步,把小值剔除(shift)原数组
}else {
temp.push(right.shift());
}
}
return temp.concat(left,right);
}
return sort(arr);
}
7. 排序:
无法保证时间和空间复杂度(取决于具体表现)
arr.sort((a,b)=> a-b ); //升序排列;b-a// 降序排列;
口诀:顺升,逆降,改变原数组;
参考链接:
sort的用法 : 原理,原地排序
8. 希尔排序[todo]
参考链接:
参考链接:
归并排序算法及其JS实现 :分而治之思想,归并思想

浙公网安备 33010602011771号