算法與數據結構

什麼是算法?算法

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

一個大牛曾說過:程序=數據結構+算法app

遞歸的兩個特色:dom

    調用自身ide

    結束條件ui

下面兩個的不一樣:  spa

# def func3(x):
#     if x>0:
#         print(x)
#         func3(x-1)
# func3(5)這個打印的結果是54321
def func4(x):
    if x > 0:
        func4(x - 1)
        print(x)


func4(5)#這個打印的結果是12345

咱們來看代碼運行的時間複雜度和空間複雜度:code

時間複雜度:blog

      print('Hello World!')#這個時間的複雜度是o(1)排序

      for  i in range(n):

             print('Hello World')  #z這個時間的複雜度是o(n)

     for i  in range(n):

             for j in range(n):

                 print('Hello World!')#這個時間的複雜度是o(n2)

     while n>1:

         print(n)

          n=n//2       #這個時間的複雜度是O(logn)

時間複雜度小結:

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

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

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

          

 

 

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

     循環減半的過程就是O(logn)

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

空間複雜度:

      它是用來評估算法內存佔用大小的一個式子

遞歸查找的二分法:

def linear_search(data_set,value):#時間複雜度是O(n)
    for i in range(range(data_set)):
        if data_set[i]==value:
            return  i
        return
def bin_search(data_set,value):#時間複雜度是O(logn)
    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

遞歸版的二分查找:  

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
li=[55,66,77,88,99,100,200,600,500]
s=bin_search_rec(li,100,0,len(li)-1)
print(s)

排序模塊:

  排序屆lowB三人組:

       冒泡排序

import  random
def bubble_sort_2(li):#時間複雜度是O(n*2)
    for i in range(len(li) - 1):
        # i 表示趟數
        # 第 i 趟時: 無序區:(0,len(li) - i)
        change = False
        for j in range(0, len(li) - i - 1):
            if li[j] > li[j+1]:
                li[j], li[j+1] = li[j+1], li[j]
                change = True
        if not change:
            return

li = list(range(10000))#生成一個列表
random.shuffle(li)#打亂列表
print(li)
bubble_sort_2(li)#冒泡排序
print(li)

       選擇排序

import random

def select_sort(li):
    for i in range(len(li) - 1):
        # i 表示趟數,也表示無序區開始的位置
        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]


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

      插入排序

import random
def insert_sort(li):
    for i in range(1, len(li)):
        # i 表示無序區第一個數
        tmp = li[i] # 摸到的牌
        j = i - 1 # j 指向有序區最後位置
        while li[j] > tmp and j >= 0:
            #循環終止條件: 1. li[j] <= tmp; 2. j == -1
            li[j+1] = li[j]
            j -= 1
        li[j+1] = tmp


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

NB排序方法:

import time


def cal_time(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        result = func(*args, **kwargs)
        t2 = time.time()
        print("%s running time: %s secs." % (func.__name__, t2-t1))
        return result
    return wrapper
算時間的裝飾器

 

   快排

# def partition(li, left, right):
#     temp = li[left]
#     while left < right:
#         while left < right and li[right] >= temp:
#             right -= 1
#         li[left] = li[right]
#         while left < right and li[left] <= temp:
#             left += 1
#         li[right] = li[left]
#
#     li[left] = temp
#     return left

# def partition(li, left, right):
#     # ri = random.randint(left, right)
#     # li[left], li[ri] = li[ri], li[left]
#     tmp = li[left]
#     while left < right:
#         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] = tmp
#     return left
# def quick_sort(li, left, right):
#     if left < right:
#         mid = partition(li, left, right)
#
#         quick_sort(li, left, mid - 1)
#
#         quick_sort(li, mid + 1, right)
#
#
# li = list(range(100))
# li.reverse()
# print(li)
# quick_sort(li, 0, len(li) - 1)
# print(li)

import random
from timewrap import *
import copy
import sys

sys.setrecursionlimit(100000)  # 設置最大遞歸深度


def partition(li, left, right):
    ri = random.randint(left, right)  # 加上這個是爲了防止最壞的狀況出現
    li[left], li[ri] = li[ri], li[left]
    tmp = li[left]
    while left < right:
        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] = tmp
    return left  # 返回歸併的的索引


