數據結構與算法

引入

程序設計語言基本數據類型:int,float,char
Python內置數據結構:list,dict,tuple.
Python擴展數據結構:棧,隊列
存儲一個student的name,age,hometown的方式html

列表+元組:[
    ('zhangsan',24,'beijing'),
    ('zhangsan',24,'beijing'),
    ('zhangsan',24,'beijing'),
    ]
    for stu in stus:
    if stu[0] == 'zhangsan':
  列表+字典 [
    {'name':'zhangsan'},
   {'age':23},
    {'hometown':'beijjing'},
    ]
  字典:{
    'zhangsan':{
    'age':24,
    'hometown':'beijing',
   }
    }
    stu['zhangsan']

經典知識點總結

1.算法與數據結構的概念node

    算法是指要解決問題的思路
    數據結構是指相互之間存在一種或多種特定關係的數據元素的集合。

2.數據結構和算法的區別python

    (1).數據結構只是靜態的描述了數據元素之間的關係
    (2).高效的程序須要在數據結構的基礎上設計和選擇算法
        程序 = 算法 + 數據結構

    總結:算法是爲了解決實際問題而設計的,數據結構是算法須要處理的問題載體

3.抽象數據類型(Abstract Data Type)mysql

    ADT概念:是指一個數學模型以及定義在這個數學模型上的一組操做的集合,即把數據類型和數據類型上的運算綁定在一塊兒,
             進行封裝。對外只聲明存儲方式和調用方法,具體實現隱藏。
    
    引入抽象數據類型的目的是把數據類型的表示和數據類型上的運算的實現與這些數據類型和運算在程序中的引用隔開,使他們相互獨立。

    經常使用的數據運算有五種:
        插入
        刪除
        修改
        查找
        排序

4.時間複雜度redis

    衡量程序執行效率的快慢,稱爲時間複雜度。
        算法完成任務最少須要多少基本操做,即最優時間複雜度。(最樂觀最理想,價值不大)
        算法完成任務最多須要多少基本操做,即最差時間複雜度。(提供了一種保證,主要關注)
        算法完成任務平均須要多少基本操做,即平均時間複雜度。(算法的全面評價)
        
    時間複雜度的幾條基本計算規則
        1.基本操做,即只有常數項,認爲其時間複雜度爲〇(1)
        2.順序結構,時間複雜度按加法計算
        3.循環結構,時間複雜度按乘法計算
        4.分支結構,時間複雜度取最大值
        5.判斷一個算法的效率時,每每只需關注操做數量的最高次頻,其餘次要項和常數項能夠忽略
        6.在沒有特殊說明時,咱們所分析的算法的時間複雜度,一般指的都是最壞時間複雜度。
        
    常見時間複雜度比較:〇(1)<〇(logn)<〇(n)<〇(nlogn)<〇(n^2)<〇(n^3)<〇(2^n)<〇(n!)<〇(n^n)

5.線性表:算法

線性表:一組序列元素的組織形式,一個線性表是某類元素的集合,還記錄着元素之間的一種順序關係,線性表是最基本的數據結構之一。 
順序表:將元素順序的存放在一塊連續的存儲區裏,元素間的順序關係由他們的存儲順序天然表示。 鏈表:將元素存放在經過連接構造起來的一系列存儲塊中。

6.順序表sql

順序表:數據元素自己連續存儲,每一個元素所佔的存儲單元大小固定相同,元素的下標是其邏輯地址,而元素存儲的物理地址(實際內存地址)能夠經過存儲區的起始地址Loc(e0)加上邏輯地址
    (第i個元素)與存儲單元大小(c)的乘積計算而得,即:Loc(ei) = Loc(e0)+c*i    故,訪問指定元素無需從頭遍歷,經過計算即可得到對應地址,其時間複雜度爲〇(1) 注:操做系統最小尋址單位是字節。int類型佔四個字節,char類型佔1個字節。計算機存儲索引從0開始,表示偏移量。 順序表的存儲方式:順序表的基本方式,順序表的外置元素方式 順序表的結構:一部分是表中元素的集合,另外一部分是爲實現正確操做而需記錄的信息 表頭信息(表頭存儲區的容量,當前表中已有元素個數),數據區 順序表存儲結構:一體式,分離式。區別:增長容量時,分離式表頭不變,一體式表頭改變

7.鏈表的提出shell

    順序表的構建須要預先知道數據大小來申請連續的存儲空間,而在進行擴充時又須要進行數據的搬遷,因此使用起來並非很靈活。
    鏈表結構能夠充分利用計算機的內存空間,實現靈活的內存動態管理。

8.鏈表數據庫

8.1-定義:鏈表(Linked list)是一種常見的基礎數據結構,是一種線性表,可是不像順序表同樣連續存儲數據,而是在每個節點(數據存儲單元)裏存放
          下一個節點的位置信息(即地址)。

8.2-單向鏈表:也叫單鏈表,是鏈表中最簡單的一種形式。它的每一個節點包含兩個域,一個信息域(元素域),一個連接域。這個連接指向鏈表中的
              下一個結點,而最後一個節點的連接則指向一個空值。
      表元素域elem用來存放具體的數據
      連接域next用來存放下一個節點的位置(python中的標識)
      變量p指向鏈表的頭結點(首節點)的位置,從p出發能找到表中的任意節點。
          
8.3 python變量標識的本質
    a = 10,首先會在內存中開啓兩個內存塊,一個存儲10,一個存儲地址,這個地址指向10,給這個地址取名a。
    a,b = b,a 交換的是a,b原來維護的指向內存塊的地址。
    
8.4 雙向鏈表:每一個節點有兩個連接,一個指向前一個節點(前驅),一個指向後一個節點(後繼)。當此節點爲第一個節點時,前驅爲空,
              當此節點爲尾節點時,後繼爲空。

9.鏈表和順序表的對比數組

9.1 順序表     
        優勢:(1) 方法簡單,各類高級語言中都有數組,容易實現。
               (2) 不用爲表示結點間的邏輯關係而增長額外的存儲開銷。
               (3) 順序表具備按元素序號隨機訪問的特色。
               
        缺點:(1) 在順序表中作插入刪除操做時,須要對全部元素進行先後移位操做,只能經過拷貝和覆蓋的方式,
                  平均移動大約表中一半的元素,所以對n較大的順序表效率低。
              (2) 須要預先分配足夠大的存儲空間,估計過大,可能會致使順序表後部大量閒置;預先分配太小,
                  又會形成溢出。                                       
9.2 鏈表  
        優勢:(1) 在鏈表中作插入刪除操做時,不會影響前面和後面的節點,所以對n較大的鏈表效率高。
              (2) 不須要預先分配足夠大的存儲空間,避免形成空間閒置或溢出的狀況。
              
        缺點:(1) 須要爲表示結點間的邏輯關係(指針變量)而增長額外的存儲開銷。
              (2) 只能經過遍歷找到某個節點,不能使用下標直接定位節點。
              
              
9.3 選擇合適的數據結構
    9.3.1 基於存儲的考慮   
    順序表的存儲空間是靜態分配的,在程序執行以前必須明確規定它的存儲規模,也就是說事先對"MAXSIZE"要有合適的設定,過大形成浪費,
    太小形成溢出。可見對線性表的長度或存儲規模難以估計時,不宜採用順序表;鏈表不用事先估計存儲規模,但鏈表的存儲密度較低
   (存儲密度是指一個結點中數據元素所佔的存儲單元和整個結點所佔的存儲單元之比,顯然鏈式存儲結構的存儲密度是小於1的)。

    9.3.2 基於運算的考慮
    在順序表中按序號訪問 ai的時間性能時O(1),而鏈表中按序號訪問的時間性能O(n),因此若是常常作的運算是按序號訪問數據元素,
    顯然順序表優於鏈表;而在順序表中作插入、刪除時平均移動表中一半的元素,當數據元素的信息量較大且表較長時,這一點是不該忽視的;
    在鏈表中做插入、刪除,雖然也要找插入位置,但操做主要是比較操做,從這個角度考慮顯而後者優於前者。

    9.3.3 基於環境的考慮
    順序表容易實現,任何高級語言中都有數組類型,鏈表的操做是基於指針的,相對來說前者簡單些,也是用戶考慮的一個因素。

    注:順序表和鏈表抓主要用於存儲,棧和隊列主要用於對數據的操做。

