3-Python內置結構-列表

1 Python內置數據結構

        Python內置了不少數據結構(容器),供咱們直接進行使用,在學習結構以前,有一些小的知識點進行補充。算法

1.1 數值型

  1. int、float、complex、bool都是class、1,5.0,2+3j都是對象即實例
  2. int:Python3的int就是長整型,且沒有大小限制,受限於內存區域大小
  3. float:有整數和小數部分組成。支持十進制和科學計數法表示。
  4. complex:有實屬和虛數部分組成,實數部分和虛數部分都是浮點數
  5. bool:int的子類,僅有2個實例,True和False,其中True表示1,False表示0
In [2]: int(10.12)    # 直接取整                                                                           
Out[2]: 10

In [3]: int(-12)                                                                                        
Out[3]: -12

In [4]: float(10)     # 轉換爲浮點數                                                          
Out[4]: 10.0

In [5]: float(-9)                                                                                       
Out[5]: -9.0

In [6]: bool(1)       # 1表示True(非0都爲True)                                                                                  
Out[6]: True

In [7]: bool(0)       # 0表示False                                                         
Out[7]: False

1.2 math模塊

        數學之中,除了加減乘除四則運算以外,還有其它更多的運算,好比乘方、開方、對數運算等等,Python 提供了一個專門輔助計算的模塊:math,模塊方法及常量以下:數據結構

  • math.ceil:向上取整
  • math.floor:向下取整
  • math.pi:數字常量,圓周率
  • math.pow:返回x的y次方,即x**y
  • path.sqrt:求x的平方根
In [22]: import math         # 導入模塊                                                                    
In [23]: math.pi                                                                                        
Out[23]: 3.141592653589793
In [24]: math.pow(2,3)       # 2**3                                                                        
Out[24]: 8.0
In [25]: math.ceil(-10.6)    
Out[25]: -10
In [26]: math.ceil(-10.5)                                                                               
Out[26]: -10
In [27]: math.ceil(12.3)                                                                                
Out[27]: 13
In [28]: math.floor(12.3)                                                                               
Out[28]: 12
In [29]: math.floor(-12.3)                                                                              
Out[29]: -13
In [32]: math.sqrt(10)                                                                                  
Out[32]: 3.1622776601683795

注意:app

  • int 取整:正負數都只取整數
  • 整除(向下取整)
In [33]: int(-12.1)     # 只會取整數部分                                                   
Out[33]: -12
In [34]: int(10.5)                                                                                      
Out[34]: 10
In [35]: 1//3           # 向下取整             
Out[35]: 0
In [36]: 2//6                                                                                           
Out[36]: 0
In [37]: 20//6                                                                                          
Out[37]: 3
In [38]: 10//3                                                                                          
Out[38]: 3

1.3 round圓整

        在Python中有一個round函數,用於對小數進行取整,不過在Python中的round有些特別,總結一句話就是4舍6入5取偶。即當小數點後面的數字小於5呢,會直接捨去大於5呢,會直接進位等於5呢,會取最近的偶數函數

In [39]: round(1.2)                                                                                     
Out[39]: 1
In [40]: round(-1.2)                                                                                    
Out[40]: -1
In [41]: round(1.5)                                                                                     
Out[41]: 2
In [42]: round(-2.5)                                                                                    
Out[42]: -2
In [43]: round(0.5)                                                                                     
Out[43]: 0
In [44]: round(-5.5)                                                                                    
Out[44]: -6
In [45]: round(1.6)                                                                                     
Out[45]: 2
In [46]: round(-1.500001)                                                                               
Out[46]: -2

1.4 經常使用的其餘函數

  • max:經常使用來在可迭代對象中求最大值
  • min: 經常使用來在可迭代對象中求最小值
  • bin:把對象轉換爲二進制
  • oct:把對象轉換爲八進制
  • hex:把對象轉換爲十六進制

