一: 插入排序
插入排序与之前学习过的冒泡排序(循环n趟,每趟与所有的数字进行比较,大就交换位置),选择排序(循环n趟,每趟对比(n-i)个数字,找出最小的,将其与i的位置的数字互换)并称为low B三人组哈哈哈,为啥low呢,自然是时间复杂度不够完美~
插入排序的核心思想:
类比斗地主吧。每次将从无序区摸出的牌与手里的牌进行对比,放到正确的位置。
循环n趟,从后往前一次对比,每个数对比i-1次,记录当前的数,如果前面的数比自己大,就将大的数依次往后移,直到移完或者下一个数不再比自己大位置,将自己插入到该位置。
javascript代码:
const insertSort = (arr) => {
for (let i = 1; i <arr.length; i++) {
const temp = arr[i]
let j = i - 1
while(j >= 0 && temp < arr[j]) {
arr[j+1] = arr[j]
j--
}
arr[j+1] = temp
}
return arr
}
console.log(insertSort(arr))
关键点:从第二张牌开始!j是指针,其实位置为当前位置-1
python代码:
def insert_sort(li):
for i in range(1,len(li)):
tmp = li[i]
j = i - 1
while j>=0 and li[j] > tmp:
li[j+1] = li[j]
j-=1
li[j+1] = tmp
return li
二:快速排序
快速排序,能叫这个名字那必然是足够快。
核心思想:递归!!先将一个区间内的元素放到他该在的位置,然后将数据分成左右两个区间,再对区间内的元素递归该过程。
先写伪代码:
假设我们使元素归位的函数叫:partition,那么快速排序伪代码就是:
const quick_sort = (arr, left, right) => {
let mid = null;
if (left < right) {
mid = partition(arr, left, right);
quick_sort(arr, left, mid - 1);
quick_sort(arr, mid + 1, right);
}
}
关键点在于如何将指定区间内的元素归位,也就是partition这个函数咋实现
partition的核心思想:
left, right两个指针,left指向要归位元素的位置,right在区间最后,把要归位的元素暂存起来,左边有个空位,左边是给比该元素小的数的,从右找第一个比该元素小的数,移过去,这时候右边有个空位,右边是给比该元素大的数的,再从左边找第一个比该元素大的数,移过去,当left和right相等的时候,就是该元素的空位。将该元素放到这个位置即可。
代码实现:
const partition = (arr, left, right) => {
let tmp = arr[left]
while (left < right) {
while (left < right && arr[right] >= tmp) {
right--
}
arr[left] = arr[right]
while (left < right && arr[left] <= tmp) {
left++
}
arr[right] = arr[left]
}
arr[left] = tmp
return left
}
2.1:快速排序的缺点
- 最坏情况
- 递归最大深度
一般语言都会有最大递归深度,比如python理论上的最大递归深度是997,虽然可以手动更改最大递归深度,但是递归还是个比较耗内存的操作,这个无法避免。以空间换时间。
最坏情况:一个完全逆序的数组比如 [9,8,7,6,5,4,3,2,1]
这样相当于每次left和right区间只减少了1个数字,其效率与lowB三人组的效率相差不大。
解决办法:随机取一个数与第一位数进行交换,再快排。无法完全避免,但可以大大减少最坏情况出现的概率。