10.棧:只容許在表的一端進行操做的線性表,FILO(先進後出)
11.隊列:只容許在表尾插入,表頭刪除的線性表,FIFO(先進先出)
12.雙端隊列:具備棧和隊列的性質的數據結構,能夠在隊列的任意一端入隊和出隊

13:棧(Stack)和隊列(Queue)是兩種操做受限的線性表。

線性表:線性表是一種線性結構,它是一個含有n≥0個結點的有限序列,同一個線性表中的數據元素數據類型相同而且知足「一對一」的邏輯關係。
        「一對一」的邏輯關係指的是對於其中的結點,有且僅有一個開始結點沒有前驅但有一個後繼結點,有且僅有一個終端結點沒有後繼但有
        一個前驅結點,其它的結點都有且僅有一個前驅和一個後繼結點。

這種受限表如今:棧的插入和刪除操做只容許在表的尾端進行(在棧中成爲「棧頂」),知足「FIFO:First In Last Out」;
                隊列只容許在表尾插入數據元素,在表頭刪除數據元素,知足「First In First Out」。

棧與隊列的相同點:
    1.都是線性結構。
    2.插入操做都是限定在表尾進行。
    3.均可以經過順序結構和鏈式結構實現。、
    4.插入與刪除的時間複雜度都是O(1),在空間複雜度上二者也同樣。
    5.多鏈棧和多鏈隊列的管理模式能夠相同。

棧與隊列的不一樣點:
    1.刪除數據元素的位置不一樣,棧的刪除操做在表尾進行,隊列的刪除操做在表頭進行。 2.應用場景不一樣;常見棧的應用場景包括括號問題的求解,表達式的轉換和求值,函數調用和遞歸實現,深度優先搜索遍歷等;常見的隊列的應用場景包括計算機系統中各類資源的管理,消息緩衝器的管理和廣度優先搜索遍歷等。
    3.順序棧可以實現多棧空間共享,而順序隊列不能。

14.排序

穩定性:兩個相同的元素在排序以後相對位置不發生改變稱之爲穩定排序。
14.1 交換排序:
    冒泡排序:每次循環找出最大值或最小值
          時間複雜度:最優 〇(n)    序列有序
                      最差 〇(n2)
                      穩定性:穩定
    快速排序:劃分交換排序(partition-exchange sort),經過一趟偶排序將要排序的數據分割成獨立的兩部分,一部分的元素比另外一部分的元素都要小。
              而後在按此方法對兩部分數據分別進行快速排序,整個排序能夠遞歸進行,以此達到整個數據變成有序序列
    
        時間複雜度:最優 〇(nlogn)
                      最差 〇(n2)
                      穩定性:不穩定    
14.2 選擇排序:每次從無序序列中選擇一個最大值或最小值放在一端。
        時間複雜度:最優 〇(n2)
                     最差 〇(n2)
                     穩定性:不穩定(考慮升序每次選擇最大的狀況)    2,2,1
                     
14.3 插入排序
    14.3.1 直接插入排序:每次從無序序列中按順序拿一個元素插入有序序列中的正確位置。
        時間複雜度:最優 〇(n)  升序排序,序列已經處於升序狀態
                     最差 〇(n2)
                     穩定性:穩定
                     
    14.3.2 希爾排序:縮小增量排序
        時間複雜度:最優 根據步長序列的不一樣而不一樣
                     最差 〇(n2)
                     穩定性:不穩定    2,2,1
                     
                     
14.4 歸併排序:分治法,先遞歸分解數組,再合併數組
        時間複雜度: 最優:〇(nlogn)
                     最差: 〇(nlogn)
                     穩定性:穩定   

 


15.搜索

    二分查找法:又稱折半查找。優勢是比較次數少,查找速度快,平均性能好。缺點是要求待查表爲有序表,且插入刪除困難。所以,折半查找適用於不常常變            動而查找頻繁的有序列表。
    時間複雜度: 最優:〇(1)
                 最差: 〇(logn)

16.樹:由n(n>=1)個有限節點組成一個具備層次關係的集合。一對多。

特色:(1)每一個節點有零個或多個子節點
     (2)沒有父節點的節點稱爲根節點
     (3)每個非根節點有且只有一個父節點
     (4)除了根節點外,每一個子節點能夠分爲多個不相交的子樹。
     
術語:節點的度:一個節點含有子樹的個數
     樹的度:一棵樹中,最大節點的度稱爲樹的度。
     葉節點或終端節點:度爲零的節點。
     父節點:若一個節點含有子節點,則這個節點稱爲其子節點的父節點。
     子節點:一個節點含有的子樹的根節點稱爲該節點的子節點。
     兄弟節點:具備相同的父節點的節點互稱爲兄弟節點。
     節點的層次:從根節點開始定義,根爲第一層,根的子節點爲第2層,以此類推。
     樹的深度或高度:樹中節點的最大層次。
     堂兄弟節點:父節點在同一層次的節點互稱爲堂兄弟。
     節點的祖先:從根到該節點所經分支上的全部節點。
     子孫:以某節點爲根的子樹中任一節點成爲該節點的子孫。
     森林:由m(m>=0)棵互不相交的樹的集合稱爲森林。
樹的種類:
      無序樹:樹中任意節點的子節點之間沒有順序關係,這種關係成爲無序樹。
      有序樹:樹中任意節點的子節點之間有順序關係。這種關係稱爲有序樹。
            二叉樹:每一個節點最多含有兩個子樹的樹稱爲二叉樹。
                徹底二叉樹:對於一個二叉樹,假設其深度爲d.除了第d層外,其餘各層的節點數目均已達最大值,且第d層全部節點
                            從左到右連續緊密排列。對於這樣的二叉樹稱爲徹底二叉樹。
                            滿二叉樹:全部葉節點都在最底層的徹底二叉樹。
                平衡二叉樹(AVL樹):當且僅當任何節點的兩顆子樹的高度差不大於1的二叉樹。
                排序二叉樹(二叉查找樹,二叉搜索樹,有序二叉樹)
      哈夫曼樹(用於信息編碼):帶權路徑最短的二叉樹稱爲哈夫曼樹或最優二叉樹。
      B樹:一種對讀寫操做進行優化的自平衡的二叉查找樹,可以保持數據有序,擁有多餘兩個子樹。

17.樹的存儲方式

       順序存儲:速度快,所佔空間大。
       鏈式存儲:能夠存儲。缺點:指針域個數不定。

18.應用場景:

(1)xml,html
(2)路由協議
(3)mysql數據庫索引
(4)文件系統的目錄結構
(5)不少經典的AI算法,好比機器學習的(decision tree)決策樹也是樹結構                       

19.二叉樹:每一個節點最多含有兩個子樹的樹稱爲二叉樹。

    性質1:二叉樹第i層最多隻有2^(i-1)個節點。
    性質2:深度爲k的二叉樹最多有(2^k)-1個節點
    性質3:葉子節點的個數與度爲2的節點的個數知足n0=n2+1
    性質4: 具備n個節點的徹底二叉樹的深度必爲log2(n+1)
    性質5:徹底二叉樹,從上到下,從左到右,編號爲i的節點,其左孩子編號爲2i,右孩子編號爲2i+1,其父節點爲i/2(根節點除外)

20.二叉樹的遍歷

