算法基础之冒泡排序,选择排序,插入排序,快排序
排序算法基础
一.算法衡量标准
问:现在有两个程序,这两个一样程序的运行时间如何衡量?前提是什么?
答:可以通过time模块来获取程序的运行时间进行比较,前提是必须在同硬件环境下(比如:CPU/内存)运行,才有意义
根据上面问题,我们单单使用时间差来衡量程序的快慢没有意义。因此,我们可以根据程序执行的大概次数来衡量程序的快慢。把这种衡量的方式称之为时间复杂度,通过它来用来评估算法运行效率,使用O()来表示
举例:
# 程序 # 时间复杂度
print('Hello World') O(1):表示执行一次
for i in range(n):
print('Hello World') O(n):表示循环执行n次
for i in range(n):
for j in range(n):
print('Hello World') O(n^2):表示循环执行n^2次
for i in range(n):
for j in range(n):
for k in range(n):
print('Hello World') O(n^3):表示循环执行n^3次
print('Hello World')
print('Hello Python')
print(‘Hello Algorithm’) O(1):表示执行一次,没有循环
for i in range(n):
print('Hello World’)
for j in range(n):
print('Hello World') O(n^2):表示循环执行两次,有两个循环
while n > 1: 例:n = 64,则2^6 = 64 即今过6次循环减半
print(n) 程序结束,所以为O(log2^n),或者O(logn) n = n // 2
总结:
-
时间复杂度是用来估计算法运行时间的一个式子(单位)。
-
一般来说,时间复杂度高的算法比复杂度低的算法慢。
-
常见的时间复杂度(按效率排序)
O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)<O(n^2logn)<O(n^3)
-
不常见的时间复杂度(看看就好)
O(n!) O(2n) O(nn) …
-
如何一眼判断时间复杂度?
-
循环减半的过程O(logn)
-
几次循环就是n的几次方的复杂度
-
了解:空间复杂度(占用内存空间大小,也是用O表示)
二.列表排序
将无序列表变为有序列表
应用场景:
各种榜单 各种表格 给二分排序用 给其他算法用
排序low B三人组:
-
冒泡排序:列表每两个相邻的数,如果前边比后边的大,那么交换这两个数。
-
选择排序:选择一个我认为的最小值的索引,然后不断的与列表中的其他数据进行比较,若该索引对应的 值大,则交换这两个数。
-
插入排序:列表被分为有序区和无序区,有序区开始只有一个元素,开始排序时会将第二个元素与第一个
元素(即有序区的初始元素)进行比较,并赋给一个变量,然后比较完根据大小进行顺序排
列,依次往后,不断的将元素从无序区插到有序区内 。
-
快速排序:选取一个元素P归位(一般第一个元素),归位指的是列表被分为两部分,左边的都比其小,
右边的都比其大,然后依次往后递归,直到左边和右边都排序结束
排序NB二人组:
-
堆排序
-
归并排序
没什么人用的排序:
-
基数排序
-
希尔排序:
相邻元素之间距离为d1,然后在各组元素内直接进行插入排序,然后再取d1除以2获得d2,将
所有元素分组每组元素相邻间距为d2,进行插入排序,直到d等于1,这是一个逐渐获得有序序列
-
桶排序
-
素,就在这个元素对应的索引位(比如元素为3,就将索引为3的位置的0元素+1)加1,然后清
三.冒泡排序
时间复杂度:O(n^2)
代码演示:
def bubble_sort(li):
for i in range(len(li)-1):
# 如果一次都没循环成功,说明排序是正确的,则直接跳出结束
flag = True
for j in range(len(li)-1-i):
if li[j] > li[j+1]:
li[j], li[j+1] = li[j+1], li[j]
flag = False
if flag:
return
li = [9,8,7,6,5,4,3,2,1]
bubble_sort(li)
print(li)
四.选择排序
时间复杂度:O(n^2)
代码演示:
def select_sort(li):
for i in range(len(li)):
# 假设最小值为i索引对应的值
minloc = i
for j in range(i+1,len(li)):
if li[minloc] > li[j]:
li[minloc],li[j] = li[j],li[minloc]
li = [9,8,7,6,5,4,3,2,1]
select_sort(li)
print(li)
五.插入排序
时间复杂度:O(n^2)
代码演示:
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 = j-1
li[j+1] = tmp
li = [9,8,7,6,5,4,3,2,1]
select_sort(li)
print(li)
六.快排序
时间复杂度:O(logn)
#归位函数
def partition(li, left, right):
# 设置最小索引值为tmp
tmp = li[left]
while left<right:
# 当右边元素比归位temp大时,一直往左走
while left<right and li[right] >= tmp:
right = right-1
# 当右边某个元素比归位temp小时,该元素传到左边
li[left] = li[right]
# 此时当左边元素比归位temp小时,一直往右走
while left < right and li[left]<=tmp:
left = left+1
# 当左边某个元素比归位temp大时,该元素传到右边
li[right] = li[left]
#全部循环走完,两边指针走到一起,该索引位就是归位的那个值
li[left] = tmp
# 然后将此索引返回出去
return left
def quick_sort(li, left,right): # left表示最小索引,right表示最大索引
if left < right:
# 归位函数,返回值就是位置的索引,分开左右
mid = partition(li, left, right)
# 归位之后再递归
quick_sort(li,left,mid-1)
quick_sort(li,mid+1,right)
li = [8,3,4,5,7,6]
quick_sort(li,0,5)
print(li)
七.希尔排序
时间复杂度:O(1+τ)≈O(1.3n)
def shell_sort(li):
gap = len(li) // 2
while gap > 0
for i in range(gap, len(li)):
tmp = li(i)
j = i - gap
while j > =0 and tmp < li(j):
li[j + gap] = li[j]
j -= gap
li[j + gap] = tmp
gap /= 2
li = [9,8,7,6,5,4,3,2,1]
shell_sort(li)
print(li)
八.计数排序
时间复杂度:O(n)
def count_sort(li):
# 列表生成式,生成一个最大元素+1的都是0的列表
count = [0 for _ in range(45)]
print(count)
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
# 循环给定列表,指定元素所对应的索引位置,有值则加一
for k in li:
count[k] += 1
print(count)
# [0, 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1]
# 清空原li列表
li.clear()
# 根据索引的顺序完成数据的添加,此时索引就是原列表的元素
for k, v in enumerate(count):
print(k,v)
for i in range(v):
li.append(k)
li = [11,3,44,33,22,4,5,32,42,3]
count_sort(li)
print(li)
-
顺序查找
从列表的第一个元素开始,顺序进行搜索,直到找到为止
-
二分查找
从有序列表的候选区data[0:n]开始,通过对待查找的值与候选区中间值进行比较,可以使候选区减少一半
# 递归版二分查找
def bin_serch_rec(data_set,value,low,high):
if low <= high:
mid =(low + high )// 2
if data_set[mid] == value:
return mid
elif data_set[mid]>value
return bin_serch_rec(data_set,vlaue,low,mid-1)
else:
return bin_serch_rec(data_set,value,mid+1,high)
else:
return