數據結構和算法基礎

Alan-song        數據結構目錄樹

數據結構基本概念

什麼是數據結構?

  1. 數據

數據即信息的載體,是可以輸入到計算機中而且能被計算機識別、存儲和處理的符號總稱。html

  1. 數據元素

數據元素是數據的基本單位,又稱之爲記錄(Record)。通常,數據元素由若干基本項(或稱字段、域、屬性)組成。node

  1. 數據結構

數據結構指的是數據元素及數據元素之間的相互關係,或組織數據的形式。算法

數據之間的結構關係

  1. 邏輯結構

表示數據之間的抽象關係(如鄰接關係、從屬關係等),按每一個元素可能具備的直接前趨數和直接後繼數將邏輯結構分爲「線性結構」和「非線性結構」兩大類。編程

  1. 存儲結構

邏輯結構在計算機中的具體實現方法,分爲順序存儲方法、連接存儲方法、索引存儲方法、散列存儲方法。markdown

邏輯結構(關係)

  1. 特色:
  • 只是描述數據結構中數據元素之間的聯繫規律
  • 是從具體問題中抽象出來的數學模型,是獨立於計算機存儲器的(與機器無關)
  1. 邏輯結構分類
  • 線性結構

對於數據結構課程而言,簡單地說,線性結構是n個數據元素的有序(次序)集合。數據結構

  • 集合中必存在惟一的一個"第一個元素";
  • 集合中必存在惟一的一個"最後的元素";
  • 除最後元素以外,其它數據元素均有惟一的"後繼";
  • 除第一元素以外,其它數據元素均有惟一的"前驅"。
  • 樹形結構(層次結構)

樹形結構指的是數據元素之間存在着「一對多」的樹形關係的數據結構,是一類重要的非線性數據結構。在樹形結構中,樹根結點沒有前驅結點,其他每一個結點有且只有一個前驅結點。葉子結點沒有後續結點,其他每一個結點的後續節點數能夠是一個也能夠是多個。app

  • 圖狀結構(網狀結構)

圖是一種比較複雜的數據結構。在圖結構中任意兩個元素之間均可能有關係,也就是說這是一種多對多的關係。ide

  • 其餘結構

除了以上幾種常見的邏輯結構外,數據結構中還包含其餘的結構,好比集合等。有時根據實際狀況抽象的模型不止是簡單的某一種,也可能擁有更多的特徵。函數

 

存儲結構(關係)

  1. 特色:
  • 是數據的邏輯結構在計算機存儲器中的映象(或表示)
  • 存儲結構是經過計算機程序來實現的,於是是依賴於具體的計算機語言的。
  1. 存儲結構分類
  • 順序存儲

順序存儲(Sequential Storage):將數據結構中各元素按照其邏輯順序存放於存儲器一片連續的存儲空間中。post

  • 鏈式存儲

鏈式存儲(Linked Storage):將數據結構中各元素分佈到存儲器的不一樣點,用記錄下一個結點位置的方式創建它們之間的聯繫,由此獲得的存儲結構爲鏈式存儲結構。

  • 索引存儲

索引存儲(Indexed Storage):在存儲數據的同時,創建一個附加的索引表,即索引存儲結構=數據文件+索引表。

線性表

線性表的定義是描述其邏輯結構,而一般會在線性表上進行的查找、插入、刪除等操做。
線性表做爲一種基本的數據結構類型,在計算機存儲器中的映象(或表示)通常有兩種形式,一種是順序映象,一種是鏈式映象。

線性表的順序存儲

  1. 定義

若將線性表L=(a0,a1, ……,an-1)中的各元素依次存儲於計算機一片連續的存儲空間,這種機制表示爲線性表的順序存儲結構。

  1. 特色
  • 邏輯上相鄰的元素 ai, ai+1,其存儲位置也是相鄰的;
  • 存儲密度高,方便對數據的遍歷查找。
  • 對錶的插入和刪除等運算的效率較差。
  1. 程序實現

