Python之算法基礎

概念

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

時間複雜度與空間複雜度

時間複雜度數據結構

一個算法的優劣能夠用時間複雜度與空間複雜度來衡量。dom

一般討論算法的複雜度:一、問題規模相同  二、機器配置相同ide

經常使用大O表示法表示時間複雜性,注意它是某一個算法的時間複雜性。函數

如何判斷一個算法的時間複雜度post

  • 循環減半的過程>>> O(logn)
  • 幾回循環就是N的幾回方的複雜度

經常使用的時間複雜度(按效率排序)優化

O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n2logn)<O(n3)ui

空間複雜度spa

  • 用來評估算法內存佔用大小的一個式子
  • 算法快總要付出點代價的,利用"空間"來換取"時間"

列表查找

指定從一個列表的全部元素中,查找指定的元素3d

一、順序查找(利用Python內置函數index,in操做,for循環機制均可實現)

二、二分查找(注:前提列表是有序的)

二分查找又稱爲半查找, 由上圖定義low(最小數索引)high(最大數索引)mid(折半數索引)

需求:按照上圖找到數字3

  • 既然是二分,每一次循環問題規模相應的要減半。mid=(low + high) // 2
  • 若是val(查找數) < mid,即在這個列表二分的左邊,high = mid - 1
  • 若是val(查找數) > mid,即反之,low = mid + 1
def bin_search(data_list, val):
    low = 0                         # 最小數下標
    high = len(data_list) - 1       # 最大數下標
    while low <= high:
        mid = (low + high) // 2     # 中間數下標
        if data_list[mid] == val:   # 若是中間數下標等於val, 返回
            return mid
        elif data_list[mid] > val:  # 若是val在中間數左邊, 移動high下標
            high = mid - 1
        else:                       # 若是val在中間數右邊, 移動low下標
            low = mid + 1
    return                          # val不存在, 返回None

ret = bin_search(list(range(1, 10)), 3)
print(ret)
二分DEMO

冒泡排序

冒泡:由於越大的元素會經由交換慢慢「浮」到數列的頂端,故名。

利用相鄰元素比較並進行位置的互換...

需求:一個打亂的列表,進行有效的排序

相鄰兩個值進行比較,將較大的值放在右側,依次比較!(排序好的便再也不比較)

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 = list(range(10))
random.shuffle(li)  # 打亂列表
bubble_sort(li)
print(li)
冒泡DEMO
def bubble_sort(li):
    for i in range(len(li) - 1):            # 無需在乎最後一個數
        go = 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]
                go = True
        if not go:
            return


li = list(range(1000))
random.shuffle(li)  # 打亂列表
bubble_sort(li)
print(li)
優化後的冒泡

選擇排序

選擇:

  • 選擇第一個值的索引賦值給特殊變量,而後循環其餘索引並進行值的比較,若是循環的值 < 特殊變量對應的值,那麼將當前值的索引放入變量中,繼續向後比較
  • 選擇第二個值的索引賦值給特殊變量,...
  • ...
def select_sort(li):
    for i in range(len(li) - 1):
        index = i                       # 選擇一個數
        for j in range(i+1, len(li)):   # 與i+1以後的每個數比較
            if li[j] < li[index]:       # 若是以後的每個數小於標識表明的最小數
                index = j               # 一直在選擇最小數
        li[i], li[index] = li[index], li[i]   # 改變位置


li = list(range(10))
random.shuffle(li)
select_sort(li)
print(li)
選擇DEMO

插入排序

插入:

  • 列表被分爲有序區和無序區兩個部分。最初有序區只有一個元素。
  • 每次從無序區選擇一個元素,插入到有序區的位置,直到無序區變空
import random


def insert_sort(li):
    for i in range(1, len(li)):   # 從下標1開始
        tmp = li[i]               # 拿出無序區第一個數
        j = i - 1                 # 有序區最大數的下標
        while j >= 0 and tmp < li[j]:  # 條件: 下標j要大於等於0 和 拿出的數小於有序區的最大數
            li[j+1] = li[j]            # 下標j對應的數要日後挪動一個位置
            j = j - 1                  # 有序區下一個元素繼續比較
        li[j+1] = tmp  # tmp從新到本身該到的位置

li = list(range(100))
random.shuffle(li)
insert_sort(li)
print(li)
插入DEMO

快速排序

import random


