算法
一.算法简单概念
1.什么是算法?
算法(Alorithm):一个计算过程,解决问题的方法
2.递归
递归的两个特点:
1.调用自身
2.结束条件
看下面几个函数:
3.时间复杂度
时间复杂度:用来评估算法运行效率的一个东西
类比生活中的一些时间,估计时间
眨一下眼:一瞬间/几毫秒
口算:28+66:几秒
烧一壶水:几分钟
睡一觉:几小时
完成一个项目:几天/几星期/几个月
飞船从地球飞出太阳系:几年
总结:时间复杂度是用来估计算法运行时间的一个式子(单位)
一般来说,时间复杂度高的算法比复杂度低的算法慢
常见的时间复杂度(安效率排序)
不常见的时间复杂度
如何一眼判断时间复杂度?
循环减半的过程:O(logn)
几次循环就是n的几次方的复杂度
4.空间复杂度
空间复杂度:用来评估算法内存占用大小的一个式子
空间换时间:程序开辟更多的内存空间来提高代码的运行效率
二.列表查找
列表查找:从列表中查找指定元素
输入:列表,待查找元素
输出:元素下标或未查找的元素
顺序查找:从列表第一个元素开始,顺序进行搜素,直到找到为止
二分查找:从有序列表的候选区data[0:n]开始,通过对待查找的值与候选区中间值的比较,可以使候选区减少一半
data_set = [3, 4, 1, 6, 7, 8, 9, 2] # 循环遍历法 def liner_search(data_set, value): for i in range(len(data_set)): if data_set[i] == value: return i return res = liner_search(data_set, 9) print(res) # 二分查找法 def bin_search(data_set,value): low=0 high=len(data_set)-1 while low<=high: mid=(low+high)//2 if data_set[mid]==value: return mid elif data_set[mid]>value: high=mid-1 else: low=mid+1 res=bin_search(data_set,9) print(res) # 递归二分查找法 def bin_search_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_search_rec(data_set,value,low,mid-1) else: return bin_search_rec(data_set, value, mid+1, high) else: return res=bin_search_rec(data_set,9,0,len(data_set)-1) print(res)
三.列表排序
1.列表排序
- 将无序列表变为有序列表
- 应用场景:
- 1.各种榜单
- 2.各种表格
- 3.给二分排序用
- 4.给其他算法用
- 输入:无序列表
- 输出:有序列表
- 升序与降序
2.排序low b 三人组:
冒泡排序
# 时间复杂:O(n^2) def bubble_sort(li): for i in range(len(li)-1): for j in range(len(li)-i-1): if li[j]>li[j+1]: li[j],li[j+1]=li[j+1],li[j] li=[3,6,6,2,9,5,3,8] bubble_sort(li) print(li)
如果冒泡排序中执行一趟二没有交换,则列表已经是有序状态,可以直接结算算法
def bubble_sort(li): for i in range(len(li)-1): flag=False for j in range(len(li)-i-1): if li[j]>li[j+1]: li[j],li[j+1]=li[j+1],li[j] flag=True if not flag: return li=[1,2,3,4,5,6,8,9] bubble_sort(li) print(li)
//golang语言的冒泡程序基本一样,go用的是数组 package main import ( "fmt" ) func bubble(lis[]int)int{ code:=0 for i:=0;i<len(lis);i++{ flag:=false for j:=0;j<len(lis)-i-1;j++{ if lis[j]>lis[j+1]{ lis[j],lis[j+1]=lis[j+1],lis[j] flag=true } } if !flag{ return code } } return code } func main() { lis:=[]int{3, 4, 1, 6, 7, 8, 9, 2} bubble(lis) fmt.Println(lis) }
选择排序
选择排序的思路:一趟遍历记录最小的数,放到第一个位置,再一趟遍历记录剩余列表中最小的数,继续放置
重点:选出最小的数
# 时间复杂度O(n^2) def select_sort(li): for i in range(len(li)-1): min_loc=i for j in range(i+1,len(li)): if li[j]<li[min_loc]: min_loc=j if min_loc !=i: li[i],li[min_loc]=li[min_loc],li[i] li=[3, 4, 1, 6, 7, 8, 9, 2] 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 tmp<li[j]: li[j+1]=li[j] j-=1 li[j+1]=tmp li=[3, 4, 1, 6, 7, 8, 9, 2] insert_sort(li) print(li)
3.三人组小结
冒泡排序,插入排序,选择排序
时间复杂度O(n^2)
空间复杂度O(1)
4.快速排序
快速排序:快
好写的排序算法里最快的
快的排序算法里最好写的
快排思路:取一个元素p(第一个元素),使元素p归位,列表被p分成两部分,左边都比p小,右边都比p大,递归完成排序
关键点:整理,递归
# 时间复杂度O(nlogn) def partition(data,left,right): tmp=data[left] while left<right: while left<right and data[right]>=tmp: right-=1 data[left]=data[right] while left<right and data[left]<=tmp: left+=1 data[right]=data[left] data[left]=tmp return left def quick_sort(data,left,right): if left<right: mid=partition(data,left,right) quick_sort(data,left,mid-1) quick_sort(data,mid+1,right) li=[3, 4, 1, 6, 7, 8, 9, 2] quick_sort(li,0,len(li)-1) print(li)
//golang 的快速排序 package main import "fmt" func partition(data[]int,left int,right int)int{ tmp:=data[left] for i:=left;i<right;i++{ for i:=left;i<right && data[right]>=tmp;i++ { right-=1 } data[left]=data[right] for i:=left;i<right && data[left]<=tmp;i++ { left+=1 } data[right]=data[left] } data[left]=tmp return left } func quick_sort(data[]int,left int,right int){ if left<right{ mid:=partition(data,left,right) quick_sort(data,left,mid-1) quick_sort(data,mid+1,right) } } func main() { li:=[]int{3,4,1,6,7,8,9,2} quick_sort(li,0,len(li)-1) fmt.Println(li) }
5.计数排序
计数排序思路:创建一个列表,用来统计每个数出现的次数
#时间复杂度O(n^2)
def count_sort(li,max_num): count=[0 for i in range(max_num+1)] for num in li: count[num]+=1 i=0 for num,m in enumerate(count): for j in range(m): li[i]=num i+=1 li=[3, 4, 1, 6, 7, 8, 9, 2] count_sort(li,max(li)) print(li)
6.归并排序
假设现在的列表分两段有序,如何将其合成为一个有序列表,这种操作称为一次归并
归并的思路:
分解:将列表越分越小,直至分成一个元素,一个元素是有序的
合并:将两个有序列表归并,列表越来越大
# 时间复杂度O(nlogn),空间复杂度O(n) def merge(li,low,mid,high): i=low j=mid+1 ltmp=[] while i <=mid and j<=high: if li[i]<=li[j]: ltmp.append(li[i]) i+=1 else: ltmp.append(li[j]) j+=1 while i<=mid: ltmp.append(li[i]) i+=1 while j<=high: ltmp.append(li[j]) j+=1 li[low:high+1]=ltmp def mergesort(li,low,high): if low<high: mid=(low+high)//2 mergesort(li,low,mid) mergesort(li,mid+1,high) merge(li,low,mid,high) li=[3, 4, 1, 6, 7, 8, 9, 2] mergesort(li,0,len(li)-1) print(li)
7.堆排序
堆排思路:
- 建立堆
- 得到堆顶元素,为最大元素
- 去掉堆顶,将堆顶最后一个元素放到堆顶,此时可通过一次调整重新使堆有序
- 堆顶元素为第二大元素
- 重复步骤3,直到堆变空
#时间复杂度O(nlogn)
def sift(data,low ,high): i=low j=2*i+1 tmp=data[i] while j<=high: if j<high and data[j]<data[j+1]: j+=1 if tmp<data[j]: data[i]=data[j] i=j j=2*i+1 else: break data[i]=tmp def heap_sort(data): n=len(data) for i in range(n//2-1,-1,-1): sift(data,i,n-1) for i in range(n-1,-1,-1): data[0],data[i]=data[i],data[0] sift(data,0,i-1) li = [3, 4, 1, 6, 7, 8, 9, 2] heap_sort(li) print(li)
8.希尔排序排序
# 时间复杂度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