算法

1 时间复杂度

 

循环减半的时间复杂度是log(n)

 

时间复杂度是用来估计算法运行时间的一个式子(单位)。

一般来说,时间复杂度高的算法比复杂度低的算法慢。

常见的时间复杂度(按效率排序) O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n2logn)<O(n3)

不常见的时间复杂度(看看就好) O(n!) O(2n) O(nn) … 如何一眼判断时间复杂度? 循环减半的过程O(logn) 几次循环就是n的几次方的复杂度

 

算法

LOW B三人组

1.二分法查找内容  使用递归的方式来查找

li=[1,2,3,4,5,6,7,8,11,22,55,78,87,88,89,97,98,99]
l2=[1,2,3,4,5]
def func(num,li,start=0,end=None,):
    if end==None:
        end=len(li)-1
    a=(start+end)//2
    if start<=end:
        if li[a]<num:
           return func(num,li,start=a+1,end=end)
        elif li[a]>num:
            return func(num,li,start=start,end=a-1)
        elif li[a]==num:
            print(a)
    else:
        return 'meiyou '

func(55,li,start=0,)

使用循环的二分法

l=[1,2,4,5,6,8,9]
def func(mun,l,start=0,end=None):
    if end==None:
        end=len(l)-1
    while end>=start:
        mid=(start+end)//2
        if mun==l[mid]:
            return mid
        elif mun>l[mid]:
            start=mid+1
        elif mun <l[mid]:
            end=mid-1
    else:
        return '么有'
ret=func(11,l,start=0)
print(ret)

 

2.斐波那契数列

# # 斐波那契数列1,2,3,5,8,13,21.....根据这样的规律,
# # 编程求出400万以内最 的斐波那契数,并求出他是第 个斐波那契数。
a,b=1,2
count=2
i=0
while a+b<400000:#注意这里不能写成while i<4000000
    i=a+b#因为循环结束后会包含大于400W,而是不进入下一次循环,所有写这个。
    a=b
    b=i
    count+=1
print(i,count)

3.冒泡算法

时间复杂度  O(n2)

首先,列表每两个相邻的数,如果前边的比后边的大,那么交换这两个数……

 如果冒泡排序中执行一趟而没有交换,则列表已经是有序状态,可以直接结束算法。  这样可以节省时间  以免都已经排序好了还要再次进行无意义的循环排序

def maopao(li):
    for i in range(len(li)-1):
        #定义一个标志位 来判断此次循环是否发生了交换,如果没有则表示排序完成
        exchange=False
        for j in range(len(li)-1-i):
            if li[j]>li[j+1]:
                li[j],li[j+1]= li[j+1],li[j]
                exchange=True
            else:
                pass
        if not exchange:
            return

li=[1,4,2,3,5,9,6,7,11,7]
maopao(li)
print(li)

4.选择排序

时间复杂度:O(n2)

li=[1,4,2,3,5,9,6,7,11,7]
def select_sort(li):
    for i in range(len(li)-1):
        #从第i趟开始,无序区是li[i:]
        #从无序区找到最小的值,保存最小值的位置,
        min_loc=i  #第一次默认是0
        for j in range(i+1,len(li)):
            #因为是跟i比  所以不用再去看一下这个i   让 li[i]和 li[i]  比较大小,
            #所以从i+1开始
            if li[j]<li[min_loc]:#这里是  如果 当前循环的值比 最小值的位置的数字小,
                min_loc=j  #记录这个位置,替换上一次的最小值的位置的值,
                            #当下个循环过来  就会跟这个新的位置上的数据比较大小,如果比他小的话继续替换
                            #直到这趟循环走完  就找到一个最小的
        if min_loc!=i: #把最小的数字放在最前边,这样有序区就多了一个数据,无需去少了一个数据
            li[i],li[min_loc]=li[min_loc],li[i]

select_sort(li)
print(li)

 5.插入排序

时间复杂度:O(n2)