廣度遍歷:隊列:先進先出
深度優先:棧:後進先出
          前序遍歷:根左右
          中序遍歷:左根右
          後序遍歷:左右根
          
        先序:0 1 3 7 8 4 9 2 5 6 
        中序:7 3 8 1 9 4 0 5 2 6 
        後序:7 8 3 9 4 1 5 6 2 0 
        
          0
       1      2
     3   4  5   6
   7  89

算法實現(基於Python)

# -*- coding: utf-8 -*-

"""
@Datetime: 2018/11/6
@Author: Zhang Yafei
"""
"""
時間複雜度:衡量算法執行效率的快慢
a+b+c=1000,且a^2+b^2=c^2(a,b,c爲天然數),如何求出全部a,b,c的天然數組合?
a,b,c
總時間=基本運算數量*執行次數
每臺機器執行的總時間不一樣
可是執行基本運算數量大致相同
"""
import time

start_time = time.time()
# for a in range(1001):
#     for b in range(1001):
#         for c in range(1001):
#             if a+b+c==1000 and a**2+b**2==c**2:
#                 print('a,b,c:',a,b,c)      #222秒
"""
T = 1000 * 1000 * 1000 * 2
T = 2000 * 2000 * 2000 * 2
T = N * N * N *2
T(n) = n^3 * 2
T(n) = n^3 * 10
T(n) = n^3 * k
從數學上,T(n) = k*g(n),在現實中,省去細枝末葉,只剩下最顯著特徵
T(n) = g(n)
g(n) = n^3
"""
#順序
#條件
#循環

for a in range(1001):
    for b in range(1001):
        c = 1000-a-b
        if a**2+b**2==c**2:
            print('a,b,c:',a,b,c)    #1秒
end_time = time.time()

print('times:',end_time-start_time)
print('finished')
"""
T(n) = n * n *(1+max(1,0))
     = n^2*2
     = 〇(n^2)
"""
1.算法基礎
# -*- coding: utf-8 -*-

"""
@Datetime: 2018/11/6
@Author: Zhang Yafei
"""
from timeit import Timer
"""
li1 = [1,2]
li2 = [23,5]
li = li1 + li2
li = [i for i in range(10000)]
li = list(range(10000))
"""


def t1():
    li = []
    for i in range(10000):
        li.append(i)


def t2():
    li = []
    for i in range(10000):
        # li = li + [i]   #218秒
        li += [i]  #1.04


def t3():
    li = [i for i in range(10000)]


def t4():
    li = list(range(10000))


def t5():
    li = []
    for i in range(10000):
        li.extend([i])


timer1 = Timer("t1()","from __main__ import t1")
print('append:',timer1.timeit(1000))
timer2 = Timer("t2()","from __main__ import t2")
print('+:',timer2.timeit(1000))
timer3 = Timer("t3()","from __main__ import t3")
print('[i for i in range]:',timer3.timeit(1000))
timer4 = Timer("t4()","from __main__ import t4")
print('list(range())',timer4.timeit(1000))
timer5 = Timer("t5()","from __main__ import t5")
print('extend:',timer5.timeit(1000))


def t6():
    li = []
    for i in range(10000):
        li.append(i)


def t7():
    li = []
    for i in range(10000):
        li.insert(0,i)


# timer6 = Timer("t6()","from __main__ import t6")
# print('append:',timer6.timeit(1000))
timer7 = Timer("t7()","from __main__ import t7")
print('insert:',timer7.timeit(1000))
2.list效率對比
# -*- coding: utf-8 -*-

"""
@Datetime: 2018/11/11
@Author: Zhang Yafei
"""
import sys
from timeit import Timer

reps = 1000
size = 10000


def forStatement():
    res = []
    for x in range(size):
        res.append(abs(x))


# 列表解析
def listComprehension():
    res = [abs(x) for x in range(size)]


# map
def mapFunction():
    res = list(map(abs, range(size)))


# 生成器表達式
def generatorExpression():
    res = list(abs(x) for x in range(size))


if __name__ == '__main__':
    print(sys.version)
    timer1 = Timer("forStatement()", "from __main__ import forStatement")
    print('for循環append', timer1.timeit(reps))
    timer2 = Timer("listComprehension()", "from __main__ import listComprehension")
    print('列表生成式', timer2.timeit(reps))
    timer3 = Timer("mapFunction()", "from __main__ import mapFunction")
    print('map:', timer3.timeit(reps))
    timer4 = Timer("generatorExpression()", "from __main__ import generatorExpression")
    print('生成器表達式', timer4.timeit(reps))
3.for_map_list生成式_生成器表達式
# -*- coding: utf-8 -*-

"""
@Datetime: 2018/11/8
@Author: Zhang Yafei
"""


class Node(object):
    """節點"""
    def __init__(self,elem):
        self.elem = elem
        self.next = None


class SingleLinkList(object):
    """單鏈表"""
    def __init__(self,node=None):
        self.__head = node

    def __str__(self):
        if not self.__head:
            return 'None'
        else:
            cur = self.__head
            list_str = ''
            while cur:
                cur_str = '{}->'.format(cur.elem) if cur.next else str(cur.elem)
                list_str += cur_str
                cur = cur.next
            return list_str

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

    def length(self):
        """鏈表長度"""
        #cur遊標,用來移動遍歷節點
        cur = self.__head
        #count記錄數量
        count = 0
        while cur:  #cur.next == None
            cur = cur.next
            count += 1
        return count

    def travel(self):
        """遍歷整個鏈表"""
        cur = self.__head
        while cur:
            print(cur.elem,end=" ")
            cur = cur.next
        print('')

    def add(self,item):
        """鏈表頭部添加元素,頭插法"""
        node = Node(item)
        node.next = self.__head
        self.__head = node

    def append(self,item):
        """鏈表尾部添加元素,尾插法"""
        node = Node(item)
        if self.is_empty():#鏈表判空
            self.__head = node
        else:
            cur = self.__head
            while cur.next:
                cur = cur.next
            cur.next = node

    def insert(self,pos,item): #insert(2,100)
        """指定位置添加元素
        :param pos 從0開始
        """
        if pos<=0:
            self.add(item)
        elif pos>(self.length()-1):
            self.append(item)
        else:
            node = Node(item)
            pre = self.__head
            count = 0
            while count < pos-1:
                pre = pre.next
                count += 1
            #當循環退出後,pre指向pos-1位置
            node.next = pre.next
            pre.next = node

    def remove(self,item):
        """刪除節點"""
        cur = self.__head
        prev = None
        while cur:
            if cur.elem == item:
                #先判斷此節點是不是頭結點
                if cur == self.__head:
                    self.__head = cur.next
                else:
                    prev.next = cur.next
                break
            else:
                prev = cur
                cur = cur.next

    def search(self,item):
        """查詢節點是否存在"""
        cur = self.__head
        while cur:
            if cur.elem == item:
                return True
            cur = cur.next
        return False

    def index(self,item):
        """查詢節點是否存在"""
        cur = self.__head
        count = 0
        while cur:
            if cur.elem == item:
                return count
            cur = cur.next
            count += 1
        return '{} is not in linklist'.format(item)

    def value(self,index):
        """查找指定位置的值"""
        if self.is_empty():
            return None
        elif index>self.length()-1:
            return 'linklist index out of range'
        cur = self.__head
        count = 0
        while count<index:
            count += 1
            cur = cur.next
        return cur.elem


if __name__ == '__main__':
    ll = SingleLinkList()
    print(ll.is_empty())
    print(ll.length())
    # print(ll)
    ll.append(1)
    print(ll.is_empty())
    print(ll.length())

    ll.append(2)
    ll.add(8)
    ll.append(3)
    ll.append(4)
    ll.append(5)
    ll.append(6)
    # print(ll)
    ll.insert(-1,9) #9,8,123456
    ll.travel()
    ll.insert(3,100) #9,8,1,100,23456
    ll.travel()
    ll.insert(10,200) #9,8,1,100,23456,200
    ll.travel()
    ll.remove(9)
    ll.travel()
    ll.remove(100)
    ll.travel()
    ll.remove(200)
    ll.travel()
    print(ll.value(3))
    print(ll.index(7))
