久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

python實(shí)現(xiàn)常見數(shù)據(jù)結(jié)構(gòu)及算法

 大傻子的文淵閣 2020-01-03

1. 概念

  • 數(shù)據(jù)結(jié)構(gòu)

    計(jì)算機(jī)存儲和組織數(shù)據(jù)的方式,。通俗的講,,計(jì)算機(jī)按不同數(shù)據(jù)結(jié)構(gòu)存儲數(shù)據(jù),決定著其保存數(shù)據(jù)的形式及將數(shù)據(jù)存入和取出的效率,,不同數(shù)據(jù)結(jié)構(gòu),存儲數(shù)據(jù)和讀取數(shù)據(jù)占用的時(shí)間和空間不同,。

  • 算法

    計(jì)算機(jī)完成一個(gè)任務(wù)的整個(gè)流程即為一種算法,。概念上講,算法和數(shù)據(jù)結(jié)構(gòu)沒有任何聯(lián)系,,但一般地,,使用不同的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)同一功能往往效率不同,因此,,算法與數(shù)據(jù)結(jié)構(gòu)密不可分,。

  • 算法的五大特性
    • 輸入: 算法具有0個(gè)或多個(gè)輸入;
    • 輸出: 算法至少有1個(gè)或多個(gè)輸出,;
    • 有窮性: 算法在有限的步驟之后會自動結(jié)束而不會無限循環(huán),,并且每一個(gè)步驟可以在可接受的時(shí)間內(nèi)完成;
    • 確定性:算法中的每一步都有確定的含義,,不會出現(xiàn)二義性,;
    • 可行性:算法的每一步都是可行的,也就是說每一步都能夠執(zhí)行有限的次數(shù)完成,;
  • 時(shí)間復(fù)雜度

    計(jì)算機(jī)實(shí)現(xiàn)某一算法所需的基本操作數(shù),。注意,時(shí)間復(fù)雜度并不是完成某一算法的耗時(shí),。所謂基本操作數(shù),,可以理解為計(jì)算機(jī)執(zhí)行指令的最小單元,例如執(zhí)行加法,,減法,,判斷,等,。通常采用大O表示法表示時(shí)間復(fù)雜度,。

  • 大O表示法

    時(shí)間復(fù)雜度和大O表示法有專門的數(shù)學(xué)函數(shù)表達(dá)式解釋,在此不作詳解(看了又忘)??梢岳斫鉃?,當(dāng)要對數(shù)量為n的數(shù)據(jù)實(shí)現(xiàn)至某一規(guī)則時(shí),所需最多操作數(shù)可以表示為與n相關(guān)的某個(gè)函數(shù)表達(dá)式的值,。一般地,,大O表示法只取決于表達(dá)式中次數(shù)最高項(xiàng),次級次數(shù)項(xiàng),,常數(shù)項(xiàng),,系數(shù)等都忽略。

  • 時(shí)間復(fù)雜度分類
    • 最壞時(shí)間復(fù)雜度
    • 最優(yōu)時(shí)間復(fù)雜度
    • 平均時(shí)間復(fù)雜度
  • 時(shí)間復(fù)雜度計(jì)算規(guī)則
    • 基本操作,,即只有常數(shù)項(xiàng),,認(rèn)為其時(shí)間復(fù)雜度為O(1);
    • 順序結(jié)構(gòu),,時(shí)間復(fù)雜度按加法進(jìn)行計(jì)算,;
    • 循環(huán)結(jié)構(gòu),時(shí)間復(fù)雜度按乘法進(jìn)行計(jì)算,;
    • 分支結(jié)構(gòu),,時(shí)間復(fù)雜度取最大值;

2. 算法初體驗(yàn)

了解了一些基本概念,,接下來對算法的作用有個(gè)初步體驗(yàn),。
現(xiàn)假設(shè)現(xiàn)要計(jì)算如下問題:
求滿足條件的所有a,b,c組合:a+b+c=1000, a^2 + b^2 =c^2。

  • 方式一(直接上代碼,,邏輯比較簡單):
import time


start_time = time.time()
for a in range(1001):
   for b in range(1001):
       for c in range(1002):
           if a+b+c == 1000 and a*a+b*b == c*c:
               print('a=%d,b=%d,c=%d' % (a, b, c))

end_time = time.time()
print('共耗時(shí):%f' % (end_time-start_time))
  • 結(jié)果
a=0,b=500,c=500
a=200,b=375,c=425
a=375,b=200,c=425
a=500,b=0,c=500
共耗時(shí):123.326442

Process finished with exit code 0
  • 方式二
import time


start_time = time.time()