在Python中,list存放於一片單一連續的內存塊,故可藉助於列表類型來描述線性表的順序存儲結構,並且列表自己就提供了豐富的接口知足這種數據結構的運算。

 1      
 2 
 3 >>>L = [1,2,3,4]
 4 >>>L.append(10)      #尾部增長元素
 5 L
 6 [1, 2, 3, 4, 10]
 7 
 8 >>>L.insert(1,20)    #插入元素
 9 L
10 [1, 20, 2, 3, 4, 10]
11 
12 >>>L.remove(3)       #刪除元素
13 L
14 [1, 20, 2, 4, 10]     
15 
16 >>>L[4] = 30         #修改
17 L
18 [1, 20, 2, 4, 30]
19 
20 >>>L.index(2)        #查找
21 2
list.py

 

 

線性表的鏈式存儲

  1. 定義

將線性表L=(a0,a1,……,an-1)中各元素分佈在存儲器的不一樣存儲塊,稱爲結點,每一個結點(尾節點除外)中都持有一個指向下一個節點的引用,這樣所獲得的存儲結構爲鏈表結構。

  1. 特色
  • 邏輯上相鄰的元素 ai, ai+1,其存儲位置也不必定相鄰;
  • 存儲稀疏,沒必要開闢整塊存儲空間。
  • 對錶的插入和刪除等運算的效率較高。
  • 邏輯結構複雜,不利於遍歷。
  1. 程序實現
  1 """
  2 linklist.py
  3 功能: 實現單鏈表的構建和功能操做
  4 重點代碼
  5 """
  6 
  7 
  8 #  建立節點類
  9 class Node:
 10     """
 11     思路: 將自定義的類視爲節點的生成類,實例對象中
 12         包含數據部分和指向下一個節點的next
 13     """
 14 
 15     def __init__(self, val, next=None):
 16         self.val = val  # 有用數據
 17         self.next = next  # 循環下一個節點關係
 18 
 19 
 20 # 作鏈表操做
 21 class LinkList:
 22     """
 23     思路: 單鏈表類,生成對象能夠進行增刪改查操做
 24         具體操做經過調用具體方法完成
 25     """
 26 
 27     def __init__(self):
 28         """
 29         初始化鏈表,標記一個鏈表的開端,以便於獲取後續
 30         的節點
 31         """
 32         self.head = Node(None)
 33 
 34     # 經過list_爲鏈表添加一組節點
 35     def init_list(self, list_):
 36         p = self.head  # p 做爲移動變量
 37         for item in list_:
 38             p.next = Node(item)
 39             p = p.next
 40 
 41     # 遍歷鏈表
 42     def show(self):
 43         p = self.head.next  # 第一個有效節點
 44         while p is not None:
 45             print(p.val)
 46             p = p.next  # p向後移動
 47 
 48     # 判斷鏈表爲空
 49     def is_empty(self):
 50         if self.head.next is None:
 51             return True
 52         else:
 53             return False
 54 
 55     # 清空鏈表
 56     def clear(self):
 57         self.head.next = None
 58 
 59     #  尾部插入
 60     def append(self, val):
 61         p = self.head
 62         while p.next is not None:
 63             p = p.next
 64         p.next = Node(val)
 65 
 66     #  頭部插入
 67     def head_insert(self, val):
 68         node = Node(val)
 69         node.next = self.head.next
 70         self.head.next = node
 71 
 72     #  指定插入位置
 73     def insert(self, index, val):
 74         p = self.head
 75         for i in range(index):
 76             # 超出位置最大範圍結束循環
 77             if p.next is None:
 78                 break
 79             p = p.next
 80 
 81         node = Node(val)
 82         node.next = p.next
 83         p.next = node
 84 
 85     #  刪除節點
 86     def delete(self, x):
 87         p = self.head
 88         #  結束循環必然兩個條件其一爲假
 89         while p.next and p.next.val != x:
 90             p = p.next
 91 
 92         if p.next is None:
 93             raise ValueError("x not in linklist")
 94         else:
 95             p.next = p.next.next
 96 
 97     # 獲取某個節點值,傳入節點位置獲取節點值
 98     def get_index(self,index):
 99         if index < 0:
100             raise IndexError("index out of range")
101         p = self.head.next
102         for i in range(index):
103             if p.next is None:
104                 raise IndexError("index out of range")
105             p = p.next
106         return p.val
linklist.py

 

 1 from linklist import *
 2 import time
 3 
 4 l = []
 5 for i in range(999999):
 6     l.append(i)
 7 
 8 link = LinkList()
 9 link.init_list(l)
10 
11 tm = time.time()
12 # for i in l:
13 #     print(i)  # 列表
14 # link.show()  # 鏈表
15 
16 # l.append(8866)
17 # link.append(8866) # 尾插入
18 
19 # l.insert(0,8866)
20 # link.head_insert(8866) # 頭插
21 
22 # link.insert(100,9999)
23 
24 # link.delete(1) #刪除
25 l.remove(1)
26 
27 # link.show()
28 # print(link.get_index(-1))
29 
30 print("time: ",time.time()-tm)
link_test.py

 

 

棧和隊列

  1. 定義

棧是限制在一端進行插入操做和刪除操做的線性表(俗稱堆棧),容許進行操做的一端稱爲「棧頂」,另外一固定端稱爲「棧底」,當棧中沒有元素時稱爲「空棧」。

  1. 特色:
  • 棧只能在一端進行數據操做
  • 棧模型具備先進後出或者叫作後進先出的規律

 

 

  1. 棧的代碼實現

棧的操做有入棧(壓棧),出棧(彈棧),判斷棧的空滿等操做。

順序存儲代碼實現:

 1 """
 2 sstack.py  棧模型的順序存儲
 3 重點代碼
 4 
 5 思路總結:
 6 1. 列表即順序存儲,但功能多,不符合棧的模型特徵
 7 2. 利用列表 將其封裝,提供接口方法
 8 """
 9 
10 # 自定義異常
11 class StackError(Exception):
12     pass
13 
14 # 順序棧類
15 class SStack:
16     def __init__(self):
17         # 空列表就是棧的存儲空間
18         # 列表的最後一個元素做爲棧頂
19         self._elems = []
20 
21     # 判斷列表是否爲空
22     def is_empty(self):
23         return self._elems == []
24 
25     # 入棧
26     def push(self,val):
27         self._elems.append(val)
28 
29     # 出棧
30     def pop(self):
31         if self.is_empty():
32             raise StackError("Stack is empty")
33         # 彈出並返回
34         return self._elems.pop()
35 
36     # 查看棧頂元素
37     def top(self):
38         if self.is_empty():
39             raise StackError("Stack is empty")
40         return self._elems[-1]
41 
42 
43 if __name__ == "__main__":
44     st = SStack() # 初始化棧
45     st.push(10)
46     st.push(20)
47     st.push(30)
48     while not st.is_empty():
49         print(st.pop())
sstack.py

 


鏈式存儲代碼實現:

 1 """
 2 lstack.py  棧的鏈式棧
 3 重點代碼
 4 
 5 思路分析:
 6 1. 源於鏈表結構
 7 2. 封裝棧的操做方法(入棧,出棧,棧空,棧頂元素)
 8 3. 鏈表的開頭做爲棧頂 ? (不用每次遍歷)
 9 """
10 
11 # 自定義異常
12 class StackError(Exception):
13     pass
14 
15 # 節點類
16 class Node:
17     def __init__(self, val, next=None):
18         self.val = val
19         self.next = next
20 
21 # 鏈式棧操做
22 class LStack:
23     def __init__(self):
24         # 標記棧的棧頂位置
25         self._top = None
26 
27     def is_empty(self):
28         return self._top is None
29 
30     def push(self,val):
31         self._top = Node(val,self._top)
32 
33     def pop(self):
34         if self._top is None:
35             raise StackError("Stack is emtpy")
36         value = self._top.val
37         self._top = self._top.next
38         return value
39 
40     def top(self):
41         if self._top is None:
42             raise StackError("Stack is emtpy")
43         return self._top.val
44 
45 if __name__ == "__main__":
46     ls = LStack()
47     ls.push(1)
48     ls.push(2)
49     ls.push(3)
50     print(ls.pop())
51     print(ls.pop())
lstack.py

 

 