1.5 類型判斷

        因爲Python是一種強類型語言,在數據比較時,只有相同數據類型,才能夠進行比較。這時咱們就須要知道對象究竟是什麼類型,type就是用來查看類型的。性能

In [47]: type('123')                                                                            
Out[47]: str
In [48]: type(123)                                                                                      
Out[48]: int
In [49]: type(True)                                                                                     
Out[49]: bool

        從上面代碼結果能夠看出type返回的是類型,並非字符串,而在數據判斷時咱們須要的是判斷,好比判斷某個變量是某個類型的,那麼這個時候就須要用到instance了。學習

# 基本用法                                       
Signature: isinstance(obj, class_or_tuple, /) --> bool

# 接受兩個參數

# obj:要判斷的對象

# class_or_tuple:一個類,或者多個類組成的元組

In [52]: isinstance(123,str)                                                                            
Out[52]: False
In [53]: isinstance(123,(str,int))   # 判斷123,是str或者是int嗎?                                                                   
Out[53]: True

2 列表

        列表是Python中最基本的數據結構。什麼是序列呢?咱們能夠認爲它是一個隊列,一個排列整齊的隊伍。列表內的個體稱爲元素,它能夠是任意對象(數字、字符串、對象、列表),多個元素組合在一塊兒,使用逗號分隔,中括號括起來,就是列表。它有以下特色:設計

  1. 列表內的元素是有序的以使用索引(下標)獲取,第一個索引是0,第二個索引是1,依此類推。
  2. 線性的存儲結構,(從左至右依次存儲)
  3. 列表是可變的,咱們能夠對其內的元素進行任意的增刪改查

建立一個列表,只要把逗號分隔的不一樣的數據項使用方括號括起來便可。以下所示:code

In [56]: a = []       # 空列表                                                                            
In [57]: b = list()    # 空列表                                                                          
In [59]: c = list(range(3))   # 接受一個可迭代對象,轉換爲列表。[0, 1, 2]

主要:列表沒辦法在初始化時就指定列表的大小對象

2.1 索引訪問

列表的索引有以下特色:

  1. 正索引:從左至右,從0開始,爲列表中每個元素編號
  2. 負索引:從右至左,從-1開始
  3. 正負索引不能夠超界,不然會引起一場IndexError
  4. 爲了理解方便,能夠認爲列表是從左至右排列的,左邊是頭部,右邊是尾部,左邊是下屆,右邊是上界
  5. 列表經過索引訪問,例如:list[index],index就是索引,使用中括號訪問。

2.2 列表和鏈表的區別

        咱們一般會把列表和鏈表拿來作對比,它倆雖然都是有序的能夠被索引,可是內部實現方法以及適用場景有很大區別。
列表在內存中的存儲方式是線性的,而鏈表是非線性的,他們的差異以下:
list
lian
由上圖咱們能夠獲得以下結論:

  • 列表:線性結構,順序結構,能夠被索引,數據存放的是連續的內存空間,取值時,只須要進行偏移量計算便可,屬於一步到位型,可是在增長數據時,須要針對其後全部的數據進行移動,因此性能不高。
  • 鏈表:線性結構,順序結構,能夠被索引,放數據的地方,在內存地址上並非連續的。增刪輸出時,只需斷開先後兩個元素先前的鏈接,增長新元素後,創建新的鏈接便可,但因爲其不連續的空間,索引發來效率低,須要從頭開始尋找。

注意:列表的增刪若是是在隊伍當中,那麼相對效率比較低,可是若是在尾部增刪,效率很快。鏈表還分爲單向和雙向,表示索引方向而已,這裏不在進行說明
擴展:
下面是其餘基於列表/鏈表特性的實現:

  1. queue:隊列(通常是從隊首或者隊尾獲取數據)分爲:先進先出隊列先進後出隊列優先級隊列
  2. stack:棧。後進先出的就被叫作棧(主要應用於函數的壓棧)

