排序算法小结

341 阅读2分钟

排序算法

1、选择排序

  • 算法步骤
    • 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
    • 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
    • 重复第二步,直到所有元素均排序完毕。
  • 时间复杂度:O(n^2)

1AOjHzEho6hPmUoQH5Inc-A-n2PqFilBQrbHPqbndWs.gif

// 选择排序
function selectSort(array) {
  if (!array || array.length <= 0) {
    return array
  }
  const len = array.length;
  for (let i = 0; i < len - 1; i++) {
    let minIndex = i;
    for (let j = i + 1; j < len; j++) {
      if (array[j] < array[minIndex]) {
        minIndex = j;
      }
    }
    let temp = array[i];
    array[i] = array[minIndex];
    array[minIndex] = temp;
  }
}

const array = [6, 7, 8, 9, 0, 5, 4, 3, 2, 1];
selectSort(array)
console.log('selectSort result', array)

2、冒泡排序

  • 算法步骤
    • 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
    • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
    • 针对所有的元素重复以上的步骤,除了最后一个。
    • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
  • 时间复杂度:O(n^2)

MFi7W_boVjMy0OEJdwzk5WjntTYX6y-QHAYFxkRbhfM.gif

function bubbleSort(array) {
  if (!array || array.length <= 0) {
    return array;
  }
  let len = array.length;
  for(i = 0; i < len - 1; i++) {
    for(let j = 0; j < len - 1 - i; j++) {
      if (array[j] > array[j + 1]) {
        let temp = array[j];
        array[j] = array[j + 1];
        array[j + 1] = temp;
      }
    }
  }
}

const array = [6, 7, 8, 9, 0, 5, 4, 3, 2, 1];
bubbleSort(array)
console.log('bubbleSort result', array)

3、快速排序

  • 算法步骤
    • 从数列中挑出一个元素,称为 "基准"(pivot);
    • 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
    • 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;
  • 时间复杂度:O(n logn) (最坏情况O(n^2))

xtQnFF0_R1c34sjrY12a6szFLyhD2VeIb_-4kZq8BnI.gif

function quickSort(array, l, r) {
  if (l < r) {
    let i = l;
    let j = r;
    let x = array[i];
    while(i < j) {
      while(i < j && x < array[j]) {
        j--;
      }
      if (i < j) {
        array[i] = array[j]
        i++;
      }
      while(i < j && array[i] < x) {
        i++;
      }
      if (i < j) {
        array[j] = array[i] 
        j--;
      }
    }
    array[i] = x;
    quickSort(array, l, i - 1)
    quickSort(array, i + 1, r)
  }
}
const array = [6, 7, 8, 9, 0, 5, 4, 3, 2, 1];
quickSort(array, 0, array.length - 1)
console.log('quickSort result', array)

4、插入排序

  • 算法步骤
    • 将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
    • 从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。
  • 时间复杂度:O(n) ~ O(n^2)

TNgiyPLYCZMP9uDk-JGh4YaD208NssGvVIBl4j_uzLc.gif

function insertSort(array) {
  if (!array || array.length <= 0) {
    return array;
  }
  let len = array.length;
  for (let i = 1; i < len; i++) {
    let x = array[i];
    let j = i
    for (; j >= 1 && array[j - 1] > x; j--) {
      array[j] = array[j - 1]
    }
    array[j] = x;
  }
}

const array = [6, 7, 8, 9, 0, 5, 4, 3, 2, 1];
insertSort(array)
console.log('insertSort result', array)

