JavaScript 数据结构与算法 之 排序算法

简介: JavaScript 数据结构与算法 之 排序算法

排序算法

冒泡排序

function bubbleSort(array, compareFn = defaultCompare) {
  const { length } = array;
  for (let i = 0; i < length; i++) {
    for( let j = 0; j < length - 1; j++) {
      if (compareFn(array[j], array[j + 1]) === Compare.BIGGER_THAN) {
        swap(array, j, j + 1);
      }
    }
  }
  return array;
}
function swap(array, a, b) {
  [array[a], array[b]] = [array[b], array[a]];
}

优化,从内循环中减去外循环中已跑过的轮数

function modifiedBubbleSort(array, compareFn = defaultCompare) {
  const { length } = array;
  for (let i = 0; i < array.length; i++) {
    for (let j = 0; j < array.length - 1 - i; j++) {
      if (compareFn(array[j], array[j + 1]) === Compare.BIGGER_THAN) {
        swap(array, j, j + 1);
      }
    }
  }
  return array;
}

优化,设置标志性变量 pos,隐喻记录每趟排序中最后一次进行交换的位置,由于 pos 位置之后的记录均已狡猾到位,所以下一趟排序时,只要扫描到 pos 位置即可

function bubbleSort2(array, compareFn = defaultCompare) {
  let i = array.length - 1; // 初始时,最后位置保持不变
  while (i > 0) {
    let pos = 0; // 每趟开始时,无交换记录
    for (let j = 0; j < i; j++) {
      if (compareFn(array[j], array[j + 1]) === Compare.BIGGER_THAN) {
        pos = j; // 记录交换的位置
        swap(array, j, j + 1);
      }
    }
    i = pos; // 为下一趟排序做准备
  }
  return array;
}

优化,传统冒泡排序中每一趟排序操作只能找到一个最大值或最小值,我们考虑利用在每趟排序中进行正向和反向两遍冒泡的方法一次可以得到两个最终值,从而使排序趟数几乎少了一半。

function bubbleSort3(array, compareFn = defaultCompare) {
  let low = 0;
  let high = array.length - 1;
  let tmp, j;
  while (low < high) {
    for (j = low; j < high; ++j) { // 正向冒泡找到最大者
      if (compareFn(array[j], array[j + 1]) === Compare.BIGGER_THAN) {
        swap(array, j, j + 1);
      }
    }
    --high; // 修改 high 值,前移一位
    for (j = high; j > low; --j) { // 反向冒泡,找到最小者
      if (compareFn(array[j], array[j - 1]) === Compare.LESS_THAN) {
        swap(array, j, j - 1);
      }
    }
    --low;
  }
  return array;
}

选择排序

找到数据结构的最小值并将其放置在第一位,接着找到第二小的并将其放置在第二位,以此类推

function selectionSort(array, compareFn = defaultCompare) {
  const { length } = array;
  let indexMin;
  for (let i = 0; i < length - 1; i++) {
    indexMin = i;
    for (let j = i; j < length; j++) {
      if (compareFn(array[indexMin], array[j]) === Compare.BIGGER_THAN) {
        indexMin = j;
      }
    }
    if (i !== indexMin) {
      swap(array, i, indexMin);
    }
  }
  return array;
};

插入排序

插入排序每次排一个数组项,以此方式构建最后的排序数组。假定第一项已经排序,接着,它和第二项进行比较——第二项是应该待在原位还是插到第一项之前呢?这样,头两项就已正确排序,接着和第三项比较,以此类推

function insertionSort(array, compareFn = defaultCompare) {
  const { length } = array;
  let tmp;
  for (let i = 1; i < length; i++) {
    let j = i;
    tmp = array[i];
    while (j > 0 && compareFn(array[i - 1], tmp) === Compare.BIGGER_THAN) {
      array[j] = array[j - 1];
      j--;
    }
    array[j] = tmp;
  }
  return array;
};
  • 希尔排序
简单插入排序的改进版,优先比较较远距离的元素,也叫缩小增量排序
实现:
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序
  1. 选择一个增量序列t1, t2,...,tk,其中 ti > tj,tk = 1
  2. 按增量序列个数 k,对序列进行 k 趟排序
  3. 每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度
