JS 中常见算法以及基础排序

本文探讨了JavaScript中的基础算法,包括控制结构、原生操作和常见算法,如查找字符串最高频率字符、数组去重、翻转字符串等。此外,还详细介绍了不同排序算法的实现,如冒泡排序、快速排序、选择排序、插入排序、希尔排序、归并排序和堆排序,分析了它们的时间复杂度和适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 算法构成
  • 控制结构(顺序、分支、循环)
  • 原操作(固有数据类型的操作)
  1. 常见js算法
  • 字符串出现频率最高的字母/数字
//js实现
var str = 'ddcflldkd';
function showMax(str) {
    var array = str.split('');
    var maxnum = 0, maxValue = ''; //存储最多字母及出现次数
    for (var i=0; i<array.length; i++) {
        var count = 0;
        for (var j=i+1; j<array.length-i; j++) {
            if (array[i] == array[j]) {
                count ++; //中间值
            }
        }
        if (count > maxnum) {
            maxnum = count;
            maxValue = array[i];
        }
    }
    return  maxValue;
}
var value = showMax(str);
console.log('value', value);

//es6实现
const strChar = str => {
    let array = [...str],
    maxValue = '',
    obj = {},
    max = 0;
    console.log('array', array);
    array.forEach(value => {
        obj[value] = obj[value] == undefined ? 1 : obj[value] +1;
        if (obj[value] > max) {
            max = obj[value];
            maxValue = value;
        }
    });
    return maxValue;
}
console.log(strChar(str));
  • 数组去重
//js
var arr = ['1', '2', '3', '1', 'a', 'b', 'b'];
var i,j,len = arr.length;
for ( i = 0 ; i < len; i++) {
    for ( j = i + 1; j < len; j++) {
       if (arr[i] == arr[j]) {
            arr.splice(j, 1);
            len--;
            j--;
        }
    }
}
console.log('array', arr);   

//es6
//-forEach() 利用对象实现
const unique = arr =>{
    let obj = {};
    arr.forEach(item => {
        obj[item] = 1;
    });
    return Object.keys(obj);
}
console.log(unique(arr));

//- new set()
const unqiue = arr => {
    return [...new Set(arr)];
}

//-filter() 利用元素首次出现位置与
const unqiue = arr => {
    return arr.filter((ele, index, array) => {
        return index === array.indexOf(ele);
    });
    
}
console.log(unqiue(arr));
  • 查找不重复数组元素
var i,j,len = arr.length,flag = 0;
for ( i = 0 ; i < len; i++) {
    for ( j = i + 1; j < len; j++) {
        if (arr[i] == arr[j]) {
            arr.splice(j, 1);
            len--;
            j--;
            flag = 1;
        }
    }
    if (flag == 1) {
        flag = 0;
        arr.splice(i, 1);
        len--;
        i--;
    }
}        
  • 翻转字符串
//js
var str = 'abbjnlfksc';
var array = str.split('');
console.log(array.reverse().join(''));

//es6 
const str = 'abbjnlfksc';
const reverseStr = str => {
    return [...str].reverse().join('');
};
console.log(reverseStr(str));
  • 数组中最大差值
//js 
//快排,max-min
arr.sort(function(num1, num2){
    return num1 - num2;
});
var value = arr[arr.length-1] - arr[0];
console.log('value', value);

//es6
const difference = arr => {
    let max = Math.max(...arr),
        min = Math.min(...arr);
        return max - min;
    }
console.log(difference(arr));
  • 不借助临时变量,进行两个整数交换
var a = 2,
    b = 3,
    [a, b] = [b, a];
    console.log(a, b);
  1. 排序
  • 冒泡排序 O(n^2) 遍历不断将最大的值推到最末位
var array = [4,9,12,5,3,7,6,17,33,21];
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 temp = array[j+1];
            array[j+1] = array[j];
            array[j] = temp;
        }
    }
}    
console.log('array', array);
//改进,当一次遍历数组不发生变化时,数组有序,无序再排序
function unqiue(array) {
    var change = 0;
    for (var i = 0; i < array.length - 1; i++) {
        change = 1;
        for (var j = 0; j < array.length - i -1; j++) {
            if (array[j] > array[j+1]) {
                var temp = array[j+1];
                array[j+1] = array[j];
                array[j] = temp;
                change = 0;
            }
        }
        if (change) { return array;  console.log('dd')}
    }
    return array;
}
  • 快速排序 O(nlogn) 对绝大多数顺序性较弱的随机数列而言,快排优于归并
const array = [9,4,12,5,3,7,6,17,33,21];
const sort = arr => {
    //排除数组长度小于1的
    if (arr.length <= 1) {
        return arr;
        }
    //基准
    const pivotIndex = Math.floor(arr.length/2);
    const pivot = arr.splice(pivotIndex, 1)[0];
    //分区
    let left = [], right = [];
    arr.forEach(a => {
        a < pivot ? left.push(a) : right.push(a);
    });   
    //递归
    return sort(left).concat([pivot], sort(right));
}
console.log(sort(array));
  • 选择排序 O(n^2) 原理和冒泡排序一致,遍历未排序区取最小(大)交换放置已排序区末尾
