1. 程式人生 > 其它 >資料結構 棧求算術表示式_用python描述資料結構

資料結構 棧求算術表示式_用python描述資料結構

技術標籤:資料結構 棧求算術表示式

pythonData-Structures-and-Algorithms

一、演算法複雜度

O(1)、O(log n),O(n),O(n log n),O(n2),O(n3),O(nn)

計算規則

1.基本迴圈程式:

  • 基本操作:複雜度O(1) ,如果是函式呼叫,將其時間複雜度代入,參與整體時間複雜度計算。
  • 加法規則(順序複合):兩部分(多部分)的順序複合,複雜度是兩部分的加和。
    T(n)=T1(n)+T2(n)=O(T1(n))+O(T2(n)) = O(max()T1(n),T2(n))
  • 乘法規則(迴圈結構):迴圈體執行T1(n)次,每次執行要T2(n)時間,那麼:
    T(n)=T1(n) * T2(n) = O(T1(n)) * O(T2(n)) = O(T1(n)*T2(n))
  • 取最大規則(分支結構): 如果演算法是條件分支,兩個分支的時間複雜性分別為 T1(n)和T2(n) ,那麼:
    T(n) = O(max()T1(n),T2(n))

2.python的計算代價

  • 時間開銷:
  1. 基本算術運算和邏輯運算是常量時間運算,O(1)
  2. 組合物件的操作:
    複製和切片操作O(n),與長度有關
    list,tuple元素訪問和賦值,是O(1)
    dict操作比較複雜
  3. 字串看組合物件來定
  4. 建立物件餘姚輔助空間和時間,代價都與物件大小有關
  5. 構造新結構,如list、tuple、set等包含n個元素,O(n)
  6. dict平均複雜度O(1),最壞情況O(n)
  • 空間開銷:
  1. 一般而言,建立n個元素的資料結構,為O(n)
  2. python中沒有預設最大元素個數,會自動擴充儲存空間。
  3. 注意python自動儲存管理系統的影響

二、抽象資料型別ADT

定義一個抽象資料型別,目的是要定義一類計算物件,它們具有某些特定功能,可以在計算中使用。

構造有理數抽象資料型別,如下

ADT Rational:               #定義有理數抽象資料型別
Rational(int num,int den)   #構造有理數num,den
+(Rational r1, Rational r2)  #r1+r2
-(Rational r1, Rational r2)  #r1-r2
*(Rational r1, Rational r2)     #r1*r2
/(Rational r1, Rational r2)     #r1/r2

日期抽象資料型別:

ADT Date:
    Date(int year,int month,int day)    #定義年月日
    difference(Date d1,Date d2)         #求d1和d2的日期差
    plus(Date d,int n)                  #日期d後n天的日期
    num_date(int year,int n)            #計算year年第n天的日期

ADT是一種思想,也是一種組織程式的技術:

  1. 圍繞一類資料定義程式模組
  2. 模組的介面和實現分離
  3. 在需要實現的時候,採用合理的技術,選擇合適的機制,實現這種ADT功能,包括具體的資料表示和操作。

三、類

  1. 類定義和使用:
    class <類名>: <語句組>
    類物件支援兩種操作:屬性訪問例項化
  2. 例項物件:初始化和使用
    使用__init__方法完成初始化,第一個引數self,其可以有更多的形式引數。
  3. 幾點說明:
  • 使用_,避免方法名字衝突,比如_numnum
  • 如果在一個方法函式裡需要呼叫在同類裡的另一個方法函式,要使用self.g(...)g()為 類的另一個函式
  • 方法函式可以通過globalnonlocal宣告來訪問全域性變數和函式.
  • 使用isinstance(obj,cls)檢查類和物件的關係,檢查obj物件是否是類cls 的例項
  1. 解調方法和類方法:
  • 在def行前加@staticmethod表示靜態方法,不需要 self引數,通過類名或值為例項物件的變數,以屬性引用的方式呼叫靜態函式
  • 在def行前加@classmethod表示類方法,習慣用cls引數名
  1. 類定義的作用於規則: 類定義的識別符號具有區域性作用域,只能在類裡使用。外部通過類名字的屬性引用方式來訪問。
  2. 私有變數
  • _一個下劃線開頭作為例項物件內部的東西,不應該在類以外訪問他們.
  • __開頭,但不結尾,在類外訪問不到這個物件。
  • 此外,具有__add__的形式表示特殊的魔法方法
  1. 繼承 在class(object):括號裡表示繼承的父類,使用issubclass(cls1,cls2)來檢查cls2是否為cls1 的基類

