顺序查找:在python list中,数据项存储位置称为下标(index),通过下标,我们就可以按照顺序来访问和查找数据项
无序表的循序排序
顺序查找的算法复杂度是O(n)
无序表循序排序搜索的比对
Case |
Bset Case |
Worst Case |
Average Case |
item is present |
1 |
n |
n/2 |
item is not present |
n |
n |
n |
有序表的循序排序
顺序查找的算法复杂度是O(n)
有序表循序排序搜索的比对
Case |
Bset Case |
Worst Case |
Average Case |
item is present |
1 |
n |
n/2 |
item is not present |
1 |
n |
n/2 |
二分查找体现解决问题典型策略:分而治之
二分法也适用递归算法来实现
这个递归调用使用列表切片,而切片操作的复杂度是O(k),这样会使整个算法的时间复杂度稍有增加
项数 |
分割次数 |
1 |
n/2 |
2 |
n/4 |
… |
… |
i |
n/2^i |
所以二分查找的算法复杂度是O(log(n))
虽然二分查找在时间复杂复杂度上优于顺序查找,但也要考虑到对数据项进行排序的开销
可视化: https://visualgo.net/zh
主流的排序算法可以分为3大类:
十大经典排序算法总结
冒泡排序:对一个列表多次重复遍历,它要比较相邻的两项,并且交换顺序排错的项
算法过程总需要n-1趟,随着趟数的增加,比对次数逐步从n-1减少到1,并包括可能发生的数据项交换
对比次数是 1 ~ n-1 的累加:1/2 n²-1/2 n
比对的时间复杂度是O(n²)
python版本
js版本
优势:无需任何额外的存储空间开销(顺序表、链表都适用)
短路冒泡排序
python版本
js版本
冒泡排序算法每一轮都是从左到右,并进行单向的位置交换的
鸡尾酒排序的元素比较和交换过程是双向的
python版本
js版本
选择排序提高了冒泡排序的性能,它每遍历一次列表只交换一次数据,即进行一次遍历时找到数据的最大的项,完成遍历后,再把它交换到正确的位置
python版本
js版本
插入排序 总是维持一个位置靠前的已排好的子表,然后每一个新的数据项被“插入”到前面的子表里,排好的子表增加一项(类似整理扑克牌)
算法复杂度仍是O(n²)
由于移动操作仅包含1次赋值,是交换操作的 1/3,所以插入排序性会较好一些
python版本
js版本
python版本
js版本
希尔排序(缩小间隔排序) 它以插入排序为基础,将原来要排序的列表划分为一些子列表,再对每一个子列表进行插入排序,再对每一个子列表执行插入排序
这里有一个含九个元素的列表,如果我们以3为间隔来划分,就会出现三个子列表,每一个可以执行插入排序
由于每趟都能使得列表更加接近有序,这过程会减少很多原先需要的“无效”比对
解释:
gap=len(arr)/2
,缩小增量继续以 gap=gap/2
的方式gap=len(arr)/2=x
,整个数组分成了x组gap=gap/2
,整哥数组分成了 x/2 组python版本
js版本
js另一个版本(易理解)
自顶向下细分,自底向下合并
归并排序 是递归算法,思路是将数据表持续分裂为两半,对两半分别进行归并排序
归并排序分为两个过程来分析:分裂和归并
具体步骤
if (end-start<1)return
mergeSort(array, start, mid)
mergeSort(array, mid+1, end)
python版本
python另一个版本
js版本
快速排序思路:依据一个“中值”数据项来把数据表分为两半:小于中值的一般和大于中值的一般,然后每部分分别进行快速排序(递归)
分裂数据表的目标:找到“中值”的位置
分裂数据表的首端
具体步骤
quickSort(array, left, partitionIndex-1)
quickSort(array, partitionIndex+1, right)
python版本
c版本(易理解)
js版本