2.3 列表的查詢

        列表提供了不少的方法,使咱們能夠方便的對它進行查詢、統計等操做。

L.index(value, [start, [stop]]) -> integer -- 在列表中獲取傳入元素的索引值,若是元素不存在,會報異常,若是存在多個,只返回找到的第一個匹配元素的索引值,其中start,stop爲表示查找區間,默認爲整個列表
L.count(value) -> integer -- 統計傳入元素在列表中出現的次數並返回

        index和count的時間複雜度都是O(n),即隨着列表的規模增長,效率會依次降低。什麼是時間複雜度? 這是在計算算法優劣時的主要參考值,咱們主要使用大寫的O來表示時間複雜度,因爲index和count函數都須要遍歷列表,因此若是這個列表有n個元素的話,那麼它的時間複雜度就爲O(n),詳細的解釋,建議自行了解,這裏知道這樣表示便可,因爲list[1]經過偏移量進行火速據訪問,能夠理解爲一步到位,因此這種方式的時間複雜度爲O(1),不會隨着規模增大而改變。

In [66]: lst                                                                                            
Out[66]: [1, 2, 3, 1, 2, 3, 3, 2, 4, 5, 7]
In [67]: lst.index(3)   # 獲取元素3的索引值                                                                                
Out[67]: 2
In [68]: lst.count(2)   # 統計元素2出現的次數                                                             
Out[68]: 3

擴展:
        若是咱們要獲取列表的元素總數,咱們須要什麼設計呢?

  1. 設計一個獲取元素總量的函數,當調用時,對列表進行遍歷獲取元素的總數,並返回
  2. 設置一個計數器,隨着元素的增長和減小對計數器進行修改

        很明顯第一個方法的時間複雜度是O(n),而第二個方法因爲事先存儲着列表元素的總數,因此它的時間複雜度是O(1),列表使用的就是方式2,而經過Python內置的len函數就能夠獲取列表的大小(不只僅針對列表,其餘元素也能夠)

In [69]: lst                                                                                            
Out[69]: [1, 2, 3, 1, 2, 3, 3, 2, 4, 5, 7]
In [70]: len(lst)                                                                                       
Out[70]: 11

2.4 列表元素修改

        咱們使用索引能夠獲取列表中對應索引位置的元素,同時咱們也能夠經過索引直接對對應索引位的元素進行修改

In [71]: lst                                                                                            
Out[71]: [1, 2, 3, 1, 2, 3, 3, 2, 4, 5, 7]
In [72]: lst[2] = 100                                                                                  
In [73]: lst                                                                                        
Out[73]: [1, 2, 100, 1, 2, 3, 3, 2, 4, 5, 7]

須要注意的時,因此不要越界,不然會報異常

2.5 列表的追加和插入

        列表提供了對其進行追加或插入的函數,即appendinsert。先來看看這兩個函數的使用方法。

L.append(object) --> None --> 接受一個元素,用於追加到列表的末尾。
L.insert(index, object) --> 接受兩個變量:索引,元素。 在列表中指定的索引位置,插入元素。

說明:

  1. 列表尾部追加元素時,append的返回值是None,會直接對原列表進行操做,對應的時間複雜度是O(1)
  2. 列表插入元素時,與append形同,返回None,直接對原列表進行操做,對應的時間負載度是O(n),由於在列表首部插入元素時,會使其餘元素總體移動。當索引超界時會有以下兩種狀況
    • 超越上界,尾部追加
    • 超於下界,首部追加
In [78]: lst                                                                                                          
Out[78]: [1, 2, 3]
In [79]: lst.insert(-500,500)                                                                                         
In [80]: lst                                                                                                       
Out[80]: [500, 1, 2, 3]
In [81]: lst.insert(500,500)                                                                                         
In [82]: lst                                                                                                       
Out[82]: [500, 1, 2, 3, 500]