8.方法查詢: 在派生類裡查詢方法,根據繼承關係來找,直到Attribute Error異常為止。

9.super() super.m1()表示呼叫父類的m1函式,而不是本類的m1.

四、線性表

list和tuple採用了順序表的實現技術。

  1. 基於下標的高效元素訪問和更新,時間複雜度O(1)
  2. 允許任意元素加入,表物件的標識(id值)不變
  3. 要求操作為O(1),且保持順序,只能採用連續表技術,表元素儲存在一塊連續儲存區裡。
  4. 要求能容納任意多的元素,且保持id不變,採用分離式實現技術

list實現策略:建立空表,分配容納8個元素的儲存區,如果區滿換一塊4倍大的儲存區,如果表很大,改變策略,換儲存區時容量加倍,目前值時5000。

操 作性質:

  • len()是O(1)操作
  • 元素訪問和賦值,尾端加入和尾端刪除(尾端切片刪除)為O(1),pop()
  • 一般位置的元素加入、切片替換、切片刪除、表拼接(extend)是O(n),pop(n)指定位置
  • list.reverse()反轉操作,O(n) list.clear()是O(1)去除元素的操作,兩種方法
  • 將表的元素計數值設定為0,變為空表。
  • 另外分配一個空表用的儲存空間,原儲存區有python直譯器的儲存管理器自動回收。

五、字串

1. python字串相關概念:

  • 字串的長度:長度為0成為空串,長度為1的字串。
  • 字元在字串勵按順序排列,和線性表一樣。
  • 字串相等,說明長度相等,且兩串的對應位置的個字元兩兩相同。
  • 字典序:字串的一種序關係。就是從左往右看兩個穿中下標相同的各對字元,相比大小。
  • 字串拼接:用+來表示字串拼接
  • 字串關係:串s1與串s2中的一個連續片段相同,稱s1是s2的字串。
  • 字首和字尾是兩種特殊字串
  • python字串是不變資料型別,python沒有字元型別
  • 統一Unicode編碼字符集

2. 字串匹配(字串查詢)

  • 樸素的傳匹配演算法
  1. 從左往右逐個字元匹配
  2. 發現不匹配,到目標穿下一個位置開始匹配
  3. 演算法複雜性O(m*n)
    def navie_matching(t,p): m,n = len(p),len(t) i,j = 0,0 while i<m and j<n: if p[i] == t[j]: i,j=i+1,j+1 else: i,j=0,j-i+1 if i == m: return -1
  • 無回溯串匹配演算法(KMP) 詳見部落格 KMP演算法
    KMP時間複雜度:O(m+n)

3. 正則表示式

  • 元字元(特殊字元):

正則表示式包re14個元字元: . ^ $ * + ? | { } [ ] ( )

  • 主要操作:
  1. 生成表示式物件: re.compile(pattern,flag=0)
  2. 檢索 : re.search(pattern,string,flag=0)在裡檢索pattern,返回一個match型別的物件,否則返回None。
  3. 匹配: re.match(pattern,string,flag=0)檢查string是否存在一個與pattern匹配的字首。成功返回match物件,否則None。
  4. 分割:re.split(pattern,string,maxsplit=0,flasg=0)以pattern作為分割串,maxsplit指明最大分割數,用0表示要求處理完整個string。返回一個列表。
  5. 找出所有匹配串:re.findall(pattern,string,flags=0)返回一個表,表中按順序給出string裡與pattern匹配的各個字串
  6. 完全匹配: re.fullmatch(string[,pos,[,endpos]])
  • 正則表示式構造
  1. 字元組描述[...]與[]裡的字元序列裡的任意字元匹配。[abc]可以與字元a,b,c匹配。
  • 區間形式: [0-9a-zA-Z]
  • 特殊形式: [^...],^表示對列出的字元組求補
  1. 圓點字元(.):萬用字元,匹配所有字元,a..b表示以a開頭b結尾的所有字串
  • d:匹配十進位制數字等價於[0-9]
  • D:匹配所有非十進位制數字[^0-9]
  • s:匹配所有空白字元 [tvnfr]
  • S:匹配所有非空字元 [^ tvnfr]
  • w:匹配字母數字 [0-9a-zA-Z]
  • W:非字母數字 [^0-9a-zA-Z]
  1. 重複
  • 貪婪匹配:用 * 匹配0次或任意多次。
    re.split('[,]*',str)
  • 非貪婪匹配 : 用 + 匹配1次或任意多。d+等價於dd*
  1. 可選描述符: ?a?要求與a匹配的字串的0或1次重複匹配
  2. 重複次數描述符: {n}
    a{n}與a匹配的串n次重複
  3. 重複次數範圍 {n,m} go{2,5}gle,匹配結構為:google,gooogle,goooogle,gooooogle.
    a{n}等價於a{n,n},a?等價於a{0,1}
    *、+、?、{m,n}都採取貪婪匹配規則
  4. 非貪婪匹配描述符:
    *?,+?,??,{m,n}?表示非貪婪匹配策略,在後面加?
  5. 選擇
  • 選擇描述符 |
    表示兩種或多種串匹配模式
  1. 首位描述符:
  • 行首描述符:以^開頭的
  • 行尾描述符: 以$符號結尾
  • 串首描述符: A開頭的
  • 串尾描述符: Z結尾的
  1. 單詞邊界b描述單詞邊界,在實際單詞邊界位置匹配空串。單詞是字母數字的任意連續序列,邊界就是非字母數字的或者無字元.表示轉義
  2. 匹配物件(match物件)
    mat表示通過匹配得到的一個match物件
  • 取得被匹配的子串:mat.group()
  • 在目標串裡的匹配位置: mat.start()
  • 目標串裡的被匹配子串的結束位置: mat.end()
  • 目標串裡被匹配的區間: mat.span()得到匹配開始位置和結束位置組成的二元組
  • 其他mat.re和mat.string(是資料與訪問,不是函式)分別取得match物件的正則表示式和目標串。
  1. 模式裡的組(group)
    被匹配的組。