for a in range(1001):
    for b in range(1001):
        c = 1000-a-b
        if a*a+b*b == c*c:
            print('a=%d,b=%d,c=%d' % (a, b, c))

end_time = time.time()
print('共耗時(shí):%f' % (end_time - start_time))
  • 結(jié)果
a=0,b=500,c=500
a=200,b=375,c=425
a=375,b=200,c=425
a=500,b=0,c=500
共耗時(shí):0.281858

Process finished with exit code 0

可以看出,,為實(shí)現(xiàn)同一目標(biāo),計(jì)算機(jī)使用不同算法結(jié)果相差多個(gè)數(shù)量級,。

  • 分析

根據(jù)上面時(shí)間復(fù)雜度計(jì)算規(guī)則,,方式一時(shí)間復(fù)雜度為O(n^3), 而方式二時(shí)間復(fù)雜度為O(n^2),。因?yàn)榇颂巒=1001,所以二者相差近3個(gè)數(shù)量級,。

  • 常見時(shí)間復(fù)雜度大小

O(1) < O(log n) < O(n) < O(nlog n) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)
這里,,log n 指以2為底,n的對數(shù),。

3. 常見數(shù)據(jù)結(jié)構(gòu)

對算法有個(gè)初步的概念后,,接下來了解下計(jì)算機(jī)中常見的數(shù)據(jù)結(jié)構(gòu)。

  • 順序表:元素順序地存放在一塊連續(xù)的存儲區(qū)里,;
    • 一體式順序表:表頭信息和內(nèi)容相連,;
    • 分離式順序表:表頭信息和內(nèi)容不相連;

    python中l(wèi)ist就是一種采用分離式技術(shù)實(shí)現(xiàn)的動態(tài)順序表。

  • 鏈表:元素存放在通過鏈接構(gòu)造起來的一系列存儲塊中,;
    • 單向鏈表
    • 單向循環(huán)鏈表:尾節(jié)點(diǎn)的下個(gè)節(jié)點(diǎn)指向頭節(jié)點(diǎn)的單向鏈表,;
    • 雙向鏈表:不僅上節(jié)點(diǎn)指向下節(jié)點(diǎn),下節(jié)點(diǎn)同時(shí)指向上節(jié)點(diǎn),;
  • 棧:一種先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu),;
  • 隊(duì)列:一種先進(jìn)先出的數(shù)據(jù)結(jié)構(gòu);

4. python實(shí)現(xiàn)常見數(shù)據(jù)結(jié)構(gòu)

  • pyhton實(shí)現(xiàn)單向鏈表
class Node(object):
    """節(jié)點(diǎn)"""

    def __init__(self, item):
        self.item = item
        self.next = None  # 指向下一節(jié)點(diǎn)


class SingleLinkList(object):
    """單向鏈表"""

    def __init__(self):
        self.__head = None  # 頭節(jié)點(diǎn)

    def is_empty(self):
        """鏈表是否為空"""
        return self.__head is None

    def length(self):
        """鏈表長度"""
        cur = self.__head
        count = 0
        while cur is not None:
            cur = cur.next
            count += 1
        return count

    def travel(self):
        """遍歷鏈表"""
        cur = self.__head  # 創(chuàng)建游標(biāo)指向頭節(jié)點(diǎn)
        while cur is not None:
            print(cur.item, end=' ')
            cur = cur.next
        print()  # 換行

    def add(self, item):
        """鏈表頭部添加節(jié)點(diǎn)"""
        node = Node(item)  # 創(chuàng)建節(jié)點(diǎn)
        node.next = self.__head  # 新節(jié)點(diǎn)下個(gè)元素指向頭節(jié)點(diǎn)
        self.__head = node  # 頭節(jié)點(diǎn)指向新節(jié)點(diǎn)

    def append(self, item):
        node = Node(item)
        if self.is_empty():
            self.__head = node
        else:
            cur = self.__head
            while cur.next is not None:
                cur = cur.next
            cur.next = node

    def insert(self, pos, item):
        """指定位置添加元素"""
        if pos <= 0:
            self.add(item)
        elif pos > (self.length()-1):
            self.append(item)
        else:
            node = Node(item)
            cur = self.__head
            index = 0
            while index < pos-1:  # 注意這里是pos-1
                index += 1
                cur = cur.next
            node.next = cur.next
            cur.next = node

    def remove(self, item):
        """刪除節(jié)點(diǎn)"""
        cur = self.__head  # 頭節(jié)點(diǎn)
        pre = None  # 前一個(gè)節(jié)點(diǎn)
        while cur is not None:
            if cur.item == item:
                if pre is None:  # 首節(jié)點(diǎn)
                    self.__head = cur.next
                else:  # 中間節(jié)點(diǎn)(或尾節(jié)點(diǎn))
                    pre.next = cur.next
                break
            # 鏈表繼續(xù)后移
            pre = cur
            cur = cur.next

    def search(self, item):
        cur = self.__head
        while cur is not None:
            if cur.item == item:
                return True
            cur = cur.next
        return False

  • python實(shí)現(xiàn)單向循環(huán)列表