5、希尔排序

  • 算法思想:希尔排序(Shell's Sort)是插入排序的一种又称“缩小增量排序”是直接插入排序算法的一种更高效的改进版本。
  • 时间复杂度:O(n) ~ O(n^2)
 function shellSort(array) {
  if (!array || array.length <= 0) {
    return array;
  }
  let len = array.length;
  for (let gap = Math.floor(len / 2); gap > 0; gap = Math.floor(gap / 2)) {
    for (let i = gap; i < len; i++) {
      let x = array[i];
      let j = i;
      for (; j >= gap && x < array[j - gap]; j -= gap) {
        array[j] = array[j - gap];
      }
      array[j] = x
    }
  }
}
const array = [6, 7, 8, 9, 0, 5, 4, 3, 2, 1];
shellSort(array)
console.log('shellSort result', array)

6、计数排序

  • 算法步骤
    • (1)找出待排序的数组中最大和最小的元素
    • (2)统计数组中每个值为i的元素出现的次数,存入数组C的第i项
    • (3)对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
    • (4)反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1
  • 时间复杂度:Ο(n+k) (其中k是整数的范围)

fcsSDJHFcNtAIH7NN4m9MfEauMWZ9BguqHmneA20hJI.gif

function countSort(array) {
  if (!array || array.length <= 0) {
    return array;
  }
  let len = array.length
  let countArray = []
  for (let i = 0; i < len; i++) {
    if (countArray[array[i]]) {
      countArray[array[i]]++
    } else {
      countArray[array[i]] = 1
    }
  }
  let resArray = []
  for (let i = 0; i < countArray.length; i++) {
    while(countArray[i]) {
      resArray.push(i)
      countArray[i]--
    }
  }
  return resArray
}

const array = [6, 7, 8, 9, 0, 5, 4, 3, 2, 1];
const arrayRes = countSort(array)
console.log('countSort result', arrayRes)

7、归并排序

  • 算法步骤
    • 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
    • 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
    • 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
    • 重复步骤 3 直到某一指针达到序列尾;
    • 将另一序列剩下的所有元素直接复制到合并序列尾。
  • 时间复杂度:O(nlogn)

B2T80Az1yNhW2OTC_0VGK27Aa0YtnJax1wx1QkLKjNM.gif

function mergeSort(array) {
  if (!array || array.length < 2) {
    return array
  }
  let len = array.length
  let middle = Math.floor(len / 2)
  let left = array.slice(0, middle)
  let right = array.slice(middle)
  return merge(mergeSort(left), mergeSort(right))
}

function merge(left, right) {
  let res = []
  while(left.length && right.length) {
    if (left[0] <= right[0]) {
      res.push(left.shift())
    } else {
      res.push(right.shift())
    }
  }
  while(left.length) {
    res.push(left.shift())
  }
  while(right.length) {
    res.push(right.shift())
  }
  return res
}

const array = [6, 7, 8, 9, 0, 5, 4, 3, 2, 1];
const res = mergeSort(array)
console.log('mergeSort result', res )

8、桶排序

  • 桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。
    • 在额外空间充足的情况下,尽量增大桶的数量
    • 使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中
  • 时间复杂度:Ο(n+k) (其中k是整数的范围)

jULthADrnGZ5Nn4GB26EkzUH6InTjqtVe8ypYoayO1E.png

function insertSort(array) {
  if (!array || array.length <= 1) {
    return array
  }
  let len = array.length
  for (let i = 1; i < len; i++) {
    let x = array[i]
    let j = i
    for (; j >= 1 && array[j - 1] > x; j--) {
      array[j] = array[j - 1]
    }
    array[j] = x
  }
}

function bucketSort(array, bucketSize = 5) {
  if (!array || array.length <= 0) {
    return array
  }
  let len = array.length
  let minValue = array[0]
  let maxValue = array[0]
  for (let i = 0; i < len; i++) {
    if (array[i] < minValue) {
      minValue = array[i]
    } else if (array[i] > maxValue) {
      maxValue = array[i]
    }
  }
  let bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1
  let buckets = new Array(bucketCount)
  for (let i = 0; i < buckets.length; i++) {
    buckets[i] = []
  }
  for (let i = 0; i < len; i++) {
    buckets[Math.floor((array[i] - minValue) / bucketSize)].push(array[i])
  }
  array.length = 0
  for (let i = 0; i < buckets.length; i++) {
    insertSort(buckets[i])
    for (let j = 0; j < buckets[i].length; j++) {
      array.push(buckets[i][j])
    }
  }
  return array
}

const array = [6, 7, 8, 9, 0, 5, 4, 3, 2, 1];
const arrayRes = bucketSort(array)
console.log('bucketSort result', arrayRes)

小结

YzjYfy1x2NIq2SdaXIuvO2SIZ0Yeu6w86Y_SbdkPUYU.png

9pNUdJrVf2UDs0IYdQ5G7o0OrgduA6eJQ0jN4PJl8rA.png