六、棧和佇列

存取關係:

  • 棧是保證元素後進先出(LIFO結構)
  • 佇列先進先出(FIFO結構)

1.棧抽象資料型別

ADT Stack:
        Stack(self)         #建立空棧
        is_empty(self)      #判斷棧是否為空,空返回True否則False
        push(self,elem)     #將元素elem加入棧,也常稱壓入或推入
        pop(self)           #彈出
        top(self)           #取得最後壓入棧的元素

python的list及其操作來實現棧:順序表技術實現棧類

  • 建立空棧對應於建立空表[]
  • list使用動態順序表技術(分離式),所以棧不會滿
  • 壓入元素對應於list.append()
  • 訪問棧頂元素 :list[-1]
  • 彈出操作: list.pop()無參,預設彈出表尾元素
    class SStack(): def __init__(self): self._elems= [] def is_empty(self): return self._elems == [] def top(self): if self._elems == []: raise StackUnderflow('in SStack.top') return self._elems[-1] def push(self,elem): drlf._elems.append() def pop(self): if self._elems == [] raise StackUnderflow('in SStack.pop') return self._elems.pop() st1 = SStack() st1.push(3) st1.push(2) while not st1.is_empty(): print(st1.pop())

棧的連結表實現: 所有棧操作都在一端進行,採用連結表技術,用表頭作為棧頂,用表尾作為棧底。

class LStak():
    def __init__(self):
        self._top=None

    def is_empty(self):
        return self._top is None
    
    def top(self):
        if self._top is None:
            raise StackUnderflow('in LStack.top')
        return self._top[-1]
    
    def push(self):
        self._top = LNode(elem,self._top)
    
    def pop(self):
        if self._top is None:
             raise StackUnderflow('in LStack.pop')
        p = self._top
        self._top = p.next
        return p.elem

2.棧的應用:

1.括號匹配問題: 三種括號[],(),{}

def check_parens(text):
    '''括號配對檢查函式,text是被檢查的正文串
    '''
    parens = "[](){}"
    open_parens="[({"
    
    def parenthese(text):
        """括號生成器,每次呼叫返回text的下一括號及其位置"""
        i,text_len=0,len(text) 
        while True:
            while i < text_len and text[i] not in parens:
                i+=1
            if i>= text_len:
                return
            yield text[i],i
            i+=1
    st = SStack()
    for pr,i in parentheses(text):
        if pr in open_parens:
            st.push(pr)
        elif st.pop() != opposite[pr]:
            print("Unmatching is found at",i,"for",pr)
            return False
    print("All parentheses are correctly matched.")
    return True

3.佇列

佇列(queue),稱為隊,先進先出,佇列沒有位置的概念,只支援預設方式的元素存入和取出。

ADT Queue:
    Queue(self)         #建立空佇列
    is_empty(self)      #判斷佇列是否為空
    enqueue(self,elem)  #將elem加入佇列,入隊
    dequeue(self)       #出隊
    peek(self)          #最早加入的元素,不刪除