def insert_sort(li):
    for i in range(1, len(li)):   # 從下標1開始
        tmp = li[i]               # 拿出無序區第一個數
        j = i - 1                 # 有序區最大數的下標
        while j >= 0 and tmp < li[j]:  # 條件: 下標j要大於等於0 和 拿出的數小於有序區的最大數
            li[j+1] = li[j]            # 下標j對應的數要日後挪動一個位置
            j = j - 1                  # 留出一個位置給tmp
        li[j+1] = tmp  # tmp從新到本身該到的位置

li = list(range(100))
random.shuffle(li)
insert_sort(li)
print(li

快速:

  • 取一個元素P(第一個元素),使元素P歸位
  • 列表被P分紅倆部分,左邊都比P小,右邊都比P大
  • 遞歸完成排序
# 降序排列

def quick_sort(li, left, right):
    if left < right:
        mid = partition(li, left, right)
        quick_sort(li, mid + 1, right)
        quick_sort(li, left, mid - 1)


def partition(li, left, right):
    tmp = li[left]           # 取出最左邊的數
    while left < right:      # 若是 left 與 right 值相等 表示tmp找到正確下標
        while left < right and li[right] <= tmp:  # 和右邊的數比較
            right -= 1
        li[left] = li[right]                        
        while left < right and li[left] >= tmp:   # 和左邊的數比較
            left += 1
        li[right] = li[left]
    li[left or right] = tmp  # tmp到達指定位置       
    return left or right     # 返回tmp下標


data = list(range(10))
random.shuffle(data)
quick_sort(data, 0, len(data)-1)
print(data)
快排DEMO1
# 升序排列

def quick_sort(li, left, right):
    i = left
    j = right
    if i >= j:
        return li
    tmp = li[i]
    while i < j:
        while i < j and li[j] >= tmp:
            j -= 1
        li[i] = li[j]
        while i < j and li[i] <= tmp:
            i += 1
        li[j] = li[i]
    li[i] = tmp
    quick_sort(li, left, j-1)
    quick_sort(li, i+1, right)
    return li

data = list(range(10))
random.shuffle(data)
quick_sort(data, 0, len(data)-1)
print(data)
快排DEMO2

堆排序

前傳:樹與二叉樹簡介

  • 樹是一種數據結構          好比:目錄結構
  • 樹是一種能夠遞歸定義的數據結構
  • 樹是由n個節點組成的集合:
    若是n=0,那這是一棵空樹;
    若是n>0,那存在1個節點做爲樹的根節點,其餘節點能夠分爲m個集合,每一個集合自己又是一棵樹。

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

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

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

那麼,堆有必定的規律,若是這個堆是這樣的呢

堆排序過程:

  1. 創建堆
  2. 獲得堆頂元素,爲最大元素
  3. 去掉堆頂,將堆最後一個元素放到堆頂,此時可經過一次調整從新使堆有序
  4. 堆頂元素爲第二大元素
  5. 重複步驟3,直到堆變空

那麼依託於這個過程,寫一下代碼

import random


def sift(data, low, high):
    """
    建堆
    :param data: 
    :param low: 
    :param high: 
    :return: 
    """
    i = low        # 堆的最高位置
    j = 2 * i + 1  # 找左孩子
    tmp = data[i]  # 最高位置對應數值
    while j <= high:  # 孩子是否存在於樹內, 一直往下找
        if j+1 <= high and data[j] < data[j+1]:
            # 若是有右孩子而且右孩子比左孩子大
            j = j+1  # j指向右孩子
        if data[j] > tmp:
            # 若是孩子比父親大
            data[i] = data[j]  # 孩子填充到父親的空位
            i = j              # 孩子成爲新父親, 父親成了孩子
            j = 2 * i + 1      # 到下一層的新孩子
        else:
            break
        data[i] = tmp          # 最高領導放到父親位置


def heap_sort(data):
    n = len(data)  # 標識 data 的長度
    # 創建好堆
    for i in range(n//2-1, -1, -1):
        sift(data, i, n-1)
    # 出數
    for i in range(n-1, -1, -1):  # i指向堆的最後
        data[0], data[i] = data[i], data[0]  # 領導退休, 刁民上位
        sift(data, 0, i-1)  # 調整出新領導


data = list(range(100))
random.shuffle(data)
heap_sort(data)
print(data)
堆排序DEMO

歸併排序,希爾排序

更新中...

相關文章
相關標籤/搜索