4.單鏈表
# -*- coding: utf-8 -*-

"""
@Datetime: 2018/11/9
@Author: Zhang Yafei
"""


class Node(object):
    """結點"""
    def __init__(self,item):
        self.elem = item
        self.prev = None
        self.next = None


class DoubleLinkList(object):
    """雙鏈表"""
    def __init__(self,node=None):#默認爲None第一次建立空鏈表
        self.__head = node

    def __str__(self):
        self.travel()
        return

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

    def length(self):
        """鏈表長度"""
        #cur遊標,用來移動遍歷節點
        cur = self.__head
        #count記錄數量
        count = 0
        while cur:  #cur.next == None
            cur = cur.next
            count += 1
        return count

    def travel(self):
        """遍歷整個鏈表"""
        cur = self.__head
        while cur:
            print(cur.elem,end=" ")
            cur = cur.next
        print('')

    def add(self,item):
        """鏈表頭部添加元素,頭插法"""
        node = Node(item)
        node.next = self.__head
        self.__head = node
        node.prev = None

    def append(self,item):
        """鏈表尾部添加元素,尾插法"""
        node = Node(item)
        if self.is_empty():#鏈表判空
            self.__head = node
        else:
            cur = self.__head
            while cur.next:
                cur = cur.next
            cur.next = node
            node.prev = cur

    def insert(self,pos,item): #insert(2,100)
        """指定位置添加元素
        :param pos 從0開始
        """
        if pos<=0:
            self.add(item)
        elif pos>(self.length()-1):
            self.append(item)
        else:
            cur = self.__head
            count = 0
            while count < pos:
                cur = cur.next
                count += 1
            #當循環退出後,pre指向pos-1位置
            node = Node(item)
            node.next = cur
            node.prev = cur.prev
            cur.prev.next = node
            cur.prev = node

    def remove(self,item):
        """刪除節點"""
        if self.is_empty():
            return
        cur = self.__head
        while cur:
            if cur.elem == item:
                #先判斷此節點是不是頭結點
                if cur == self.__head:
                    self.__head = cur.next
                    if cur.next:
                        #判斷鏈表是否只有一個節點
                        cur.next.prev = None
                else:
                    cur.prev.next = cur.next
                    if cur.next:
                        #判斷鏈表是不是尾節點
                        cur.next.prev = cur.prev
                break
            else:
                cur = cur.next

    def search(self,item):
        """查詢節點是否存在"""
        cur = self.__head
        while cur:
            if cur.elem == item:
                return True
            cur = cur.next
        return False

    def index(self,item):
        """查詢節點是否存在"""
        cur = self.__head
        count = 0
        while cur:
            if cur.elem == item:
                return count
            cur = cur.next
            count += 1
        return '{} is not in linklist'.format(item)

    def value(self,index):
        """查找指定位置的值"""
        if self.is_empty():
            return None
        elif index>self.length()-1:
            return 'linklist index out of range'
        cur = self.__head
        count = 0
        while count<index:
            count += 1
            cur = cur.next
        return cur.elem


if __name__ == '__main__':
    dll = DoubleLinkList()
    print(dll.is_empty())
    print(dll.length())
    # print(dll)
    dll.append(1)
    print(dll.is_empty())
    print(dll.length())

    dll.append(2)
    dll.add(8)
    dll.append(3)
    dll.append(4)
    dll.append(5)
    dll.append(6)
    # print(dll)
    dll.insert(-1, 9)  # 9,8,123456
    dll.travel()
    dll.insert(3, 100)  # 9,8,1,100,23456
    dll.travel()
    dll.insert(10, 200)  # 9,8,1,100,23456,200
    dll.travel()
    dll.remove(9)
    dll.travel()
    dll.remove(100)
    dll.travel()
    dll.remove(200)
    dll.travel()
    print(dll.value(0))
    print(dll.index(8))
    print(dll.search(4))
5.雙鏈表
# -*- coding: utf-8 -*-

"""
@Datetime: 2018/11/8
@Author: Zhang Yafei
"""


class Node(object):
    """節點"""
    def __init__(self,elem):
        self.elem = elem
        self.next = None


class SingleCycleLinkList(object):
    """單向循環鏈表"""
    def __init__(self,node=None):
        self.__head = node
        if node:
            node.next = node

    def __str__(self):
        if not self.__head:
            return 'None'
        else:
            cur = self.__head
            list_str = ''
            while cur:
                cur_str = '{}->'.format(cur.elem) if cur.next else str(cur.elem)
                list_str += cur_str
                cur = cur.next
            return list_str

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

    def length(self):
        """鏈表長度"""
        #cur遊標,用來移動遍歷節點
        if self.is_empty():
            return 0
        cur = self.__head
        #count記錄數量
        count = 1
        while cur.next != self.__head:  #cur.next == None
            cur = cur.next
            count += 1
        return count

    def travel(self):
        """遍歷整個鏈表"""
        if self.is_empty():
            return
        cur = self.__head
        while cur.next != self.__head:
            print(cur.elem,end=" ")
            cur = cur.next
        #退出循環,cur指向尾節點,但尾節點的元素未打印
        print(cur.elem)

    def add(self,item):
        """鏈表頭部添加元素,頭插法"""
        node = Node(item)
        if self.is_empty():
            self.__head = node
            node.next = node
        else:
            cur = self.__head
            while cur.next != self.__head:
                cur = cur.next
            node.next = self.__head
            self.__head = node
            # cur.next = node
            cur.next = self.__head

    def append(self,item):
        """鏈表尾部添加元素,尾插法"""
        node = Node(item)
        if self.is_empty():#鏈表判空
            self.__head = node
            node.next = node
        else:
            cur = self.__head
            while cur.next != self.__head:
                cur = cur.next
            node.next = cur.next
            cur.next = node

    def insert(self,pos,item): #insert(2,100)
        """指定位置添加元素
        :param pos 從0開始
        """
        if pos<=0:
            self.add(item)
        elif pos>(self.length()-1):
            self.append(item)
        else:
            node = Node(item)
            pre = self.__head
            count = 0
            while count < pos-1:
                pre = pre.next
                count += 1
            #當循環退出後,pre指向pos-1位置
            node.next = pre.next
            pre.next = node

    def remove(self,item):
        """刪除節點"""
        if self.is_empty():
            return
        cur = self.__head
        prev = None
        while cur.next != self.__head:
            if cur.elem== item:
                #先判斷此節點是不是頭結點
                if cur == self.__head:
                    #頭結點的狀況
                    #找尾節點
                    rear = self.__head
                    while rear.next != self.__head:
                        rear = rear.next
                    self.__head = cur.next
                    rear.next = self.__head
                else:
                    #中間節點
                    prev.next = cur.next
                return
            else:
                prev = cur
                cur = cur.next
        #退出循環,cur指向尾節點
        if cur.elem == item:
            if cur == self.__head:
               #鏈表中只有一個節點
                self.__head = None
            else:
                # prev.next = cur.next
                prev.next = self.__head

    def search(self,item):
        """查詢節點是否存在"""
        if self.is_empty():
            return False
        cur = self.__head
        while cur.next != self.__head:
            if cur.elem == item:
                return True
            cur = cur.next
        #退出循環,cur指向尾節點
        if cur.elem == item:
            return True
        return False

    def index(self,item):
        """查詢節點是否存在"""
        if self.is_empty():
            return None
        cur = self.__head
        count = 0
        while cur.next != self.__head:
            if cur.elem == item:
                return count
            cur = cur.next
            count += 1
        if cur.elem == item:
            return count
        raise ValueError('{} is not in linkCyclelist'.format(item))

    def value(self,index):
        """查找指定位置的值"""
        if self.is_empty():
            raise AttributeError('LinkCycleList is None')
        elif index>self.length()-1:
            raise IndexError('linklist index out of range')
        cur = self.__head
        count = 0
        while count<index:
            count += 1
            cur = cur.next
        return cur.elem


