python自動開發之(算法)第二十七天

 

一、什麼是算法?算法

算法(Algorithm):一個計算過程,解決問題的方法數據結構

二、複習:遞歸app

遞歸的兩個特色:(1) 調用自身 (2)結束條件dom

def func1(x):
    print(x)
    func1(x-1)

def func2(x):
    if x>0:
        print(x)
        func2(x+1)


def func3(x):
    if x>0:
        print(x)
        func3(x-1)

def func4(x):
    if x>0:
        func4(x-1)
        print(x)
View Code

func1和func2不是遞歸ide

func3和func4是遞歸,可是結果不同,func3(5)打印的是5,4,3,2,1 而func4(5)結果是1,2,3,4,5函數

三、時間複雜度優化

時間複雜度:用來評估算法運行效率的一個東西ui

小結:spa

  時間複雜度是用來估計算法運行時間的一個式子(單位)。3d

  通常來講,時間複雜度高的算法比複雜度低的算法快。

  常見的時間複雜度(按效率排序)

  O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)<O(nlogn)<O(n^3)

  不常見的時間複雜度(看看就好)

  O(n!) O(2n) O(nn) …

  如何一眼判斷時間複雜度?

  循環減半的過程O(logn)

  幾回循環就是n的幾回方的複雜度

 四、空間複雜度

  空間複雜度:用來評估算法內存佔用大小的一個式子

五、列表查找

  列表查找:從列表中查找指定元素

  輸入:列表、待查找元素

  輸出:元素下標或未查找到元素

六、順序查找

   從列表第一個元素開始,順序進行搜索,直到找到爲止。

七、二分查找

  從有序列表的候選區data[0:n]開始,經過對待查找的值與候選區中間值的比較,可使候選區減小一半。

def bin_search(data_set,val):
    '''
    mid:下標
    low:每次循環的列表最左邊下標
    high:每次循環的列表最右邊下標
    :param data_set:列表
    :param val: 要找的值
    :return:
    '''
    low = 0
    high = len(data_set)-1
    while low <= high:
        mid = (low+high)//2
        if data_set[mid] == val:
            return mid
        elif data_set[mid] > val:
            high = mid - 1
        else:
            low = mid + 1
    return
View Code

八、列表排序

  將無序列表變爲有序列表

  應用場景: 各類榜單 各類表格 給二分查找用 給其餘算法用

  輸入:無序列表

  輸出:有序列表

九、排序中比較慢的三種: 冒泡排序 選擇排序 插入排序

   快速排序

   排序NB二人組: 堆排序 歸併排序

     沒什麼人用的排序: 基數排序 希爾排序 桶排序

  算法關鍵點: 有序區 無序區

十、冒泡排序

  首先,列表每兩個相鄰的數,若是前邊的比後邊的大,那麼交換這兩個數

  n = len(list),循環了i趟(i=n-1),第i趟循環比較了(j = n-i-1 )次,j是每趟循環比較的次數 

import random,time

#裝飾器
def cal_time(func):
    def wrapper(*args,**kwargs):
        t1 = time.time()
        ret = func(*args,**kwargs)
        t2 = time.time()
        print('time cost: %s \r\nfunc from %s'%(t2-t1,func.__name__))
        return func
    return wrapper

@cal_time
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]
            #降續
            # if li[j] < li[j+1]:
            #     li[j],li[j+1]=li[j+1],li[j]



data = list(range(1000))
random.shuffle(data)
print(data)
bubble_sort(data)
print(data)
View Code

  優化後的冒泡排序:

    若是冒泡排序中執行一趟而沒有交換,則列表已是有序狀態,能夠直接結束算法。

import random,time

#裝飾器
def cal_time(func):
    def wrapper(*args,**kwargs):
        t1 = time.time()
        ret = func(*args,**kwargs)
        t2 = time.time()
        print('time cost: %s \r\nfunc from %s'%(t2-t1,func.__name__))
        return func
    return wrapper

@cal_time
def bubble_sort(li):
    for i in range(len(li) - 1):
        exchange = 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]
                exchange = True
            #降續
            # if li[j] < li[j+1]:
            #     li[j],li[j+1]=li[j+1],li[j]
            #     exchange = True
        #這裏是指上一趟,值之間沒有發生交換,就退出循環
        if not exchange:
            break


