python線性數據結構 --list

順序表:由一組有限個元素的序列抽象組成,並使用一大段連續的內存來存儲表中的元素,這樣的表稱之爲順序表,列表也是順序表的一種

  • 列表內的個體稱之爲元素,列表由多個元素組成
  • 元素可以是任意的對象(數字,字符串,對象,列表等)
  • 列表內的元素有順序,可以使用索引來查找定位元素
  • 列表是線性的數據結構
  • 使用[ ]包圍
  • 列表的長度和內容都可以改變

列表的初始化

list():生成空的列表
list(iterable):從可迭代的對象當中導入數據到列表中
[ ] :直接賦予元素,如[1,2,3,‘abc’]就可以定義一個列表
list()是一個函數,不能對其賦值,比如list=[1,2,3],否則list會被當成列表名而不是方法名(list()方法用於生成列表),需要使用del list來刪除此標識符

>>> list=[1,2]
>>> a=list(range(5))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-27-8488c00fa318> in <module>
      1 list=[1,2]
----> 2 a=list(range(5))

TypeError: 'list' object is not callable    #此處報錯說list對象不可以被調用,因爲list已經被聲明成了變量
>>> del list
>>> a=list(range(5))
>>> a
[0, 1, 2, 3, 4]     #刪除之前誤操作聲明的list變量,之後就可以正常使用list()函數
a=[]      #定義a爲列表,並且不賦予元素
x=list()  #這樣就生成了一個空列表
y=list(range(10)) #將0-9這10個元素賦予到列表y中
z=[1,3.1,'a',(1,1)] #賦予四個元素給列表z,列表是一個容器,元素可以是任何數據類型

索引

索引也叫下標
正索引:從左至右,從0開始,爲每個元素編號。非空列表的索引範圍爲[0,長度-1]
負索引:從右至左,從-1開始,非空列表索引範圍爲[-長度,-1]
越界:正負索引都不可以越界,否則引發IndexError
索引訪問:使用索引訪問列表元素的方式爲list_name[index],這裏的index即爲索引。比如訪問列表a的第一個元素,a[0]
時間複雜度:使用索引訪問列表元素的時間複雜度爲O(1)

查詢

(1)使用索引來查詢元素(直接使用索引,可以立即返回數據)

>>> x = 'abcdefg'
>>> a = list(x)  ##對列表進行初始化
>>> a[2]
'c'  

(2)使用元素值來查詢索引(可能會遍歷列表)

>>> a = [1,'11','a',[1,2],(2,3)]
>>> a.index((2,3))  ##返回元素所在的索引,默認使用正索引
4
>>> a.index([1,2])  
3
>>> a.index('11')
1
index()方法的時間複雜度是O(n)

(3)統計元素出現的次數(必定遍歷列表)

>>> a = [1,2,1,2,1,'1','m',1]
>>> a.count(1)
4
>>> a.count('1')  #注意字符串'1'和數值1是不同的元素
1
count()方法的時間複雜度爲O(n)

(4)統計元素的總個數或者統計列表長度

>>> a = [1,2,['1',2],(2,2),'mn']
>>> len(a)
5
len()方法的時間複雜度爲O(1),因爲列表的長度就記錄在對象的元數據中

修改

需要先定位需要修改的元素的位置,然後進行修改

>>> L1=['a','abc',1,2]
>>> L1[1]=123  #直接通過索引定位,然後以賦值的方式修改元素
>>> print(L1)
['a',123,1,2]

增加單個元素

append()方法
直接使用列表調用append(object)
修改列表不會導致新列表產生,因此返回值爲None
尾部追加的時間複雜度爲O(1)

>>> L1=['a','abc',1,2]
>>> L1.append([1,2])
>>> print(L1)
['a', 'abc', 1, 2, [1, 2]]

>>> L2=[1,1]
>>> add=L2[0]+L2[1]   #這就是計算Fibonacci數列的雛形add=L2[i-1]+L2[i-2]
>>> L2.append(add)
>>> print(L2)   
[1,1,2]