不少場景下咱們對列表操做不是一個一個元素的追加,更多的時候,咱們可能須要的是批量的操做,列表提供了一個extend函數用於知足這種需求。

L.extend(iterable) --> None -- 從一個可迭代對象中把元素擴展追加到當前列表中

說明:

  1. extend直接操做原列表,因此其返回值爲None
  2. 若是擴展的可迭代對象過於大,那麼可能會引發GC進行內存整理,由於擴充起來的元素,有可能會被當前列表所申請的內存空間更大。建議少用
  3. 擴種列表還有其餘方法好比列表相+,列表相*,當使用這兩種方式是會返回新的列表,不會修改原列表
# extend
In [86]: lst                                                                                                          
Out[86]: [500, 1, 2, 3, 500]
In [87]: lst.extend('abc')                                                                                            
In [88]: lst                                                                                                       
Out[88]: [500, 1, 2, 3, 500, 'a', 'b', 'c']


# + *
In [94]: lst                                                                                                          
Out[94]: [500, 1, 2, 3, 500]
In [95]: lst + ['a','b','c']                                                                                     
Out[95]: [500, 1, 2, 3, 500, 'a', 'b', 'c']
In [96]: lst * 2                                                                                                      
Out[96]: [500, 1, 2, 3, 500, 500, 1, 2, 3, 500]

注意:使用+進行列表拼接的時候,因爲返回了新的列表,原來相加的兩個列表可能就沒有用了,而若是這兩個列表很是大,那麼等於重複佔用了新的內存空間,內存資源很寶貴,省着點用哈

2.6 列表使用*重複帶來的問題

        咱們使用*能夠快速的生成一些特定的列表形式,好比我須要一個6個元素的列表,每一個元素的值爲1,我就能夠這樣寫 lst = [1]; lst * 6,這樣寫的確沒什麼問題,可是在某些場景下會產生意想不到的問題,好比在列表嵌套的時候。

In [97]: lst = [[1,2,3]]                                                                                              
In [98]: lst1 = lst * 3                                                                                               
In [99]: lst1                                                                                                         
Out[99]: [[1, 2, 3], [1, 2, 3], [1, 2, 3]]
In [100]: lst1[1][1] = 20                                                                                             
In [101]: lst1                                                                                                     
Out[101]: [[1, 20, 3], [1, 20, 3], [1, 20, 3]]

有沒有發現什麼問題?我明明修改的是lst1的第二個元素的第二個值爲20,爲何全都改變了?這是由於在列表是一個引用類型,lst中實際上存儲的是[1,2,3]的內存地址,而咱們使用*3的時候,等於複製了三份這個地址,因此lst1的3個元素,其實都指向了一個內存地址,因此咱們隨便修改一個元素,其餘的也都會跟着被改變(畢竟是1個地址啊),咱們通常稱這種複製爲影子複製(shadow copy),知道了緣由,咱們就能夠想辦法解決了,既然你複製的是門牌號,那有沒有辦法複製門牌號裏面的數據呢?答案固然是能夠的,咱們使用copy模塊的deepcopy完成,它能夠幫咱們一層一層的找到元素真正的位置,而後進行復制。咱們稱deepcopy爲深拷貝

In [102]: import copy          # 導入copy模塊                                                
In [103]: lst                                                                                                         
Out[103]: [[1, 20, 3]]
In [104]: lst1 = lst           # 複製一個新的列表                                                                         
In [105]: lst1[0][1] = 1000     # 對新列表進行賦值                                                                    
In [106]: lst1                                                                                                        
Out[106]: [[1, 1000, 3]]       # 會同時影響lst和lst1
In [107]: lst                                                                                                         
Out[107]: [[1, 1000, 3]]
In [108]: lst2 = copy.deepcopy(lst)     # 這裏使用深copy                                                                  
In [109]: lst2                                                                                                        
Out[109]: [[1, 1000, 3]]
In [110]: lst2[0][1] == 2000           # 對lst2進行修改後,不會影響原列表,由於已經把元素拷貝過來了                                                            
Out[110]: False
In [111]: lst2[0][1] = 2000                                                                                           
In [112]: lst2                                                                                                        
Out[112]: [[1, 2000, 3]]
In [113]: lst1                                                                                                        
Out[113]: [[1, 1000, 3]]
In [114]: lst                                                                                                         
Out[114]: [[1, 1000, 3]]