隊列

  1. 定義

隊列是限制在兩端進行插入操做和刪除操做的線性表,容許進行存入操做的一端稱爲「隊尾」,容許進行刪除操做的一端稱爲「隊頭」。

  1. 特色
  • 隊列只能在隊頭和隊尾進行數據操做
  • 隊列模型具備先進先出或者叫作後進後出的規律

 

  1. 隊列的代碼實現

隊列的操做有入隊,出隊,判斷隊列的空滿等操做。

順序存儲代碼實現:

 1 """
 2 squeue.py 隊列的順序存儲
 3 
 4 思路分析:
 5 1. 基於列表完成數據存儲
 6 2. 經過封裝規定數據操做
 7 3. 先肯定列表的哪一段做爲隊頭
 8 """
 9 
10 # 自定義隊列異常
11 class QueueError(Exception):
12     pass
13 
14 # 隊列操做
15 class SQueue:
16     # 初始化
17     def __init__(self):
18         self._elems = []
19 
20     # 判斷隊列是否爲空
21     def is_empty(self):
22         return self._elems == []
23 
24     # 入隊 列表尾部定義爲隊尾
25     def enqueue(self,val):
26         self._elems.append(val)
27 
28     # 出隊 列表的第一個元素
29     def dequeue(self):
30         if not self._elems:
31             raise QueueError("Queue is empty")
32         return self._elems.pop(0)
33 
34 if __name__ == "__main__":
35     sq = SQueue()
36     for i in range(10):
37         sq.enqueue(i)
38 
39 ###########  將隊列翻轉 #############
40     from sstack import *
41     st = SStack()
42     # 循環出隊入棧
43     while not sq.is_empty():
44         st.push(sq.dequeue())
45     # 循環出棧入隊
46     while not st.is_empty():
47         sq.enqueue(st.pop())
48 
49     while not sq.is_empty():
50         print(sq.dequeue())
squeue.py

 


鏈式存儲代碼實現: 待補充lqueue.py

樹形結構

基礎概念

  1. 定義

樹(Tree)是n(n≥0)個節點的有限集合T,它知足兩個條件:有且僅有一個特定的稱爲根(Root)的節點;其他的節點能夠分爲m(m≥0)個互不相交的有限集合T一、T二、……、Tm,其中每個集合又是一棵樹,並稱爲其根的子樹(Subtree)。

 

  1. 基本概念
  • 一個節點的子樹的個數稱爲該節點的度數,一棵樹的度數是指該樹中節點的最大度數。
  • 度數爲零的節點稱爲樹葉或終端節點,度數不爲零的節點稱爲分支節點,除根節點外的分支節點稱爲內部節點。
  • 一個節點的子樹之根節點稱爲該節點的子節點,該節點稱爲它們的父節點,同一節點的各個子節點之間稱爲兄弟節點。一棵樹的根節點沒有父節點,葉節點沒有子節點。
  • 一個節點系列k1,k2, ……,ki,ki+1, ……,kj,並知足ki是ki+1的父節點,就稱爲一條從k1到kj的路徑,路徑的長度爲j-1,即路徑中的邊數。路徑中前面的節點是後面節點的祖先,後面節點是前面節點的子孫。
  • 節點的層數等於父節點的層數加一,根節點的層數定義爲一。樹中節點層數的最大值稱爲該樹的高度或深度。
  • m(m≥0)棵互不相交的樹的集合稱爲森林。樹去掉根節點就成爲森林,森林加上一個新的根節點就成爲樹。

 

二叉樹

定義與特徵

  1. 定義