insert()方法
insert(index,object)在指定索引的左側插入新元素
插入數據也不會導致新列表產生,返回值爲None
允許index越界
insert()方法的時間複雜度爲O(n)

>>> L2=[1,2,3]
>>> L2.insert(1,'a')
>>> print(L2)
>>> L2.insert(-1,'b')
>>> print(L2)
>>> L2.insert(5,'c')
>>> print(L2)
>>> L2.insert(100,'d') #index超越了右邊界,直接在尾部添加
>>> print(L2)
>>> L2.insert(-100,'a') #index超越了左邊界,在頭部添加
>>> print(L2)
[1, 'a', 2, 3]
[1, 'a', 2, 'b', 3]
[1, 'a', 2, 'b', 3, 'c']
[1, 'a', 2, 'b', 3, 'c', 'd']
['a', 1, 'a', 2, 'b', 3, 'c', 'd']

增加多個元素

extend(iterable)方法,追加一個可迭代序列,在原列表修改,無新列表產生,返回None
列表的連接操作,L1=L2+L3,列表的連接,有新列表產生,返回新列表
列表乘以n,L1=L2*3,將本列表元素重複3次,有新列表產生

>>> L1=[1,2]
>>> L1.extend(range(3))
>>> print(L1)
[1, 2, 0, 1, 2]

>>> L1=[1,2]
>>> L2=['a','b']
>>> L3=L1+L2
>>> print(L3)
[1, 2, 'a', 'b']

>>> L1=[1,1]
>>> L1+=[L1[i-1]+L1[i-2]]  ##計算Fibonacci數列的關鍵公式(i>=2),不建議使用此種方式,資源消耗較大,因爲列表相加會先將兩個列表放入內存

#列表乘法
>>> L1=[1]
>>> L2=L1*3
>>> print(L2)
[1,1,1]
>>> [[0] * 3 for i in range(5)]  ##產生一個包含列表的大列表
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]

刪除

remove(value),從左至右查找匹配value值的元素,匹配後刪除元素,並返回None。找不到則報ValueError
remove()方法不會產生新列表
pop(index),指定索引就刪除該索引的元素,返回元素值,不指定索引就刪除最尾部的元素,並且返回元素值
pop(index),索引超界會拋出IndexError錯誤。
clear()方法直接清空列表,返回None,不會產生新列表

>>> L2=[1,2,3,4]
>>> L2.remove(2)
>>> L2
[1,3,4]

>>> L2.pop(1)
>>> L2
[1,4]

>>> clear(L2)
>>> L2
[]

反轉

reverse()方法,將列表元素按反序列出,返回None
這種方式不推薦,性能消耗較高,可以使用反向讀取的方式實現這種反轉

L1=[1,9,2,4,7,1]
for i in range(-1,-len(L1),-1):
     print(L1[i], end=' ')
print()

排序

sort(key=None,reverse=False),沒有新列表產生,返回None
同種數據之間進行比較,不同數據之間比較會報錯,比如整型和字符串比較就會報錯
最好是整型數據之間進行比較
默認爲升序排序,reverse爲True時表示反轉降序排列,key是一個函數,指定如何排序list.sort(function),function通常是lambda函數
lambda函數

>>>> L1=[100, 20, 31]
>>>> L1.sort()  #排序後不會返回列表,但列表已經被排序
>>>> L1
[20, 31, 100]

in成員操作

可用於判斷某個value是否存在於列表當中,時間複雜度爲O(n)
可用於判斷真假,返回Ture或者False

>>> 'a' in ['a','b','c','d']
True
>>> if 'a' in ['a','b','c','d']:  #實現條件判斷邏輯
	 	pass

>>> for i in [1,2,3,4,5]:  #遍歷列表元素
		pass

列表複製(深淺拷貝)