const sortSelect = arr => {
   let minIndex; 
    for (let i = 0; i < arr.length - 1; i++) {
        minIndex = i;
        //取未排序区最小值
        for (let j = i + 1; j < arr.length; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
    //交换
    [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
    }
    return arr;
}
console.log(sortSelect(array));
  • 插入排序 O(n^2) 假设第一个元素已经有序,从后向前遍历,比较,若小于交换向前继续比较,大于开始下一个元素对比
const insertSort = arr => {
    for (let i = 0; i < arr.length; i++) {
    //从后向前遍历
        for (let j = i + 1; j > 0; j--) {
            if (arr[j] < arr[j-1]) {
                [arr[j], arr[j-1]] = [arr[j-1], arr[j]];
            }else {
                break;
            }
        }
    }
    return arr;
}
console.log(insertSort(array));


//优化,二分插入排序
const insertTwoSort = arr => {
    let tmp, left, right, mid;
    for(let i = 1; i < arr.length; i++) {
        tmp = arr[i];
        left = 0;
        right = i - 1;
        //二分法取已排序区比tmp大的值
        while(left <= right) {
            mid = parseInt((left + right) / 2);
            if (tmp < arr[mid]) {
                right = mid - 1;
            }else {
                left = mid + 1;
            }
        }
        //插入值
        for (let j = i - 1; j >= left; j--) {
            arr[j+1] = arr[j];
        }
        arr[left] = tmp;
    }
    return arr;
}
  • 希尔排序 O(nlog n) 不定步数的插入排序,先分割子序列并在序列内进行插入排序,然后对整体进行一次直接插入排序
const sort = arr => {
    let gap = parseInt(arr.length/2), tmp, j;
    while(gap > 0) {
        for (let i = gap; i < arr.length; i++) {
            tmp = arr[i];
            j = i - gap;
            while(j >= 0 && tmp < arr[j]) {
                arr[j+gap] = arr[j];
                j = j - gap;
            }
            arr[j+gap] = tmp;
        }
        gap = parseInt(gap/2);
    }
    return arr;
}
  • 归并排序 O(nlogn) 将无序的数组先拆分为N部分进行有序处理,然后合并
//递归调用合并函数
const sort = arr => {
    const len = arr.length,
    mid = Math.floor(len/2),
    left = arr.slice(0, mid),
    right = arr.slice(mid, len);
    if (len < 2) return arr; 
    return merge(sort(left), sort(right));
}
//合并 有序数组
const merge = (left, right) => {
    let result = [];
    while (left.length || right.length) {
        if (left.length && right.length) {
            if (left[0] < right[0]) {
                result.push(left.shift());
            }else {
                result.push(right.shift());
            }
        }else  if(left.length) {
            result.push(left.shift());
        }else {
            result.push(right.shift());
        }
    }
    return result;
}
  • 堆排序 O(nlogn) 堆概念的选择排序
    把最大堆堆顶的最大数取出,将剩余的堆继续调整为最大堆,再次将堆顶的最大数取出,这个过程持续到剩余数只有一个时结束
//从最底层子节点开始依次向根结点比较,若子节点小于父节点,交换,取到根结点为最大值,将根结点值与最底层第一个子节点交换,从剩余的堆继续找出最大值,重复执行直到剩余一个数

//交换
const swap = (arr, i , j) => {
    let temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
//建立最大堆
const buildMaxHeap = arr => {
    const iParent = Math.floor(arr.length/2) - 1;
    for (let i = 0; i <= iParent; i++) {
        maxHeapify(arr, i, arr.length);
    }
}
//最大堆排序 将堆的末端子节点作调整,使得子节点永远小于父节点
const maxHeapify = (arr, i, heapSize) => {
    let max, left, right;
    while(true) {
        max = i;
        left = 2 * i + 1;
        right = 2 * ( i + 1 );
        //子节点大于节点,标记
        if (left < heapSize && arr[i] < arr[left]) {
            max = left;
        }
        if (right < heapSize && arr[max] < arr[right]) {
            max = right;
        }
        //若有标记节点,则交换
        if (max != i) {
            swap(arr, max, i);
            i = max;
        //或去掉while(true){} 改为递归实现maxHeapify(arr, max, heapSize);
        }else {
            break;
        }
    }
}
const sort = arr => {
//建立最大堆
    buildMaxHeap(arr);
//堆排序
    for (let i = arr.length - 1; i > 0; i--) {
        swap(arr, 0 ,i);
        maxHeapify(arr, 0, i);
    }
    return arr;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值