class Node(object):
    """單向鏈表節(jié)點(diǎn)"""

    def __init__(self, item):
        self.item = item
        self.next = None


class SinCycLinkList(object):
    """單向循環(huán)鏈表"""

    def __init__(self):
        self.__head = None

    def is_empty(self):
        return self.__head is None

    def length(self):
        if self.is_empty():
            return 0
        cur = self.__head
        count = 1
        while cur.next != self.__head:
            count += 1
            cur = cur.next
        return count

    def travel(self):
        cur = self.__head
        if self.is_empty():
            return
        while cur.next != self.__head:
            print(cur.item, end=' ')
            cur = cur.next
        print(cur.item)

    def add(self, item):
        node = Node(item)
        cur = self.__head
        if self.is_empty():
            self.__head = node
            node.next = node
            return
        while cur.next != self.__head:
            cur = cur.next
        node.next = self.__head
        self.__head = node
        cur.next = node

    def append(self, item):
        node = Node(item)
        if self.is_empty():
            self.add(item)
            return
        cur = self.__head
        while cur.next != self.__head:
            cur = cur.next
        node.next = self.__head
        cur.next = node

    def insert(self, pos, item):
        if pos <= 0:
            self.add(item)
        elif pos > self.length() - 1:
            self.append(item)
        else:
            node = Node(item)
            cur = self.__head
            index = 0
            while index < pos-1:
                cur = cur.next
                index += 1
            node.next = cur.next
            cur.next = node

    def remove(self, item):
        if self.is_empty():
            return
        cur = self.__head
        pre = None
        # 要刪除的是頭節(jié)點(diǎn)的話需要知道尾節(jié)點(diǎn),,因此先判斷是頭節(jié)點(diǎn)的情況
        if cur.item == item:
            while cur.next != self.__head:
                pre = cur
                cur = cur.next
            # 循環(huán)執(zhí)行完后,,cur為尾節(jié)點(diǎn)
            if pre is None:  # 只有頭節(jié)點(diǎn)
                self.__head = None
            else:
                cur.next = self.__head.next
                self.__head = self.__head.next
        else:
            while cur.next != self.__head:
                if cur.item == item:
                    pre.next = cur.next
                    return
                else:
                    pre = cur
                    cur = cur.next
            if cur.item == item:
                pre.next = self.__head

    def search(self, item):
        if self.is_empty():
            return False
        cur = self.__head
        while cur.next != self.__head:
            if cur.item == item:
                return True
            cur = cur.next
        if cur.item == item:
            return True
        return False

  • python實(shí)現(xiàn)雙向鏈表
class DNode(object):
    """雙向鏈表節(jié)點(diǎn)"""

    def __init__(self, item):
        self.item = item
        self.pre = None
        self.next = None


class DoubleLinkList(object):
    """雙向鏈表"""

    def __init__(self):
        self.__head = None

    def is_empty(self):
        return self.__head is None

    def length(self):
        cur = self.__head
        count = 0
        while cur is not None:
            cur = cur.next
            count += 1
        return count

    def travel(self):
        cur = self.__head
        while cur is not None:
            print(cur.item, end=' ')
            cur = cur.next
        print()

    def add(self, item):
        node = DNode(item)
        if self.is_empty():
            self.__head = node
        else:
            node.next = self.__head
            self.__head.pre = node
            self.__head = node

    def append(self, item):
        if self.is_empty():
            self.append(item)
        else:
            cur = self.__head
            while cur.next is not None:
                cur = cur.next
            node = DNode(item)
            node.pre = cur
            cur.next = node

    def insert(self, pos, item):
        if pos <= 0:
            self.add(item)
        elif pos > self.length()-1:
            self.append(item)
        else:
            cur = self.__head
            index = 0
            while index < pos-1:
                cur = cur.next
                index += 1
            node = DNode(item)
            node.next = cur.next
            node.pre = cur
            cur.next.pre = node
            cur.next = node

    def remove(self, item):
        cur = self.__head
        while cur is not None:
            if cur.item == item:
                if cur.pre is None:  # 頭節(jié)點(diǎn)
                    self.__head = cur.next
                else:
                    cur.pre.next = cur.next
                if cur.next is not None:
                    cur.next.pre = cur.pre
                return
            cur = cur.next

    def search(self, item):
        cur = self.__head
        while cur is not None:
            if cur.item == item:
                return True
            cur = cur.next
        return False

  • python實(shí)現(xiàn)棧