if __name__ == '__main__':
    ll = SingleCycleLinkList()
    print(ll.is_empty())
    print(ll.length())
    # print(ll)
    ll.append(1)
    print(ll.is_empty())
    print(ll.length())

    ll.append(2)
    ll.add(8)
    ll.append(3)
    ll.append(4)
    ll.append(5)
    ll.append(6)
    # print(ll)
    ll.insert(-1,9) #9,8,123456
    ll.travel()
    ll.insert(3,100) #9,8,1,100,23456
    ll.travel()
    ll.insert(10,200) #9,8,1,100,23456,200
    ll.travel()
    ll.remove(9)
    ll.travel()
    ll.remove(100)
    ll.travel()
    ll.remove(200)
    ll.travel()
    print(ll.value(0))
    print(ll.index(8))
    # help(SingleCycleLinkList)
6.單向循環鏈表
 -*- coding: utf-8 -*-

"""
@Datetime: 2018/11/8
@Author: Zhang Yafei
"""


class Node(object):
    """結點"""
    def __init__(self,item):
        self.elem = item
        self.prev = None
        self.next = None


class DoubleCycleLinkList(object):
    """雙鏈表"""
    def __init__(self,node=None):#默認爲None第一次建立空鏈表
        self.__head = Node('HEAD')
        self.__head.next = node
        self.__head.prev = node
        if node is not None:
            node.next = self.__head
            node.prev = self.__head

    def __str__(self):
        self.travel()
        return

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

    def length(self):
        """鏈表長度"""
        #cur遊標,用來移動遍歷節點
        if self.is_empty():
            return 0
        cur = self.__head.next
        #count記錄數量
        count = 0
        while cur != self.__head:  #cur.next == None
            cur = cur.next
            count += 1
        return count

    def travel(self):
        """遍歷整個鏈表"""
        cur = self.__head.next
        while cur != self.__head:
            print(cur.elem,end=" ")
            cur = cur.next
        print('')

    def add(self,item):
        """鏈表頭部添加元素,頭插法"""
        node = Node(item)
        if self.is_empty():
             #空鏈表
            node.next = self.__head
            node.prev = self.__head
            self.__head.next = node
            self.__head.prev = node
        else:
            #非空鏈表
            node.next = self.__head.next
            self.__head.next = node
            node.prev = self.__head
            node.next.prev = node

    def append(self,item):
        """鏈表尾部添加元素,尾插法"""
        node = Node(item)
        if self.is_empty():#鏈表判空
            node.next = self.__head
            node.prev = self.__head
            self.__head.next = node
            self.__head.prev = node
        else:
            cur = self.__head
            while cur.next != self.__head:
                cur = cur.next
            node.next = cur.next
            node.prev = cur
            cur.next = node
            self.__head.prev = node

    def insert(self,pos,item): #insert(2,100)
        """指定位置添加元素
        :param pos 從0開始
        """
        if pos<=0:
            self.add(item)
        elif pos>(self.length()-1):
            self.append(item)
        else:
            cur = self.__head.next
            count = 0
            while count < pos:
                cur = cur.next
                count += 1
            #當循環退出後,pre指向pos-1位置
            node = Node(item)
            node.next = cur
            node.prev = cur.prev
            cur.prev.next = node
            cur.prev = node

    def remove(self,item):
        """刪除節點"""
        if self.is_empty():
            return
        cur = self.__head.next
        while cur:
            if cur.elem == item:
                #先判斷此節點是不是頭結點
                if cur == self.__head.next:
                    self.__head.next = cur.next
                    if cur.next == self.__head:
                        #判斷鏈表是否只有一個節點
                        self.__head.next = None
                        self.__head.prev = None
                    else:
                        cur.next.prev = self.__head
                else:
                    cur.prev.next = cur.next
                    if cur.next != self.__head:
                        #判斷鏈表是不是尾節點
                        cur.next.prev = cur.prev
                    else:
                        self.__head.prev = cur.prev
                break
            else:
                cur = cur.next

    def search(self,item):
        """查詢節點是否存在"""
        if self.is_empty():
            return False
        cur = self.__head.next
        while cur:
            if cur.elem == item:
                return True
            cur = cur.next
        return False

    def index(self,item):
        """查詢指定元素的索引"""
        cur = self.__head.next
        count = 0
        while cur:
            if cur.elem == item:
                return count
            cur = cur.next
            count += 1
        return '{} is not in linklist'.format(item)

    def value(self,index):
        """查找指定位置的值"""
        if self.is_empty():
            return None
        elif index>self.length()-1:
            return 'linklist index out of range'
        cur = self.__head.next
        count = 0
        while count<index:
            count += 1
            cur = cur.next
        return cur.elem


if __name__ == '__main__':
    dcl = DoubleCycleLinkList()
    print(dcl.is_empty())
    print(dcl.length())
    # print(dcl)
    dcl.append(1)
    print(dcl.is_empty())
    print(dcl.length())

    dcl.append(2)
    dcl.add(8)
    dcl.append(3)
    dcl.append(4)
    dcl.append(5)
    dcl.append(6)
    # print(dcl)
    dcl.insert(-1, 9)  # 9,8,123456
    dcl.travel()
    dcl.insert(3, 100)  # 9,8,1,100,23456
    dcl.travel()
    dcl.insert(10, 200)  # 9,8,1,100,23456,200
    dcl.travel()
    dcl.remove(9)
    dcl.travel()
    dcl.remove(100)
    dcl.travel()
    dcl.remove(200)
    dcl.travel()
    print(dcl.value(0))
    print(dcl.index(5))
    print(dcl.search(4))
7.雙向循環鏈表
# -*- coding: utf-8 -*-

"""
@Datetime: 2018/11/10
@Author: Zhang Yafei
"""


class Stack(object):
    """"""
    def __init__(self):
        self.__list = []  #私有變量,不容許外部調用者對其進行操做

    def push(self,item):
        """添加一個新的元素item到棧頂"""
        self.__list.append(item)   #順序表尾部插入時間複雜度O(1),頭部插入O(n),故尾部方便
        #self.__list.insert(0,item)   #鏈表表尾部插入時間複雜度O(n),頭部插入O(1),故鏈表用頭插方便

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

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

    def is_empty(self):
        """判斷棧是否爲空"""
        return self.__list == []
        # return not self.__list       #0,{},[],(),'',None在python中都是False,

    def size(self):
        """返回棧的元素個數"""
        return self.__list.__len__()


if __name__ == '__main__':
    s = Stack()
    s.push(1)
    s.push(2)
    s.push(3)
    s.push(4)

    print(s.pop())
    print(s.pop())
    print(s.pop())
8.棧的實現
# -*- coding: utf-8 -*-

"""
@Datetime: 2018/11/10
@Author: Zhang Yafei
"""


class Queue(object):
    """隊列"""
    def __init__(qelf):
        qelf.__list = []

    def enqueue(qelf,item):
        """往隊列添加一個item元素"""
        qelf.__list.append(item)   #O(1)  入隊頻繁時,用隊尾插入,隊頭刪除
        # qelf.__list.insert(0,item)   #O(n),出隊頻繁時,隊頭插入,隊尾刪除

    def dequeue(qelf):
        """往隊列頭部刪除一個元素"""
        return qelf.__list.pop(0)  #O(n)
        # return qelf.__list.pop()  #O(1)    當出隊比較頻繁時,用pop比較方便

    def iq_empty(self):
        """判斷隊是否爲空"""
        return qelf.__list == []

    def qize(self):
        """返回隊列的大小"""
        return len(qelf.__list)


if __name__ == '__main__':
    q = Queue()
    q.enqueue(1)
    q.enqueue(2)
    q.enqueue(3)
    q.enqueue(4)

    print(q.dequeue())
    print(q.dequeue())
    print(q.dequeue())
    print(q.dequeue())
