python線性數據結構 [TOC] 1 線性數據結構 本章要介紹的線性結構:list、tuple、string、bytes、bytearray。 線性表:是一種抽象的數學概念,是一組元素的序列的抽象,由有窮個元素組成(0個或任意個)。 線性表又可分為 順序表和鏈接表。 順序表:一組元素在記憶體中有序 ...
python線性數據結構
目錄
<center>碼好python的每一篇文章.</center>
1 線性數據結構
本章要介紹的線性結構:list、tuple、string、bytes、bytearray。
-
線性表:是一種抽象的數學概念,是一組元素的序列的抽象,由有窮個元素組成(0個或任意個)。
線性表又可分為 順序表和鏈接表。
-
順序表:一組元素在記憶體中有序的存儲。列表list就是典型的順序表。
-
鏈接表:一組元素在記憶體中分散存儲鏈接起來,彼此知道連接的是誰。
對於這兩種表,數組中的元素進行查找、增加、刪除、修改,看看有什麼影響:
-
查找元素
對於順序表,是有序的在記憶體中存儲數據,可快速通過索引編號獲取元素,效率高。。
對於鏈接表是分散存儲的,只能通過一個個去迭代獲取元素,效率差。
-
增加元素
對於順序表,如果是在末尾增加元素,對於整個數據表來說沒什麼影響,但是在開頭或是中間插入元素,後面的所有元素都要重新排序,影響很大(想想數百萬或更大數據量)。
對於鏈接表,不管在哪裡加入元素,不會影響其他元素,影響小。
-
刪除元素
對於順序表,刪除元素和增加元素有著一樣的問題。
對於鏈接表,不管在哪裡刪除元素,不會影響其他元素,影響小。 -
修改元素
對於順序表,可快速通過索引獲取元素然後進行修改,效率高。對於鏈接表,只能通過迭代獲取元素然後進行修改,效率低。
總結:順序表對於查找與修改效率最高,增加和刪除效率低。鏈接表則相反。
2.內建常用的數據類型
2.1 數值型
-
int 整數類型
說明:整數包括負整數、0、正整數(... -2,-1,0,1,2, ...)。
x1 = 1 x2 = 0 x3 = -1 print(type(x1), x1) print(type(x2), x2) print(type(x3), x3) # 輸出結果如下: <class 'int'> 1 <class 'int'> 0 <class 'int'> -1
int( )方法:可以將數字或字元串轉為整數,預設base=10,表示10進位,無參數傳入則返回0。
x1 = int() x2 = int('1') x3 = int('0b10',base=2) #base=2,表二進位,與傳入參數類型一致。 x4 = int(3.14) print(type(x1), x1) print(type(x2), x2) print(type(x3), x3) print(type(x4), x4) # 輸出結果如下: <class 'int'> 0 <class 'int'> 1 <class 'int'> 2 <class 'int'> 3
-
float 浮點類型
說明:由整數和小數部分組成,傳入的參數可以為int
、str
、bytes
、bytearray
。x1 = float(1) x2 = float('2') x3 = float(b'3') print(type(x1), x1) print(type(x2), x2) print(type(x3), x3) # 輸出結果如下: <class 'float'> 1.0 <class 'float'> 2.0 <class 'float'> 3.0
-
complex (複數類型)
說明:由實數和虛數部分組成,都是浮點數。
傳入參數可以為
int
、str
,如果傳入兩參,前面一個為實數部分,後一個參數為虛數部分。x1 = complex(1) x2 = complex(2,2) x3 = complex('3') print(type(x1), x1) print(type(x2), x2) print(type(x3), x3) # 輸出結果如下: <class 'complex'> (1+0j) <class 'complex'> (2+2j) <class 'complex'> (3+0j)
-
bool (布爾類型)
說明:為int的子類,返回的是True和False,對應的是1和0。
x1 = bool(0) x2 = bool(1) x3 = bool() x4 = 2 > 1 print(type(x1), x1) print(type(x2), x2) print(type(x3), x3) print(type(x4), x4) # 輸出結果如下: <class 'bool'> False <class 'bool'> True <class 'bool'> False <class 'bool'> True
2.2 序列(sequence)
2.2.1 list 列表
說明: 列表是由若幹元素對象組成,且是有序可變
的線性數據結構,使用中括弧[ ]
表示。
-
初始化
lst = [] # 空列表方式1 #或者 lst = list() # 空列表方式2 print(type(lst),lst) # 輸入結果如下: <class 'list'> []
-
索引
說明: 使用正索引(從左至右)、負索引(從右至左)訪問元素,時間複雜度為
O(1)
,效率極高的使用方式。按照給定區間獲取到數據,叫做切片。
正索引:
從左至右,從0開始索引,區間為[0,長度-1],左包右不包。
lst = ['a','b','c','d'] print(lst[0]) # 獲取第一個元素 print(lst[1:2]) # 獲取第二個元素,左包右不包,切片 print(lst[2:]) # 獲取第三個元素到最後一個元素,切片 print(lst[:]) # 獲取所有元素,切片 # 輸出結果如下: a ['c'] ['c', 'd'] ['a', 'b', 'c', 'd']
負索引:
從右至左,從-1開始索引,區間為[-長度,-1]
lst = ['a','b','c','d'] print(lst[-1]) print(lst[-2:]) # 輸出結果如下: d ['c', 'd']
-
查詢
index( )方法:
L.index(value, [start, [stop]]) -> integer
返回的是索引id,要迭代列表,時間複雜度為O(n)。
lst = ['a','b','c','d'] print(lst.index('a',0,4)) # 獲取區間[0,4]的元素'a'的索引id # 輸出結果如下: 0
備註:如果查詢不到元素,則拋出
ValueError
。count( ) 方法:L.count(value) -> integer
返回的是元素出現的次數,要迭代列表,時間複雜度為O(n)。
lst = ['a','b','a','b'] print(lst.count('a')) # 輸出結果如下: 2
len( ) 方法:返回的是列表元素的個數,時間複雜度為O(1)。
lst = ['a','b','c','d'] print(len(lst)) # 輸出結果如下: 4
備註:所謂的O(n) 是指隨著數據的規模越來越大,效率下降,而O(1)則相反,不會隨著數據規模大而影響效率。
-
修改
列表是有序可變,所以能夠對列表中的元素進行修改。
lst = ['a','b','c','d'] lst[0] = 'A' print(lst) # 輸出結果如下: ['A', 'b', 'c', 'd']
-
增加
append( ) 方法:
L.append(object) -> None
尾部追加元素,就地修改,返回None。
lst = ['a','b','c','d'] lst.append('e') print(lst) # 輸出結果如下: ['a', 'b', 'c', 'd', 'e']
insert( )方法:
L.insert(index, object) -> None
,在指定索引位置插入元素對象,返回None。
lst = ['a','b','c','d'] lst.insert(0,'A') # 在索引0位置插入'A',原有的元素全部往後移,增加了複雜度 print(lst) # 輸出結果如下: ['A', 'a', 'b', 'c', 'd']
extend( )方法:
L.extend(iterable) -> None
可以增加多個元素,將可迭代對象的元素追加進去,返回None。
lst = ['a','b','c','d'] lst.extend([1,2,3]) print(lst) # 輸出結果如下: ['a', 'b', 'c', 'd', 1, 2, 3]
還可以將列表通過
+
和*
,拼接成新的列表。lst1 = ['a','b','c','d'] lst2 = ['e','f','g'] print(lst1 + lst2) print(lst1 * 2) # 將列表裡面的元素各複製2份 # 輸出結果如下: ['a', 'b', 'c', 'd', 'e', 'f', 'g'] ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd']
這裡還有一個特別要註意情況如下:
lst1 = [[1]] * 3 # 結果:[[1], [1], [1]] print(lst1) lst1[0][0] = 10 # 結果:[[10], [1], [1]],是這樣嘛?? print(lst1) # 輸出結果如下: [[1], [1], [1]] [[10], [10], [10]] # 為什麼結果會是這個?請往下看列表複製章節,找答案!
-
刪除
remove()方法:
L.remove(value) -> None
從左至右遍歷查找,找到就刪除該元素,返回None,找不到則拋出
ValueError
。lst = ['a','b','c','d'] lst.remove('d') print(lst) # 輸出結果如下: ['a', 'b', 'c'] # 元素'd'已經被刪除
pop() 方法:
L.pop([index]) -> item
預設刪除尾部元素,可指定索引刪除元素,索引越界拋出
IndexError
。lst = ['a','b','c','d'] lst.pop() print(lst) # 輸出結果如下: ['a', 'b', 'c']
clear() 方法:
L.clear() -> None
清空列表所有元素,慎用。
lst = ['a','b','c','d'] lst.clear() print(lst) # 輸出結果如下: [] # 空列表了
-
反轉
reverse( ) 方法:
L.reverse()
將列表中的元素反轉,返回None。
lst = ['a','b','c','d'] lst.reverse() print(lst) # 輸出結果如下: ['d', 'c', 'b', 'a']
-
排序
sort() 方法:
L.sort(key=None, reverse=False) -> None
對列表元素進行排序,預設為升序,reverse=True為降序。
lst = ['a','b','c','d'] lst.sort(reverse=True) print(lst) # 輸出結果如下: ['d', 'c', 'b', 'a']
-
in成員操作
判斷成員是否在列表裡面,有則返回True、無則返回False。
lst = ['a','b','c','d'] print('a' in lst) print('e' in lst) # 輸出結果如下: True False
-
列表複製
說明: 列表複製指的是列表元素的複製,可分為淺copy和深copy兩種。列表元素對象如列表、元組、字典、類、實例這些歸為引用類型(指向記憶體地址),而數字、字元串先歸為簡單類型,好讓大家理解。
示例一:這是屬於拷貝嘛?
lst1 = [1,[2,3],4] lst2 = lst1 print(id(lst1),id(lst2),lst1 == lst2, lst2) # id() 查看記憶體地址 # 輸出結果如下: 1593751168840 1593751168840 True [1, [2, 3], 4]
顯然不是屬於任何copy,說白了都是指向同一個記憶體地址。
示例二:淺拷貝copy
說明: 淺拷貝對於
引用類型
對象是不會copy的,地址指向仍是一樣。lst1 = [1,[2,3],4] lst2 = lst1.copy() print(id(lst1),id(lst2),lst1 == lst2, lst2) print('=' * 30) lst1[1][0] = 200 # 修改列表的引用類型,所有列表都會改變 print(lst1, lst2) # 輸出結果如下: 1922175854408 1922175854344 True [1, [2, 3], 4] ============================== [1, [200, 3], 4] [1, [200, 3], 4]
示例三:深拷貝deepcopy
說明: 深拷貝對於
引用類型
對象也會copy成另外一份,地址指向不一樣。import copy lst1 = [1,[2,3],4] lst2 = copy.deepcopy(lst1) print(id(lst1),id(lst2),lst1 == lst2, lst2) print('=' * 30) lst1[1][0] = 200 # 修改列表的引用類型,不會影響其他列表 print(lst1, lst2) # 輸出結果如下: 2378580158344 2378580158280 True [1, [2, 3], 4] ============================== [1, [200, 3], 4] [1, [2, 3], 4]
2.2.2 tuple 元組
說明: 元組是由若幹元素對象組成,且是有序不可變
的數據結構,使用小括弧( )
表示。
-
初始化
t1 = () # 空元素方式1,一旦創建將不可改變 t2 = tuple() # 空元素方式2,一旦創建將不可改變 t3 = ('a',) # 元組只有一個元素,一定要加逗號',' t4 = (['a','b','c']) # 空列表方式2
備註: 元組如果只有一個元素對象,一定要在後面加逗號
,
否則變為其他數據類型。 -
索引
同列表一樣,不再過多舉例。t = ('a','b','c','d') print(t[0]) print(t[-1]) # 輸出結果如下: a d
-
查詢
同列表一樣,不再過多舉例。
t = ('a','b','c','d') print(t.index('a')) print(t.count('a')) print(len(t)) # 輸出結果如下: 0 1 4
-
增刪改
元組是
不可變
類型,不能增刪改元素對象。但是要註意如下場景:
元組中的元素對象(記憶體地址)不可變,引用類型可變。----這裡又出現引用類型的情況了。
# 元組的元組不可修改(即記憶體地址) t = ([1],) t[0]= 100 print(t) # 結果報錯了 TypeError: 'tuple' object does not support item assignment ############################################ # 元組裡面的引用類型對象可以修改(如嵌套了列表) t = ([1],2,3) t[0][0] = 100 # 對元組引用類型對象的元素作修改 print(t) # 輸出結果如下: ([100], 2, 3)
2.2.3 string 字元串
說明: 字元串是由若幹字元組成,且是有序不可變
的數據結構,使用引號表示。
-
初始化
多種花樣,使用單引號、雙引號、三引號等。name = 'tom' age = 18 str1 = 'abc' # 單引號字元串 str2 = "abc" # 雙引號字元串 str3 = """I'm python""" # 三引號字元串 str4 = r"c:\windows\note" # r首碼,沒有轉義(轉義字元不生效) str5 = f'{name} is {age} age.' # f首碼,字元串格式化,v3.6支持 print(type(str1), str1) print(type(str2), str2) print(type(str3), str3) print(type(str4), str4) print(type(str5), str5) # 輸出結果如下: <class 'str'> abc <class 'str'> abc <class 'str'> I'm python <class 'str'> c:\windows\note <class 'str'> tom is 18 age.
-
索引
同列表一樣,不再過多舉例。
str = "abcdefg" print(str[0]) print(str[-1]) # 輸出結果如下: a g
-
連接
通過加號
+
將多個字元串連接起來,返回一個新的字元串。str1 = "abcd" str2 = "efg" print(str1 + str2) # 輸出結果如下: abcdefg
join( ) 方法:
S.join(iterable) -> str
s表示分隔符字元串,iterable為可迭代對象字元串,結果返回字元串。
str = "abcdefg" print('->'.join(str)) # 輸出結果如下: a->b->c->d->e->f->g
-
字元查找
find( ) 方法:
S.find(sub[, start[, end]]) -> int
從左至右查找子串sub,也可指定區間,找到返回正索引,找不到則返回
-1
。str = "abcdefg" print(str.find('a',0,7)) print(str.find('A')) # 輸出結果如下: 0 -1
rfind( ) 方法:
S.rfind(sub[, start[, end]]) -> int
從右至左查找子串sub,也可指定區間,找到返回正索引,找不到則返回
-1
。str = "abcdefg" print(str.rfind('a')) print(str.rfind('A')) # 輸出結果如下: 0 -1
還有
index()
和find()
類似,不過找不到會拋異常,不建議使用。像
s.count()
還可以統計字元出現的次數。像
len(s)
還可以統計字元串的長度。 -
分割
split( ) 方法:
S.split(sep=None, maxsplit=-1) -> list of strings
sep表示分隔符,預設為空白字元串,maxsplit=-1表示遍歷整個字元串,最後返回列表。
str = "a,b,c,d,e,f,g" print(str.split(sep=',')) # 輸出結果如下: ['a', 'b', 'c', 'd', 'e', 'f', 'g']
rsplit( ) 方法與上面不同就是,從右至左遍歷。
splitlines() 方法:
S.splitlines([keepends]) -> list of strings
按行來切割字元串,keepends表示是否保留行分隔符,最後返回列表。
str = "a\nb\nc\r\nd" print(str.splitlines()) print(str.splitlines(keepends=True)) # 輸出結果如下: ['a', 'b', 'c', 'd'] ['a\n', 'b\n', 'c\r\n', 'd']
partition() 方法 :
S.partition(sep) -> (head, sep, tail)
從左至右查詢分隔符,遇到就分割成頭、分隔符、尾的三元組,返回的是一個元組tuple。
str = "a*b*c*d" print(str.partition('*')) # 輸出結果如下: ('a', '*', 'b*c*d')
rpartition() 方法 :
S.rpartition(sep) -> (head, sep, tail)
與上方法不同,就是從右至左,不過這個比較常用,可以獲取尾碼部分信息。
str1 = "http://www.python.org:8843" str2 = str1.rpartition(':') port = str2[-1] print(port)
-
替換
replace() 方法:
S.replace(old, new[, count]) -> str
遍歷整個字元串,找到全部替換,count表示替換次數,預設替換全部,最後返回一個
新的字元串
。str = "www.python.org" print(str.replace('w','m')) # 返回的是一個新的字元串 print(str) # 字元串不可變,保持原樣 # 輸出結果如下: mmm.python.org www.python.org
-
移除
strip() 方法:
S.strip([chars]) -> str
在字元串兩端移除指定的
字元集chars
, 預設移除空白字元。str = " * www.python.org *" print(str.strip("* ")) # 去掉字元串首尾帶有星號'*' 和 空白' ' # 輸出結果如下: www.python.org
還有
lstrip()
和rstrip
分別是移除字元串左邊和右邊字元集。 -
首尾判斷
startswith() 方法:
S.startswith(prefix[, start[, end]]) -> bool
預設判斷字元串開頭是否有指定的字元prefix,也可指定區間。
str = "www.python.org" print(str.startswith('www',0,14)) print(str.startswith('p',0,14)) # 輸出結果如下: True False
endswith() 方法:
S.endswith(suffix[, start[, end]]) -> bool
預設判斷字元串結尾是否有指定的字元suffix,也可指定區間。
str = "www.python.org" print(str.startswith('www',0,14)) print(str.startswith('p',0,14)) # 輸出結果如下: True False
str = "www.python.org" print(str.endswith('g',11,14)) # 輸出結果如下: True
-
格式化
c風格格式化:
格式字元串:使用%s(對應值為字元串),%d(對應值為數字)等等,還可以在中間插入修飾符%03d。
被格式的值:只能是一個對象,可以是元組或是字典。
name = "Tom" age = 18 print("%s is %d age." % (name,age)) # 輸出結果如下: Tom is 18 age.
format格式化:
格式字元串:使用花括弧{ }, 花括弧裡面可以使用修飾符。
被格式的值:*args為可變位置參數,**kwargs為可變關鍵字參數。
# 位置傳參 print("IP={} PORT={}".format('8.8.8.8',53)) # 位置傳參 print("{Server}: IP={1} PORT={0}".format(53, '8.8.8.8', Server='DNS Server')) # 位置和關鍵字傳參傳參 # 輸出結果如下: IP=8.8.8.8 PORT=53 DNS Server: IP=8.8.8.8 PORT=53
# 浮點數 print("{}".format(0.123456789)) print("{:f}".format(0.123456789)) # 小數點預設為6位 print("{:.2f}".format(0.123456789)) # 取小數點後兩位 print("{:15}".format(0.123456789)) # 寬度為15,右對齊 # 輸出結果如下: 0.123456789 0.123457 # 為什麼是這個值?大於5要進位 0.12 0.123456789 # 左邊有4個空格
-
其他常用函數
str = "DianDiJiShu" print(str.upper()) # 字母全部轉化為大寫 print(str.lower()) # 字母全部轉化為小寫 # 輸出結果如下: DIANDIJISHU diandijishu
2.2.4 bytes 位元組
bytes
和 bytearray
從python3引入的兩種數據類型。
在電腦的世界里,機器是以0
和 1
組成的,也叫二進位(位元組)來通信的,這套編碼我們叫做ASCII
編碼。
所以機器通信的語言就叫做機器語言。然而我們人類想要跟機器通信,那麼需要怎麼做呢?
- 把人類的語言編碼成機器能夠識別的語言,通常叫做編碼(字元串轉換為ASCII碼)。
- 把機器的語言解碼成人類能夠識別的語言,通常叫做解碼(ASCII碼轉換為字元串)。
至今現代編碼的發展史過程大概是這樣的:ASCII(1位元組) -> unicode(2~4位元組) -> utf-8(16位元組),utf8是多位元組編碼,一般使用13位元組,特殊使用4位元組(一般中文使用3位元組),向下相容ASCII編碼。
中國也有屬於自己的編碼:gbk
ASCII碼表常用的必須牢記(整理部分):
詳細ASCII碼下載鏈接:
鏈接:https://pan.baidu.com/s/1fWVl57Kqmv-tkjrDKwPvSw 提取碼:tuyz
所以,機器上的進位就是位元組,1位元組等於8位,例如:十進位2,用2進位和16進位表示:
# 二進位
0000 0010 # 一個位元組bytes
# 16進位,機器基本都是顯示16進位
0x2
bytes 是不可變類型
bytes() # 空bytes,一旦創建不可改變
bytes(int) # 指定位元組的大小,用0填充
bytes(iterable_of_ints) # [0.255]整數的可迭代對象
bytes(string, encoding[, errors]) # 等價於string.encoding(),字元串編碼成位元組
bytes(bytes_or_buffer) # 複製一份新的位元組對象
-
初始化
b1 = bytes() b2 = bytes(range(97,100)) b3 = bytes(b2) b4 = bytes('123',encoding='utf-8') b5 = b'ABC' b6 = b'\xe4\xbd\xa0\xe5\xa5\xbd'.decode('utf-8') print(b1, b2, b3, b4, b5, b6, sep='\n') # 輸出結果如下: b'' b'abc' b'abc' b'123' b'ABC' 你好
2.2.5 bytearray 位元組數組
bytearray 是可變數組,可以進行增刪改操作,類似列表。
bytearray() # 空bytearray,可改變
bytearray(iterable_of_ints) # [0.255]整數的可迭代對象
bytearray(string, encoding[, errors]) # 等價於string.encoding(),字元串編碼成位元組
bytearray(bytes_or_buffer) # 複製一份新的位元組數組對象
bytearray(int) # 指定位元組的大小,用0填充
-
增刪改
# 初始化 b = bytearray() print(b) # 輸出結果如下: bytearray(b'') #-------------------------- # 增加元素對象 b.append(97) print(b) b.extend([98,99]) print(b) # 輸出結果如下: bytearray(b'a') bytearray(b'abc') #-------------------------- # 插入元素對象 b.insert(0,65) print(b) # 輸出結果如下: bytearray(b'Aabc') #-------------------------- # 刪除元素對象 b.pop() print(b) # 輸出結果如下: bytearray(b'Aab')
今天就到這了,下一回合咱再接著嘮嗑 set (集合)
和 dict (字典)
,敬請耐心等待。
如果喜歡的我的文章,歡迎關註我的公眾號:點滴技術,掃碼關註,不定期分享