class Stack(object):
    """棧"""

    def __init__(self):
        """創(chuàng)建一個(gè)新的空棧"""
        self.__list = list()  # 棧底層使用list來實(shí)現(xiàn)

    def is_empty(self):
        """判空"""
        return self.__list == []

    def size(self):
        """返回棧中元素個(gè)數(shù)"""
        return len(self.__list)

    def push(self, item):
        """添加一個(gè)新的元素item到棧頂"""
        self.__list.append(item)

    def pop(self):
        """彈出棧頂元素"""
        if self.is_empty():
            return None
        return self.__list.pop()

    def peek(self):
        """返回棧頂元素"""
        if self.is_empty():
            return None
        return self.__list[self.size()-1]

  • python實(shí)現(xiàn)隊(duì)列
class Queue(object):
    """隊(duì)列"""

    def __init__(self):
        self.__list = list()  # 使用list實(shí)現(xiàn)隊(duì)列

    def is_empty(self):
        return self.__list == []

    def size(self):
        return len(self.__list)

    def enqueue(self, item):
        """往隊(duì)列中添加一個(gè)元素"""
        self.__list.append(item)

    def dequeue(self):
        """從隊(duì)列頭中取出元素"""
        if self.is_empty():
            return None
        return self.__list.pop(0)

添加和獲取元素也可以分別使用list.insert(0, item)list.pop()實(shí)現(xiàn)。因此實(shí)現(xiàn)隊(duì)列時(shí),,考慮是插入多還是刪除多來選擇使用不同的方法(實(shí)際上這里取出次數(shù)<=添加次數(shù)),。

5. 常見排序算法

介紹常見排序算法前介紹一個(gè)概念:排序算法的穩(wěn)定性。指根據(jù)算法排序后,,原本相等的兩個(gè)元素的先后位置是否改變,,改變則稱不穩(wěn)定。作為了解即可,,實(shí)際使用中用到穩(wěn)定性的情況并不多,。

  • 冒泡排序:相鄰元素兩兩對比,將值大(小)的元素位置后移,;
  • 選擇排序:特定位置的元素與其他元素對比,,確保該位置元素最大(小);
  • 插入排序:列表分為兩部分,,前者為已有序列表,,將后者無序元素挨個(gè)和前者中元素比較,放置對應(yīng)位置,;
  • 快速排序:找一個(gè)基準(zhǔn)元素,,將所有小于基準(zhǔn)元素的放置一側(cè),大于(等于)基準(zhǔn)元素的放置另一側(cè),,遞歸,,直至列表大小為0或者1,即肯定有序,;
  • 希爾排序:插入排序的改進(jìn)版,,先按一定間隔分組,每組插入排序,,然后縮小間隔繼續(xù),,直至間隔大小為1;
  • 歸并排序:將數(shù)組分解最小之后,,然后合并兩個(gè)有序數(shù)組,,基本思路是比較兩個(gè)數(shù)組的最前面的數(shù),,誰小就先取誰,取了后相應(yīng)的指針就往后移一位,,然后再比較,,直至一個(gè)數(shù)組為空,最后把另一個(gè)數(shù)組的剩余部分復(fù)制過來,;

6. python實(shí)現(xiàn)常見排序算法

實(shí)現(xiàn)排序一般需要2-3層循環(huán),,對每層循環(huán)的作用應(yīng)有清晰的邏輯,否則容易暈導(dǎo)致出錯(cuò),??梢韵雀鶕?jù)算法核心思想算出外層邏輯需要幾次循環(huán)直接定義出,然后再定義內(nèi)部每次循環(huán)的邏輯,。

  • python實(shí)現(xiàn)冒泡排序
def bubble_sort(alist):
    # 因?yàn)槊芭菖判蛎看螌⒆畲蟮臄?shù)移動到最后,,因此需要n-1次循環(huán)即可,因?yàn)槠渌藕煤?,第一個(gè)即是最小元素
    for i in range(len(alist)-1):  # n-1次循環(huán)
        # 每次循環(huán)旨在將前n-i個(gè)元素中的最大元素放置至最后
        # 由于是兩兩相鄰比較,,即拿到一個(gè)元素與該元素后元素比較,因此循環(huán)至n-i-1即可
        for j in range(len(alist)-i-1):
            # 核心思想為:將大的數(shù)向后移動
            if alist[j] > alist[j+1]:
                alist[j], alist[j+1] = alist[j+1], alist[j]

  • 穩(wěn)定性:穩(wěn)定,;
  • 最壞時(shí)間復(fù)雜度:O(n^2),;
  • 最優(yōu)時(shí)間復(fù)雜度:O(n),表示遍歷一次后發(fā)現(xiàn)沒有需要交換的元素,。當(dāng)然,,為實(shí)現(xiàn)次功能需要額外加判斷條件及時(shí)退出循環(huán),如下:
def bubble_sort(alist):
    # 因?yàn)槊芭菖判蛎看螌⒆畲蟮臄?shù)移動到最后,,因此需要n-1次循環(huán)即可,,因?yàn)槠渌藕煤螅谝粋€(gè)即是最小元素
    for i in range(len(alist) - 1):  # n-1次循環(huán)
        # 每次循環(huán)旨在將前n-i個(gè)元素中的最大元素放置至最后
        # 由于是兩兩相鄰比較,,即拿到一個(gè)元素與該元素后元素比較,,因此循環(huán)至n-i-1即可
        count = 0  # 定義一個(gè)計(jì)數(shù)器,當(dāng)前后元素發(fā)生位置變化時(shí)加1,,如果最后計(jì)數(shù)器為0,,說明本身就是正序的
        for j in range(len(alist) - i - 1):
            
            # 核心思想為:將大的數(shù)向后移動
            if alist[j] > alist[j + 1]:
                alist[j], alist[j + 1] = alist[j + 1], alist[j]
                count += 1
        if count == 0:
            break
           
  • python實(shí)現(xiàn)選擇排序
def select_sort(alist):
    # 第一次將首位置換成最小值,以此類推,,共需要n-1次
    for i in range(len(alist)-1):
        # 拿到第i個(gè)元素,,與其之后的元素挨個(gè)比較,把較小值放置i位
        for j in range(i+1, len(alist)):
            if alist[i] > alist[j]:
                alist[i], alist[j] = alist[j], alist[I]

穩(wěn)定性:不穩(wěn)定,,從后往前放置時(shí),先滿足條件的元素先被放置最后,,會與相等的元素改變先后位置,;
最壞時(shí)間復(fù)雜度:O(n^2),;
最優(yōu)時(shí)間復(fù)雜度:O(n^2):需要從首個(gè)位置排到最后個(gè)位置;

  • python實(shí)現(xiàn)插入排序
def insert_sort(alist):
    # 首次分為第一個(gè)元素和其余元素兩部分,,從第二個(gè)元素開始,,與前面元素挨個(gè)比較,直到找到屬于自己的位置,。因此外層需要n-1次
    for i in range(len(alist)-1):
        # 將i+1位置的元素,,向前挨個(gè)比較,找到自己的位置,。即由第i個(gè)元素依次向前直至第0個(gè)元素
        for j in range(i+1, 0, -1):
            if alist[j] < alist[j-1]:
                alist[j], alist[j-1] = alist[j-1], alist[j]

穩(wěn)定性:穩(wěn)定,;
最壞時(shí)間復(fù)雜度:O(n^2);
最優(yōu)時(shí)間復(fù)雜度:O(n)。

  • python實(shí)現(xiàn)快速排序
"""
 快速排序和前面三種思想上有較大不同,,不再是外層循環(huán)次數(shù)下,,內(nèi)層循環(huán)實(shí)現(xiàn)將某一元素放至某位置。其核心思想是以某個(gè)值作為基準(zhǔn)值,,
 將小于該值的元素放至左側(cè)(交換位置),,大于該值的元素放至右側(cè)(交換位置),然后分別將左右兩側(cè)列表遞歸再次排序,。
"""


# 為了實(shí)現(xiàn)遞歸而不用重新定義左右列表變量,,將左右下標(biāo)作為參數(shù)
def quick_sort(alist, left, right):
    # 1. 遞歸退出條件
    if left >= right:
        return
    # 2. 核心:
    # 以首值為基準(zhǔn)值,判斷元素大小交換位置
    mid_value = alist[0]
    while left < right:
        # 循環(huán)找出小于基準(zhǔn)值的元素放至左側(cè)
        while left < right and alist[right] >= mid_value:
            right -= 1
        alist[left] = alist[right]
        # 循環(huán)找出大于基準(zhǔn)值的元素放至右側(cè)
        while left < right and alist[left] < mid_value:
            left += 1
        alist[right] = alist[left]
    # 循環(huán)結(jié)束后,,left=right,,該位置放基準(zhǔn)值
    alist[left] = mid_value
    # 對基準(zhǔn)值左右兩側(cè)元素遞歸快排
    quick_sort(alist, 0, left-1)
    quick_sort(alist, left+1, right)