9.隊列的實現
# -*- coding: utf-8 -*-

"""
@Datetime: 2018/11/10
@Author: Zhang Yafei
"""


class Dqueue(object):
    """雙端隊列"""
    def __init__(self):
        self.__list = []

    def __str__(self):
        queue = list(map(str,self.__list))
        if not self.__list:
            return 'None'
        else:
            return ' '.join(queue)

    def add_front(self,item):
        """往隊列頭部插入元素"""
        self.__list.insert(0,item)

    def add_rear(self,item):
        """往隊列尾部插入元素"""
        self.__list.append(item)

    def pop_front(self):
        """隊列頭部刪除元素"""
        self.__list.pop(0)

    def pop_rear(self):
        """隊列尾部刪除元素"""
        self.__list.pop()

    def is_empty(self):
        """判斷隊列是否爲空"""
        return not self.__list

    def size(self):
        """返回隊列的大小"""
        return len(self.__list)


if __name__ == '__main__':
    dqueue = Dqueue()
    print(dqueue)
    dqueue.add_front(1)
    print(dqueue)
    dqueue.add_front(2)
    print(dqueue)
    dqueue.add_front(3)
    print(dqueue)
    dqueue.add_rear(4)
    print(dqueue)
    dqueue.add_rear(5)
    print(dqueue)
    dqueue.add_rear(6)
    print(dqueue)
    dqueue.pop_front()
    print(dqueue)
    dqueue.pop_rear()
    print(dqueue)
    dqueue.pop_front()
    print(dqueue)
    dqueue.pop_rear()
    print(dqueue)
    dqueue.pop_front()
    print(dqueue)
    dqueue.pop_rear()
    print(dqueue)
10.雙端隊列
# -*- coding: utf-8 -*-

"""
@Datetime: 2018/11/10
@Author: Zhang Yafei
"""


def bubble_sort(alist):
    """冒泡排序,每一次循環找出最大值"""
    n = len(alist)
    for i in range(n-1):
        count = 0
        for j in range(n-i-1):
            if alist[j] > alist[j+1]:
                alist[j],alist[j+1] = alist[j+1],alist[j]
                count += 1
        if not count:
            return


def bubble_sort2(alist):
    """冒泡排序,每一次循環找出最小值"""
    n = len(alist)
    for i in range(n-1,0,-1):
        for j in range(i):
            if alist[j] > alist[j+1]:
                alist[j],alist[j+1] = alist[j+1],alist[j]


if __name__ == '__main__':
    li = [54,26,93,17,77,31,44,55,20]
    print(li)
    bubble_sort(li)
    # bubble_sort2(li)
    print(li)
11.冒泡排序
# -*- coding: utf-8 -*-

"""
@Datetime: 2018/11/10
@Author: Zhang Yafei
"""
import time


def select_sort1(alist):
    start = time.clock()
    for i in range(0,len(alist)):
        min_v = min(alist[i:len(alist)])
        j = alist.index(min_v)
        alist[i],alist[j] = alist[j],alist[i]
    use_time = time.clock()-start
    print(use_time)


def select_sort(alist):
    start = time.clock()
    n = len(alist)
    for j in range(n-1):  #j:0~n-2
        min_index = j
        for i in range(j+1,n):
            if alist[min_index] > alist[i]:
                min_index = i
        alist[j],alist[min_index] = alist[min_index],alist[j]
    use_time = time.clock()-start
    print(use_time)


if __name__ == '__main__':
    li = [54,226,93,17,77,31,44,55,20]
    print(li)
    select_sort(li)
    # select_sort1(li)
    print(li)
12.簡單選擇排序
# -*- coding: utf-8 -*-

"""
@Datetime: 2018/11/10
@Author: Zhang Yafei
"""
from timeit import Timer

# alist = [54, 226, 93, 17, 77, 31, 44, 55, 20]
# alist1 = [54, 226, 93, 17, 77, 31, 44, 55, 20]


def insert_sort(alist):
    """插入排序"""
    #從第二個位置,即下標爲1的元素開始向前插入
    for i in range(1,len(alist)):
        for j in range(i,0,-1):
            #從第i個元素開始向前比較,若是小於前一個,則交換,不然終止循環
            if alist[j]<alist[j-1]:
                alist[j-1],alist[j] = alist[j],alist[j-1]
            else:
                break


def insert_sort1(alist1):
    """插入排序"""
    #從右邊的無序序列中
    for j in range(1,len(alist1)):
        #i表明內層循環起始值
        i = j
        #執行從右邊的無序序列中取出第一個元素,即i位置的元素,而後將其插入到前面的正確的位置中
        while i > 0:
            if alist1[i]<alist1[i-1]:
                alist1[i],alist1[i-1] = alist1[i-1],alist1[i]
                i -= 1
            else:
                break


if __name__ == '__main__':
    li = [54, 226, 93, 17, 77, 31, 44, 55, 20]
    print(li)
    # insert_sort(li)
    insert_sort1(li)
    print(li)
    # for_time = Timer('insert_sort()','from __main__ import insert_sort')
    # while_time = Timer("insert_sort1()","from __main__ import insert_sort1")
    # print('for_time',for_time.timeit(1000))
    # print('while_time',while_time.timeit(1000))
13.插入排序
# -*- coding: utf-8 -*-

"""
@Datetime: 2018/11/10
@Author: Zhang Yafei
"""


def shell_sort(alist):
    """希爾排序"""
    gap = len(alist) // 2
    # gap變化到0以前,插入算法執行的次數
    while gap > 0 :
        #插入算法,與普通插入算法的區別就是gap步長
        for i in range(gap,len(alist)):
            # i=[gap,gap+1,gap+2,...]
            j = i
            while j > 0:
                if alist[j] < alist[j-gap]:
                    alist[j],alist[j-gap] = alist[j-gap],alist[j]
                    j -= gap
                else:
                    break
        gap //= 2


if __name__ == '__main__':
    li = [54, 226, 93, 17, 77, 31, 44, 55, 20]
    print(li)
    shell_sort(li)
    print(li)
14.希爾排序
# -*- coding: utf-8 -*-

"""
@Datetime: 2018/11/11
@Author: Zhang Yafei
"""


def quick_sort(alist,first,last):
    """快速排序"""
    if first >= last:
        return
    mid_value = alist[first]
    low = first
    high = last
    #遊標從右往左一直走,知道遇到比當前mid_value小的元素,將該元素賦值給low所指的位置
    while low < high:
        #high左移
        while low < high and alist[high] >= mid_value:
            high -= 1
        alist[low] = alist[high]

        while low<high and alist[low] < mid_value:
            low += 1
        alist[high] = alist[low]
    # 從循環退出,low=high
    alist[low] = mid_value

    #對low左邊的列表執行快速排序
    quick_sort(alist,first,low-1)
    #對low右邊的列表排序
    quick_sort(alist,low+1,last)


if __name__ == '__main__':
    li = [54, 226, 93, 17, 77, 31, 44, 55, 20]
    print(li)
    quick_sort(li,0,len(li)-1)
    print(li)
15.快速排序
# -*- coding: utf-8 -*-

"""
@Datetime: 2018/11/11
@Author: Zhang Yafei
"""


def merge_sort(alist):
    """歸併排序"""
    n = len(alist)
    if n<=1:
        return alist
    mid = n//2

    left_li = merge_sort(alist[:mid])
    right_li = merge_sort(alist[mid:])

    left_pointer,right_pointer = 0,0
    result = []
    while left_pointer < len(left_li) and right_pointer < len(right_li):
        if left_li[left_pointer] < right_li[right_pointer]:
            result.append(left_li[left_pointer])
            left_pointer += 1
        else:
            result.append(right_li[right_pointer])
            right_pointer += 1

    result += left_li[left_pointer:]
    result += right_li[right_pointer:]

    return result


