第十五章 算法

“”"

  • 衡量算法的好坏
    时间复杂度
    空间复杂度
  • 查找
    顺序查找
    折半查找
  • 排序
    冒泡排序
    选择排序
    插入排序
    希尔排序
    快速排序
    归并排序

算法
解决特定问题的方案

一、衡量算法的好坏

(1) 时间复杂度

     算法运行的时候执行规模、频度。
     最好执行次数、平均执行次数、最坏执行次数(为准)
     常数时间复杂度:在任何时刻访问时间复杂度都是一致的。O(1)
    x=1
    y=2

     O(n): 根据n的大小变化的时间复杂度
     一层循环就是O(n)
    n=5
    for i in  range(n):
        pass

     O(n^2):嵌套循环
     for i in range(n):
         for j in range(n-2):
             pass

     O(logn):log2为底 n的对数 ,当循环的次数在循环中折半
     while n!=0:
         print(n)
         n=n//2

     常用时间复杂度的排序
     O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)<O(n^3)

(2)空间复杂度:
    用空间换时间的方式。

二、查找

查找:顺序查找、折半查找

 (1) 顺序查找
        从前到后,顺序进行与关键字相匹配的查找

         时间复杂度O(n)
        def search(li,key):
            for index,i in enumerate(li):
                if i==key:
                    return index
            return -1
        print(search([1,2,3,44,5,77,88],44))

 (2) 折半查找
        选择中间的元素进行比较,每次排除一半的元素

         时间复杂度 O(logn)
         折半查找必须要在已排序的基础上进行
        """
        key比较中间的元素mid
        if key >mid: 舍弃左半部分,取右半部分,继续查找
        else       :  舍弃右半部分,区左半部分,继续查找
        """
        """
        舍弃左半部分:  start:  mid+1    end  不变
        舍弃右半部分:  start: 不变      end mid-1
        """
        def middleSearch(li,key):
            start=0
            end=len(li)-1
            while start<=end:
                mid=(start+end)//2
                if key>li[mid]:
                    start=mid+1
                elif key<li[mid]:
                    end=mid-1
                else:
                    return mid
            return -1
        print(middleSearch([1,2,4,77,88,99,100],3))
        
         思考:折半查找一定顺序查找吗?
         折半查找需要先排序
         当查找次数较多的时候,可以选择使用折半查找。
         查找分几种?
         折半查找怎么找?
         折半是不是一定比顺好?

三、排序

按照稳定性上:稳定排序和不稳定排序
3 4 5(1) 6 -9  -1 5(2)           -9 -1 3 4 5(1)  5(2)  6

 1.  冒泡排序
 
     最重要的排序方法
     思路:将相邻的两个元素进行比较 i  i+1 , 通过比较来决定是否交换位置。
          每一次排序都会选出一个(最大)最小值。
    li=[23,-8,29,2,6,18,33]
     内循环---外循环
    def bublesort(li):
        n=len(li)-1
        for j in range(n):
            for i  in range(n-j):
                if li[i]>li[i+1]:
                    li[i],li[i+1]=li[i+1],li[i]
                print(li)
     bublesort(li)
     时间复杂度:O(n^2)   最佳时间复杂度(O(n))
     稳定性:稳定排序