二叉樹(Binary Tree)是n(n≥0)個節點的有限集合,它或者是空集(n=0),或者是由一個根節點以及兩棵互不相交的、分別稱爲左子樹和右子樹的二叉樹組成。二叉樹與普通有序樹不一樣,二叉樹嚴格區分左孩子和右孩子,即便只有一個子節點也要區分左右。

 

  1. 二叉樹的特徵
  • 二叉樹第i(i≥1)層上的節點最多爲2i−12^{i-1}2i1個。

  • 深度爲k(k≥1)的二叉樹最多有2k-12^k-12k1個節點。

  • 在任意一棵二叉樹中,樹葉的數目比度數爲2的節點的數目多一。

  • 滿二叉樹 :深度爲k(k≥1)時有2k-12^k-12k1個節點的二叉樹。

  • 徹底二叉樹 :只有最下面兩層有度數小於2的節點,且最下面一層的葉節點集中在最左邊的若干位置上。

二叉樹的遍歷

遍歷 :沿某條搜索路徑周遊二叉樹,對樹中的每個節點訪問一次且僅訪問一次。

先序遍歷: 先訪問樹根,再訪問左子樹,最後訪問右子樹;
中序遍歷: 先訪問左子樹,再訪問樹根,最後訪問右子樹;
後序遍歷: 先訪問左子樹,再訪問右子樹,最後訪問樹根;
層次遍歷: 從根節點開始,逐層從左向右進行遍歷。

 1 /*求二叉樹的結點總數*/
 2 #include<stdio.h>
 3 #define maxsize 100
 4 typedef char datatype;
 5 /*二叉鏈表類型定義*/
 6 typedef struct Binnode
 7 {
 8     datatype data;                   /*數據域*/
 9     struct BinNode* lchild,*rchild;  /*指向左、右孩子的指針*/
10 }BinNode,*Bintree;
11 /*按先序建立二叉樹*/
12 Bintree CreateTree(Bintree T)
13 {
14     datatype ch;
15     scanf("%c",&ch);
16     if(ch=='#')
17         return NULL;
18     else
19     {
20         T=(Bintree)malloc(sizeof(BinNode));
21         T->data=ch;
22         T->lchild=CreateTree(T->lchild);/*建立左子樹*/
23         T->rchild=CreateTree(T->rchild);/*建立右子樹*/
24         return T;
25     }
26 }
27 /*求二叉樹結點總數*/
28 int Count(Bintree T)
29 {
30     if(T==NULL)
31         return 0;                   /*空二叉樹結點數爲0*/
32     else                            /*左右子樹結點總數加1*/
33         return Count(T->lchild)+Count(T->rchild)+1;
34 }
35 main()
36 {
37     Bintree t;
38     printf("請按先序的方式輸入二叉樹的結點元素(注:#表示節點爲空):");
39     t=CreateTree(t);
40     printf("二叉樹結點總數:%d",Count(t));
41 }
42 --------------------- 
43 做者:雲淡風輕58 
44 來源:CSDN 
45 原文:https://blog.csdn.net/dwenxue/article/details/72477492 
46 版權聲明:本文爲博主原創文章,轉載請附上博文連接!
binary_tree.py

 

 

遞歸思想和實踐

  1. 什麼是遞歸?

所謂遞歸函數是指一個函數的函數體中直接調用或間接調用了該函數自身的函數。這裏的直接調用是指一個函數的函數體中含有調用自身的語句,間接調用是指一個函數在函數體裏有調用了其它函數,而其它函數又反過來調用了該函數的狀況。

  1. 遞歸函數調用的執行過程分爲兩個階段

遞推階段:從原問題出發,按遞歸公式遞推從未知到已知,最終達到遞歸終止條件。
迴歸階段:按遞歸終止條件求出結果,逆向逐步代入遞歸公式,迴歸到原問題求解。

  1. 優勢與缺點

優勢:遞歸能夠把問題簡單化,讓思路更爲清晰,代碼更簡潔
缺點:遞歸因系統環境影響大,當遞歸深度太大時,可能會獲得不可預知的結果

遞歸示例:

 1 """
 2 求一個數的階乘
 3 遞歸實現
 4 """
 5 
 6 def recursion(num):
 7     if num <= 1:
 8         return 1
 9     return num * recursion(num - 1)
10 
11 print("n! = ",recursion(5))
recusion.py

 

 

二叉樹的代碼實現

二叉樹順序存儲

二叉樹自己是一種遞歸結構,可使用Python 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],
          ],
     ]
]

 

