python的算法

一、复习:

递归的两个特点:

1、调用自身。

2、结束条件。

 1 1.def func1(x)
 2     print(x)
 3     func1(x-1)
 4 
 5 
 6 2.def func2(x)
 7     if x>0:
 8     print(x)
 9     func2(x+1)
10 
11 
12 3.def func3(x)
13      if x>0:
14         print(x)
15         func3(x-1)
16 
17 
18 4.def func4(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 in range(n):
 7     print('Hello World')
 8         for i in range(n):
 9             print('Hello World')
10 #用时间复杂度来讲是O(n²)
11 
12 for i in range(n):
13     for i in range(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)<O(login)<O(n)<O(nlogn)<O(n²)<O(n²logn)<O(n³)

4.不常见的时间复杂度(看看就好)

  O(n!)  O(2^n)  O(n^n)
5.如何一眼判断时间复杂度?

  循环减半的过程---O(logn)

  几次循环就是n的几次方的复杂度

三、空间复杂度

1.空间复杂度:用来评估算法内存占用大小的一个式子

2.“空间换时间”

四、列表查找:从列表中查找指定元素

  输入:列表、待查找元素

  输出:元素下标或未查到元素

顺序查找:

  从列表第一个元素开始,顺序进行搜索,直到找到为止。

1 def ordinary_lookup(number):
2     dict = range(1000)
3     for i in dict:
4         if i == number:
5             print(i)
6             break
7 ordinary_lookup(200)

二分查找

  从有序列表的候选区data[0:n]开始,通过对待查找的值与候选区中间值的比较,可以使候选区减少一半。

 1 import time,random
 2 
 3 def cal_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         return x
10     return wrapper
11 
12 @cal_time
13 def bin_search(data_set,val):
14     low = 0
15     high = len(data_set) - 1
16     while low <= high:
17         mid = (low + high)//2
18         if data_set[mid] == val:
19             return mid
20         elif data_set[mid] <val:
21             low = mid + 1
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             return binary_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_time
48 def binary_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 def random_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 in range(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     return result
15 
16 #用于生成一个关于姓名的列表包含字典
17 
18 def bin_search(val):
19     data_set = random_list(10000)
20     low = 0
21     high = len(data_set) - 1
22     while low <= high:
23         mid = (low + high)//2
24         if data_set[mid]['id'] == val:
25             return mid
26         elif data_set[mid]['id'] <val:
27             low = mid + 1
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 = False
4         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 = True
8         if not flag:
9             break

选择排序

  一趟便利记录最小的数,放到第一个位置;

  再一趟遍历记录剩余列表中最小的数,继续放置;

  需要记住两个概念,无序区,最小数的位置。

  时间复杂度:O(n²)

1 def select_sort(li):
2     for i in  range(len(li)-1):
3         min_loc = i
4         for j in range(i+1,len(li)):
5             if li[j] < li[min_loc]:
6                 min_loc = j
7         li[min_loc],li[i] = li[i],li[min_loc]

插入排序

  列表被分为有序区和无序区两个部分。最初有序区只有一个元素。

  每次从无序区选择一个元素,插入到有序区的位置,直到无序区变空。

  需要记住两个概念,摸到的牌,手里的牌。

  时间复杂度:O(n²)

1 def insert_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 def partition(data,left,right):
 2     tmp = data[left]
 3     while left < right and left < right:
 4         while data[right] >= tmp:
 5             right = right - 1
 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]= tmp
11     return left
12 
13 def quick_sort(data,left,right ):
14     if left < right:
15         mid = partition(data,left,right)
16         quick_sort(data,left,mid - 1)
17         quick_sort(data,mid + 1 ,right)

堆排序--树与二叉树简介

  树是一种数据结构    比如:目录结构

  树是一种可以递归定义的数据结构

  树是由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 = low
 3     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 <data[j]:
 9             data[i] = data[j]
10             i=j
11             j=2*i+1
12         else:                #省长能罩住下一级孩子
13             break
14     data[i] = tmp
15 
16 def heap_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 def merge(data,low,mid,high):
 2     i = low
 3     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] = ltmp
19     # j = 0
20     # for i in range(low,high+1):
21     #     data[i]=ltmp[j]
22     #     j+=1
23 
24 def merge_sort(data,low,high):
25     if low < high:
26         mid = (low+high)//2
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模块

转载于:https://www.cnblogs.com/baifumei/p/6898307.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值