初學python之以時間複雜度去理解列表常見使用方法

 

列表list,一個有序的隊列前端

列表內的個體爲元素,由若干個元素按照順序進行排列,列表是可變化的,也就是說能夠增刪python

 

list定義算法

經常使用的列表定義方式: 使用[] 或者 a = list()app

取數列表能夠用range()dom

 

 

列表查詢方法ide

index函數

index = 索引,以0開始查找spa

方法:value,[start,[stop]]對象

經過對應位置的索引進行查找,找到列表內的元素是否有匹配,若有則返回索引值排序

匹配到第一個元素則當即返回索引位

有時候從右邊查找更加便利,好比反斜槓/ 從右邊找更加便捷

 

例:

 

In [22]: a

Out[22]: [1, 2, 3, 5, 10, 20, 33, 55]

 

In [23]: a.index(3)

Out[23]: 2

 

In [24]: a.index(33)

Out[24]: 6

 

從右向左查找 index(value, [start, [stop]]) 

 

從某個值開始查找

 

In [46]: a.index(33,3)

Out[46]: 6

 

In [50]:a.index(55,-1)

Out[50]: 7

 

計算元素出現的次數

 

In [53]: a = [1,1,1,3,2,11,5,43,1,1]

In [54]: a.count(1)

Out[54]: 5

 

 

時間複雜度

     計算機科學中,算法的時間複雜度是一個函數,它定性描述了該算法的運行時間。這是一個關於表明算法輸入值的字符串的長度的函數。時間複雜度經常使用大O符號表述,不包括這個函數的低階項和首項係數。使用這種方式時,時間複雜度可被稱爲是漸近的,它考察當輸入值大小趨近無窮時的狀況

 

index 和count 方法對應的時間複雜度

數學符號對應 O

O(n)

O(2)

O(1)

 

n表示多少個元素,意思爲有多少個元素就從前到後多少個元素

將全部的元素都遍歷一遍

 

須要考慮index方法和count方法適用性,是否該用,選型哪一個須要考慮

隨着列表數據規模增長而效率降低,若是能作到O1/2/3 這樣則能夠很快返回結果

 

 

list列表元素修改

對某一項索引位置賦值(修改)

 

In [59]: a

Out[59]: [1, 1, 1, 3, 2, 11, 5, 43, 1, 1]

In [60]: a[1] = 2

In [61]: a

Out[61]: [1, 2, 1, 3, 2, 11, 5, 43, 1, 1]

 

列表就地修改

對列表自己進行追加元素

 

lst.append(100)

[1, 2, 3, 2, 2, 5, 6, 100]

 

append 對list進行增長元素,返回一個None

 

In [71]: lst = [1,2,3,2,2,5,6]

 

In [72]: a = lst.append(100)

 

In [73]: type(a)

Out[73]: NoneType

 

In [74]: a

 

In [75]: print(a)

None

 

這裏返回值爲空

 

list運算

 

In [77]: a = [1,2,3]

 

In [78]: a * 3

Out[78]: [1, 2, 3, 1, 2, 3, 1, 2, 3]

這裏有返回打印

有輸出則是沒有被就地修改,都是構造新的列表

咱們看到增長以後原列表發生了變化,這樣被稱爲就地修改,就地修改成只對當前列表進行修改,修改的是對象的自己

 

append對時間複雜度爲O(1),由於經過索引進行修改,並且是從尾部進行修改

這樣經過索引線性修改所耗時間很快,並不是O(n) ,O(n)爲逐步遍歷,找到某個項再進行修改

 

 

insert 插入元素

In [81]: a.insert(1,'a')

In [82]: a

Out[82]: [1, 'a', 2, 3]

 

insert 爲在指定處插入對象,這樣會引發整個內存結構變化,全部數據統一貫後錯位,若是量級大則不要去作,儘量new一個

因此儘量避免挪動

insert時間複雜度爲 O(n),若是放在開頭則不建議,通常list規模很大,因此要考慮效率問題

因此,insert更適合鏈表方式

 

 

extend 將迭代對象追加

迭代對象不用解釋了,能夠是列表,能夠是字典等等

 

b = {'c':123}

In [85]: a.extend(b)

In [86]: a

Out[86]: [1, 'a', 2, 3, 'c']

 

追加迭代本身

 

In [88]: a.extend(a)

 

In [89]: a

Out[89]: [1, 'a', 2, 3, 'c', 1, 'a', 2, 3,'c']

 

remove 刪除某個元素

remove 爲刪除某個內容,而並不是索引

remove 爲就地修改,在作位置的挪動,因此這裏須要注重效率

In [89]: a

Out[89]: [1, 'a', 2, 3, 'c', 1, 'a', 2, 3,'c']

 

In [90]: a.remove(1)

 

In [91]: a

Out[91]: ['a', 2, 3, 'c', 1, 'a', 2, 3,'c']

 

In [92]: a.remove(1)

 

In [93]: a

Out[93]: ['a', 2, 3, 'c', 'a', 2, 3, 'c']

在順序列表中,在中間包括開頭,須要考慮效率問題

 

 

pop 彈出

從尾部進行彈出而且刪除尾部的元素

In [103]: a = [1,2,3,11,13,12,20]

 

In [104]: a.pop()

Out[104]: 20

 

pop效率爲O(1) 因爲是在尾部進行就地修改,因此效率很是高

 

使用index進行pop,而索引則是從1開始並不是是0

 

In [108]: a.pop(0)

Out[108]: 1

 

In [109]: a

Out[109]: [2, 3, 11, 13, 12]

 