二叉樹鏈式存儲

二叉樹遍歷:

 1 """
 2 bitree.py  二叉樹的簡單實踐
 3 
 4 思路分析:
 5 1. 使用鏈式存儲,一個Node表示一個樹的節點
 6 2. 節點考慮使用兩個屬性變量分別表示左鏈接和右鏈接
 7 """
 8 from squeue import *
 9 
10 # 二叉樹節點
11 class Node:
12     def __init__(self,val,left=None,right = None):
13         self.val = val
14         self.left = left
15         self.right = right
16 
17 # 二叉樹遍歷類
18 class Bitree:
19     def __init__(self,root = None):
20         self.root = root
21 
22     # 先序遍歷
23     def preOrder(self,node):
24         if node is None:  # 終止條件
25             return
26         print(node.val,end = '')
27         self.preOrder(node.left)
28         self.preOrder(node.right)
29 
30     #  中序遍歷
31     def inOrder(self, node):
32         if node is None:  # 終止條件
33             return
34         self.inOrder(node.left)
35         print(node.val,end = "")
36         self.inOrder(node.right)
37 
38     #  後序遍歷
39     def postOrder(self, node):
40         if node is None:  # 終止條件
41             return
42         self.postOrder(node.left)
43         self.postOrder(node.right)
44         print(node.val, end="")
45 
46     # 層次遍歷
47     def levelOrder(self,node):
48         """
49         讓初始節點先入隊,誰出隊就遍歷誰,而且讓它的左右孩子分別入隊,直到隊列爲空
50         """
51         sq = SQueue()
52         sq.enqueue(node) # 初始節點入隊
53         while not sq.is_empty():
54             node = sq.dequeue()
55             #  打印出隊元素
56             print(node.val,end='')
57             if node.left:
58                 sq.enqueue(node.left)
59             if node.right:
60                 sq.enqueue(node.right)
61 
62 
63 
64 if __name__ == "__main__":
65     # B F G  D  I H E C A
66     # 根據後續遍歷構建二叉樹
67     b = Node('B')
68     f = Node('F')
69     g = Node('G')
70     d = Node('D',f,g)
71     i = Node('I')
72     h = Node('H')
73     e = Node('E',i,h)
74     c = Node('C',d,e)
75     a = Node('A',b,c)  #樹根
76 
77     # 將a做爲遍歷的起始位置
78     bt = Bitree(a)
79 
80     bt.preOrder(bt.root)
81     print()
82     bt.inOrder(bt.root)
83     print()
84     bt.postOrder(bt.root)
85     print()
86     bt.levelOrder(bt.root)
bitree.py

 

 

算法基礎

基礎概念特徵

  1. 定義

算法(Algorithm)是一個有窮規則(或語句、指令)的有序集合。它肯定了解決某一問題的一個運算序列。對於問題的初始輸入,經過算法有限步的運行,產生一個或多個輸出。

數據的邏輯結構與存儲結構密切相關:

  • 算法設計: 取決於選定的邏輯結構
  • 算法實現: 依賴於採用的存儲結構
  1. 算法的特性
  • 有窮性 —— 算法執行的步驟(或規則)是有限的;
  • 肯定性 —— 每一個計算步驟無二義性;
  • 可行性 —— 每一個計算步驟可以在有限的時間內完成;
  • 輸入 ,輸出 —— 存在數據的輸入和出輸出
  1. 評價算法好壞的方法
  • 正確性:運行正確是一個算法的前提。
  • 可讀性:容易理解、容易編程和調試、容易維護。
  • 健壯性:考慮狀況全面,不容以出現運行錯誤。
  • 時間效率高:算法消耗的時間少。
  • 儲存量低:佔用較少的存儲空間。

時間複雜度計算

算法效率——用依據該算法編制的程序在計算機上執行所消耗的時間來度量。「O」表示一個數量級的概念。根據算法中語句執行的最大次數(頻度)來 估算一個算法執行時間的數量級。

計算方法:

寫出程序中全部運算語句執行的次數,進行加和
若是獲得的結果是常量則時間複雜度爲1
若是獲得的結果中存在變量n則取n的最高次冪做爲時間複雜度