2. 选择排序

     思路:每次选择一个最小或者最大的的元素放在前面,排好序。
     li=[23,-8,29,2,6,18,33]
     min_value=0
     li_temp=[]
     for i in li:
         if i==0:
             min_value=li[0]
         else:
             if i<min_value:
                 min_value=i
     print(min_value)
    """
    1. 不取最小值 ,而是使用索引
      min设置成最小值的索引
    2. 外循环
    """
    
    li=[-9 ,-20 , -100,  10  , 3   ,11  , 7 ,  5]
    第一轮
     def choosesort(li):
         n=len(li)
         min_index=0   假定第0个元素是最小值的索引
          使用for遍历从1个元素到最后一个元素,找到真正 最小值的索引
         for i in range(1,n):
             if li[i]<li[min_index]:
                 min_index=i
          for循环结束之后,min_index是真正的最小值索引
         li[min_index],li[0]=li[0],li[min_index]
         print(li)
    
         min_index = 1   假定第1个元素是最小值的索引
          使用for遍历从2个元素到最后一个元素,找到真正 最小值的索引
         for i in range(2, n):
             if li[i] < li[min_index]:
                 min_index = i
          for循环结束之后,min_index是真正的最小值索引
         li[min_index], li[1] = li[1], li[min_index]
         print(li)
     choosesort(li)
    
    
    def choosesort(li):
        n=len(li)
        for j in range(n-1):
            min_index=j   假定第j个元素是最小值的索引
             使用for遍历从j+1个元素到最后一个元素,找到真正 最小值的索引
            for i in range(j+1,n):
                if li[i]<li[min_index]:
                    min_index=i
             for循环结束之后,min_index是真正的最小值索引
            li[min_index],li[j]=li[j],li[min_index]
            print(li)
     choosesort(li)
     li=[-9 ,-20 , -100,  10  , 3   ,11  , 7 ,  5]
      [-100, -20, -9, 3, 5, 7, 10, 11]
    
     时间复杂度:O(n^2) 没有最佳排序。
     稳定性: 不稳定排序


 3. 插入排序
 
     像大小个排队
     思路:从第二个元素开始,插入先有的已排好序的列表中。
     li=[-9 ,-20 , -100,  10  , 3   ,11  , 7 ,  5]
     n=len(li)
     for i in  range(1,n):
          第一次
         i=1  6
         temp=li[i]  7
          拿着-20跟前面排好队[-9]的元素比较,插入的到[-9]的列表中
         j=i-1
         while j>=0 and temp<li[j]:
             li[j+1]=li[j]
             j-=1
         li[j+1]=temp
         print(li)
    
     时间复杂度:O(n^2)    最佳O(n) 排好序。
     稳定性:稳定排序

 4.希尔排序
 
     缩小增量排序。
     以插入排序为基础,设置一系列增量,按照增量进行分组,将组内的元素进行排序,
     再取其他的增量。增量(大---小1)
     对于增量没有固定的值。 11   6   3   2  1
    li=[-9 ,-20 , -100,  10  , 3   ,-110  , 7 ,  -5]
    increment=[3,2,1]
    def shell(li,increment):
        n=len(li)
        for inc in increment:3   2  1
            for k in range(inc):  0   1   2
                for i in  range(k+inc,n,inc):
                    temp=li[i]
                    j=i-inc
                    while j>=0 and temp<li[j]:
                        li[j+inc]=li[j]
                        j-=inc
                    li[j+inc]=temp
                    print(li)
     shell(li,increment)
     时间复杂度:跟增量设置有关  最差的情况:O(n^2)
     稳定性:不稳定
    
 5. 快速排序
 
     从列表中选取一个中心点。使得中心点左侧的元素都小于该元素,中心点右侧的元素都大于该元素
    def quicksort(li):
        n=len(li)
        if n<=1:
            return li
        else:
            mid_index=0
            small=[]
            big=[]
            for i in range(1,n):
                if li[mid_index]>li[i]:
                    small.append(li[i])
                else:
                    big.append(li[i])
        return quicksort(small)+[li[mid_index]]+quicksort(big)
    li=[-9 ,-20 , -100,  10  , 3   ,-110  , 7 ,  -5,7]
     print(quicksort(li))
     时间复杂度:O(n^2)
     稳定性:稳定

 6.归并排序
 
     分久必合,合久必分。
    def merage(li,low,high):
        if low <high:
            mid=(low+high)//2
            merage(li,low,mid)
            merage(li,mid+1,high)
            _merage_sort(li,low,mid,high)
            return li
    def _merage_sort(li,low,mid,high):
        i=low   i是左半部分的第一个元素
        j= mid+1   j是右半部分的第一个元素
        temp=[]
        while i<=mid and j<=high:
            if li[i]<=li[j]:
                temp.append(li[i])
                i+=1
            else:
                temp.append(li[j])
                j+=1
        while j<=high:   左边被取完了
            temp.append(li[j])
            j+=1
        while i<=mid:   右边被取完
            temp.append(li[i])
            i+=1
        li[low:high+1]=temp
    
    li=[-9 ,-20 , -100,  10  , 3   ,-110  , 7 ,  -5,7]
    print(merage(li,0,len(li)-1))
    
    时间复杂度:O(nlogn)
     稳定性:稳定排序

“”"