冒泡排序
N个数字要排序完成,总共进行N-1趟排序,每i趟的排序次数为(N-i)次,所以可以用双重循环语句,外层控制循环多少趟,内层控制每一趟的循环次数
比较两个相邻的项,如果前一项大于后一项则交换他们的位置
每一轮比较,最大的项就会被依次交换(冒泡)到最后
function bubbleSort(arr) {
let len = arr.length;
for (let i = 0; i < len; i++) {
for (let j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j+1]) {//相邻元素两两对比,前一项大于后一项则交换他们的位置
[arr[j + 1], arr[j]] = [arr[j], arr[j + 1]];
}
}
}
return arr;
}
选择排序
选择排序跟冒泡排序非常类似,唯一的区别就是选择排序每次遍历时,将各个元素比较,将最大值或最小值的索引存放在一个变量中,全部比较完了以后,再将该索引上的元素进行就交换。
简单来说就是选择排序是每次遍历交换一次,而冒泡排序每次遍历需要交换多次,因此选择排序一般来说是要比冒泡排序效率高一点的。
const selectSort = function(arr) {
for(let i = 0; i < arr.length - 1; i++) {
let min = i;
for(let j = min; j < arr.length; j++) {
if(arr[j] < arr[min]) {
// 发现比min小的,则重新赋值min
min = j
}
// 将得到的最小值的索引min上的元素与我们初始遍历的位置上的元素交换
const temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
}
}
// 返回排序后的数组
return arr
}
let arr = [45, 66, 1, 19, 34, 80, 2]
console.log(selectSort(arr));
插入排序
-
先把第一个元素做为有序数组
-
把当前索引i指定的元素依次和 [0,i-1] 的有序数组内的元素 比较:比当前元素大的则向后移动其位置,直到找到比当前元素小的元素,插到其后面,得到新的有序数组
-
开始下一轮循环,直到循环完成,返回排序后的数组
const insertSort = (arr) => { // 1. 从索引为1的元素开始向后遍历数组 for(let i = 1; i < arr.length; i++) { let temp = arr[i] // 当前索引i指定的元素(即当前要插入的元素) let j = i // 3. 从右往左将有序区域内的元素与temp比较 while(arr[j - 1] > temp && j > 0) { arr[j] = arr[j - 1] j-- } // 4. 将temp插入到合适的位置 arr[j] = temp } // 返回排序后的数组 return arr }
归并排序
// 归并(合并两个有序数组)
const merge = function(left, right) {
let result = []
while(left.length && right.length) {
if(left[0] < right[0]){
result.push(left.shift())
} else {
result.push(right.shift())
}
}
while(left.length) {
result.push(left.shift())
}
while(right.length) {
result.push(right.shift())
}
console.log('result', result)
return result
}
// 采用自上而下的递归方法拆分再自下而上合并
const mergeSort = function(arr) {
if(arr.length < 2) {
return arr
}
const middle = Math.floor(arr.length/2)
const left = arr.slice(0,middle);
const right = arr.slice(middle);
return merge(mergeSort(left), mergeSort(right))
}
快速排序
方法一:
- 选择数组中间项作为基数,并从数组中取出此基数;
- 定义两个空数组,遍历数组,逐个与基数比对,较小的放左边容器,较大的放右边容器;
- 递归处理两个数组的元素,并将处理后的数据与基数按大小合并成一个数组,返回
改进之处:1)使用splice方法取基准点元素时间复杂度高;2)定义两个数组存储数据空间复杂度更高
const quickSort = function (arr) {
if(arr.length < 2) {
return arr
}
// 抽出基准点元素
const mask = arr.splice(Math.floor(arr.length/2), 1)[0]
const left = []
const right = []
for(let i = 0; i < arr.length; i++) {
if(arr[i] < mask) {
left.push(arr[i])//比基准点小的放在左边数组
} else {
right.push(arr[i])//比基准点大的放在右边数组
}
}
//递归执行以上操作,对左右两个数组进行操作,直到数组长度为 <= 1
return [...quickSort(left), mask, ...quickSort(right)]
}
方法二:
-
通过下标取数组中间项作为基准点
-
创建两个指针,左边的指向数组第一个项,右边的指向最后一个项,移动左指针 i,直到找到一个比基准点大的项,接着,移动右边的指针 j,直到找到一个比基准点小的项,然后交换它们。重复这个过程,直到 i >= j。这个使比基准点小的都在左侧,比基准点大的都在右侧。这一步叫划分操作
-
接着,算法对划分后的小数组(较基准点小的值组成的的小数组, 以及较基准点大的值组成的小数组)重复之前的两个步骤,直到排序完成