目录
一、顺序查找
代码实现
时间复杂度
二、二分查找(Binary Search)
基本思路
示例:在这个列表中查找 第四个元素 25。
代码实现(非递归)
递归实现:
代码如下
时间复杂度: O(log2n)
三、冒泡排序 (Bubble Sort)
1、基本思路:
2、代码实现(1.0)
3、代码实现(2.0)
4、代码实现(3.0)
四、鸡尾酒排序(Cocktail Sort/Shaker Sort)
1.基本思路
2.代码实现;
3.评价:
arr = [12,53,25,66,52,1,7,5,8,3.14,85]
n = int(input("请输入要查找的数字哈"))
ok = False # 判断是否找到
for each in arr:
if each == n:
ok = True
break # 找到了就退出循环
if ok:
print("找到了!")
else:
print("没找到。")
eg:输入 85 输出 "找到了!"
其时间复杂度是O(n)
如果一个序列中数据元素的个数为n,且每个元素被查找的概率是均等的(1/n),在查找成功的情况下,第1、2、3、…、n元素的比较次数分别为1、2、3、…、n,因此,查找成功的情况下查找一个元素的平均比较次数是1(1/n)+2(1/n)+...+n(1/n)=(n+1)/2,即平均需要比较的次数是表长的一半。
假如要在一个有序序列 li 中查找某个元素item,则可以让item首先和 li 的中间元素比较
• 如果相等,则成功;
• 如果小于中间元素,则在左半区间查找;
• 如果大于等于中间元素,则在右边半区间查找。
L:左位置
H:右位置
Middle:中间位置
def binarySearch(li, v):
L = 0 # 区间左端点
H = len(li)-1
OK = False
while L
输出:
可分解为三个子问题:
(1)和中间的元素的直接比较问题;
(2)左区间上的查找问题;
(3)右区间上的查找问题。
# 二分法递归实现
def binarySearch(li,v):
if len(li) == 0:
return -1
else:
Middle = len(li)//2
if li[Middle] == v:
return Middle
else:
if v< li[Middle]: # 左区间
return binarySearch(li[:Middle],v)
else: # 右区间
return binarySearch(li[Middle+1:],v)
def pr(l,v):
index = binarySearch(l,v)
if index !=-1:
print("你所查找的数字在第{}个元素".format(index+1))
else:
print("没找到这个数字!")
test = [5,7,12,25,34,37,44,55,58,80,82,105,52]
pr(test,25)
pr(test,520)
输出如下
你所查找的数字在第4个元素
没找到这个数字!
二分查找的基本思想是将n个元素分成大致相等的两部分,取a[n/2]与x做比较,如果x=a[n/2],则找到x,算法中止;如果xa[n/2],则只要在数组a的右半部搜索x.
时间复杂度即是while循环的次数。
总共有n个元素,
渐渐跟下去就是n,n/2,n/4,....n/2^k(接下来操作元素的剩余个数),其中k就是循环的次数
由于你n/2^k取整后>=1
即令n/2^k=1
可得k=log2n,(是以2为底,n的对数)
所以时间复杂度可以表示O(h)=O(log2n)
冒泡排序的思想是对相邻元素比较大小,如果逆序就交换它们。
对于n个元素的序列,需要进行n-1趟冒泡。
li = [49,38,27,97,76,13,27,49]
index = 1
for i in range(len(li)-1,0,-1): # 外循环 次数n-1
for j in range(i):
if li[j] > li[j+1]:
li[j],li[j+1] = li[j+1],li[j] # 假如前面的大于后面的元素,则交换
print("第{1}轮排序:{0}".format(li,index))
index +=1
print("排序完成后:{}".format(li))
输出结果:
可以发现:其实在第五轮就已经排好序了,可是还是进行了后面的排序
那么有没有改进方法?
基本思路:在上面情况下,如果能判断出数列已经有序,并做出标记,那么剩下的几轮排序就不必执行了。
# 2.0
def bubble_sort(array):
index = 1
for i in range(len(array)-1):
# 有序标记
is_sorted = True
for j in range(len(array)-i-1): # 第i轮排序进行n-i-1次交换
if array[j] > array[j+1]:
array[j],array[j+1] = array[j+1],array[j]
# 有元素交换,所有不是有序的
is_sorted = False
if is_sorted:
break
else: # 进行了交换
print("第{1}轮排序:{0}".format(array,index))
index += 1
li = [49,38,27,97,76,13,27,49]
bubble_sort(li)
print("最后排序的结果为\n{}".format(li))
输出结果为:
基本思路:假如有一这样的序列:
这个数列的特点是,前半部分的元素无序,后半部分的元素按升序排列,并且后半部分元素中的最小值也大于前半部分元素的最大值。
按2.0来看:
第一轮:将执行n-i-1即为7轮
3和4,不变
4和2,交换
4和1,交换
4和5,不变
5和6,不变
6和7,不变
7和8,不变
那么问题在哪:在后半部分已经是有序的了,可是每一轮还是白白地比较了许多次。
解决:这个问题的关键点在于对数列有序区的界定。
我们可以在每一轮排序后,记录下最后一次元素交换的位置,该位置即为无序数列的边界,再往后就是有序区了。
代码如下
# 3.0
def bubble_sort(array):
index = 1
# 记录最后一次交换位置
lase_exchange_index = 0
# 无序数列的边界,比较只用比到这里
sort_border = len(li)-1
for i in range(len(array)-1):
# 有序标记
is_sorted = True
for j in range(sort_border):
if array[j] > array[j+1]:
array[j],array[j+1] = array[j+1],array[j]
# 有元素交换,所有不是有序的
is_sorted = False
# 更新无序边界
lase_exchange_index = j
sort_border = lase_exchange_index
if is_sorted:
break
else: # 进行了交换
print("第{1}轮排序:{0}".format(array,index))
index += 1
li = [3,4,2,1,5,6,7,8]
bubble_sort(li)
print("最后排序的结果为\n{}".format(li))
输出结果:
鸡尾酒排序是基于冒泡排序的一种升级排序法。
鸡尾酒排序的元素比较和交换过程是双向的
奇数轮从左往右,偶数轮从右往左
eg:由8个数字组成一个无序数列{2,3,4,5,6,7,8,1},希望对其进行从小到大的排序。
按照冒泡排序看,只有1位置不对,却还要进行七轮排序:
import time
def cock_tail_sort(li):
for i in range(len(li)//2):
# 有序标记
is_sorted = True
# 奇数轮,从左往右比较和交换
for j in range(i,len(li)-i-1): # 第i轮排序进行n-i-1次交换
if li[j] > li[j+1]:
li[j],li[j+1] = li[j+1],li[j]
# 有元素交换,所有不是有序的
is_sorted = False
if is_sorted:
break
# 偶数轮:从右往左
is_sorted = True
for j in range(len(li)-i-1,i,-1): # 第i轮排序进行n-i-1次交换
if li[j] < li[j-1]:
li[j],li[j-1] = li[j-1],li[j]
# 有元素交换,所有不是有序的
is_sorted = False
if is_sorted:
break
li = list([3,4,14,1,5,6,7,8,1,-1,0,9,11])
li1 = [2,3,4,5,6,7,8,1]
cock_tail_sort(li)
print(li)
a = time.time()
cock_tail_sort(li1)
b = time.time()
print("时间为:{}".format(b-a))
print(li1)
输出:
优点是能够在特定条件下,减少排序的回合数;而缺点也很明显,就是代码量几乎增加了1倍。它能发挥出优势的场景,是大部分元素已经有序的情况