if __name__ == '__main__':
    li = [54, 226, 93, 17, 77, 31, 44, 55, 20]
    print(li)
    sorted_list = merge_sort(li)
    print(li)
    print(sorted_list)
16.歸併排序
# -*- coding: utf-8 -*-

"""
@Datetime: 2018/11/11
@Author: Zhang Yafei
"""


def binary_search(alist,item):
    """二分查找"""
    n = len(alist)
    if n > 0:
        mid = n//2
        if alist[mid] == item:
            return True
        elif item < alist[mid]:
            return binary_search(alist[:mid],item)
        else:
            return binary_search(alist[mid+1:],item)
    return False


def binary_search_2(alist,item):
    """二分查找非遞歸查版本"""
    n = len(alist)
    first = 0
    last = n-1
    while first <= last:
        mid = (first + last) // 2
        if alist[mid] == item:
            return True
        elif item < alist[mid]:
            last = mid - 1
        else:
            first = mid + 1
    return False


if __name__ == '__main__':
    li = [17, 20, 31, 44, 54, 55, 77, 93, 226]
    print(binary_search(li,31))
    print(binary_search_2(li,31))
17.二分查找
# -*- coding: utf-8 -*-

"""
@Datetime: 2018/11/11
@Author: Zhang Yafei
"""


class Node(object):
    """樹節點"""
    def __init__(self, item=None):
        self.elem = item
        self.lchild = None
        self.rchild = None


class Tree(object):
    """二叉樹"""
    def __init__(self):
        self.root = None

    def add(self, item):
        node = Node(item)
        if self.root is None:
            self.root = Node(item)
            return
        queue = [self.root]
        while queue:
            cur_node = queue.pop(0)
            if cur_node.lchild is None:
                cur_node.lchild = node
                return
            else:
                queue.append(cur_node.lchild)
            if cur_node.rchild is None:
                cur_node.rchild = node
                return
            else:
                queue.append(cur_node.rchild)

    def breadth_travel(self):
        """廣度遍歷"""
        if not self.root:
            return
        queue = [self.root]
        while queue:
            cur_node = queue.pop(0)
            print(cur_node.elem,end=' ')
            if cur_node.lchild:
                queue.append(cur_node.lchild)
            if cur_node.rchild:
                queue.append(cur_node.rchild)

    def preorder(self, node):
        """先序遍歷"""
        if not node:
            return
        print(node.elem, end=' ')
        self.preorder(node.lchild)
        self.preorder(node.rchild)

    def inorder(self,node):
        """中序遍歷"""
        if not node:
            return
        self.inorder(node.lchild)
        print(node.elem,end=' ')
        self.inorder(node.rchild)

    def postorder(self,node):
        """後序遍歷"""
        if not node:
            return
        self.postorder(node.lchild)
        self.postorder(node.rchild)
        print(node.elem,end=' ')


if __name__ == '__main__':
    tree = Tree()
    tree.add(0)
    tree.add(1)
    tree.add(2)
    tree.add(3)
    tree.add(4)
    tree.add(5)
    tree.add(6)
    tree.add(7)
    tree.add(8)
    tree.add(9)
    tree.breadth_travel()
    print('')
    tree.preorder(tree.root)
    print('')
    tree.inorder(tree.root)
    print('')
    tree.postorder(tree.root)
    print('')
18.二叉樹的廣度、深度優先及先、中、後序遍歷
# -*- coding: utf-8 -*-

"""
@Datetime: 2019/4/10
@Author: Zhang Yafei

桶排序(Bucket sort)或所謂的箱排序,是一個排序算法,工做的原理是將數組分到有限數量的桶裏。
每一個桶再個別排序(有可能再使用別的排序算法或是以遞歸方式繼續使用桶排序進行排序)。桶排序是
鴿巢排序的一種概括結果。當要被排序的數組內的數值是均勻分配的時候,桶排序使用線性時間

桶排序如下列程序進行:
    1. 設置一個定量的數組看成空桶子。
    2. 尋訪序列,而且把項目一個一個放到對應的桶子去。
    3. 對每一個不是空的桶子進行排序。
    4. 從不是空的桶子裏把項目再放回原來的序列中。
"""


def bucket_sort2(array):
    # 1.建立n個空桶
    n = len(array)
    new_list = [[] for _ in range(n)]

    # 2.把arr[i] 插入到bucket[n*array[i]]
    for data in array:
        index = int(data * n)
        new_list[index].append(data)

    # 3.桶內排序
    for i in range(n):
        new_list[i].sort()

    # 4.產生新的排序後的列表
    index = 0
    for i in range(n):
        for j in range(len(new_list[i])):
            array[index] = new_list[i][j]
            index += 1
    return array


def bucket_sort(nums):
    # 選擇一個最大的數
    max_num = max(nums)
    # 建立一個元素全是0的列表, 當作桶
    bucket = [0] * (max_num + 1)
    # 把全部元素放入桶中, 即把對應元素個數加一
    for i in nums:
        bucket[i] += 1

    # 存儲排序好的元素
    sort_nums = []
    # 取出桶中的元素
    for j in range(len(bucket)):
        if bucket[j] != 0:
            for y in range(bucket[j]):
                sort_nums.append(j)
    return sort_nums


if __name__ == '__main__':
    data = [54, 26, 93, 17, 77, 31, 44, 55, 20]
    data2 = [0.897, 0.565, 0.656, 0.1234, 0.665, 0.3434]
    data3 = data2.copy()
    sort_data = bucket_sort(data)
    sort_data2 = bucket_sort2(data2)
    print(data)
    print(sort_data)
    print(data3)
    print(sort_data2)
19.桶排序
# -*- coding: utf-8 -*-

"""
@Datetime: 2019/4/10
@Author: Zhang Yafei
"""


def swap(data, root, last):
    data[root], data[last] = data[last], data[root]


def adjust_heap(data, par_node, high):
    """
    調整父節點 與孩子大小, 製做大頂堆
    :param data:
    :param par_node:
    :param high:
    :return:
    """
    new_par_node = par_node
    j = 2 * par_node + 1  # 取根節點的左孩子, 若是隻有一個孩子 high就是左孩子,若是有兩個孩子 high 就是右孩子

    while j <= high:  # 若是 j = high 說明沒有右孩子,high就是左孩子
        if j < high and data[j] < data[j + 1]:  # 若是這兒不判斷 j < high 可能超出索引
            # 一個根節點下,若是有兩個孩子,將 j  指向值大的那個孩子
            j += 1
        if data[j] > data[new_par_node]:  # 若是子節點值大於父節點,就互相交換
            data[new_par_node], data[j] = data[j], data[new_par_node]
            new_par_node = j  # 將當前節點,做爲父節點,查找他的子樹
            j = j * 2 + 1

        else:
            # 由於調整是從上到下,因此下面的全部子樹確定是排序好了的,
            # 若是調整的父節點依然比下面最大的子節點大,就直接打斷循環,堆已經調整好了的
            break


# 索引計算: 0 -->1 --->....
#    父節點 i   左子節點:偶數:2i +1  右子節點:基數:2i +2  注意:當用長度表示最後一個葉子節點時 記得 -1

# 從第一個非葉子節點(即最後一個父節點)開始,即 list_.length//2 -1(len(list_)//2 - 1)
# 開始循環到 root 索引爲:0 的第一個根節點, 將全部的根-葉子 調整好,成爲一個 大頂堆
def heap_sort(lst):
    """
    根據列表長度,找到最後一個非葉子節點,開始循化到 root 根節點,製做 大頂堆
    :param lst: 將列表傳入
    :return:
    """
    length = len(lst)
    last = length - 1  # 最後一個元素的 索引
    last_par_node = length // 2 - 1

    while last_par_node >= 0:
        adjust_heap(lst, last_par_node, length - 1)
        last_par_node -= 1  # 每調整好一個節點,從後往前移動一個節點
    while last > 0:
        # swap(lst, 0, last)
        lst[0], lst[last] = lst[last], lst[0]
        # 調整堆少讓 adjust 處理最後已經排好序的數,就不處理了
        adjust_heap(lst, 0, last - 1)
        last -= 1

    return lst  # 將列表返回