穩(wěn)定性:不穩(wěn)定,后前交互比較大小替換位置,,必然不穩(wěn)定,;
最壞時(shí)間復(fù)雜度:O(n^2),最大需要遞歸n-1次,,每次中,,內(nèi)層循環(huán)最大都要比較n次;
最優(yōu)時(shí)間復(fù)雜度:O(nlogn),,每次幾乎分一半一半時(shí),,需要logn次循環(huán);
PS:快速排序較前面三種排序難度提升,,但很重要,。

  • python實(shí)現(xiàn)希爾排序
"""
希爾排序是插入排序的改進(jìn)版,先以一定步長將列表分為多個(gè)子列表,,然后對每個(gè)子列表插入排序,。執(zhí)行完成后,縮小步長繼續(xù),,直至步長為0,。
這里可能會有疑惑,,最終步長為1時(shí)就是插入排序,為什么還要多幾次步長不為1的循環(huán),?
實(shí)際上,,前面知道插入排序后面每個(gè)元素向前插入時(shí),需要從前往后遍歷比較,,但如果比首個(gè)元素都小則可直接插入,。我們可以理解為,對大部分
無序隨機(jī)數(shù)列,,步長取合適時(shí),,時(shí)間復(fù)雜度會有很大改善。
"""


def shell_sort(alist):
    # 取首次步長為列表長度一半
    gap = len(alist) // 2
    while gap > 0:
        # 內(nèi)層類似插入排序,,只不過步長為gap
        # 循環(huán)次數(shù):gap->len
        for i in range(gap, len(alist)):
            # 內(nèi)層:將第i個(gè)元素依次與前面元素比較調(diào)整位置,,不過步長為gap
            for j in range(i, 0, -gap):
                if alist[j] < alist[j-gap]:
                    alist[j], alist[j-gap] = alist[j-gap], alist[j]
        # 排序后gap減小
        gap = gap // 2

穩(wěn)定:不穩(wěn)定;
最壞時(shí)間復(fù)雜度:O(n^2),;
最優(yōu)時(shí)間復(fù)雜度:(數(shù)學(xué)統(tǒng)計(jì)最優(yōu)可達(dá)O(n^1.3))

  • python實(shí)現(xiàn)歸并排序
"""
歸并排序,,如名字一樣,是將序列一邊合并一邊排序,。其核心思想為:
先將序列遞歸的折半拆分,,直到長度為1,然后執(zhí)行排序后作為本層遞歸的返回,。
需注意歸并排序每層遞歸都有返回值,,因此比前面幾個(gè)排序耗費(fèi)空間。
"""


def merge_sort(alist):
    # 1. 遞歸退出條件
    if len(alist) <= 1:
        return alist  # 注意有返回值
    # 2.核心思想
    # 二分分解
    num = len(alist) // 2
    # 取左右兩截(內(nèi)部遞歸)
    left_list = merge_sort(alist[0:num])
    right_list = merge_sort(alist[num:])
    # 返回根據(jù)左右兩截實(shí)現(xiàn)的排序序列
    return merge(left_list, right_list)


def merge(left_list, right_list):
    # 排序核心:將左右兩個(gè)有序數(shù)列內(nèi)依次取滿足大小比較的元素,,放置新序列
    # 定義左右兩序列的其實(shí)元素位置
    left, right = 0, 0
    # 定義一個(gè)新序列接收排序后序列
    result = list()
    # 循環(huán)退出條件:一側(cè)遍歷完,,將另一側(cè)剩余元素直接添加至后面
    while left < len(left_list) and right < len(right_list):
        if left_list[left] < right_list[right]:
            result.append(left_list[left])
            left += 1
        else:
            result.append(right_list[right])
            right += 1
    result += left_list[left:]
    result += right_list[right:]
    return result

穩(wěn)定性:穩(wěn)定;
最壞時(shí)間復(fù)雜度:O(nlogn),;
最優(yōu)時(shí)間復(fù)雜度:O(nlogn),;

  • 常見排序算法效率比較
排序方法 平均時(shí)間復(fù)雜度 最優(yōu)時(shí)間復(fù)雜度 最壞時(shí)間復(fù)雜度 輔助空間 穩(wěn)定性
冒泡排序 O(n^2) O(n) O(n^2) O(1) 穩(wěn)定
選擇排序 O(n^2) O(n^2) O(n^2) O(1) 不穩(wěn)定
插入排序 O(n^2) O(n) O(n^2) O(1) 穩(wěn)定
快速排序 O(nlogn) O(nlogn) O(n^2) O(logn)-O(n) 不穩(wěn)定
希爾排序 O(nlogn)-O(n^2) O(n^1.3) O(n^2) O(1) 不穩(wěn)定
歸并排序 O(nlogn) O(nlogn) O(nlogn) O(n) 穩(wěn)定

7. 常見搜索算法

