一、复习:
递归的两个特点:
1、调用自身。
2、结束条件。
1 1.deffunc1(x)2 print(x)3 func1(x-1)4
5
6 2.deffunc2(x)7 if x>0:8 print(x)9 func2(x+1)10
11
12 3.deffunc3(x)13 if x>0:14 print(x)15 func3(x-1)16
17
18 4.deffunc4(x)19 if x>0:20 func4(x-1)21 print(x)
看上列代码如果是func1跟func2就是无限循环,没有合理的结束条件。func3跟func4就是有合理条件,可以循环结束。
ps:但是func3跟func4虽然都没问题。但是print 的方式并不同,func3输出5.3.2.1。但是func4的输出结果是1.2.3.4.5 因为他每次循环是没有走print就进入了下一个循环 之中,往外出的时候才会进行打印。
二、时间复杂度
类比生活中的一些事件,估计时间:
1.眨一下眼 一瞬间/几毫秒
2.口算“29+68” 几秒
3.烧一壶水 几分钟
4.睡一觉 几小时
5.完成一个项目 几天/几星期/几个月
6.飞船从地铁飞出太阳系 几年
时间复杂度的表示方式
1 print('Hello World')2 print('Hello Python')3 print('Hello Algorithm')4 #用时间复杂度来讲是O(1)
5
6 for i inrange(n):7 print('Hello World')8 for i inrange(n):9 print('Hello World')10 #用时间复杂度来讲是O(n²)
11
12 for i inrange(n):13 for i inrange(n):14 print('Hello World')15 #用时间复杂度来讲是O(n²)
16
17 while n > 1:18 print(n)19 n = n // 2
20 #用时间复杂度来讲是O(logn)
时间复杂度-小结:
1.时间复杂度是用来估计算法运行事假你的一个式子(单位)。
2.一般来说,时间复杂度高的算法比复杂度低的算法慢。
3.常见的时间复杂度(按效率排序)
O(1)
4.不常见的时间复杂度(看看就好)
O(n!) O(2^n) O(n^n)
5.如何一眼判断时间复杂度?
循环减半的过程---O(logn)
几次循环就是n的几次方的复杂度
三、空间复杂度
1.空间复杂度:用来评估算法内存占用大小的一个式子
2.“空间换时间”
四、列表查找:从列表中查找指定元素
输入:列表、待查找元素
输出:元素下标或未查到元素
顺序查找:
从列表第一个元素开始,顺序进行搜索,直到找到为止。
1 defordinary_lookup(number):2 dict = range(1000)3 for i indict:4 if i ==number:5 print(i)6 break
7 ordinary_lookup(200)
二分查找
从有序列表的候选区data[0:n]开始,通过对待查找的值与候选区中间值的比较,可以使候选区减少一半。
1 importtime,random2
3 defcal_time(func):4 def wrapper(*args,**kwargs):5 ti =time.time()6 x = func(*args,**kwargs)7 ti2 =time.time()8 print('time cost:',func.__name__,ti2-ti)9 returnx10 returnwrapper11
12 @cal_time13 defbin_search(data_set,val):14 low =015 high = len(data_set) - 1
16 while low <=high:17 mid = (low + high)//2
18 if data_set[mid] ==val:19 returnmid20 elif data_set[mid] <21 low="mid">
22 else:23 high = mid - 1
24 return
25
26
27 def_binary_search(dataset, find_num):28 if len(dataset) > 1:29 mid = int(len(dataset) / 2)30 if dataset[mid] == find_num: #find it
31 #print("找到数字", dataset[mid])
32 pass
33 elif dataset[mid] > find_num: #找的数在mid左面
34 #print("\033[31;1m找的数在mid[%s]左面\033[0m" % dataset[mid])
35 returnbinary_search(dataset[0:mid], find_num)36 else: #找的数在mid右面
37 #print("\033[32;1m找的数在mid[%s]右面\033[0m" % dataset[mid])
38 return binary_search(dataset[mid + 1:], find_num)39 else:40 if dataset[0] == find_num: #find it
41 #print("找到数字啦", dataset[0])
42 pass
43 else:44 pass
45 #print("没的分了,要找的数字[%s]不在列表里" % find_num)
46
47 @cal_time48 defbinary_search(data_set, val):49 return_binary_search(data_set, val)50 #不要在递归里面直接加装饰器会无限调用。
51 #循环要比递归有效率
52 #切片是一个特别耗费时间的操作
53
54 data = list(range(100000))55 bin_search(data,152)56 binary_search(data, 152)
练习:使用二分查找法,进行查找相应的id号码。
1 defrandom_list(n):2 ids = list(range(1001,1001+n))3 result =[]4 a1 = ['周','x','x,'x','x','x','x','x','x']
5 a2 = ['杰','x','x','x','x','x','x','x']6 a3 = ['伦','x','','','x','x','x','x','x','x']7 for i inrange(n):8 age = random.randint(18,60)9 id =ids[i]10 name = random.choice(a1)+random.choice(a2)+random.choice(a3)11 name_dict = {'id':id,'name':name,'age':age}12 result.append(name_dict)13
14 returnresult15
16 #用于生成一个关于姓名的列表包含字典
17
18 defbin_search(val):19 data_set = random_list(10000)20 low =021 high = len(data_set) - 1
22 while low <=high:23 mid = (low + high)//2
24 if data_set[mid]['id'] ==val:25 returnmid26 elif data_set[mid]['id'] <27 low="mid">
28 else:29 high = mid - 1
30 return
31 print(bin_search(1160))32
33 #用二分查找进行查找生成列表内的id号在第几个
各种排序演示网站http://www.atool.org/sort.php
五、列表排序:将无序列表变为有序列表
1.应用场景:
各种榜单
各种表格
给二分排序用
给其他算法用
2.使用方式
输入:无序列表
输出:有序列表
分为生序和降序
3.排序low b 三人组:
冒泡排序
选择排序
插入排序
4.快速排序
5.排序NB两人组:
堆排序
归并排序
6.什么人用的排序
基数排序
希尔排序
桶排序
冒泡排序
首先,列表每两个相邻的数,如果前边的比后面的打,那么交换这两个数...
需要记住两个概念,趟,无序区。
时间复杂度:O(n²)
1 def bubble_sort(li):2 for i in range(len(li)-1): #记录多少趟3 flag =False4 for j in range(0,len(li)-i-1): #交换了多少次5 if li[j] > li[j+1]:6 li[j],li[j+1] = li[j+1],li[j] #交换7 flag =True8 ifnot flag:9 break
选择排序
一趟便利记录最小的数,放到第一个位置;
再一趟遍历记录剩余列表中最小的数,继续放置;
需要记住两个概念,无序区,最小数的位置。
时间复杂度:O(n²)
1 defselect_sort(li):2 for i in range(len(li)-1):3 min_loc =i4 for j in range(i+1,len(li)):5 if li[j]
插入排序
列表被分为有序区和无序区两个部分。最初有序区只有一个元素。
每次从无序区选择一个元素,插入到有序区的位置,直到无序区变空。
需要记住两个概念,摸到的牌,手里的牌。
时间复杂度:O(n²)
1 definsert_sort(li):2 for i in range(1,len(li)):3 tmp =li[i]4 j = i - 1
5 while j>=0 and li[j] >tmp:6 li[j+1] =li[j]7 j = j - 1
8 li[j+1] = tmp
快速排序:快
写好的排序算法里最快的
快的排序算法里最好写的
时间复杂度:O(nlogn)
需要记住两个概念,整理,递归。
快排的思路:
1.取一个元素p(第一个元素),使元素p归位;
2.列表被p分成两个部分,左边都比p小,右边都比p大;
3.递归完成排序。
1 defpartition(data,left,right):2 tmp =data[left]3 while left < right and left <4 while data>=tmp:5 right = right - 14>
6 data[left] =data[right]7 while left < right and data[left] <=tmp:8 left = left +1
9 data[right] =data[left]10 data[left]=tmp11 returnleft12
13 defquick_sort(data,left,right ):14 if left <15 mid="partition(data,left,right)16" quick_sort>
堆排序--树与二叉树简介
树是一种数据结构 比如:目录结构
树是一种可以递归定义的数据结构
树是由n个节点组成的集合:
如果n=0,那这是一颗空树;
如果n>0,那存在1个节点作为树的根节点,其他节点可以分为m个集合,每个集合本身又是一棵树。
一些概念
根节点、叶子节点
树的深度(高度)
树的度
孩子节点/父节点
子树
特殊且常用的树--二叉树
二叉树:度不超过2的树(节点最多有两个叉)
两种特殊二叉树
满二叉树
完全二叉树
二叉树的存储方式
链式存储方式
顺序存储方式(列表)
父节点和左孩子节点的编号下标有什么关系?
0-1 1-3 2-5 3-7 4-9 i - 2i+1
父节点和右孩子节点的编号下标有什么关系
0-2 1-4 2-6 3-8 4-10 i - 2i+2
堆:
大根堆:一颗完全二叉树,满足任一节点都比其孩子节点大
小根堆:一个完全二叉树,满足任一节点都比其孩子节点小
堆排序过程
1.建立堆
2.得到堆顶元素,为最大元素。
3.去掉堆顶,将堆最后一个元素放到堆顶,此时可通过一次调整重新使堆有序。
4.堆顶元素为第二大元素。
5.重复步骤3,直到堆变空。
时间复杂度:O(nlogn)
1 def sift(data,low,high): #调整
2 i =low3 j = 2*i+1
4 tmp=data[i]5 while j<=high: #省长已经是村民了
6 if j+1 <=high and data[j]< data[j+1]:7 j+=1
8 if tmp
12 else: #省长能罩住下一级孩子
13 break
14 data[i] =tmp15
16 defheap_sort(data):17 n =len(data)18 for i in range(n//2-1,-1,-1): #建堆时low变high不变 i代表low
19 sift(data,i,n-1)20 #建堆完成
21 for j in range(n-1,-1,-1): #j代表high ,挨个出数时 high变low不变
22 data[0],data[j] =data[j],data[0]23 sift(data,0,j-1)
归并排序
假设现在的列表分成两段有序,如何将其合成为一个有序列表
两各列表都是有序列表,从第一个数据拿出来进行对比,如果小的数据就拿出来。
时间复杂度:O(nlogn)
这种操作我们叫做一次归并。
分解:将列表越分越小直至分成一个元素。
一个元素是有序的。
合并:将两个有序列表归并,列表越来越大。
1 defmerge(data,low,mid,high):2 i =low3 j = mid+1
4 ltmp =[]5 while i <=mid and j<=high:6 if data[i]<=data[j]:7 ltmp.append(data[i])8 i += 1
9 else:10 ltmp.append(data[j])11 j += 1
12 while i<=mid:13 ltmp.append(data[i])14 i += 1
15 while j <=high:16 ltmp.append(data[j])17 j += 1
18 data[low:high+1] =ltmp19 #j = 0
20 #for i in range(low,high+1):
21 #data[i]=ltmp[j]
22 #j+=1
23
24 defmerge_sort(data,low,high):25 if low <26 mid="(low+high)//2</p">
27 merge_sort(data,low,mid)28 merge_sort(data,mid+1,high)29 merge(data,low,mid,high)
希尔排序
希尔排序是一种分组插入排序算法。
首先取一个整数d1 = n/2,将元素分为d1个组,每组相邻量元素之间距离为d1,在各组内进行直接插入排序;
取第二个整数d2 = d1/2,重复上述分组排序过程,直到di=1,既所有元素在同一组内进行直接插入排序。
希尔排序每趟并不适这些元素有序,而是使整体数据越来越接近有序;最后一趟排序使得所有数据有序。
排序-小结
快速排序、堆排序、并归排序 三种排序算法的时间复杂度都是O(nlogn)
一般情况下,就运行时间而言:
快速排序
三种排序算法的缺点:
快速排序:计算情况下排序效率低;不稳定
并归排序:需要额外的内存开销
堆排序:在快的排序算法中相对较慢;不稳定
排序方法
最坏情况
平均情况
最好情况
稳定性
代码复杂度
冒泡排序
O(n²)
O(n²)
O(n²)
稳定
简单
直接选择排序
O(n²)
O(n²)
O(n²)
不稳定
简单
直接插入排序
O(n²)
O(n²)
O(n²)
稳定
简单
快速排序
O(n²)
O(nlogn)
O(nlogn)
不稳定
较复杂
堆排序
O(nlogn)
O(nlogn)
O(nlogn)
不稳定
复杂
归并排序
O(nlogn)
O(nlogn)
O(nlogn)
稳定
较复杂
希尔排序
O(1.3n)
不稳定
较复杂
ps:python 内置函数有堆的使用 可以百度自己查询使用方法 heapq模块
26>15>27>21>