佇列類的list實現

class SQueue():
    def __init__(self,init_len=8):
        self._len = init_len        #儲存區元素長度
        self._elems = [0]*init_len  #元素儲存
        self._head = 0              #表頭元素下標
        self._num = 0               #元素個數
    
    def is_empty(self):
        return self._num == 0
    
    def peek(self):
        if self._num == 0:
            raise QueueUnderflow
        return self._elems[self._head]
    
    def dequeue(self):
        if self._num == 0:
            raise QueueUnderflow
        e = self._elems[self._head]
        self._head = (self._head+1) % self._len
        self._num -= 1
        return e
    
    def enqueue(self,e):
        if self._num == self._len:
            self.__extend()
        self._elems[(self._head+self._num) % self._len] = e
        self._num += 1

    def __extend(self):
        old_len = self._len
        self._len *= 2
        new_elems = [0]*self._len
        for i in range(old_then):
            new_elems[i] = self._elems[(self._head + i )% old_len]
        self._elems,self._head = new_elems,0

七、二叉樹和樹

1.二叉樹

是節點的有窮集合。包含一個根節點,其餘節點分屬兩顆不相交的二叉樹,分別是根節點的左子樹和右子樹

  • 路徑,數從根節點到任意一個節點都有路徑,且唯一。
  • 二叉樹是層次結構,樹根看作做高層元素,規定跟層數為0。
  • 高度(深度):根節點高度為0。

2.二叉樹性質

  1. 在非空二叉樹第i層至多有 2i 個節點(i>=0)
  2. 高度為h的二叉樹至多有 2h+1-1 個節點(h>=0)
  3. 對於任何非空二叉樹T,其他節點個數為n0,度數為二的節點個數為n2,那麼n0 = n2 +1

3.滿二叉樹,擴充二叉樹

  1. 滿二叉樹:二叉樹中所有分支節點度數為2,滿二叉樹是一般二叉樹的一個子集。
    滿二叉樹的節點比分支節點多一個
  2. 擴充二叉樹:對二叉樹T,加入足夠多的節點,使其變為滿二叉樹T2。T2稱為T的擴充二叉樹。

3.完全二叉樹:對一個高度h的二叉樹,第0到h-1層的節點都滿,而最後一層不滿,且節點在左邊,空位在右邊。
性質:
1.n個節點的完全二叉樹高度h=[log2n]
2.n個節點的完全二叉樹,按照從上到下從左到右的順序從0開始編號,對任意節點i(0<=i<=n-1)都有

  • 序號為0的是根
  • 對i>0,父節點編號為(i-1)/2
  • 2*i+1<n,左子節點序號為2*i+1,否則無左子節點
  • 2*i+2<n,右子節點序號為2*i+2,否則無右子節點

3.抽象資料型別

ADT BinTree:
    BinTree(self,data,left,right)       #構造操作,建立二叉樹
    is_empty(self)                      #判斷是否為空
    num_nodes(self)                     #求二叉樹節點個數
    data(self)                          #獲取二叉樹根儲存的資料                     
    left(self)                          #左子樹
    right(self)                         #右子樹
    set_left(self,btree)                #用btree代替原左子樹
    set_right(self,btree)               #用btree代替原右子樹
    traversal(self)                     #遍歷二叉樹中個節點資料的迭代器
    forall(self,op)                     #對二叉樹的每個節點進行op操作

4.遍歷二叉樹

  • 深度優先:順著一條路儘可能往下走,必要時回溯
    • 先根序遍歷(DLR順序)
    • 中根序遍歷(LDR)
    • 後根序遍歷(LRD)
  • 寬度優先:按層次逐層訪問樹中各節點。

5.二叉樹的list實現

二叉樹是遞迴結構

  • 空樹用None表示
  • 非空二叉樹用包含三個元素的表[d,l,r]表示,d表示根節點元素,l和r兩顆子樹
    例如:
    ['A', ['B',None,None], ['C', ['D',['F',None,None], ['G',None,None]], ['E',['H',None,None], ['I',None,None]] ] ]

ptython二叉樹實現

from graphviz import Digraph
import uuid
from random import sample