常見算法除排序算法外還有就是搜索算法了。常見的搜索算法有針對有序序列的二分查找法,,和針對二叉樹的廣度優(yōu)先深度優(yōu)先算法,。
樹是另一種抽象的數(shù)據(jù)結(jié)構(gòu),主要有根節(jié)點(diǎn)和子節(jié)點(diǎn)等概念,。一般主要使用的就是二叉樹,,即每個(gè)節(jié)點(diǎn)最多只有兩個(gè)子節(jié)點(diǎn)的樹。對樹概念比較陌生的讀者可以自行百度一波,,樹數(shù)據(jù)結(jié)構(gòu)的使用可以參考下圖來理解,,另外xml,html等都是樹結(jié)構(gòu)。

樹的使用.png

另外,,對二叉樹或完全二叉樹和滿二叉樹(概念自行百度)有一些數(shù)學(xué)性質(zhì),,如需了解可自行學(xué)習(xí)。
  • python實(shí)現(xiàn)二分查找
"""
二分查找法核心思想為:
找中間值將序列(等分地)分成兩段,,判斷要找的元素比中間值大還是小,小的話在左側(cè)段繼續(xù)二分查找,,大的在右側(cè),。
python實(shí)現(xiàn)二分查找可以通過遞歸和非遞歸兩種方式實(shí)現(xiàn)
"""


def binary_search(alist, item):
    """非遞歸實(shí)現(xiàn)二分查找"""
    # 定義出始末下標(biāo)
    start = 0
    end = len(alist)-1
    # 循環(huán)結(jié)束條件:二分查找的序列長度為大于0
    while start <= end:
        # 找到中間值下標(biāo)
        mid_point = (start+end) // 2
        if item == alist[mid_point]:
            return True
        elif item > alist[mid_point]:
            start = mid_point+1
        else:
            end = mid_point-1
    return False

def binary_search(alist, item):
    """遞歸實(shí)現(xiàn)二分查找"""
    # 遞歸結(jié)束條件:二分到長度為0時(shí)說明未找到
    if len(alist) == 0:
        return False
    mid_point = len(alist) // 2
    if alist[mid_point] == item:
        return True
    if alist[mid_point] > item:
        return binary_search(alist[:mid_point], item)
    else:
        return binary_search(alist[mid_point+1:], item)

最壞時(shí)間復(fù)雜度:O(logn);
最優(yōu)時(shí)間復(fù)雜度:O(1),;

  • python表示二叉樹節(jié)點(diǎn)及實(shí)現(xiàn)樹的創(chuàng)建
class Node(object):
    """二叉樹節(jié)點(diǎn)"""
    # 二叉樹節(jié)點(diǎn)三個(gè)屬性:值,,左子節(jié)點(diǎn),右子節(jié)點(diǎn)
    def __init__(self, item):
        self.item = item
        self.lchild = None
        self.rchild = None


class Tree(object):
    """(滿)二叉樹"""
    # 二叉樹初始化時(shí)需要根節(jié)點(diǎn)
    def __init__(self):
        self.__root = None

    def add(self, item):
        """添加元素"""
        node = Node(item)
        if self.__root is None:
            self.__root = node
        else:
            # 核心思想:將頭節(jié)點(diǎn)加入至隊(duì)列,,先判斷左節(jié)點(diǎn),,為空則將節(jié)點(diǎn)放置左側(cè);若不為空,,判斷右節(jié)點(diǎn),,為空則放置右節(jié)點(diǎn)。若左右都不為空,,分別將左右
            # 節(jié)點(diǎn)加入至隊(duì)列尾,,再取隊(duì)列首節(jié)點(diǎn)繼續(xù)上面邏輯
            queue = list()
            queue.append(self.__root)
            while queue:
                cur = queue.pop()
                if cur.lchild is None:
                    cur.lchild = node
                    return
                if cur.rchild is None:
                    cur.rchild = node
                    return
                # 左右都不為空,將左右節(jié)點(diǎn)放置隊(duì)列尾
                queue.append(cur.rchild)
                queue.append(cur.rchild)

  • python實(shí)現(xiàn)二叉樹深度優(yōu)先遍歷
"""
二叉樹深度優(yōu)先遍歷根據(jù)遍歷順序不同可分為三類:
先序遍歷:先訪問根節(jié)點(diǎn),,再訪問左節(jié)點(diǎn),,最后右節(jié)點(diǎn);
中序遍歷:先訪問左節(jié)點(diǎn),,再訪問根節(jié)點(diǎn),,最優(yōu)右節(jié)點(diǎn);
后續(xù)遍歷:先訪問左節(jié)點(diǎn),,再當(dāng)問右節(jié)點(diǎn),,最后根節(jié)點(diǎn),注意左節(jié)點(diǎn)永遠(yuǎn)在右節(jié)點(diǎn)前,,后續(xù)指根節(jié)點(diǎn)和右節(jié)點(diǎn)的順序,。
"""