下圖表示隨問題規模n的增大,算法執行時間的增加率。

 

排序和查找

排序

排序(Sort)是將無序的記錄序列(或稱文件)調整成有序的序列。

常見排序方法:

  • 冒泡排序

冒泡排序是一種簡單的排序算法。它重複地走訪過要排序的數列,一次比較兩個元素,若是他們的順序錯誤就把他們交換過來。走訪數列的工做是重複地進行直到沒有再須要交換,也就是說該數列已經排序完成。

  • 選擇排序

工做原理爲,首先在未排序序列中找到最小元素,存放到排序序列的起始位置,而後,再從剩餘未排序元素中繼續尋找最小元素,而後放到排序序列末尾。以此類推,直到全部元素均排序完畢。

  • 插入排序

對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入。插入排序在實現上,一般在從後向前掃描過程當中,須要反覆把已排序元素逐步向後挪位,爲最新元素提供插入空間。

  • 快速排序

步驟:

從數列中挑出一個元素,稱爲 "基準"(pivot),
從新排序數列,全部元素比基準值小的擺放在基準前面,全部元素比基準值大的擺在基準的後面(相同的數能夠到任一邊)。在這個分區退出以後,該基準就處於數列的中間位置。這個稱爲分區(partition)操做。
遞歸地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序。

常見排序代碼實現:

 1 """
 2 sort.py 排序算法訓練
 3 """
 4 
 5 # 冒泡
 6 def bubble(list_):
 7     n = len(list_)
 8     #  外層表示比較多少輪
 9     for i in range(n - 1):
10         #  表示每輪兩兩比較的次數
11         for j in range(n - 1 - i):
12             # 從小到大排序
13             if list_[j] > list_[j + 1]:
14                 list_[j],list_[j + 1] = list_[j + 1],list_[j]
15 
16 # 完成一輪交換
17 def sub_sort(list_,low,high):
18     # 選定基準
19     x = list_[low]
20     # low向後 high向前
21     while low < high:
22         # 後面的數往前放
23         while list_[high] >= x and high > low:
24             high -= 1
25         list_[low] =  list_[high]
26         # 前面的數日後放
27         while list_[low] < x and low < high:
28             low += 1
29         list_[high] = list_[low]
30 
31     list_[low] = x
32     return low
33 
34 
35 def quick(list_,low,high):
36     # low 表示列表第一個元素索引,high表示最後一個元素索引
37     if low < high:
38         key = sub_sort(list_,low,high)
39         quick(list_,low,key - 1)
40         quick(list_, key + 1,high)
41 
42 
43 
44 l = [4,9,3,1,2,5,8,4]
45 # bubble(l)
46 quick(l,0,len(l)-1)
47 print(l)
sort.py
 1 """
 2 sort.py 排序算法訓練
 3 """
 4 
 5 # 冒泡
 6 def bubble(list_):
 7     n = len(list_)
 8     #  外層表示比較多少輪
 9     for i in range(n - 1):