if __name__ == '__main__':
    data = [54, 26, 93, 17, 77, 31, 44, 55, 20]
    print(data)
    heap_sort(data)
    print(data)
20.堆排序
# -*- coding: utf-8 -*-

"""
@Datetime: 2019/4/10
@Author: Zhang Yafei
"""

def cycle_sort(array):
    """
    圈排序(不穩定排序)
    默認升序
    計數排序是另開闢空間存放排序結果,圈排序是不開闢空間,直接進行組內交換
    """
    ans = 0  # 記錄發生交換的次數,不用在乎,可有可無,可刪

    # 外層循環處理列表中的每個圈,一次遍歷出現一個圈
    for cycleStart in range(0, len(array) - 1):
        item = array[cycleStart]  # 取出待排序的元素,item一直記錄一圈的元素

        # 找到item應該放的位置,跟計數排序類似,統計列表中有多少個元素比item小
        pos = cycleStart  # 記錄位置
        for i in range(cycleStart + 1, len(array)):
            if array[i] < item:
                pos += 1

        # item也存在圈但這個圈只有它本身,表示item已經歸位,不用改變
        if pos == cycleStart:
            continue  # 跳過本次循環繼續下次循環

        # 這四行代碼是處理列表中相同的元素
        while item == array[pos]:  # 若是相同,就直接放在pos的後一個位置
            pos += 1
        array[pos], item = item, array[pos]  # item最終歸位,並把item賦新值
        ans += 1

        # 處理新的item
        while pos != cycleStart:  # pos=cycleStart就表明又回到了起點,表示已有元素歸到
            # cycleStart位置上,一圈處理完畢

            # 如下代碼跟上面思路同樣
            pos = cycleStart
            for i in range(cycleStart + 1, len(array)):
                if array[i] < item:
                    pos += 1

            while item == array[pos]:
                pos += 1
            array[pos], item = item, array[pos]
            ans += 1


if __name__ == '__main__':
    data = [54, 26, 93, 17, 77, 31, 44, 55, 20]
    print(data)
    cycle_sort(data)
    print(data)
21.圈排序
# -*- coding: utf-8 -*-

"""
@Datetime: 2019/4/10
@Author: Zhang Yafei
"""


def comb_sort(the_list):
    the_len = len(the_list)
    if the_len <2:#0和1
        print("無需排序")
        return the_list
    else:
        i = int(the_len/1.3)
        while i >= 1:
            for j in range(the_len):
                if i + j >= the_len:
                    i = int(i/1.3)
                    break
                else:
                    if the_list[j] >= the_list[j+i]:
                        the_list[j], the_list[j+i] = the_list[j+i], the_list[j]


if __name__ == '__main__':
    data = [54, 26, 93, 17, 77, 31, 44, 55, 20]
    print(data)
    comb_sort(data)
    print(data)
22.梳排序
# -*- coding: utf-8 -*-

"""
@Datetime: 2019/4/10
@Author: Zhang Yafei
"""
import math


def radix_sort(the_list, radix=10):
    """
    基數排序
    :param the_list:
    :param radix:
    :return:
    """
    i = int(math.ceil(math.log(max(the_list), radix)))
    bucket = [[] for i in range(radix)]
    for i in range(1, i + 1):  # i次循環
        for val in the_list:
            bucket[int(val % (radix ** i) / (radix ** (i - 1)))].append(val)  # 析取整數第K位數字 (從低到高)
        print(f'{i}: {bucket}')
        del the_list[:]  # 把列表清空但列表還在,效果同the_list=[]同樣
        for each in bucket:
            the_list.extend(each)  # 桶合併
        bucket = [[] for _ in range(radix)]


if __name__ == '__main__':
    data = [54, 26, 93, 17, 77, 31, 44, 55, 20]
    print('排序前:', data)
    radix_sort(data, 2)
    print('排序後:', data)
23.基數排序
# -*- coding: utf-8 -*-

"""
@Datetime: 2019/4/10
@Author: Zhang Yafei
"""
import random


def monkey_sort_test(num_list):
    """
    猴子排序,思想是:每次都隨機打亂數組,直到有序爲止
    """
    while True:
        i = 1
        while i < len(data):
            # 判斷是否有序
            if data[i-1] < data[i]:
                i += 1
            else:
                break
        if i == len(data):
            break
        random.shuffle(num_list)


if __name__ == '__main__':
    data = [54, 26, 93, 17, 77, 31, 44, 55, 20]
    print('排序前:', data)
    monkey_sort_test(data)
    print('排序後:', data)
24.猴子排序

 

擴展

# -*- coding: utf-8 -*-

"""
@Datetime: 2019/1/8
@Author: Zhang Yafei
"""
import redis


class FifoQueue(object):
    def __init__(self):
        """
        先進先出隊列:利用redis中的列表,雙端隊列改成先進先出隊列
        """
        self.server = redis.Redis(host='127.0.0.1', port=6379)

    def push(self, request):
        """Push a request"""
        self.server.lpush('USERS', request)

    def pop(self, timeout=0):
        """Pop a request"""
        data = self.server.rpop('USERS')
        return data


if __name__ == '__main__':
    q = FifoQueue()
    q.push(11)
    q.push(22)
    q.push(33)

    print(q.pop())
    print(q.pop())
    print(q.pop())
1.基於redis實現先進先出隊列
# -*- coding: utf-8 -*-

"""
@Datetime: 2019/1/8
@Author: Zhang Yafei
"""
import redis


class LifoQueue(object):
    """Per-spider LIFO queue."""
    def __init__(self):
        self.server = redis.Redis(host='127.0.0.1', port=6379)

    def push(self, request):
        """Push a request"""
        self.server.lpush("USERS", request)

    def pop(self, timeout=0):
        """Pop a request"""
        data = self.server.lpop('USERS')
        return data


if __name__ == '__main__':
    q = LifoQueue()
    q.push(11)
    q.push(22)
    q.push(33)

    print(q.pop())
    print(q.pop())
    print(q.pop())
2.基於redis實現後進先出棧
 -*- coding: utf-8 -*-

"""
@Datetime: 2019/1/8
@Author: Zhang Yafei
"""
import redis


class PriorityQueue(object):
    """Per-spider priority queue abstraction using redis' sorted set"""
    def __init__(self):
        self.server = redis.Redis(host='127.0.0.1', port=6379)

    def push(self, request,score):
        """Push a request"""
        # data = self._encode_request(request)
        # score = -request.priority
        # We don't use zadd method as the order of arguments change depending on
        # whether the class is Redis or StrictRedis, and the option of using
        # kwargs only accepts strings, not bytes.
        self.server.execute_command('ZADD', 'xxxxxx', score, request)

    def pop(self, timeout=0):
        """
        Pop a request
        timeout not support in this queue class
        """
        # use atomic range/remove using multi/exec
        pipe = self.server.pipeline()
        pipe.multi()
        pipe.zrange('xxxxxx', 0, 0).zremrangebyrank('xxxxxx', 0, 0)
        results, count = pipe.execute()
        if results:
            return results[0]


if __name__ == '__main__':
    q = PriorityQueue()

    # q.push('alex',99)    # 廣度優先:分值小的優先
    # q.push('oldboy',56)
    # q.push('eric',77)

    q.push('alex',-99)       # 深度優先:分值大的優先
    q.push('oldboy',-56)
    q.push('eric',-77)

    v1 = q.pop()
    print(v1)
    v2 = q.pop()
    print(v2)
    v3 = q.pop()
    print(v3)
3.基於redis實現優先級隊列
相關文章
相關標籤/搜索