boxmoe_header_banner_img

Hello! 欢迎来到盒子萌!

加载中

文章导读

01算法


avatar
Jack 2023年 5月 1日 230

JavaScript算法

一、算法复杂度

给定一个或多个已知值,通过一系列的运算输出所需结果的过程,叫做算法。一个需求可能可以通过多种算法来实现,学习算法让我们了解怎样的算法效率更高更快,从而让我们针对某个需求做出最合适的选择。作为一名前端攻城狮,算法可能目前离你很远,但是如果你想在编程的路上走的更远一些,或涉猎到更多的数据逻辑,算法对你的帮助很大。所以想成为一名高端的开发者,算法是必须要学习的。

讨论一个算法的好坏,有最主要的两个方面:该算法所需时间-时间复杂度,该算法占用空间(内存)-空间复杂度。耗时短占用低肯定是最优选择,而往往我们需要在两者中找到一个平衡点。作为一名程序开发者,大多数情况下,时间复杂度比空间复杂度的影响更大一些,能做的改良和优化也更多,所以一般如果不做特别说明,我们在讨论算法复杂度的时候都是指时间复杂度

1. 时间复杂度

一个算法所需要的时间需要具体上机运行才知道,很显然不可能每个都验证一遍再做选择。我们可以对算法耗时进行合理的预测。

一个算法中语句的执行次数我们叫做时间频度,记做T(n)n表示问题规模,n增大T(n)也随之增大。而我们预估算法的效率,就是对T(n)的变化趋势进行分析,为了方便分析,我们需要简化一下T(n)函数,所以我们引入时间复杂度的概念:若有某个辅助函数 f(n),使得当n趋近与无穷大时,T(n)/f(n) 的极限值为不等于0的常数,则称 f(n) 是 T(n)的同数量级函数,记做 T(n) = O( f(n) )O( f(n) )就是时间复杂度的表示法。

总结一下:用O( f(n) )来表示算法时间复杂度。

2. 复杂度计算举例

理论上,我们对 O( f(n) ) 中的 f(n) 没有写法限制,但是因为我们关注的是随 n 增大复杂度的变化趋势,所以各常数项和系数我们是直接省略不做考虑的。

let a = 1;
let b = 2;
console.log(a+b);
//O(1)
let z = 0;
for(let i=0;i<n;i++){
    let a = i*2;
    z += a;
}
console.log(z);
//O(n)
let c = 0;
for(let i=1;i<n;i++){
    for(let j=1;j<n;j++){
        c += i*j
    }
}
console.log(c);
/*
O(n²)
即使两次循环规模变量n不一样,讨论规模增大时,复杂度的变化趋势,可将即使不一样的规模视作相同变量
*/
let c = 0;
for(let i=1;i<n;i++){
    for(let j=i;j<n;j++){
        c += i*j
    }
}
console.log(c);
//O(n²)
for(let i=1;i<n;i*=2){
    console.log(i+1);
}
//O(log₂n)
for(let i=0;i<n;i++){
    for(let j=1;j<n;j*=2){
        console.log(i+j);
    }
}
//O(nlog₂n)
function Fibonacci(n){
    if( n<=1 ){
        return 1;
    }
    return Fibonacci(n-1) + Fibonacci(n-2);
}
//O(2ⁿ)

二、js中常用算法

1.数组整数字去重

//基础写法
function fn(arr){
    let newArr = [...arr];
    for(let i=newArr.length-1;i>=0;i--){
        for(let j=i-1;j>=0;j--){
            if( newArr[i] === newArr[j] ){
                newArr.splice(j,1);
                i --;
            }
        }
    }
    return newArr;
}
//O(n^2)
//优化算法复杂度
function fn(arr){
    let tmp = {};
    let newArr = [];

    for(let i=0,length=arr.length;i<length;i++){
        let value = arr[i];
        if( !tmp[value] ){
            tmp[value] = true;
            newArr.push(value);
        }
    }

    return newArr;
}
//O(n)

注意:Set结构帮助我们实现去重,不代表复杂度为 1 ,因为内部对数组已经进行了遍历,相当于做了封装。

2. 判断回文

数据结构课程中使用栈结构实现了回文,此处我们讨论一下复杂度。

3. 寻找重复最多字符

let str = "abfsafsafghjiq15445454";

function fn(str){
    let length = str.length;
    let tmp = {};

    for(let i=0;i<length;i++){
        let val = str.charAt(i);
        if( tmp[val] ){
            tmp[val] ++;
        }else{
            tmp[val] = 1;
        }
    }

    let max = 1;
    let k = [str.charAt(0)];
    for (let [key,value] of Object.entries(tmp)) {
        if( value > max ){
            k = [key];
            max = value;
        }else if( value === max ){
            k.push(key);
        }
    }
    return k;
}

console.log(fn(str));
//O(n)

三、排序算法

1. 冒泡排序

动图演示(动图来源visualgo (opens new window)):img

function bubbleSort (arr) {
    let 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] ){
                swap(arr,j,j+1);
            }
        }
    }
}
function swap(arr,i,j){
    let tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}   

2. 选择排序

动图演示(动图来源visualgo (opens new window)):img