function shellSort(arr) {
  var len = arr.length,
      temp,
      gap = 1;
  // 动态定义间隔序列
  while(gap < len /5) {
    gap = gap * 5 + 1;
  }
  for (gap; gap > 0; gap = Math.floor(gap/5)) {
    for (var i = gap; i < len; i++) {
      temp = arr[i];
      for (var j = i - gap; j >= 0 && arr[j] > temp; j -= gap) {
        arr[j + gap] = arr[j];
      }
      arr[j + gap] = temp;
    }
  }
  return arr;
}

归并排序

归并排序是一种分而治之算法。思想是将原始数据切分成较小的数组,直到每个小数组只有一个位置,接着将 小数组归并成较大的数组,直到最后只有一个排序完毕的大数组。

function mergeSort(array, compareFn = defaultCompare) {
  if (array.length > 1) {
    const { length } = array
    const middle = Math.floor(length / 2);
    const left = mergeSort(array.slice(0, middle), compareFn);
    const right = mergeSort(array.slice(middle, length), compareFn);
    array = merge(left, right, compareFn);
  }
  return array;
}
function merge(left, right, compareFn) {
  let i = 0;
  let j = 0;
  const result = [];
  while (i < left.length && j < right.length) {
    if (compareFn(left[i], right[j]) === Compare.LESS_THAN) {
      result.push(left[i++]);
    } else {
      result.push(right[j++]);
    }
  }
  if (i < left.length) {
    result.concat(left.slice(i));
  } else {
    result.concat(right.slice(j));
  }
  return result;
}

快速排序

步骤

  1. 首先,从数组中选择一个值作为主元,即数组中间那个值
  2. 划分:创建两个指针(引用),左边一个指向数组的第一个值,右边指向数组最后一个值。移动左指针,直到我们找到一个比主元大的值,接着移动右指针直到找到一个比主元小的值,然后交换他们,重复这个过程,直到左指针超过了右指针。这个过程将使得比主元小的值都排在主元之前,比主元大的值都排在主元之后
  3. 算法对划分后的小数组(较主元小的值组成的子数组,以及较主元大的值组成的子数组)重复之前的两个步骤,直至数组已经完全排序。
function quicksort(array, compareFn = defaultCompare) {
  return quick(array, 0, array.length - 1, compareFn);
}
相关文章
|
28天前
|
机器学习/深度学习 存储 算法
【算法与数据结构】复杂度深度解析(超详解)
【算法与数据结构】复杂度深度解析(超详解)
【算法与数据结构】复杂度深度解析(超详解)
|
1月前
|
算法 JavaScript 前端开发
LZH 算法的模拟实现,JavaScript 版本
LZH 算法的模拟实现,JavaScript 版本
13 0
|
28天前
|
存储 算法 索引
【算法与数据结构】队列的实现详解
【算法与数据结构】队列的实现详解
|
1月前
|
算法
【算法与数据结构】二叉树(前中后)序遍历2
【算法与数据结构】二叉树(前中后)序遍历
|
4天前
|
JavaScript 前端开发 算法
【JavaScript技术专栏】使用JavaScript实现常见算法
【4月更文挑战第30天】本文介绍了如何使用JavaScript实现常见算法,包括排序、搜索和图算法。首先,通过JavaScript的`sort`方法讨论了排序算法,以快速排序为例展示了自定义排序的实现。接着,探讨了二分查找这一高效的搜索算法,并提供了实现代码。最后,解释了深度优先搜索(DFS)图算法,并给出了在JavaScript中的实现。理解并运用这些算法能有效提升编程能力。
|
6天前
|
存储 机器学习/深度学习 算法
|
8天前
|
算法 索引
数据结构于算法-基础排序
数据结构于算法-基础排序
6 0
|
9天前
|
存储 算法 Python
程序设计的艺术:算法与数据结构的魅力
程序设计的艺术:算法与数据结构的魅力
7 0
|
10天前
|
存储 算法
数据结构开篇(普普通通浅浅聊数据结构)什么是数据结构 、什么是算法、重要性、如何学好数据结构呢
数据结构开篇(普普通通浅浅聊数据结构)什么是数据结构 、什么是算法、重要性、如何学好数据结构呢
|
17天前
|
存储 人工智能 算法
有哪些数据结构与算法是程序员必须要掌握的?——“数据结构与算法”
有哪些数据结构与算法是程序员必须要掌握的?——“数据结构与算法”