- 插入排序:最普通的排序算法,从数组下标为1的元素开始遍历。拿到当前元素循环与前面的所有元素比较,如果当前元素小于前一位元素则交换位置,否则跳出循环。 动画展示如下图:
代码如下:
function sort(array) {
let arg = array.slice(0); //复制元素避免污染原数组
for (let i = 1; i < arg.length; i++) {
let j = i
while (j > 0) {
if (arg[j] < arg[j - 1]) {
let temp = arg[j]
arg[j] = arg[j - 1]
arg[j - 1] = temp
j--
} else {
break
}
}
}
return arg;
}
- 二分查找:前提需要该数组是有序的。1.先从有序数组的中间元素开始查找,如果与该元素相等则直接返回该索引,否则进行下一步。2.如果指定的元素大于或者小于中间元素,则在大于或小于的那一半区域内查找,重复第一步直到找到目标元素。找不到则返回-1 代码演示如下:
function sort(array, target) {
let i = 0;
let len = array.length - 1;
let mid;
while (i <= len) {
mid = Math.floor((len + i) / 2)
if (array[mid] == target) {
return mid
} else if (array[mid] < target) {
i = mid + 1
} else {
len = mid - 1
}
}
return -1
}
console.log(sort([10, 12, 14, 18, 19], 10))
- 二分插入排序: 每次插入操作前,采用上文中二分查找的方式。查找插入的位置,然后再插入元素(先挪动后再插入) 如果不理解可以参考b站视频: www.bilibili.com/video/BV1iE…
代码如下:
function binaryInsertSort(arr) {
var i, cur, left, right, mid;
for (i = 1; i < arr.length; i++) {
left = 0;
right = i - 1;
cur = arr[i];
while (left <= right) {
mid = Math.floor((left + right) / 2);
if (cur < arr[mid]) {
right = mid - 1;
} else {
left = mid + 1;
}
}
arr.splice(left, 0, arr.splice(i, 1)[0]);
}
return arr;
}
binaryInsertSort([10, 12, 14, 18, 1])
- 希尔排序 图形解释更加清楚如下:
function shellSort(arr) {
let len = arr.length;
// gap 即为增量
for (let gap = Math.floor(len / 2); gap > 0; gap = Math.floor(gap / 2)) {
for (let i = gap; i < len; i++) {
let j = i;
let current = arr[i];
while (j - gap >= 0 && current < arr[j - gap]) {
arr[j] = arr[j - gap];
j = j - gap;
}
arr[j] = current;
console.log(arr)
}
}
}
shellSort([15, 4, 1, 32, 33, 5]);
- 冒泡排序 1、比较相邻的两个元素,如果前一个比后一个大,则交换位置。 2、比较完第一轮的时候,最后一个元素是最大的元素。 3、这时候最后一个元素是最大的,所以最后一个元素就不需要参与比较大小。 代码如下:
function shellSort(arr) {
for (let j = 0; j < arr.length - 1; j++) {
for (let i = 0; i < arr.length - j - 1; i++) {//因为不需要对比最后一位
if (arr[i] > arr[i + 1]) {
let temp = arr[i]
arr[i] = arr[i + 1]
arr[i + 1] = temp
}
}
}
return arr
}
shellSort([15, 4, 1, 10, 33, 5]);
- 选择排序 定义一个最小值minIndex初始化是第一个,循环遍历数组找到比minIndex小的调换位置,继续遍历i+1后面的元素
function shellSort(arr) {
for (let i = 0; i < arr.length; i++) {
let 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]]
}
console.log(arr)
}
console.log(shellSort([15, 4, 1, 10, 33, 5]));
- 归并排序
实现思路如下图(一直觉得不需要分治只需要合并,可能是代码不太好写所以分治)
js代码实现:
function mergeSort(arr) {
let len = arr.length
if (len < 2) {
return arr
}
let middle = Math.floor(len / 2)
//拆分成两个子数组
let left = arr.slice(0, middle)
let right = arr.slice(middle, len)
//递归拆分
let mergeSortLeft = mergeSort(left)
let mergeSortRight = mergeSort(right)
//合并
return merge(mergeSortLeft, mergeSortRight)
}
const merge = (left, right) => {
const result = [];
while (left.length && right.length) {
// 注意: 判断的条件是小于或等于,如果只是小于,那么排序将不稳定.
if (left[0] <= right[0]) {
result.push(left.shift()); //每次都要删除left或者right的第一个元素,将其加入result中
} else {
result.push(right.shift());
}
}
//将剩下的元素加上
while (left.length) result.push(left.shift());
while (right.length) result.push(right.shift());
return result;
};
console.log(mergeSort([15, 4, 15, 10, 33, 5]));
- 快速排序 原理比较简单,取数组第一个元素为中间元素(理论上是任意元素都可以)。循环遍历数组,大于中间元素的放在中间元素的右边,小于等于中间元素的放在左边。重复以上步骤直到数组长度为0即可,代码如下。 此排序方法还有另外一种描述具体可以参考一下如下链接:www.bilibili.com/video/BV1at… js代码如下:
function sort(arr) {
if (arr.length < 1) {
return arr
}
let mid = arr.shift()
let left = [],
right = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] > mid) {
right.push(arr[i])
} else {
left.push(arr[i])
}
}
return sort(left).concat(mid, sort(right))
}
console.log(sort([5, 4, 11, 2, 1]));
- 计数排序(非比较排序) 原理:首先获取数组的最大值,新建一个数组长度为最大值+1用0填充(称为统计数组)。遍历数组获得每个值的出现次数,然后遍历(长度为统计数组的长度)。嵌套循环统计次数大于0的(为了重复元素),添加到新数组即可。
function sort(arr) {
let max = Math.max.apply(null, arr)
let arg = new Array(max + 1).fill(0) //计数数组
let array = [];
for (let i = 0; i < arr.length; i++) {
let idx = arr[i]
arg[idx]++
}
for (let h = 0; h < max + 1; h++) {
for (let k = arg[h]; k > 0; k--) {
array.push(h);
}
}
console.log(array)
}
sort([0, 5, 5, 5, 77, 1, 8, 7])