10         #  表示每輪兩兩比較的次數
11         for j in range(n - 1 - i):
12             # 從小到大排序
13             if list_[j] > list_[j + 1]:
14                 list_[j],list_[j + 1] = list_[j + 1],list_[j]
15 
16 # 完成一輪交換
17 def sub_sort(list_,low,high):
18     # 選定基準
19     x = list_[low]
20     # low向後 high向前
21     while low < high:
22         # 後面的數往前放
23         while list_[high] >= x and high > low:
24             high -= 1
25         list_[low] =  list_[high]
26         # 前面的數日後放
27         while list_[low] < x and low < high:
28             low += 1
29         list_[high] = list_[low]
30 
31     list_[low] = x
32     return low
33 
34 
35 def quick(list_,low,high):
36     # low 表示列表第一個元素索引,high表示最後一個元素索引
37     if low < high:
38         key = sub_sort(list_,low,high)
39         quick(list_,low,key - 1)
40         quick(list_, key + 1,high)
41 
42 
43 # 選擇排序
44 def select(list_):
45     # 沒輪選出一個最小值,須要 len(list_) - 1 輪
46     for i in range(len(list_) - 1):
47         min = i  # 假設 list_[i] 爲最小值
48         for j in range(i + 1,len(list_)):
49             if list_[min] > list_[j]:
50                 min = j # 擂主換人
51         # 進行交換,將最小值換到應該在的位置
52         if min != i:
53             list_[i],list_[min] = list_[min],list_[i]
54 
55 # 插入排序
56 def insert(list_):
57     # 控制每次比較的數是誰,從第二個數開始
58     for i in range(1,len(list_)):
59         x = list_[i]  # 空出list_[i]的位置
60         j = i - 1
61         while j >= 0 and list_[j] > x:
62             list_[j + 1] = list_[j]
63             j -= 1
64         list_[j + 1] = x
65 
66 
67 l = [4,9,3,1,2,5,8,4]
68 # bubble(l)
69 # quick(l,0,len(l)-1)
70 # select(l)
71 insert(l)
72 
73 print(l)
search.py

 

 

查找

查找(或檢索)是在給定信息集上尋找特定信息元素的過程。

二分法查找

當數據量很大適宜採用該方法。採用二分法查找時,數據需是排好序的。

二分查找代碼實現:

 1 """
 2 search.py 二分查找方法訓練
 3 """
 4 
 5 # list_爲有序數列,key爲要查找的關鍵值,返回key在數列中的索引號
 6 def search(list_,key):
 7     # 第一個數index 最後一個數index
 8     low,high = 0,len(list_) - 1
 9 
10     # 循環每次去除一半內容
11     while low <= high:
12         mid = (low + high) // 2
13         # 取後半部分
14         if list_[mid] < key:
15             low = mid + 1
16         # 取前半部分
17         elif list_[mid] > key:
18             high = mid - 1
19         else:
20             return mid
21 
22 
23 l = [1,2,3,4,5,6,7,8,9,10]
24 print("Key index:",search(l,10))
search.py

 

exercise

 1 """
 2 一段文字中有()[]{},編寫一個接口程序去判斷括號是否匹配正確
 3 """
 4 
 5 from lstack import *
 6 
 7 text = "The core (of) extensible programming [is] defining functions. Python allows {mandatory [and]} optional (arguments, {keyword} arguments), and even arbitrary argument lists."
 8 
 9 # 將驗證條件提早定義好
10 parens = "()[]{}"  # 特殊處理的字符集
11 left_parens = "([{"  # 入棧字符集
12 # 驗證匹配關係 
13 opposite = {'}':'{',']':'[',')':'('}
14 
15 ls = LStack()  # 存儲括號的棧
16 
17 # 編寫生成器,用來遍歷字符串,不斷的提供括號及其位置
18 def parent(text):
19     # i 遍歷字符串的索引位置
20     i,text_len = 0,len(text)
21 
22     # 開始遍歷字符串
23     while True:
24         while i < text_len and text[i] not in parens:
25             i += 1
26 
27         # 到字符串結尾了
28         if i >= text_len:
29             return
30         else:
31             yield text[i],i
32             i += 1
33 
34 # 功能函數判斷提供的括號是否匹配
35 def ver():
36     for pr,i in parent(text):
37         if pr in left_parens:
38             ls.push((pr,i)) # 左括號入棧
39         elif ls.is_empty() or ls.pop()[0] != opposite[pr]:
40             print("Unmatching is found at %d for %s"%(i,pr))
41             break
42     else:
43         if ls.is_empty():
44             print("All parentheses are matched")
45         else:
46             # 左括號多了
47             d = ls.pop()
48             print("Unmatching is found at %d for %s" %(d[1],d[0]))
49 
50 # 邏輯驗證
51 ver()
exec_1.py
 1 """
 2 求一個數的階乘
 3 """
 4 
 5 # n次
 6 
 7 def fun(num):
 8     result = 1
 9     for i in range(1,num + 1):
10         result *= i
11     return result
12 
13 print(fun(5))
exce_2.py
相關文章
相關標籤/搜索