2.7 刪除元素

        列表對象同時提供了專門的方法用於對列表元素進行刪除:removepopclear

L.remove(value) --> None -- 刪除列表中匹配value的第一個元素.
L.pop([index]) --> item -- 刪除並返回index對應的item,索引超界拋出IndexError錯誤,若是不指定index,默認是列表的最後一個
L.clear() --> None -- 清空列表,不建議進行操做,能夠等待GC自行進行銷燬

        當咱們使用remove和pop時,依然須要考慮效率問題,remove刪除一個元素的時候,它首先須要遍歷這個列表,查找匹配到的元素後移除,它的時間複雜度是O(n),使用pop指定index刪除時,雖然能夠1步定位到元素,可是若是刪除的列表是首部或者中間的元素,那麼將會使列表中的後續數據集體搬家,但當你使用pop不指定index時,它默認會在列表的默認刪除,這種操做的時間複雜度爲O(1)。因此建議若是須要頻繁的對列表進行增刪改,建議使用鏈表類型,而若是須要頻繁的查或者只是從末尾彈出,就可使用列表,由於這樣效率更高,以上只是建議。

In [1]: lst = [1,2,3,4]                                                                                               
In [2]: lst.remove(2)                                                                                                 
In [3]: lst                                                                                                           
Out[3]: [1, 3, 4]
In [4]: lst.pop()                                                                                                     
Out[4]: 4
In [5]: lst                                                                                                           
Out[5]: [1, 3]
In [6]: lst.pop(1)                                                                                                    
Out[6]: 3
In [7]: lst                                                                                                           
Out[7]: [1]
In [8]: lst.clear()                                                                                                   
In [9]: lst                                                                                                        
Out[9]: []

2.8 其餘操做

        當咱們的列表中存儲的是int類型的數據,而咱們想要對其進行排序,那麼就可使用列表的排序,當咱們想要判斷一個元素是否存在於列表中時,就可使用成員判斷。

L.reverse() -- 原地反轉,原地將列表元素進行反轉
L.sort(key=None, reverse=False) -> None -- 對列表進行原地排序
in: 成員判斷,判斷元素是否在列表中 1 in [1,2,3],因爲要遍歷,因此它的時間複雜度爲O(n)

        sort比較特別,它有兩個參數,其中key能夠接受一個函數,使列表中的元素按照函數處理事後的類型進行排序,默認爲空,即不處理。reverse則有兩個值TrueFalse,表示正序或者反序,默認爲False表示正序。

線性數據結構的通病,找元素,須要進行遍歷。

# 列表是順序結構,但凡是 順序不一致,那麼兩個列表就不相等
In [11]: l1 = [1,2,3,[4,5]]                                                                             
In [12]: [4,5] in l1                                                                                    
Out[12]: True
In [13]: [5,4] in l1      # 順序改變,因此不相等                                                                                
Out[13]: False

In [10]: lst = [ 2, 1 ,3 ,4 ,5 ]                                                                                      
In [11]: lst.reverse()                                                                                                
In [12]: lst                                                                                                          
Out[12]: [5, 4, 3, 1, 2]
In [13]: lst.sort()                                                                                                   
In [14]: lst                                                                                                        
Out[14]: [1, 2, 3, 4, 5]
In [15]: lst.sort(reverse=True)                                                                                      
In [16]: lst                                                                                                          
Out[16]: [5, 4, 3, 2, 1]
In [17]
相關文章
相關標籤/搜索