def _quick_sort(li, left, right):
    if left < right:  # 至少有兩個元素
        mid = partition(li, left, right)
        _quick_sort(li, left, mid - 1)
        _quick_sort(li, mid + 1, right)


@cal_time
def quick_sort(li):
    return _quick_sort(li, 0, len(li) - 1)


@cal_time
def sys_sort(li):
    li.sort()


li = list(range(100000))
random.shuffle(li)#這是打亂列表的順序
li.reverse()
li1 = copy.deepcopy(li)
li2 = copy.deepcopy(li)

sys_sort(li1)  # 0.17502140998840332 secs.系統使用C寫的比較快
quick_sort(li2)  # quick_sort running time: 0.0004992485046386719 secs.
# print(li)
View Code

  堆排序:

from timewrap import *
import random

def _sift(li, low, high):
    """
    :param li:
    :param low: 堆根節點的位置
    :param high: 堆最後一個節點的位置
    :return:
    """
    i = low  # 父親的位置
    j = 2 * i + 1  # 孩子的位置
    tmp = li[low]  # 原省長
    while j <= high:
        if j + 1 <= high and li[j + 1] > li[j]:  # 若是右孩子存在而且右孩子更大
            j += 1
        if tmp < li[j]:  # 若是原省長比孩子小
            li[i] = li[j]  # 把孩子向上移動一層
            i = j
            j = 2 * i + 1
        else:
            li[i] = tmp  # 省長放到對應的位置上(幹部)
            break
    else:
        li[i] = tmp  # 省長放到對應的位置上(村民/葉子節點)


def sift(li, low, high):
    """
    :param li:
    :param low: 堆根節點的位置
    :param high: 堆最有一個節點的位置
    :return:
    """
    i = low         # 父親的位置
    j = 2 * i + 1   # 孩子的位置
    tmp = li[low]   # 原省長
    while j <= high:
        if j + 1 <= high and li[j+1] > li[j]: # 若是右孩子存在而且右孩子更大
            j += 1
        if tmp < li[j]: # 若是原省長比孩子小
            li[i] = li[j]  # 把孩子向上移動一層
            i = j
            j = 2 * i + 1
        else:
            break
    li[i] = tmp


@cal_time
def heap_sort(li):
    n = len(li)
    # 1. 建堆
    for i in range(n//2-1, -1, -1):
        sift(li, i, n-1)
    # 2. 挨個出數
    for j in range(n-1, -1, -1):    # j表示堆最後一個元素的位置
        li[0], li[j] = li[j], li[0]
        # 堆的大小少了一個元素 (j-1)
        sift(li, 0, j-1)


li = list(range(10000))
random.shuffle(li)
heap_sort(li)
print(li)

# li=[2,9,7,8,5,0,1,6,4,3]
# sift(li, 0, len(li)-1)
# print(li)
View Code

   歸併排序

import random
from timewrap import *
import copy
import sys


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 _merge_sort(li, low, high):
    if low < high:  # 至少兩個元素
        mid = (low + high) // 2
        _merge_sort(li, low, mid)
        _merge_sort(li, mid+1, high)
        merge(li, low, mid, high)
        # print(li[low:high+1])


def merge_sort(li):
    return _merge_sort(li, 0, len(li)-1)


li = list(range(16))
random.shuffle(li)
print(li)
# li=[10,8,11,7]
# merge_sort(li)
# 
# print(li)
View Code

 NB算法的時間複雜度都是O(nlongn):

通常狀況下:就運行時間而言:

    快速排序<歸併排序<堆排序

 三種排序算法的缺點:

  快速排序:極端狀況下排序效率低

  歸併排序:須要額外的內存開銷

  堆排序:在快的排序算法中相對較慢

相關文章
相關標籤/搜索