#关键点,要记住设置的几变量
def charupaixu(li):
    for i in range(1,len(li)):
        #这个temp存放的是当前循环的值 每次for循环存放不同的值t
        #用他去和他前边所有索引位置的只进行比较
        #这里注意  这个temp是已经被抽取出来的数据了  所以他是悬空的
        # temp的原来占的位置就空了出来,他左边数据可以挪动过来
        temp=li[i]
        #这个j值是一个边变化的值  是索引小于temp的所有的索引值
        j=i-1
        #当j 大于等于0  而且 temp 小于他位置左边的数据的值的时候
    
        while j>=0 and temp < li[j]:
            # 给这个小于
            li[j+1]=li[j]
            #每次循环都要给j 减去  1  用于从右到左依次比较,大小
            j=j-1
        #直到左边的数据不再小于temp的时候, 这时候这个索引位置j即是比temp大  紧挨着他的值
        #所以 把拿出来的temp这张牌插入到 j+1位置上 就是  j的左边 紧挨着的位置
        li[j+1]=temp

charupaixu(li)
print(li)

 

代码

#关键点,要记住设置的几变量
def charupaixu(li):
    for i in range(1,len(li)):
        #这个temp存放的是当前循环的值 每次for循环存放不同的值t
        #用他去和他前边所有索引位置的只进行比较
        #这里注意  这个temp是已经被抽取出来的数据了  所以他是悬空的
        # 他的原来占的位置就空了出来,他左边的数据可以挪动过来
        temp=li[i]
        #这个值是一个边变化的值  是索引小于temp的所有的值
        j=i-1
        #当j 大于等于0  而且 temp 小于他位置左边的数据的值的时候

        while j>=0 and temp < li[j]:
            # 给这个小于
            li[j+1]=li[j]
            #每次循环都要给j 减去  1  用于从右到左依次比较,大小
            j=j-1
        #直到左边的数据不再小于temp的时候, 这时候这个索引位置j即是比temp大  紧挨着他的值
        #所以 把拿出来的temp这张牌插入到 j+1位置上 就是  j的左边 紧挨着的位置
        li[j+1]=temp

charupaixu(li)
print(li)
View Code

 

 补充:布尔运算的短路功能

print(1>2 and 3>1)  #and运算,当前边的返回值已经是false的时候就不会去看后边的结果  直接返回False了

False  #or也有同理的功能

 

三种排序 都是时间复杂度:O(n2)

速度是  选择排序>插入排序>冒泡排序

NIU  B 三人组:

