一、二分查找
首先建立一个列表(输入时确保数字有序),然后使用二分查找寻找要查找元素的下标。此处有两个知识点,一个是建立数字列表的推导式:
My_list = [int(i) for i in input().split()]
其实也可以用input().split()转换为列表,然后用for循环将其转化为int类型赋值到一个新的空列表中,不过那样太麻烦了。然后是关于运算符,“//”是取整除,用二分查找时必须用整除,不然会报错为float不能作为下标,以下是二分查找的代码实现:
import sys
def EF(lis,find_val):
low = 0
high = len(lis)-1
while low <= high:
mid = (low+high) // 2 # //表示向下取整
if find_val > lis[mid]:
low = mid+1
elif find_val < lis[mid]:
high = mid-1
elif find_val == lis[mid]:
return mid
st1 = [int (i) for i in input().split()]
print(EF(st1,4)+1)
二分查找的效率为O(logN)
二、冒泡排序
步骤:
1.指向数组中相邻的两个元素(最开始是数组开头的两个元素),并比较它们的大小。
2.如果它们的顺序错了,就将它们两个的位置互换,如果顺序已经正确,就什么都不做。
3.将两个指针右移一格。重复第1、2步,直至指针到达数组末尾。
注意:这里的前三步骤其实是一个轮回,这个轮回结束后,最大值将被放到数组的最后,就好像最大的气泡冒出了水面一样。而冒泡排序就是不断地重复这一轮回的过程,直至整个数组的顺序正确。
以下是冒泡排序的代码实现,其实也可以用两个for循环进行排序:
import sys
st1 = [int(i) for i in input().split()]
def maopao_sort(list):
un_sorted_len = len(list)-1
sorted = False
while not sorted:
sorted = True
for i in range(un_sorted_len):
if list[i]>list[i+1]:
sorted = False
list[i],list[i+1] = list[i+1],list[i]
un_sorted_len = un_sorted_len - 1
maopao_sort(st1)
print(st1)
冒泡排序的时间复杂度是O(N*2),也称二次时间,这个时间复杂度多出现于嵌套循环中,即两个for循环嵌套
三、选择排序
步骤:
1.从左到右检查数组的每个数字,找出值最小的那个,我建议你用一个单独的变量来记住检查过的数字的最小值。
2.知道本次检查的最小值后,将其与本次检查的起点交换位置,第一次是0,第二次是1,以此类推
3.重复前两步,直至整个数组排好序
import sys
st1 = [int(i) for i in input().split()]
def choose_sort(list):
for i in range(len(list)):
lowest_num = i
for j in range(i+1,len(list)):
if list[j] < list[lowest_num]:
lowest_num = j
if lowest_num != i:
list[lowest_num],list[i] = list[i],list[lowest_num]
choose_sort(st1)
print(st1)
选择排序的时间复杂度是O(N*2),但实际上它比冒泡排序的效率要快一倍左右,即实际的效率应为O(N*2/2),但大O记法忽略常数,所以与冒泡排序一样。
四、插入排序
步骤:
1.在第一轮里,先将索引1的值移走,用一个临时变量保存,这样索引一就有一个空位
2.将空隙左侧的每一个值与临时变量的值进行比较,如果左侧的值大于临时变量的值,就将该值右移一格,随着值右移,空隙会左移,如果遇到比临时变量小的值,或者空隙已经到达了数组的最左端,就结束平移阶段。
3.将临时变量放入空隙
4.重复前三个步骤,直至数组有序
import sys
st1 = [int(i) for i in input().split()]
def insert_sort(list):
for i in range(1,len(list)):
flag = i
val = list[flag]
while flag>0 and list[flag-1]>val: #list[flag]<val 从大到小
list[flag] = list[flag-1]
flag-=1
list[flag] = val
insert_sort(st1)
print(st1)
插入排序的时间复杂度为O(N*2),在最坏情况下是这样的,但在平均情况下,插入排序其实是优于前两种排序的。
五、快速排序
为了省去重复编写排序算法的烦恼,大部分编程语言都有自己的排序函数,其中很多函数依赖的就是快速排序算法,尽管在最坏情况下它的时间复杂度与插入排序和选择排序差不多,但在平均情况下它的表现的确足够优异。
快速排序依赖一个名为分区的概念,下面我们先对这个概念进行一下了解:
分区指从数组随机选取一个值,用它为轴,将比它小的值放在它左边,比它大的值放在右边,从技术上讲,选任意值为轴都可以。
具体步骤为:首先选取一个值为轴,可以选取最右边的值为轴,然后放置指针,它们应该分别指向除去轴元素的数组的最左和最右的元素。然后开始进行分区,步骤如下:
1、左指针逐个向右移动,遇到大于等于轴的值时停下
2、右指针逐个向左移动,遇到小于等于轴的值时停下
3、将两指针指向的值换位置
4、重复上述步骤,直至两指针重合或者左指针移动到右指针右边
5、将轴与左指针所指的值交换位置
分区完成时,轴左侧的值肯定比轴小,右侧的值肯定比轴大,所以轴的位置也就确定了。需要注意的是,这仅仅是第一次分区,轴两侧肯定还有些数字的顺序是错误的,所以接下来要重复进行分区的操作。
上面讲的是分区的具体步骤,而快速排序严重依赖分区,它的运行方式如下:
1、将数组分区,使轴到正确的位置上去
2、对轴左右两侧的数组递归重复第1、2步,也就是说两个子数组也需要各自进行分区,然后再分区再分区直至顺序正确。
3、当分出的子数组长度为0或1时,达到我们的要求,无需操作
对于这一块的知识,个人认为了解其原理即可,你并不需要编写快速排序的程序,很多时候自己编写的不知道BUG出在哪的程序完全可以用一个sort函数替代。这会让你产生一种挫败感,不要为了编程而编程,前人的成果在那里放着呢,能用就用。
快速排序的时间复杂度为O(NlogN),最坏情况下时间复杂度为O(N*2)
我们一般谈算法的速度指的并不是时间,而是随着输入的增加,其运行时间将以什么样的速度增加。