• js常见算法及算法思想-排序


    目录

    1.冒泡排序

    2.选择排序

    3.插入排序

    4.归并排序

    5.快速排序


    把某个乱序的数组变成升序序或者降序的数组, js比较常用sort方法进行排序

    1.冒泡排序

    • 比较所有相邻元素,如果第一个比第二个大就交换他们

    • 执行一次后可以保证最后一个数字是最大的

    • 重复执行 n-1 次,就可以完成排序

    1. // 时间复杂度 O(n ^ 2) n为数组长度
    2. // 空间复杂度 O(1)
    3. Array.prototype.bubbleSort = function () {
    4. for (i = 0; i < this.length - 1; i++) {
    5. for (let j = 0; j < this.length - 1 - i; j++) {
    6. if (this[j] > this[j + 1]) {
    7. // 交换数据
    8. [this[j], this[j + 1]] = [this[j + 1], this[j]];
    9. }
    10. }
    11. }
    12. }

    2.选择排序

    • 找到数组中最小的值,选中它并放到第一位

    • 接着找到数组中第二小的值,选中它并放到第二位

    • 重复上述步骤执行 n-1 次

    1. // 时间复杂度:O(n ^ 2) n为数组长度
    2. // 空间复杂度:O(1)
    3. Array.prototype.selectionSort = function () {
    4. for (let i = 0; i < this.length - 1; i++) {
    5. let indexMin = i;
    6. for (let j = i; j < this.length; j++) {
    7. // 如果当前这个元素 小于最小值的下标 就更新最小值的下标
    8. if (this[j] < this[indexMin]) {
    9. indexMin = j;
    10. }
    11. }
    12. // 避免自己和自己进行交换
    13. if (indexMin !== i) {
    14. // 进行交换数据
    15. [this[i], this[indexMin]] = [this[indexMin], this[i]];
    16. }
    17. }
    18. }

    3.插入排序

    • 从第二个数,开始往前比较

    • 它大就往后排

    • 以此类推进行到最后一个数

    1. // 时间复杂度 O(n ^ 2)
    2. Array.prototype.insertionSort = function () {
    3. // 遍历数组 从第二个开始
    4. for (let i = 1; i < this.length; i++) {
    5. // 获取第二个元素
    6. const temp = this[i];
    7. let j = i;
    8. while (j > 0) {
    9. // 如果当前元素小于前一个元素 就开始往后移动
    10. if (this[j - 1] > temp) {
    11. this[j] = this[j - 1];
    12. } else {
    13. // 否则就跳出循环
    14. break
    15. }
    16. // 递减
    17. j--;
    18. }
    19. // 前一位置赋值为当前元素
    20. this[j] = temp;
    21. }
    22. }

    4.归并排序

    • 分:把数组劈成两半 在递归的对子数组进行分操作,直到分成一个个单独的数

    • 合:把两个树合并为有序数组,再对有序数组进行合并, 直到全部子数组合并为一个完整的数组

    1. // 时间复杂度 O(nlogn) 分需要劈开数组,所以是logn, 合则是n
    2. // 空间复杂度 O(n)
    3. Array.prototype.mergeSort = function () {
    4. const rec = (arr) => {
    5. // 递归终点
    6. if (arr.length === 1) return arr
    7. // 获取中间索引
    8. const mid = arr.length >> 1;
    9. // 通过中间下标,进行分割数组
    10. const left = arr.slice(0, mid);
    11. const right = arr.slice(mid);
    12. // 左边和右边的数组进行递归,会得到有序的左数组,和有序的右数组
    13. const orderLeft = rec(left);
    14. const orderRight = rec(right);
    15. // 存放结果的数组
    16. const res = [];
    17. while (orderLeft.length || orderRight.length) {
    18. // 如左边和右边数组都有值
    19. if (orderLeft.length && orderRight.length) {
    20. // 左边队头的值小于右边队头的值 就左边队头出队,否则就是右边队头出队
    21. res.push(orderLeft[0] < orderRight[0] ? orderLeft.shift() : orderRight.shift())
    22. } else if (orderLeft.length) {
    23. // 把左边的队头放入数组
    24. res.push(orderLeft.shift())
    25. } else if (orderRight.length) {
    26. // 把右边的队头放入数组
    27. res.push(orderRight.shift())
    28. }
    29. }
    30. return res
    31. }
    32. const res = rec(this)
    33. // 把结果放入原数组
    34. res.forEach((n, i) => this[i] = n)
    35. }

    合并两个有序链表:

    1. // 时间复杂度O(n) n为链表1和链表2的长度之和
    2. // 空间复杂度O(1)
    3. var mergeTwoLists = function (list1, list2) {
    4. // 新建一个新链表 作为返回值
    5. const res = {
    6. val: 0,
    7. next: null
    8. }
    9. // 指向新链表的指针
    10. let p = res;
    11. // 建立两个指针
    12. let p1 = list1;
    13. let p2 = list2;
    14. // 遍历两个链表
    15. while (p1 && p2) {
    16. // 如果链表1 小于 链表2的值 就接入链表1的值
    17. if (p1.val < p2.val) {
    18. p.next = p1;
    19. // 需要往后移动
    20. p1 = p1.next;
    21. } else {
    22. // 否则接入链表2的值
    23. p.next = p2;
    24. // 需要往后移动
    25. p2 = p2.next;
    26. }
    27. // p永远要往后移动一位
    28. p = p.next;
    29. }
    30. // 如果链表1或者链表2还有值,就把后面的值全部接入新链表
    31. if (p1) {
    32. p.next = p1;
    33. }
    34. if (p2) {
    35. p.next = p2;
    36. }
    37. return res.next;
    38. };

    5.快速排序

    • 分区:从数组中任意选择一个 基准, 所有比基准小的元素放在基准前面比基准大的元素放在基准后面

    • 递归: 递归的对基准前后的子数组进行分区

    1. // 时间复杂度 O(nlogN)
    2. // 空间复杂度 O(1)
    3. Array.prototype.quickSort = function () {
    4. const rec = (arr) => {
    5. // 如果数组长度小于等于1 就不用排序了
    6. if (arr.length <= 1) { return arr }
    7. // 存放基准前后的数组
    8. const left = [];
    9. const right = [];
    10. // 取基准
    11. const mid = arr[0];
    12. for (let i = 1; i < arr.length; i++) {
    13. // 如果当前值小于基准就放到基准前数组里面
    14. if (arr[i] < mid) {
    15. left.push(arr[i]);
    16. } else {
    17. // 否则就放到基准后数组里面
    18. right.push(arr[i]);
    19. }
    20. }
    21. // 递归调用两边的子数组
    22. return [...rec(left), mid, ...rec(right)];
    23. };
    24. const res = rec(this);
    25. res.forEach((n, i) => this[i] = n);
    26. }

  • 相关阅读:
    数据分享|R语言逻辑回归、线性判别分析LDA、GAM、MARS、KNN、QDA、决策树、随机森林、SVM分类葡萄酒交叉验证ROC...
    JAVA在线课程教学大纲系统计算机毕业设计Mybatis+系统+数据库+调试部署
    链路聚合实验(华为)
    使用VC++输出调频波
    MySQL——命令行客户端的字符集问题
    新质生产力资讯简报合集2024年(170篇)
    微信小程序按钮点击时的样式hover-class=“hover“
    Vue3入门
    企业信息化的供给侧改革
    Hybrid综合应用
  • 原文地址:https://blog.csdn.net/Lc_style/article/details/126309735