起因:在掘金上看到的关于一些技术的博客,时常看见,却也没看见几篇关于算法的文章,所以自己就想好好总结一下
1.时间复杂度:时间复杂度是描述算法运行的时间。我们把算法需要运算的次数用输入大小为n的函数来表示,计作T(n) 。时间复杂度通常用来表示O(n),公式为T(n)=O(f(n)),其中f(n)表示每行代码的执行次数之和,注意是执行次数。
有一些算法功底的人都应该知道什么是算法复杂度,通俗点讲就是最多次代码运算的次数为f(n)即可
常见的时间复杂度 O(1) console.log
O(n) 数组的操作
O(n2) 双重for循环
O(log(n)) 二分查找 (nlog(n),2n)
2。空间复杂度:空间复杂度是对算法运行过程中临时占用空间大小的度量 O(1):算法执行所需要的临时空间不随着某个变量 n 的大小而变化,即此算法空间复杂度为一个常量,可表示为 O(1)
O(n)复杂度:一段for()循环
- 排序算法(sorting algorithm)是一种能将一串数据依照特定顺序进行排列的一种算法。 排序算法的一个指标是稳定性,稳定性即:如果只按照第一个数字排序的话,第一个数字相同而第二个数字不同的,第二个数字按照原有排序的就是稳定排序,不按照原有排序的就是不稳定排序。
稳定性 冒泡排序 稳定 选择排序 不稳定 插入排序 稳定 希尔排序 不稳定 快速排序 不稳定 归并排序 稳定
冒泡排序(Bubble Sort) 我们先来了解一下冒泡排序算法,虽然比较容易实现,但是比较慢。之所以称之为冒泡排序是因为使用这种排序算法时,像气泡一样从数组的一端冒到另一端。 实现原理 每次比较,相邻的元素,如果第一个比第二个大,就交换两个元素的位置 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
代码
function bubbleSort(arr) {
const len = arr.length;
for (let i = 0; i < len - 1; i++) {
for (let j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j+1]) {
const temp = arr[j+1];
arr[j+1] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
选择排序(Selection Sort) 选择排序是一种简单直观的排序算法。选择排序从数组的开头开始,将第一个元素和其他元素进行比较,检查完所有元素后最小的元素会被放到数组的第一个位置,然后从第二个元素开始继续。这个过程一直进行到数组的倒数第二个位置。
function selectionSort(arr) {
const len = arr.length;
let minIndex;
let temp;
for (let i = 0; i < len - 1; i++) {
minIndex = i;
for (let j = i + 1; j < len; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j; // 保存最小数的索引
}
}
temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
return arr;
}
插入排序(Insertion Sort) 插入排序类似于按首字母或者数字对数据进行排序。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
function insertionSort(arr) {
const len = arr.length;
let preIndex;
let 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];
preIndex--;
}
arr[preIndex + 1] = current;
}
return arr;
}
希尔排序(Shell Sort) 希尔排序之所以叫希尔排序,因为它就希老爷子(Donald Shell)创造的。希尔排序对插入做了很大的改善。核心理念与插入排序的不同之处在于,它会优先比较距离较远的元素,而不是相邻的元素。当开始用这个算法遍历数据集时,所有元素之间的距离会不断减少,直到处理到数据的末尾。
function shellSort(arr) {
const len = arr.length;
let gap = Math.floor(len / 2);
while (gap > 0) {
for (let i = gap; i < len; i++) {
const temp = arr[i];
let j = i;
while (j >= gap && arr[j - gap] > temp) {
arr[j] = arr[j - gap];
j -= gap;
}
arr[j] = temp;
}
gap = Math.floor(gap / 2);
}
return arr;
}
快速排序(Quick Sort) 快速排序一般用来处理大数据集,速度比较快。快速排序通过递归的方式,将数据依次分为包含较小元素和较大元素的不同子序列。 实现原理 这个算法首先要在列表中选择一个元素作为基准值,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面。这个基准值一般有 4 种取法: 无脑拿第一个元素 无脑拿最后一个元素 无脑拿中间的元素 随便拿一个 下面的解法基于取最后一个元素实现:
function partition(arr, low, high) {
let i = low - 1; // 较小元素的索引
const pivot = arr[high];
for (let j = low; j < high; j++) {
// 当前的值比 pivot 小
if (arr[j] < pivot) {
i++;
[arr[i], arr[j]] = [arr[j], arr[i]]
}
}
[arr[i + 1], arr[high]] = [arr[high], arr[i + 1]]
return i + 1;
}
function quickSort(arr, low, high) {
if (low < high) {
const pi = partition(arr, low, high)
quickSort(arr, low, pi - 1)
quickSort(arr, pi + 1, high)
}
return arr;
}
归并排序(Merge Sort) 归并排序是把一系列排好序的子序列合并成一个大的完整有序序列。 实现原理 把长度为 n 的输入序列分成两个长度为 n / 2 的子序列,载 对这两个子序列分别采用归并排序,最后将两个排序好的子序列合并成一个最终的排序序列。
代码
function mergeSort(arr) {
const len = arr.length;
if (arr.length > 1) {
const mid = Math.floor(len / 2); // 对半分
const L = arr.slice(0, mid);
const R = arr.slice(mid, len);
let i = 0;
let j = 0;
let k = 0;
mergeSort(L); // 对左边的进行排序
mergeSort(R); // 对右边的进行排序
while (i < L.length && j < R.length) {
if (L[i] < R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++
}
k++;
}
// 检查是否有剩余项
while (i < L.length) {
arr[k] = L[i];
i++;
k++;
}
while (j < R.length) {
arr[k] = R[j];
j++;
k++;
}
}
return arr;
}