pop的特性直接將前端顯示,移除+修改並行操做

在清除對象過多的狀況下,會引發大規模GC垃圾回收,一樣要考慮到效率問題

 

 

list的排序

sort() 排序

 

In [113]: a = [63,1,44,2,19,94,64,21]

In [114]: a.sort()

In [115]: a

Out[115]: [1, 2, 19, 21, 44, 63, 64, 94]

 

reverse進行到排序

默認爲: sort(Key=None,reverse=False)

默認狀況下是升序排列,降序由大到小,那麼進行到排序:

In [116]: a.sort(reverse=True)

 

In [117]: a

Out[117]: [94, 64, 63, 44, 21, 19, 2, 1]

 

可是當前若是遇到字符串則沒法進行

In [117]: a

Out[117]: [94, 64, 63, 44, 21, 19, 2, 1]

 

In [118]: a.append('haha')

 

In [119]: a.sort(reverse=False)

---------------------------------------------------------------------------

TypeError                               Traceback (most recent call last)

<ipython-input-119-83555bcb738d> in<module>()

----> 1 a.sort(reverse=False)

 

TypeError: unorderable types: str() <int()

 

那麼咱們可使用key=None 的方法進行對字符串排序

 

In [121]: a.sort(key=str)

 

In [122]: a

Out[122]: [1, 19, 2, 21, 44, 63, 64, 94,'haha']

 

In [123]: a.sort(key=str,reverse=True)

 

In [124]: a

Out[124]: ['haha', 94, 64, 63, 44, 21, 2,19, 1]

一樣能夠按照字母進行正排倒排

In [125]: a.append('ab')

 

In [126]: a.append('ba')

 

In [127]: a.sort(key=str,reverse=True)

 

In [128]: a

Out[128]: ['haha', 'ba', 'ab', 94, 64, 63,44, 21, 2, 19, 1]

 

In [129]: a.sort(key=str)

 

In [130]: a

Out[130]: [1, 19, 2, 21, 44, 63, 64, 94,'ab', 'ba', 'haha']

 

排序規則:將每一個元素轉爲字符串,其都是直接轉爲ASCII碼進行排序,這裏的str爲當前定義的函數,若是是本身寫的函數能夠自定義排序規則

 

 

取隨機數

涉及random

choice 從非空序列的元素中隨機選擇

 

In [167]: a

Out[167]: [1, 19, 2, 21, 44, 63, 64, 94,'ab', 'ba', 'haha']

 

In [168]: import random

 

In [169]: random.choice(a)

Out[169]: 1

 

In [170]: random.choice(a)

Out[170]: 64

 

randrange取之間的隨機數的,以及步長

 

In [172]: random.randrange(1,10)

Out[172]: 5

 

shuffle 打亂元素

In [174]: random.shuffle(a)

 

In [175]: a

Out[175]: [94, 64, 'ba', 21, 44, 19, 63, 2,1, 'ab', 'haha']

 

 

 

列表複製

== 和is 的區別

In [131]: lst0 = list(range(4))

 

In [132]: lst0

Out[132]: [0, 1, 2, 3]

 

In [133]: id(lst0)

Out[133]: 140196597896584

首先進行哈希匹配

 

In [134]: hash(id(lst0))

Out[134]: 140196597896584

 

給lst1 進行賦值 讓其等於lst0

In [135]: lst1 = list(range(4))

 

In [136]: id(lst1)

Out[136]: 140196608816840

查看兩個列表的值

In [138]: lst1

Out[138]: [0, 1, 2, 3]

 

In [139]: lst0

Out[139]: [0, 1, 2, 3]

 

In [140]: lst0 == lst1

Out[140]: True

 

In [141]: lst0 is lst1

Out[141]: False

 

經過以上,能夠明白:

  ==   比較返回值 判斷是否依次相等

  is   比較內存地址是否一致

 

地址空間的引用

In [142]: id(lst0[1])

Out[142]: 9177888

 

In [143]: id(lst1[1])

Out[143]: 9177888

 

以上看到,是沒有複製的過程,而是被引用了一樣的內存地址空間

 

使用copy進行復制並返回一個新的列表

 

In [150]: lst0

Out[150]: [0, 1, 2, 3]

 

In [151]: lst5=lst0.copy()

 

In [152]: lst5

Out[152]: [0, 1, 2, 3]

 

使用= 進行拷貝

 

In [163]: lst5 = lst0

 

In [164]: lst0[1] = 555

 

In [165]: lst0

Out[165]: [0, 555, 2, 3]

 

In [166]: lst5

Out[166]: [0, 555, 2, 3]

 

由於賦值的是引用類型,因此直接將嵌套的list拷貝的內存地址

經過這個內存地址修改,則對兩個list同時修改

 

須要注意的是:須要觀察拷貝的類型是什麼,否則會引發反作用,可是也能夠經過特性批量進行操做

 

深拷貝和潛拷貝的基本概念

淺拷貝

     在通常都是實現了淺拷貝,只拷貝了第一層結構,

     被稱爲 shadow copy,可是引用的都是同一個內存地址

 

深拷貝

若是出現層次嵌套,會對引用類型進行深刻拷貝,在結構上拷貝的如出一轍,引用的內存地址則獨立開闢

使用deepcopy能夠進行深拷貝

 

 

使用list求100內的質數:

 

lst1 = []

 

for x in range(2,101):

    for i in lst1:

        if x % i == 0:

           break

    else:                   

        lst1.append(x)

 

print(lst1)

相關文章
相關標籤/搜索