# 二叉樹類
class BTree(object):
    # 初始化
    def __init__(self, data=None, left=None, right=None):
        self.data = data    # 資料域
        self.left = left    # 左子樹
        self.right = right  # 右子樹
        self.dot = Digraph(comment='Binary Tree')

    # 前序遍歷
    def preorder(self):

        if self.data is not None:
            print(self.data, end=' ')
        if self.left is not None:
            self.left.preorder()
        if self.right is not None:
            self.right.preorder()

    # 中序遍歷
    def inorder(self):

        if self.left is not None:
            self.left.inorder()
        if self.data is not None:
            print(self.data, end=' ')
        if self.right is not None:
            self.right.inorder()

    # 後序遍歷
    def postorder(self):

        if self.left is not None:
            self.left.postorder()
        if self.right is not None:
            self.right.postorder()
        if self.data is not None:
            print(self.data, end=' ')

    # 層序遍歷
    def levelorder(self):

        # 返回某個節點的左孩子
        def LChild_Of_Node(node):
            return node.left if node.left is not None else None
        # 返回某個節點的右孩子
        def RChild_Of_Node(node):
            return node.right if node.right is not None else None

        # 層序遍歷列表
        level_order = []
        # 是否新增根節點中的資料
        if self.data is not None:
            level_order.append([self])

        # 二叉樹的高度
        height = self.height()
        if height >= 1:
            # 對第二層及其以後的層數進行操作, 在level_order中新增節點而不是資料
            for _ in range(2, height + 1):
                level = []  # 該層的節點
                for node in level_order[-1]:
                    # 如果左孩子非空,則新增左孩子
                    if LChild_Of_Node(node):
                        level.append(LChild_Of_Node(node))
                    # 如果右孩子非空,則新增右孩子
                    if RChild_Of_Node(node):
                        level.append(RChild_Of_Node(node))
                # 如果該層非空,則新增該層
                if level:
                    level_order.append(level)

            # 取出每層中的資料
            for i in range(0, height):  # 層數
                for index in range(len(level_order[i])):
                    level_order[i][index] = level_order[i][index].data

        return level_order

    # 二叉樹的高度
    def height(self):
        # 空的樹高度為0, 只有root節點的樹高度為1
        if self.data is None:
            return 0
        elif self.left is None and self.right is None:
            return 1
        elif self.left is None and self.right is not None:
            return 1 + self.right.height()
        elif self.left is not None and self.right is None:
            return 1 + self.left.height()
        else:
            return 1 + max(self.left.height(), self.right.height())

    # 二叉樹的葉子節點
    def leaves(self):

        if self.data is None:
            return None
        elif self.left is None and self.right is None:
            print(self.data, end=' ')
        elif self.left is None and self.right is not None:
            self.right.leaves()
        elif self.right is None and self.left is not None:
            self.left.leaves()
        else:
            self.left.leaves()
            self.right.leaves()

    # 利用Graphviz實現二叉樹的視覺化
    def print_tree(self, save_path='./Binary_Tree.gv', label=False):

        # colors for labels of nodes
        colors = ['skyblue', 'tomato', 'orange', 'purple', 'green', 'yellow', 'pink', 'red']

        # 繪製以某個節點為根節點的二叉樹
        def print_node(node, node_tag):
            # 節點顏色
            color = sample(colors,1)[0]
            if node.left is not None:
                left_tag = str(uuid.uuid1())            # 左節點的資料
                self.dot.node(left_tag, str(node.left.data), style='filled', color=color)    # 左節點
                label_string = 'L' if label else ''    # 是否在連線線上寫上標籤,表明為左子樹
                self.dot.edge(node_tag, left_tag, label=label_string)   # 左節點與其父節點的連線
                print_node(node.left, left_tag)

            if node.right is not None:
                right_tag = str(uuid.uuid1())
                self.dot.node(right_tag, str(node.right.data), style='filled', color=color)
                label_string = 'R' if label else ''  # 是否在連線線上寫上標籤,表明為右子樹
                self.dot.edge(node_tag, right_tag, label=label_string)
                print_node(node.right, right_tag)

        # 如果樹非空
        if self.data is not None:
            root_tag = str(uuid.uuid1())                # 根節點標籤
            self.dot.node(root_tag, str(self.data), style='filled', color=sample(colors,1)[0])     # 建立根節點
            print_node(self, root_tag)

        self.dot.render(save_path)                              # 儲存檔案為指定檔案

6. 優先佇列

優先佇列存入的每項資料都有附加的數值,表示由優先程度。任何時候的訪問和彈出都按照優先順序最高的順序。

list實現優先佇列:

class PrioQue:
    def __init__(self,elist=[]):
        self._elems = list(elist)
        self._elems.sort(reverse=True)   #從大到小排列
    
    def enqueue(self,e):
        i = len(self._elems) - 1
        while i>=0:
            if self._elems[i] <=e:
                i -= 1
            else:
                break
        self._elems.insert(i+1,e)
    
    def is_empty(self):
        return not self._elems

    def peek(self):
        if self.is_empty():
            raise PrioQueueError("in top)
        return self._elems[-1]

    def dequeue(self):
        if self.is_empty():
            raise PrioQueueError("in pop)
        return self._elems.pop()

7.採用樹形結構實現優先佇列的一種有效技術為堆。

  • 在一個堆中從樹根到任何一個葉節點的路徑上,節點裡存的資料按照優先關係遞減。
  • 堆中最優元素必定位於二叉樹根節點
  • 位於數不同路徑上的元素不必關係優先順序

如果是最小元素優先,稱為小頂堆,反之稱為大頂堆

基於堆的優先佇列類

class PrioQueue:
    def __init__(self,elist=[]):
        self._elems = list(elist)
        if elist:
            self.buildheap()
    def is_empty(self):
        return not self._elems
    
    def peek(self):
        if self.is_empty():
            raise PrioQueueError('in peek')
        return self._elems[0]
    
    #入隊操作,主要由siftup完成
    def enqueue(self,e):
        self._elems.append(None)
        self.siftup(e,len(self._elems)-1)

    def siftup(self,e,last):
        elems,i,j = self._elems,last,(last-1)//2
        while i>0 and e < elems[j]:
            elems[i] = elems[j]
            i,j=j,(j-1)//2
        elems[i] = e
    
    def dequeue(self):
        if self.is_empty():
            raise PrioQueueError('in dequeue')
        elems = self._elems
        e0 = elems[0]
        e = elems.pop()
        if len(elems) > 0 :
            self.siftdown(e,0,len(elems))
        return e0

    def dequeue(self,e,begin,end):
        elems,i,j = self._elems,begin,begin*2+1
        while j< end:
            if j+1 < end and elems[j+1] < elems[j]:         
            #elems[j]不大於其他兄弟節點的資料
                j +=1
            if e< elems[j]:
                break
            elems[i] = elems[j]
            i,j = j,2*j+1
        elems[i] = e

    def buildheap(self):
        end = len(self._elems)
        for i in range(end//2,-1,-1):
            self.siftdown(self._elems[i],i,end)

堆構造複雜度為O(n),插入彈出操作為O(logn),最壞情況O(n),其他操作O(1)。

八、字典和集合

九、排序演算法

1. 插入排序

平均複雜度O(n2) ,穩定

def insert_sort(lst):
    for i in range(1,len(lst)):     #開始時片段[0:1]已排序
        x = lst[i]
        j = i
        while j>0 and lst[j-1].key >x.key:
            lst[j] = lst[j-1]       #反序逐個後移元素,確定插入排序
            j -= 1
        lst[j] = x

2. 選擇排序

def select_sort(lst):
    for i in range(len(lst)-1):   #只需迴圈len(lst)-1次
        k=i                         #k是已知最小元素位置
        for j in range(i,len(lst)): 
            if lst[j].key < lst[k].key:
                k=j
            if i != k:          #lst[k]確定最小的元素,檢查是否需要交換
                lst[i],lst[k] = lst[k],lst[i]

3.起泡排序

def bubble_sort(lst=[]):
    for i in rane(len(lst):
        found = False
        for j in range(1,len(lst)-i):
            if lst[j-1].key > lst[j].key :
            lst[j-1],lst[j] = lst[j],lst[j-1]
            found = True
        if not found:
            break

快速排序

def quick_sort(lst):
    qsort_rec(lst,0,len(lst-1))

def qsort_rec(lst,1,r):
    if 1 >= r:
        return          #分段無記錄或只有一個記錄
    i=1
    j=r
    pivot = lst[i]      #lst[i]是初始空位
    while i<j:          #找pivot的最終位置
        while i<j and lst[j].key >= pivot.key:      #用j向左掃描小於pivot的記錄
            j-=1
        if i<j:
            lst[i] = lst[j]
            i+=1        #小記錄移到右邊
        while i<j and lst[i].key <= pivot.key:
            i+=1        #用i向右掃描找大於pivot的記錄
        if i<j:
            lst[j] = lst[i]
            j-=1        #大記錄移到右邊
        lst[i] = pivot  #將pivot存入其最終位置
        qsort_rec(lst,1,i-1)    #遞迴處理左半區
        qsort_rec(lst,i+1,r)    #遞迴處理右半區