def preorder(root):
    """遞歸實(shí)現(xiàn)先序遍歷"""
    if root is None:
        return
    print(root.item)
    preorder(root.lchild)
    preorder(root.rchild)

def inorder(root):
    """遞歸實(shí)現(xiàn)中序遍歷"""
    if root is None:
        return
    inorder(root.lchild)
    print(root.item)
    inorder(root.rchild)

def postorder(root):
    """遞歸實(shí)現(xiàn)后續(xù)遍歷"""
    if root is None:
        return
    postorder(root.lchild)
    postorder(root.rchild)
    print(root.item)
  • python實(shí)現(xiàn)二叉樹廣度優(yōu)先遍歷
"""
廣度優(yōu)先遍歷的核心:從根節(jié)點(diǎn)開始,從上到下,,從左到右遍歷整個(gè)樹的節(jié)點(diǎn)
"""


def breadth_travel(root):
    if root is None:
        return
    queue = list()
    queue.append(root)
    while queue:
        node = queue.pop(0)
        print(node.item)
        if node.lchild is not None:
            queue.append(node.lchild)
        if node.rchild is not None:
            queue.append(node.rchild)
  • 整合上述方法
class Node(object):
    """二叉樹節(jié)點(diǎn)"""
    # 二叉樹節(jié)點(diǎn)三個(gè)屬性:值,,左子節(jié)點(diǎn),右子節(jié)點(diǎn)
    def __init__(self, item):
        self.item = item
        self.lchild = None
        self.rchild = None


class Tree(object):
    """(滿)二叉樹"""
    # 二叉樹初始化時(shí)需要根節(jié)點(diǎn)
    def __init__(self):
        self.root = None

    def add(self, item):
        """添加元素"""
        node = Node(item)
        if self.root is None:
            self.root = node
        else:
            # 核心思想:將頭節(jié)點(diǎn)加入至隊(duì)列,,先判斷左節(jié)點(diǎn),,為空則將節(jié)點(diǎn)放置左側(cè);若不為空,,判斷右節(jié)點(diǎn),,為空則放置右節(jié)點(diǎn),。若左右都不為空,分別將左右
            # 節(jié)點(diǎn)加入至隊(duì)列尾,,再取隊(duì)列首節(jié)點(diǎn)繼續(xù)上面邏輯
            queue = list()
            queue.append(self.root)
            while queue:
                cur = queue.pop(0)  # 注意是取第0個(gè)元素,,與下面的append相斥
                if cur.lchild is None:
                    cur.lchild = node
                    return
                if cur.rchild is None:
                    cur.rchild = node
                    return
                # 左右都不為空,將左右節(jié)點(diǎn)放置隊(duì)列尾
                queue.append(cur.lchild)
                queue.append(cur.rchild)

    def preorder(self, root):
        """遞歸實(shí)現(xiàn)先序遍歷"""
        if root is None:
            return
        print(root.item)
        self.preorder(root.lchild)
        self.preorder(root.rchild)

    def inorder(self, root):
        """遞歸實(shí)現(xiàn)中序遍歷"""
        if root is None:
            return
        self.inorder(root.lchild)
        print(root.item)
        self.inorder(root.rchild)

    def postorder(self, root):
        """遞歸實(shí)現(xiàn)后續(xù)遍歷"""
        if root is None:
            return
        self.postorder(root.lchild)
        self.postorder(root.rchild)
        print(root.item)

    def breadth_travel(self, root):
        """廣度優(yōu)先遍歷"""
        if root is None:
            return
        queue = list()
        queue.append(root)
        while queue:
            node = queue.pop(0)
            print(node.item)
            if node.lchild is not None:
                queue.append(node.lchild)
            if node.rchild is not None:
                queue.append(node.rchild)

深度優(yōu)先一般用遞歸,,廣度優(yōu)先一般用隊(duì)列,。一般情況下能用遞歸實(shí)現(xiàn)的算法大部分也能用堆棧來實(shí)現(xiàn)。

8. 結(jié)語

算法在編程語言中至關(guān)重要,,但真正掌握好算法并不是一時(shí)半會兒能搞定的,。理解掌握常用算法能對以后的積累和解決問題提供一定基礎(chǔ)和思路。
上述算法比較簡單,,但掌握起來也并不容易,。不需要記住每個(gè)的具體步驟,而且實(shí)現(xiàn)方式也不是唯一,,但需要細(xì)心理解每個(gè)算法的核心思想,,多寫幾次,才能達(dá)到比較熟練的水平,。

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多