data = list(range(1000))
random.shuffle(data)
print(data)
bubble_sort(data)
print(data)
View Code

十一、選擇排序

  一趟遍歷記錄最小的數,放到第一個位置; 再一趟遍歷記錄剩餘列表中最小的數,繼續放置;

import random,time

#裝飾器
def cal_time(func):
    def wrapper(*args,**kwargs):
        t1 = time.time()
        ret = func(*args,**kwargs)
        t2 = time.time()
        print('time cost: %s --> \nfunc from %s'%(t2-t1,func.__name__))
        return func
    return wrapper

@cal_time
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
        li[i],li[min_loc] = li[min_loc],li[i]
View Code

十二、插入排序

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
View Code

1三、練習 用冒泡法把打亂的帶ID的信息表排序

import random


def random_list(n):
    ids = range(1000,1000+n)
    result = []
    a1 = ["","","","","","",""]
    a2 = ["","","","","","",""]
    a3 = ["","","","","","",""]
    for i in range(n):
        age = random.randint(16,38)
        id = ids[i]
        name = '%s%s%s'%(random.choice(a1),random.choice(a2),random.choice(a3))
        dic = {}
        dic['id'] = id
        dic['姓名'] = name
        dic['年齡'] = age
        result.append(dic)
    return result


def bubble_sort(li):
    for i in range(len(li)-1):
        for j in range(len(li)-i-1):
            if li[j]['id'] > li[j+1]['id']:
                li[j],li[j+1] = li[j+1],li[j]

data1 = random_list(100)
random.shuffle(data1)
print(data1)
bubble_sort(data1)
print(data1)
View Code

1四、快速排序:快

  好寫的排序算法裏最快的

  快的排序算法裏最好寫的  

     快排思路:

    取一個元素p(第一個元素),使元素p歸位;

    列表被p分紅兩部分,左邊都比p小,右邊都比p大;

    遞歸完成排序。

#快排的複雜度是O(nlog(n)),這是一個特殊狀況 
#口訣 右手左手一個慢動做,右手左手慢動做重播(遞歸)
import time,random,copy

def cal_time(func):
    def wrapper(*args,**kwargs):
        t1 = time.time()
        ret = func(*args,**kwargs)
        t2 = time.time()
        print('time cost: %s from %s'%(t2-t1,func.__name__))
        return func
    return wrapper


def quick_sort_x(data,left,right):
    #這裏的left和right是定義列表data,最少有兩個元素
    if left<right:
        #partition分割函數,mid是放好的元素的下標
        mid = partition(data,left,right)
        #如下相似二分
        quick_sort_x(data,left,mid-1)
        quick_sort_x(data,mid+1,right)

#快排的複雜度是O(nlog(n)),這是一個特殊狀況
def partition(data,left,right):
    #獲取左邊的第一個元素,這裏寫left不能寫零,由於後面須要遞歸
    tmp = data[left]
    #終止條件爲當left和right碰上時,因此左小於右時爲while循環的條件(left和right是下標)
    while left < right:
        #循環條件是右邊比tmp大,直到找到右邊比tmp小的數,中止循環
        while left < right and data[right] >= tmp:
            right -= 1
        #把找到的右邊比tmp小的數移到左邊空出來的位置
        data[left] = data[right]
        #循環條件是左邊比tmp小,繼續循環,直到找到左邊比tmp大的數,結束循環
        while left < right and data[left] <= tmp:
            left += 1
        #把左邊找到的大於tmp的數移到右邊空出來的位置
        data[right] = data[left]
    #當左右相等時,就把tmp放到left和right碰到的位置
    data[left] = tmp
    #mid的值和lef或right值相同,return哪一個均可以
    #mid = left
    # return mid
    return left

#對遞歸函數的裝飾,須要再封裝一層
@cal_time
def quik_sort(data):
    #0及是left,len(data)-1爲right
    return quick_sort_x(data,0,len(data)-1)
View Code
import time,random,copy

