一 插入排序
1.1 核心思想
插入排序(Insert ion Sort),其核心思想:将数组中的所有元素(从第二个元素开始,第一个默认已排好序)依次跟前面已经排好的所有元素相比较,如果选择的元素比已排序的元素小,则交换位置,直到全部元素都比较过。
因此,直接插入排序可以用两个循环完成:
第一层循环:遍历待比较的所有数组元素(从第二个元素开始)
第二层循环:将上层循环选择的元素(selected)与已经排好序的所有元素(ordered)相比较,从选择元素的前面一个开始直到数组的起始位置。如果selected < ordered,那么将二者交换位置,继续遍历;反之,留在原地,选择下一个元素。
1.2 过程示意图
排序过程示意图(图片来自于网络):
1.3 python 实现过程
#插入排序
def insert_sort(ls):
#假设左边已排序,右边未排序,每次从右边取一个数,遍历已排序的子序列,直到找到合适的位置
print("before: ",ls)
for j in range(1, len(ls)):
#将该元素与已排序好的前序数组依次比较,如果该元素小,则交换
#range(x, 0, -1):从x倒序循环到0,依次比较
#每次比较如果小于会交换位置,正好按递减的顺序
for i in range(j, 0, -1):
#符合条件则交换
#ls[i] < ls[i - 1]:
# [i], ls[i-1] = ls[i-1], ls[i]
if ls[i] < ls [i - 1]:
temp = ls[i]
ls[i] = ls[i - 1]
ls[i - 1] = temp
print(ls)
print("after: ", ls)
⚠️注意⚠️ 这个地方提供了两种交换方式
(1) 直接交换,中间用 , 连接
(2)借用中间数temp
1.4 实现结果
1.5 时间复杂度
最优时间复杂度:O(n)(升序序列,序列已经处于升序状态)
最坏时间复杂度:O(n2)
稳定性:稳定
二 冒泡排序
2.1 核心思想
-
将序列当中的左右元素,依次比较,保证右边的元素始终大于左边的元素;
( 第一轮结束后,序列最后一个元素一定是当前序列的最大值;) -
对序列当中剩下的n-1个元素再次执行步骤1。
-
对于长度为n的序列,一共需要执行n-1轮比较 (利用while循环可以减少执行次数)
2.2 排序示意图
交换过程示意图(第一次)(来自网络):
2.3 python 代码实现
#冒泡排序
def bubble_sort(ls):
print("before: ", ls)
for j in range(len(ls) -1 , 0, -1):
#j = [len(ls) - 1, len(ls) - 2, ..., 1] 每次需要比较的次数
#i = [0, 1, 2, 3, ..., j - 1] 需要比较的下标
#对于每一轮交换,都将序列当中的左右元素进行比较
#每轮交换当中,序列最后的元素一定是最大的
#因此每轮循环到序列未排序的位置即可
for i in range(j):
if ls[i] > ls[i + 1]:
ls [i], ls[i+1] = ls [i + 1], ls[i]
print(ls)
print("after: ",ls)
if __name__ == "__main__":
ls = [54, 26, 93, 17, 77, 31, 44, 55, 20]
bubble_sort(ls)
2.4 实现结果
2.5 时间复杂度
最优时间复杂度:O(n)(表示遍历一次发现没有任何可以交换的元素排序结束,在内循环可以做一个标识判断,如果首次循环没有任何交换,则跳出)
最坏复杂度:O(n2)
稳定性:稳定
三、选择排序
3.1 核心思想
选择排序( Selection Sort )是一种简单直观的排序算法,基本原理:首先在未排序中找到最小(大)的元素,存放在排序序列的起始位置,然后在从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序的末尾,依次类推,直到所有元素均排序完毕。
选择排序的主要优点与数据移动有关。如果某个元素位于正确的最终位置上,则它不会被移动。选择排序每次交换一对元素,它们当中至少有一个被移到其最终位置上,因此对 n 个元素的表进行排序共进行至多 n - 1次交换。在所有完成依靠交换去移动元素的排序方法中,选择排序属于非常好的一种。
3.2 排序示意图
排序过程,图示(图来源网络):
假设右边为已排序,然后从左边未排序中选择一个最大值,放到右边来。
3.3 python 实现过程
这里代码的思想为:假设左边为已排序,右边为排序。
#选择排序
def selection_sort(ls):
print("before: ", ls)
for i in range (len(ls)-1):
#i = [0, 1, 2, 3, ..., len(ls) - 2]
#j = [i + 1, i + 2, ..., len(ls) - 1]
main_index = i
for j in range(i + 1, len(ls)):
if ls[j] < ls[main_index]:
main_index = j
if main_index !=i:
ls[main_index], ls[i] = ls[i], ls[main_index]
print(ls)
print("after: ", ls)
if __name__ == "__main__":
ls = [54, 26, 93, 17, 77, 31, 44, 55, 20]
selection_sort(ls)
3.4 实现结果
3.5 时间复杂度
最优时间复杂度:O(n2)
最坏时间复杂度:O(n2)
稳定性:不稳定(考虑升序每次选择最大的情况)
四、快速排序
4.1 核心思想
快速排序(Quick Sort),又称为划分交换排序(Partition-exchange Sort),通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要笑,然后在按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
快速排序过程:
① 从数列中选出一个元素,称为“基准”(pivot)。
② 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准大的摆在基准的后面(相同的数,可以放到任意一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
③ 递归(recursive)把小于基准值元素子数列和大于基准值元素的子数列排序。
递归的的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。
4.2 排序过程示意图
4.3 python 实现过程
#快速排序
def quick_sort(ls, start, end):
'''
快速排序-1
low和high分别指向序列的头和尾
low += 1, high -= 1
在low自增的过程中,直到找到大于mid_val的下标
在high自减的过程中,直到找到小于mid_val的下标
然后将这两个值交换
'''
if start >= end:
return
low = start
high = end
mid_val = ls[low]
while low < high:
while low < high and ls[high] > mid_val:
high -= 1
ls[low] = ls[high]
while low < high and ls[low] < mid_val:
low +=1
ls[high] = ls[low]
ls [low] = mid_val
print("mid: ", mid_val, ls)
quick_sort(ls, start, low - 1) #左边的子序列
quick_sort(ls, low + 1, end) #右边的子序列
return ls
if __name__ == "__main__":
ls = [54, 26, 93, 17, 77, 31, 44, 55, 20]
print("before:", ls)
res = quick_sort(ls, 0, len(ls) - 1)
print("quick sort: ", res)
4.4 实现结果
4.5 时间复杂度
最优时间复杂度:O(nlogn)
最坏时间复杂度:O(n2)
稳定性:不稳定
五 二分查找
5.1 基本思想
二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好,其缺点是要求待查找表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。
基本思想:假设表中元素是按升序排序,将表中间位置记录关键字与查找关键字比较,如果两者相等,则查找成功,否则利用中间位置记录分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一个子表。重复以上过程,知道找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
5.2 python实现代码
#二分查找
def binary_search_recursion(ls,item):
n = len(ls)
if n < 1:
return False
mid = n // 2
#与中间值比较
if item == ls[mid]:
return True
#去左边子序列查找
elif item < ls[mid]:
return binary_search_recursion(ls[:mid], item)
#去右边子序列查找
else:
return binary_search_recursion(ls[mid + 1:],item)
if __name__ == "__main__":
ls = [17, 20, 26, 31, 44, 54, 55, 77, 93]
num = int(input("请输入一个整数"))
res = binary_search_recursion(ls, num)
print("查找结果:", res)
5.3 实现结果
5.4 时间复杂度
最优时间复杂度:O(1)
最坏时间复杂度:O(logn)