排序中的快排很容易被百度面到
排序是将乱序变成有序,对于js这门语言来说,本身是不难的,因为自带一个sort
方法,但是面试的时候面试官肯定不会让你用这个方法去实现排序,所以你还是得掌握下五种排序问题
算法中排序可以分为两类,一个是基础排序算法,一个是进阶排序算法,基础排序算法有冒泡排序,选择排序,插入排序,进阶排序算法有快速排序,归并排序,下面依次讲解,均以升序为例
基础排序算法
基础排序容易想到,但是效率低
冒泡排序
思想:重复遍历数列,依次比较两个相邻的元素,顺序错误则交换位置,直到没有任何元素需要交换为止
既然是相邻,那么第一个元素若是下标i
,那么第二个就是i + 1
,顺序不同则交换位置,这里我们可以直接用解构写法去交换位置
ini
let arr = [2, 3, 1, 4, 5]
// 2,1,3,4,5
// 1,2,3,4,5
function bubbleSort(arr){
const len = arr.length
for(let i = 0; i < len; i++){
for(let j = i + 1; j < len; j++){
if(arr[i] > arr[j]){
// arr[i] = arr[j]
// temp = arr[i]
// arr[j] = temp
[arr[i], arr[j]] = [arr[j], arr[i]]
}
}
}
return arr
}
空间复杂度为0
,时间复杂度为n * n
选择排序
思想:每次从待排序的元素中选择最小的元素与第一个元素互换位置,然后从剩余的未排序元素中继续选择最小的元素,与待排序的第一个元素互换位置,直到顺序为止
两层循环,第一层确定好最小元素的下标,然后第二层去找是否有比最小值更小的元素,找到后会确定最终的最小元素的下标,然后再去比较下标,下标是否变更了,变更了就去互换位置
ini
let arr = [5, 3, 2, 4, 1]
// 1, 3, 2, 4, 5
// 1, 2, 3, 4, 5
function selectSort(arr){
const len = arr.length
let minIndex
for(let i = 0; i < len; i++){
minIndex = i
for(let j = i; j < len; j++){
if(arr[j] < arr[minIndex]){
minIndex = j
}
}
if(minIndex != i){
[arr[i], arr[minIndex]] = [arr[minIndex], arr[i]]
}
}
return arr
}
空间复杂度为0
,时间复杂度为n * n
插入排序
思想:将数组分为已排序和未排序的两部分,初始时已排序部分只包含第一个元素,然后逐步将未排序部分的元素插入到已排序部分的正确位置,直到所有元素都被排序完
先不管第一个元素,因为是有序的,先拿到第二个元素,从下标1
开始,现在开始插队,j - 1
代表有序中的下标,只要该元素比后面无序的第一个大,那就将其插入到有序的前一个(这个过程是先占好位置,再赋值新值过去),j--
使新元素能够插入到能插入的最前面去
ini
let arr = [5, 3, 2, 4, 1]
// 3, 5, 2, 4, 1
// 2, 3, 5, 4, 1
// 2, 3, 4, 5, 1
// 1, 2, 3, 4, 5
function insertSort(arr){
const len = arr.length
let temp
for(let i = 1; i < len; i++){
temp = arr[i]
let j = i
while(j > 0 && arr[j - 1] > temp){
arr[j] = arr[j - 1]
j--
}
arr[j] = temp
}
return arr
}
空间复杂度为0
,时间复杂度为n * n
进阶排序算法
快速排序(快排)
快排考察的最多,快排之所以称之为快排就是因为快,所以时间复杂度肯定小于
n * n
并且快排的代码实现非常简单
思想:采用分而治之的思想,通过一趟排序将数组分割成独立的两部分,其中一部分的元素都要比另一部分的元素小,然后对这两部分继续递归地进行快排,直到整个序列有序
基准值可从任意位置取,这里我取第一个,比基准值小的放左边,大的放右边,然后分别对两边进行相同操作,既然是递归,那就需要有个出口,就是当数组的长度为1时
css
let arr = [5, 1, 3, 6, 2, 4, 7]
// [5, 1, 3, 4, 2] [6, 7]
// [1, 2] [3, 5, 4] [6] [7]
// [1] [2] [3, 4] [5] [6] [7]
// [1] [2] [3] [4] [5] [6] [7]
function quickSort(arr) {
if(arr.length <= 1) return arr
const len = arr.length
const base = arr[0]
let left = [], right = []
for(let i = 1; i < len; i++){
if(arr[i] < base){
left.push(arr[i])
}else{
right.push(arr[i])
}
}
return [...quickSort(left), base, ...quickSort(right)]
}
空间复杂度为n
,时间复杂度为n * log(n)
归并排序
归并排序比快排要难些
思想:依旧是采用分而治之的思想,将数组不断地分割成两个子数组,直到每个数组只有一个元素,然后再将相邻地子数组两两合并,如何划分就如何合并,但是合并过程中需要排序,此时的排序比较两部分的第一部分,小的就放前面
合并的过程就是排序的过程,因此得名归并排序
ini
let arr = [5, 1, 3, 6, 2, 4, 7]
function mergeSort(arr) {
if (arr.length <= 1) return arr
const mid = Math.floor(arr.length / 2);
const leftArr = arr.slice(0, mid);
const rightArr = arr.slice(mid);
const merge = (leftArr, rightArr) => {
let res = [];
let leftIdx = 0;
let rightIdx = 0;
// 比较左右两部分的元素,依次将较小的元素加入结果数组中
while (leftIdx < leftArr.length && rightIdx < rightArr.length) {
if (leftArr[leftIdx] < rightArr[rightIdx]) {
res.push(leftArr[leftIdx]);
leftIdx++;
} else {
res.push(rightArr[rightIdx]);
rightIdx++;
}
}
// 将剩余的元素加入结果数组
while (leftIdx < leftArr.length) {
res.push(leftArr[leftIdx]);
leftIdx++;
}
while (rightIdx < rightArr.length) {
res.push(rightArr[rightIdx]);
rightIdx++;
}
return res;
}
return merge(mergeSort(leftArr), mergeSort(rightArr));
}
空间复杂度为n
,时间复杂度为n * log(n)
最后
以上五种排序算法你都需要做到可以手写,尤其是快排最容易被问到
另外有不懂之处欢迎在评论区留言,如果觉得文章对你学习有所帮助,还请"点赞+评论+收藏"一键三连,感谢支持!