def cal_time(func):
    def wrapper(*args,**kwargs):
        t1 = time.time()
        ret = func(*args,**kwargs)
        t2 = time.time()
        print('time cost: %s from %s'%(t2-t1,func.__name__))
        return func
    return wrapper


def quick_sort_x(data,left,right):
    #這裏的left和right是定義列表data,最少有兩個元素
    if left<right:
        #partition分割函數,mid是放好的元素的下標
        mid = partition(data,left,right)
        #如下相似二分
        quick_sort_x(data,left,mid-1)
        quick_sort_x(data,mid+1,right)

#快排的複雜度是O(nlog(n)),這是一個特殊狀況
def partition(data,left,right):
    #獲取左邊的第一個元素,這裏寫left不能寫零,由於後面須要遞歸
    tmp = data[left]
    #終止條件爲當left和right碰上時,因此左小於右時爲while循環的條件(left和right是下標)
    while left < right:
        #循環條件是右邊比tmp大,直到找到右邊比tmp小的數,中止循環
        while left < right and data[right] >= tmp:
            right -= 1
        #把找到的右邊比tmp小的數移到左邊空出來的位置
        data[left] = data[right]
        #循環條件是左邊比tmp小,繼續循環,直到找到左邊比tmp大的數,結束循環
        while left < right and data[left] <= tmp:
            left += 1
        #把左邊找到的大於tmp的數移到右邊空出來的位置
        data[right] = data[left]
    #當左右相等時,就把tmp放到left和right碰到的位置
    data[left] = tmp
    #mid的值和lef或right值相同,return哪一個均可以
    #mid = left
    # return mid
    return left

#對遞歸函數的裝飾,須要再封裝一層
@cal_time
def quik_sort(data):
    #0及是left,len(data)-1爲right
    return quick_sort_x(data,0,len(data)-1)

#冒泡排序
@cal_time
def bubble_sort(li):
    for i in range(len(li) - 1):
        exchange = 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]
                exchange = True
            #降續
            # if li[j] < li[j+1]:
            #     li[j],li[j+1]=li[j+1],li[j]
            #     exchange = True
        #這裏是指上一趟,值之間沒有發生交換,就退出循環
        if not exchange:
            break

data = list(range(5000))
random.shuffle(data)
#深度拷貝
data1 = copy.deepcopy(data)
data2 = copy.deepcopy(data)

#快排和冒泡的比較
quik_sort(data1)
bubble_sort(data2)
print(data1)
View Code

升續:

降續:

 

排序速度的定義:

 

通常狀況下快排比冒泡快,快排有遞歸深度的問題,若是深度高的話,須要調整。

 1五、堆排序

(1)樹與二叉樹簡介

  樹是一種數據結構 好比:目錄結構

  樹是一種能夠遞歸定義的數據結構

  樹是由n個節點組成的集合:

    若是n=0,那這是一棵空樹;

    若是n>0,那存在1個節點做爲樹的根節點,其餘節點能夠分爲m個集合,每一個集合自己又是一棵樹。

  一些概念

    根節點、葉子節點

    樹的深度(高度)

    樹的度

    孩子節點/父節點 子樹

  

(2)二叉樹

  二叉樹:度不超過2的樹(節點最多有兩個叉)

   

(3)滿二叉樹,徹底二叉樹

 (4)二叉樹的存儲方式

  鏈式存儲方式

  順序存儲方式(列表)

  

  父節點和左孩子節點的編號下標有什麼關係?

  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

(5)小結

  二叉樹是度不超過2的樹

  滿二叉樹與徹底二叉樹

  (徹底)二叉樹能夠用列表來存儲,經過規律能夠從父親找到孩子或從孩子找到父親

(6)堆排序

  大根堆:一棵徹底二叉樹,知足任一節點都比其孩子節點大

  小根堆:一棵徹底二叉樹,知足任一節點都比其孩子節點小

(7)堆排序過程

  a、創建堆

  b、獲得堆頂元素,爲最大元素

  c、去掉堆頂,將堆最後一個元素放到堆頂,此時可經過一次調整從新使堆有序。

  d、堆頂元素爲第二大元素。

  e、 重複步驟3,直到堆變空。

相關文章
相關標籤/搜索