🏀试试用 JS 写写排序

131 阅读1分钟

说实话,在写项目的时候,需要自己手写一个排序的情况可能性还真的小。

那为啥突然想写这样一篇文章,之前都是用的 C/C++ 来实现这些排序,这次用下 JS 来实现

冒泡排序

思路就是比较相邻的两个元素,是大于还是小于,取决于你是想要升序还是降序排序

平均复杂度O(n^2),最好O(n),最坏O(n^2),是稳定排序

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]) {
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
      }
    }
  }
  return arr;
}

选择排序

每次遍历都找出当前下标后面的最大(最小)值的下标,然后当前下标交换

复杂度都是O(n^2),而且是不稳定排序

function selectionSort(arr) {
  const len = arr.length;
  let index;
  for (let i = 0; i < len; i++) {
    index = i;
    for (let j = i + 1; j < len; j++) {
      arr[j] < arr[index] ? index = j : ""
    }
    [arr[index], arr[i]] = [arr[i], arr[index]]
  }
  return arr
}

插入排序

分两组:左边有序,右边无序。在右边每一个都会跟左边倒序比较,找到比自身大的(小的)就插入

平均复杂度O(n^2),最好O(n),最快O(n^2),和冒泡一样,这个是稳定排序

function insertSort(arr) {
  const len = arr.length;
  let tempIndex, temp;
  for (let i = 1; i < len; i++) {
    tempIndex = i - 1;
    temp = arr[i];
    while (tempIndex >= 0 && arr[tempIndex] > temp) {
      arr[tempIndex + 1] = arr[tempIndex];
      tempIndex--;
    }
    arr[tempIndex + 1] = temp;
  }
  return arr;
}

希尔排序

是插入排序的一种更高效的版本

平均复杂度是O(n logn),是不稳定排序

function shellSort(arr) {
  const len = arr.length;
  let temp, gap = 1;
  while (gap < len / 3) {
    gap = gap * 3 + 1;
  }
  for (; gap > 0; gap = Math.floor(gap / 3)) {
    for (let i = gap; i < len; i++) {
      temp = arr[i];
      let j
      for (j = i - gap; j > 0 && arr[j] > temp; j -= gap) {
        arr[j + gap] = arr[j];
      }
      arr[j + gap] = temp;
    }
  }
  return arr;
}

归并排序

归并排序是采用的分治的思想来实现的

复杂度都是O(n logn),而且它是稳定排序

function mergeSort(arr) {
  const len = arr.length;
  if (len < 2) {
    return arr;
  }
  const middle = Math.floor(len / 2),
    left = arr.slice(0, middle),
    right = arr.slice(middle);
  return merge(mergeSort(left), mergeSort(right));
}

function merge(left, right) {
  let result = [];
  while (left.length && right.length) {
    let t = left[0] <= right[0] ? left.shift() : right.shift();
    result.push(t);
  }

  left.length && (result = result.concat(left));
  right.length && (result = result.concat(right));

  return result;
}

快速排序

在一个区间中取一个基准,让这个基准的左边都比这个小,右边都比这个大;再分别对区间进行排序

平均复杂度是O(n logn),最坏的情况时O(n^2),是不稳定排序

function quickSort(arr, left, right) {
  let len = arr.length, partitionIndex;
    left = typeof left != "number" ? 0 : left,
    right = typeof right != "number" ? len - 1 : right;

  if (left < right) {
    partitionIndex = partition(arr, left, right);
    quickSort(arr, left, partitionIndex - 1);
    quickSort(arr, partitionIndex + 1, right);
  }
  return arr;
}

function partition(arr, left, right) {
  let flag = left,
    index = flag + 1;
  for (let i = index; i <= right; i++) {
    if(arr[i] < arr[flag]) {
      [arr[index], arr[i]] = [arr[i], arr[index]]
      index++;
    }
  }
  [arr[index - 1], arr[flag]] = [arr[flag], arr[index - 1]]
  return index - 1
}

堆排序

复杂度都是O(n logn),是不稳定排序

let len;

function buildMaxHeap(arr) {
  len = arr.length;
  for (let i = Math.floor(len / 2); i >= 0; i--) {
    heapify(arr, i);
  }
}

function heapify(arr, i) {
  let left = i * 2 + 1,
    right = i * 2 + 2;
  let largest = i;
  if (left < len && arr[left] > arr[largest]) {
    largest = left;
  }
  if (right < len && arr[right] > arr[largest]) {
    largest = right;
  }
  if (largest !== i) {
    [arr[i], arr[largest]] = [arr[largest], arr[i]];
    heapify(arr, largest);
  }
}

function heapSort(arr) {
  buildMaxHeap(arr);
  for (let i = arr.length - 1; i > 0; i--) {
    [arr[0], arr[i]] = [arr[i], arr[0]];
    len--;
    heapify(arr, 0)
  }
  return arr;
}

又回顾了一遍