1:快排   (三人组中最快的

 

#此函数是对数据处理的函数
#使用当前需要排序的列表段  即是索引区间位置的这些数据
def partition(li, left, right):
    #找到列表区间中最左边的数据 拿出来  悬空
    #  然后开始和这个区间的数据进行对比
    temp = li[left]
    #当右索引大于左索引的时候,证明  没有找到这个 temp的中间位置
    # 并把他左右分别放置比自己大小的数据
    while left < right:
        #用于比较temp 和从最右边的数据开始 的大小  ,只要是 这个右边的数据比 temp大
        #则这个右边的数据当前位置正确,右索引减一,
        # 再次比较 当不符合while条件之 右边比temp小的时候
        while left < right and temp < li[right]:
            right -= 1
        #把当前右边的数据拿过来放到这个temp空出来的位置
        li[left] = li[right]
        #然后开始比较左边的数据,同理 当不符合他的条件之左边数据大于temp时
        while left < right and temp > li[left]:
            left += 1
        #把这个数据拿出来,放到刚才空出来的 right索引位置
        li[right] = li[left]
    # 直到left=right的时候,证明找到了 这个temp的索引位置
    #把temp放到这个位置上去
    li[left]=temp
    #此时以这个索引位置为分界点,左边比他大 右边比他小  自己位置是属于自己应有的位置
    #返回这个位置
    return left

 

#此函数是一个递归函数,用于一次次调用另外一个函数完成,对中间数据左右两边
# 放置左比自己小右边比自己大的数据,
def quick_sort(li, left, right):
    if left < right:
        #接收返回的mid  这个位置
        mid = partition(li, left, right)
        #然后再次调用自身,来排序 这个mid 左右两边的数据
        quick_sort(li, left, mid - 1)
        quick_sort(li, mid + 1, right)

代码  正序  从小到大排

#快排
li = [5, 21, 3, 6, 2, 1, 7, 9, 8]
li2=[4,3,1,6,8,2,5,7,9]
#此函数是对数据处理的函数
#使用当前需要排序的列表段  即是索引区间位置的这些数据
def partition(li, left, right):
    #找到列表区间中最左边的数据 拿出来  悬空
    #  然后开始和这个区间的数据进行对比
    temp = li[left]
    #当右索引大于左索引的时候,证明  没有找到这个 temp的中间位置
    # 并把他左右分别放置比自己大小的数据
    while left < right:
        #用于比较temp 和从最右边的数据开始 的大小  ,只要是 这个右边的数据比 temp大
        #则这个右边的数据当前位置正确,右索引减一,
        # 再次比较 当不符合while条件之 右边比temp小的时候
        while left < right and temp < li[right]:
            right -= 1
        #把当前右边的数据拿过来放到这个temp空出来的位置
        li[left] = li[right]
        #然后开始比较左边的数据,同理 当不符合他的条件之左边数据大于temp时
        while left < right and temp > li[left]:
            left += 1
        #把这个数据拿出来,放到刚才空出来的 right索引位置
        li[right] = li[left]
    # 直到left=right的时候,证明找到了 这个temp的索引位置
    #把temp放到这个位置上去
    li[left]=temp
    #此时以这个索引位置为分界点,左边比他大 右边比他小  自己位置是属于自己应有的位置
    #返回这个位置
    return left
#此函数是一个递归函数,用于一次次调用另外一个函数完成,对中间数据左右两边
# 放置左比自己小右边比自己大的数据,
def quick_sort(li, left, right):
    if left < right:
        #接收返回的mid  这个位置
        mid = partition(li, left, right)
        #然后再次调用自身,来排序 这个mid 左右两边的数据
        quick_sort(li, left, mid - 1)
        quick_sort(li, mid + 1, right)


quick_sort(li, 0, len(li) - 1)
print(li)
View Code

倒叙  从大到小排  只要把partition的大于号小于号翻转就行了

#快排
li = [5, 21, 3, 6, 2, 1, 7, 9, 8]
li2=[4,3,1,6,8,2,5,7,9]
#此函数是对数据处理的函数
#使用当前需要排序的列表段  即是索引区间位置的这些数据
def partition(li, left, right):
    #找到列表区间中最左边的数据 拿出来  悬空
    #  然后开始和这个区间的数据进行对比
    temp = li[left]
    #当右索引大于左索引的时候,证明  没有找到这个 temp的中间位置
    # 并把他左右分别放置比自己大小的数据
    while left < right:
        #用于比较temp 和从最右边的数据开始 的大小  ,只要是 这个右边的数据比 temp大
        #则这个右边的数据当前位置正确,右索引减一,
        # 再次比较 当不符合while条件之 右边比temp小的时候
        while left < right and temp > li[right]:
            right -= 1
        #把当前右边的数据拿过来放到这个temp空出来的位置
        li[left] = li[right]
        #然后开始比较左边的数据,同理 当不符合他的条件之左边数据大于temp时
        while left < right and temp < li[left]:
            left += 1
        #把这个数据拿出来,放到刚才空出来的 right索引位置
        li[right] = li[left]
    # 直到left=right的时候,证明找到了 这个temp的索引位置
    #把temp放到这个位置上去
    li[left]=temp
    #此时以这个索引位置为分界点,左边比他大 右边比他小  自己位置是属于自己应有的位置
    #返回这个位置
    return left
#此函数是一个递归函数,用于一次次调用另外一个函数完成,对中间数据左右两边
# 放置左比自己小右边比自己大的数据,
def quick_sort(li, left, right):
    if left < right:
        #接收返回的mid  这个位置
        mid = partition(li, left, right)
        #然后再次调用自身,来排序 这个mid 左右两边的数据
        quick_sort(li, left, mid - 1)
        quick_sort(li, mid + 1, right)


quick_sort(li, 0, len(li) - 1)
print(li)
View Code

什么是最坏情况:

代码优化  避免出现最坏情况  

#快排
li = [5, 21, 3, 6, 2, 1, 7, 9, 8]
li2=[4,3,1,6,8,2,5,7,9]
#此函数是对数据处理的函数
#使用当前需要排序的列表段  即是索引区间位置的这些数据
import  random
def partition(li, left, right):
    #找到列表区间中最左边的数据 拿出来  悬空
    #  然后开始和这个区间的数据进行对比
    
    #做一个随机取数据的函数,避免出现最坏情况
    randi=random.randint(left,right)
    li[randi],li[left]=li[left],li[randi]
    temp = li[left]
    #当右索引大于左索引的时候,证明  没有找到这个 temp的中间位置
    # 并把他左右分别放置比自己大小的数据
    while left < right:
        #用于比较temp 和从最右边的数据开始 的大小  ,只要是 这个右边的数据比 temp大
        #则这个右边的数据当前位置正确,右索引减一,
        # 再次比较 当不符合while条件之 右边比temp小的时候
        while left < right and temp > li[right]:
            right -= 1
        #把当前右边的数据拿过来放到这个temp空出来的位置
        li[left] = li[right]
        #然后开始比较左边的数据,同理 当不符合他的条件之左边数据大于temp时
        while left < right and temp < li[left]:
            left += 1
        #把这个数据拿出来,放到刚才空出来的 right索引位置
        li[right] = li[left]
    # 直到left=right的时候,证明找到了 这个temp的索引位置
    #把temp放到这个位置上去
    li[left]=temp
    #此时以这个索引位置为分界点,左边比他大 右边比他小  自己位置是属于自己应有的位置
    #返回这个位置
    return left
#此函数是一个递归函数,用于一次次调用另外一个函数完成,对中间数据左右两边
# 放置左比自己小右边比自己大的数据,
def quick_sort(li, left, right):
    if left < right:
        #接收返回的mid  这个位置
        mid = partition(li, left, right)
        #然后再次调用自身,来排序 这个mid 左右两边的数据
        quick_sort(li, left, mid - 1)
        quick_sort(li, mid + 1, right)


quick_sort(li, 0, len(li) - 1)
print(li)
View Code

 

 

 

 

 

 注意  什么是堆

 

二:堆排

对排序的用的是

b=[2,8,1,4,9,6,5,7]
def sift(data,low,high):
    #取出一个索引位置,从上向下调整
    i=low
    #取一个索引  找到他的堆的下部位置
    j=2*i+1
    #把这个准备向下调整的数据保存到tmp这个变量中
    tmp=data[i]
    while j<=high:
        #先判断他的孩子节点 的左右两个孩子的大小,
        #如果右孩子比较大的话就使用右孩子
        if j<high and data[j] < data[j+1]:
            j+=1
        #然后再用这个tmp跟他的比较大的孩子进行比较,如果他的孩子大于这个数值
        if tmp<data[j]:
            #把这个tmp索引位置空出来给比较大的孩子
            data[i]=data[j]
            #然后继续往下走,重新给i赋值  去继续往下走 判断他的孩子跟他的大小
            i=j
            j=2*i+1
        #当条件不成立的时候,则不做替换了跳出while循环
        else:
            break
    #给 这是后把顶端的数据向下调整到这个i的位置上
    data[i]=tmp
#建堆函数
def heap_sort(data):
    #建堆是从后往前找
    n=len(data)
    # n//2-1 就是第一个非叶子节点的节点,

    for i in range(n//2-1,-1,-1):
        #这里定义的n-1把他当左high最后的一个叶子节点所在索引位,所有的之地呢的数据都不会超过这个索引位置,
        #否则会发生索引越界

        #取出这个data列表中从此跟节点到  n-1  去执行上边的向下调整函数  从  堆的底端开始调整
        sift(data,i,n-1)
    for i in range(n-1,-1,-1):#i表示当前的high的值,也表示棋子的位置
        #交换退休和要上去的值
        data[0],data[i]=data[i],data[0]
        #此时堆的范围之0到i-1  因为取出来了一个少了一个  
        sift(data,0,i-1)
heap_sort(b)
print(b)

 

posted on 2018-06-07 21:04  王大拿  阅读(113)  评论(0)    收藏  举报

导航