function selectionSort(arr){
    let len = arr.length;
    let minIndex;
    for(let i = 0; i < len ; i++) {
        minIndex = i;
        for(let j = i+1; j < len ; j++) {
            if( arr[j] < arr[minIndex] ){
                minIndex = j;
            }
        }
        swap(arr,i,minIndex);
    }
}
function swap(arr,i,j){
    let tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

3. 插入排序

动图演示(动图来源visualgo (opens new window)):img

function insertSort (arr) {
    let len = arr.length;
    let j;
    let current;
    for(let i = 1; i < len; i++) {
        current = arr[i];
        j = i-1;
        while(j>=0 && arr[j] > current){
            arr[j+1] = arr[j];
            j --;
        }
        arr[j+1] = current;
    }
}

4. 归并排序

动图演示(动图来源visualgo (opens new window)):img

//划分
function mergeSort(arr){
    let len = arr.length;

    if( len < 2 ){
        return arr;
    }

    let mid = Math.floor(len/2);
    let left = arr.slice(0,mid);
    let right = arr.slice(mid);

    return merge(mergeSort(left),mergeSort(right));
}

//排序
function merge(left,right){
    let result = [];

    while ( left.length > 0 && right.length > 0 ){
        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;
}

5. 快速排序

动图演示(动图来源visualgo (opens new window)):img

function quickSort(arr){
    let len = arr.length;
    quick(arr,0,len-1);
}

function quick(arr,left,right){
    let point = left;
    let index = point+1;

    for(let i = index; i <= right; i++) {
        if( arr[i] < arr[point] ){
            swap(arr,i,index);
            index ++;
        }
    }

    swap(arr,point,index-1);

    index --;
    let leftE = index-1;
    let rightB = index+1;

    if( leftE > left ){
        quick(arr,point,leftE);
    }
    if( rightB < right){
        quick(arr,rightB,right);
    }

}
function swap(arr,i,j){
    let tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

6. 堆排序

动图演示(动图来源博客园 (opens new window)):

img

function heapSort (arr) {
    let len = arr.length;
    for(let j = len; j > 1 ; j--) {
        let i = Math.floor(j/2) - 1;
        heap(arr,i,j);
    }
}
function heap (arr,i,len) {
    while ( i>=0 ){
        let left = 2*i+1,
            right = 2*i+2;

        let max = arr[i];
        let maxIndex = i;

        if( left < len && arr[left] > max ){
            max = arr[left];
            maxIndex = left;
        }

        if( right < len && arr[right] > max ){
            maxIndex = right;
        }

        swap(arr,i,maxIndex);

        i--;
    }

    swap(arr,0,len-1);
    //console.log(arr);
}
function swap(arr,i,j){
    let tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}
function heapSort(arr){
    let len = arr.length;

    //初始堆调整
    for(let j = Math.floor(len/2)-1; j >=0 ; j--) {
        heap(arr,j,len);
    }

    for(let i = len-1; i > 0; i--) {
        swap(arr,0,i);
        len --;
        heap(arr,0,len);
    }
}

function heap(arr,i,len){
    let left = 2*i+1,
        right = 2*i+2,
        max = arr[i],
        maxIndex = i
    ;

    if( left < len && arr[left] > max ){
        max = arr[left];
        maxIndex = left;
    }

    if( right < len && arr[right] > max ){
        maxIndex = right;
    }

    if( maxIndex !== i ){
        swap(arr,i,maxIndex);
        heap(arr,maxIndex,len);
    }
}
function swap(arr,i,j){
    let tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

7. 计数排序

动图演示(动图来源博客园 (opens new window)):

img

function countSort (arr) {
    let count = [];
    arr.forEach(item=>{
        if(!count[item])count[item] = 0;
        count[item] ++;
    });
    let j = 0;
    count.forEach((item,i)=>{
        while ( item > 0 ){
            arr[j] = i;
            item --;
            j ++;
        }
    });
}

8. 桶排序

图片展示(图片来源博客园 (opens new window)):

img

function quickSort(arr){
    let len = arr.length;
    quick(arr,0,len-1);
}

function quick(arr,left,right){
    let point = left;
    let index = point+1;

    for(let i = index; i <= right; i++) {
        if( arr[i] < arr[point] ){
            swap(arr,i,index);
            index ++;
        }
    }

    swap(arr,point,index-1);

    index --;
    let leftE = index-1;
    let rightB = index+1;

    if( leftE > left ){
        quick(arr,point,leftE);
    }
    if( rightB < right){
        quick(arr,rightB,right);
    }

}
function swap(arr,i,j){
    let tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

function bucketSort (arr) {
    let bucketSize = 10;
    let len = arr.length;
    let bucketArr = [];

    for(let i = 0; i < len; i++)
    {
        let index = Math.floor(arr[i]/bucketSize);
        if( !bucketArr[index] )bucketArr[index] = [];
        bucketArr[index].push(arr[i]);
    }

    let j = 0;
    for(let i = 0,len = bucketArr.length; i <len ; i++) {
        let item = bucketArr[i];
        if( !item )continue;
        quickSort(item);
        item.forEach(v=>{
            arr[j ++] = v;
        });
    }
}

9. 基数排序

动图演示(动图来源博客园 (opens new window)):

img

function radixSort (arr) {
    let len = arr.length;
    //找出数组中最大数的位数
    let maxNum = arr[0];
    let radixArr = [];
    for(let i = 1; i < len; i++) {
        if( arr[i] > maxNum ){
            maxNum = arr[i];
        }
    }
    let maxDigit = maxNum.toString().length;

    let x = 10,y = 1;
    for(let i = 0; i < maxDigit; i++) {
        for(let j = 0; j < len; j++) {
            let v = Math.floor(arr[j] % x / y);
            if( !radixArr[v] )radixArr[v] = [];
            radixArr[v].push(arr[j]);
        }
        x *= 10;
        y *= 10;

        let index = 0;
        for(let j = 0,len = radixArr.length; j <len ; j++) {
            let item = radixArr[j];
            if(!item)continue;
            item.forEach(v=>{
                arr[index ++] = v;
            });
        }
        radixArr = [];
    }
}


评论(0)

查看评论列表

暂无评论


发表评论

表情 颜文字
插入代码