列表複製其實就是增加一個新變量去引用此列表,因此原列表和新列表的列表地址是一樣的
如果分別創建兩個內容相同的列表,他們的地址是不同的,因爲這是兩個不同的對象,雖然內容相同,但是在內存上的地址是不一樣的

>>> a=list(range(10))
>>> b=list(range(10))
>>> print(id(a))
>>> print(id(b))
140304108579144
140304039850120

>>> a=b  #將列表b給a引用,這是就相當於列表複製了,=號相當於引用數加1,因此地址一致
>>> print(id(a))
>>> print(id(a))
140304039937608
140304039937608

copy()複製方法

使用copy()方法實現列表的淺複製,對於字面常量,copy()方法是可以完全複製過來的,這就相當於拷貝出了兩份
對於引用類型的元素,copy()方法只能淺拷貝,不能將整個元素拷貝過來,拷貝過來的只有它的引用地址

>>> a = list(range(4))
>>> b = a.copy() #copy函數只會複製內容,若列表元素中包含引用地址,那麼copy複製的也是引用地址,但是a,b是兩個不同的對象,只是內容相同
>>> print(a == b)
>>> a[2] = 10  ##對於字面常量,copy()完全複製出了兩份,因此重新對a[2]賦值不會影響到b列表,因此後面兩個列表是不等價的
>>> print(a == b) 
True
False

>>> a = [1,2,[2,3,4,'a'],5]
>>> b=a.copy()
>>> print(a==b)  ##b從a列表copy後兩個列表是等價的
>>> a[2] = 'hello' #若對a[2][1]進行改變,那麼a,b都會發生改變
>>> print(a==b) ##這時候直接對a[2]進行修改,a[2]的對象發生了改變,內存地址也發生了改變,這時b[2]的對象的地址仍然是原來的地址,因此這時兩個列表不等價
True
False

>>> a = [1,2,[2,3,4,'a']]
>>> b=a.copy()
>>> print(a==b)  ##b從a列表copy後兩個列表是等價的
>>> a[2][0] = 'hello' ##這次修改的是a列表的某個列表元素中的元素,由於修改列表的元素不會對列表的地址產生修改,因此a[2]在內存中指向的仍然是原來的列表,只是這個列表的元素髮生了變化,而b列表也是指向這個列表,因此這時兩個列表是等價的
>>> print(a==b)
True
True

在這裏插入圖片描述
(1)b列表通過copy()方法複製a列表,但這是淺複製,b[2]存儲的是列表[2,3,4,‘a’]的引用地址
(2)通過a[2]=‘hello’對其進行賦值時,只是將a[2]的地址改變爲‘hello’的地址,所以b[2]不會受到影響
(3)通過a[2][1]=‘hello’對其進行賦值時,直接將列表[2,3,4,‘a’]中的3的地址0xe改變爲‘hello’的地址,這時候列表[2,3,4,‘a’]的地址仍然是0xc,在a和b列表中對這個子列表的引用地址仍然是0xc,所以,這樣賦值會導致a和b列表都會產生改變

深度拷貝deepcopy()方法

淺拷貝只會拷貝引用元素的地址,而深度拷貝會完全拷貝引用類型,相當於創建了一個新的引用類型

>>> import copy
>>> a = [1, [2, 3], 4]
>>> b = copy.deepcopy(a)
>>> print(id(a[0]))
>>> print(id(b[0]))
9331040
9331040
#字面常量直接拷貝,不具有引用類型的特性
>>> print(id(a[1]))
>>> print(id(b[1]))
140304039791304
140304039938824
#引用類型的深度拷貝相當於重新創建了一個對象,因此這時候再對a[1][0]進行修改就不會影響到b列表了

打印Fibonacci數列

a=[1,1]
for i in range(1,100):
    if a[i]+a[i-1] <= 100:
        a+=[a[i]+a[i-1]]
    else:
        break
print(a)
------------------------------------
list=[1,1]
for i in range(20):
    if list[len(list)-1] <= 100:
        list.append(list[i]+list[i+1])
    else:
        break
print(list)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章