日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python list 底层实现的数据结构_Python数据结构大起底——list篇

發布時間:2024/9/27 python 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python list 底层实现的数据结构_Python数据结构大起底——list篇 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

python內置的多種數據結構為編程提供了相當的便利,靈活的使用python中的內置數據類型可以達到事半功倍的效果,本文是對Python一些常用數據類型的整理,并列舉出來了一些使用技巧。

使用最多的數據結構 list

list內置了許多方法,常用的如:list.append(x)

list.insert(i,x)

list.remove(x)

list.pop(i)

list.index(x, start, end)

list.sort(key, reverse)

list.reverse()

list.copy()

...

上面的方法中,根據字面意思就能知道方法的作用,靈活使用這些方法,可以實現出來其他的數據結構。

使用list實現stack

stack是一個后進先出的數據結構,不理解stack的可以參看我的這篇博客,他的接口一般被這樣定義:

// Stack 接口,java代碼表示public Interface Stack{

// 添加一個元素 public void push(Item item);

// 移除最后添加的元素,并返回這個元素 public Item pop();

// 空監測 public isEmpty();

}

在python的list中,pop()方法依舊存在,使用不帶參數的pop方法,就會從移除list最后一個元素,而push()方法則等價于list的append方法。所以可以直接把list當做stack來使用。

stack = []

stack.append('a') # stack = ['a']

stack.append('b') # stack = ['b']

last = stack.pop() # last='b', stack=['a']

如果你覺得這樣做不是很安全,萬一一不小心調用了別的方法,很容易破壞數據結構,那么你可以使用list自己實現一個Stack(雖然這看上去有點脫褲子放屁):

class Stack:

def __init__(self):

| self._stack = []

def is_empty(self):

return False if self.stack else True

def pop(self):

return self._stack.pop()

def push(self, item):

self._stack.append(item)

def __iter__(self):

for item in self._stack:

yield item

使用list實現queue

queue的特點是先進先出,不理解queue的可以參看我的這篇文章,queue的接口一般包含如下幾種方法:

// Queue接口,java代碼表示public Interface Queue{

// 入隊操作,添加到最右(后) public void enqueue(Item);

//出隊操作,移除最早入隊的(最左邊) public Item dequeue();

public isEmpty();

}

值得慶祝的是,當我們要使用queue的時候并不要自己去編寫一個queque的結構,直接使用python collections模塊里面的deque即可,當然你也可以嘗試自己實現。

deque保留了list的append方法,但是有而外的添加了一個popleft方法,從而實現了dequeque的操作。

from collections import deque

queue = deque()

queue.append(1) # [1]

queue.append(2) # [1, 2]

queue.append(3) # [1, 2, 3]

first = queue.popleft() # first=1, queue=[2, 3]

list Comprehensions 列表推導

python官方文檔列出了三中創建列表的方式,他們分別是迭代器,lambda和列表推導

# 使用迭代去

squares = []

for x in range(10):

squares.append(x**2)

# 使用lambda

squares = list(map(lambda x:x**2, range(10)))

# 使用列表推導

squares = [x**2 for x in range(10)]

列表推導式可以讓代碼變得更加簡潔,解決2SUM問題,使用列表推導只需要一行代碼即可暴力求解:

# 從1到100,兩兩組合,求所有合為105的組合

[(x, y) for x in range(1,101) y in range(1,101) if (x != y and x+y == 105)]

列表推導式還支持嵌套,如生成一個二維數組

# 生成一個5*5的二維數組

[[i for i in range(5)] for col in range(5) ]

del操作

list之所以能夠把很多不同類型的數據放在一個集合里面,其他原因在于python的引用特性,所以對于列表內的任何一個元素都可以直接del。

a = [1, 2, 3, 4, 5]

del a[0] # 可以直接del

del a[2:4] # 也可以按照范圍del,范圍是左閉右開[2:4)

引用的陷阱

[[i for i in range(5)] for col in range(5) ]

這是上面用來創建二維數組的例子,有些比較聰明的人,可能會想到利用python的語言特性,與時代嗎可能會這么寫:

[[i for i in range(5)] * 5]

這看上去很簡潔,并且兩段代碼輸出的內容確實一毛一樣的,但這并不稱得上是聰明,簡直愚蠢。事實上,當你嘗試修改二維數組的任何一列的時候,每一列都會被改變。

a = [[i for i in range(5)] * 5]

# output a:

# [

# [1,2,3,4,5],

# [1,2,3,4,5],

# [1,2,3,4,5],

# [1,2,3,4,5],

# [1,2,3,4,5],

# ]

a[0][0] = 5

# output a:

# [

# [5,2,3,4,5],

# [5,2,3,4,5],

# [5,2,3,4,5],

# [5,2,3,4,5],

# [5,2,3,4,5],

# ]

出現上面巨大bug的原因就是,內存中事實上只創建了a[0],后面的幾列由于使用的是*操作符,都沒有創建新的內存空間,本質上他們是同一塊內存塊。

copy和deepcopy

同樣的問題還會出現在數組拷貝的時候。

a = [[1,2,3], [4,5,6]]

b = a.copy()

a[0][0] = [9]

print(a, b)

上面的代碼使用list的copy方法,把a復制了一份給b,按照字面意思理解,也就是說重新開辟了一塊兒內存空間,并把a的內容copy進去,這樣a和b就完全是兩個獨立的內存空間了。

但事實上上面的代碼,修改了a[0][0]之后,b[0][0]緊跟著也變成了9.這就有點匪夷所思了。這是由于拷貝的深度有限,list默認的copy在一維數組使用并沒有太大問題,但一旦數組內包含了其他深一層的引用,copy只會復制最上層,這樣對于兩塊內存塊來說,再往下一層,本質上還是使用了同一塊內存塊。所以就發生了上面匪夷所思的問題。

解決問題的辦法是使用深拷貝,python 的list并沒有實現deepcopy,但我們可以在copy模塊中找到他。

import copy

a = [[1,2,3], [4,5,6]]

b = copy.deepcopy(a)

然后從最外層到最內層,完完全全的拷貝了a,a與b再也不會有哪一個元素共同同一塊兒內存了。

總結

python對list的實現和功能的設計恰到好處,既不感到臃腫,又絕對夠用,畢竟他是python數據結構的核心。在某些情況下你也可以選擇不使用list,這個時候可以參見python的collections模塊,尋找其他適合你的集合類型。

總結

以上是生活随笔為你收集整理的python list 底层实现的数据结构_Python数据结构大起底——list篇的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。