1. deque()
deque雖然使用時(shí)很像list,但是兩者截然不同滑负。deque是一個(gè)doubly linked list而list是一個(gè)array骡技,所以處理兩端數(shù)據(jù)的時(shí)候deque的復(fù)雜度是O(1),而list是O(n)凹耙。但deque處理中部數(shù)據(jù)的效率低稀轨,是O(n)扼脐。因此,當(dāng)處理隨機(jī)狀態(tài)時(shí)奋刽,使用list更好瓦侮。
from collections import deque
D = deque()
D.append(5)
print(D)
print(D.popleft())
print(D)
D.append(6)
print(D[0])
print(D)
>>>
deque([5])
5
deque([])
6
deque([6])
2. Card Shuffling Simulator
洗牌的流程是先將一副牌分成盡量均勻的A和B兩部分,之后選擇A或者B的第一張作為洗牌之后的第一張佣谐,然后A和B各自的順序保持不變肚吏,但是彼此交叉在一起形成新順序。A和B未洗的牌越多狭魂,就越容易被優(yōu)先選中罚攀。
2.1 將牌分成兩部分
為了保證盡量均勻,每張牌用擲篩子的方式(randint(0, 1))選擇分到哪一部分雌澄。
from random import randint
nb_of_heads = 0
for _ in range(52):
#總共52張牌斋泄,沒有大小王
outcome = randint(0, 1)
if outcome == 1:
nb_of_heads += 1
print(nb_of_heads)
簡(jiǎn)化后的寫法
from random import randint
sum(randint(0, 1) for _ in range(52))
2.2 洗牌
根據(jù)分成兩個(gè)部分的牌數(shù)量將牌切成兩部分,記錄數(shù)量為i2(第二部分牌開始的index)镐牺,第一部分牌開始的index為i1(初始值為0)炫掐,洗后的牌index為i(初始值為0),剩余未洗卡牌數(shù)量為nb_of_cards_left(初始值為52)睬涧。
在洗牌過程中會(huì)出現(xiàn)一部分的牌全部洗完的狀況募胃,這時(shí)講剩余部分的牌直接放入洗過的牌的后邊。
deck = list(range(52))
cut = sum(randint(0, 1) for _ in range(52))
new_deck = [None] * 52
i1 = 0
i2 = cut
i = 0
nb_of_cards_left = 52
while i1 < cut and i2 < 52:
if randint(0, nb_of_cards_left - 1) < cut - i1:
#rand(0, nb_of_cards_left - 1) 能夠根據(jù)兩部分剩余厚度等概率選擇下一張洗的牌
new_deck[i] = deck[i1]
i1 += 1
else:
new_deck[i] = deck[i2]
i2 += 1
i += 1
nb_of_cards_left -= 1
if i1 == cut:
new_deck[i: ] = deck[i2: ]
else:
new_deck[i: ] = deck[i1: cut]
print(new_deck)
3. Identity
首先明確概念畦浓,計(jì)算機(jī)程序中的各種數(shù)字并不是真正的值痹束。比如3,3.14讶请,這些數(shù)實(shí)際上由兩部分構(gòu)成:一部分是name--"3", "3,14"祷嘶,另一部分是storage,存儲(chǔ)的binary bits秽梅。這兩個(gè)部分分別叫做v-name和v-storage抹蚀,計(jì)算機(jī)中并不存在值這個(gè)概念,它是一個(gè)抽象概念企垦,大體可以理解為v-name指向v-storage。
v-name可以出現(xiàn)多次晒来,比如可以有N個(gè)"2"作為v-name钞诡,2 + 2中,v-name2出現(xiàn)了兩次。在v-name中有兩種形式荧降,constant expressions和variable expressions接箫。
constant expression:例如2和1+1。如下面程序所示朵诫,2和1+1都指向相同的binary bits辛友。所以,1+1的過程實(shí)際上是先做運(yùn)算1+1剪返,根據(jù)值2的v-storage再分配一個(gè)v-name废累。等號(hào)實(shí)際上是把v-name指向了v-storage,所以下面程序x=2的時(shí)候是把2所在的v-storage再加上一個(gè)新的v-name x脱盲。
>>> id(2)
4297636928
>>> id(1 + 1)
4297636928
>>> x = 2
>>> id(x)
4297636928
對(duì)于基礎(chǔ)類型邑滨,都和上述的int類型一致,例如下面列舉的bool類型和str類型钱反。
>>> id(False)
4297244992
>>> a = False
>>> id(a)
4297244992
>>> b = False
>>> id(b)
4297244992
>>> id('abc')
4314648336
>>> a = 'abc'
>>> id(a)
4314648336
>>> b = 'abc'
>>> id(b)
4314648336
對(duì)于非基礎(chǔ)類型掖看,比如List, tuple, set, dictionary,要根據(jù)實(shí)際情況分析面哥。比如由于list可修改哎壳,所以他的分配都是動(dòng)態(tài)的,x = [2]和y = [2]兩者的存儲(chǔ)位置不同尚卫;而tuple是不可修改的耳峦,所以他的分配是靜態(tài)的,x = (2)和y = (2)兩者的存儲(chǔ)位置相同焕毫;set和dictionary是經(jīng)過hash的蹲坷,所以不僅x = {2}和y = {2}不同,他們也都和{2}不同邑飒。
>>> id([2])
4316726600
>>> x = [2]
>>> id(x)
4316726600
>>> y = [2]
>>> id(y)
4316726664
>>> id((2))
4297636928
>>> x = (2)
>>> id(x)
4297636928
>>> y = (2)
>>> id(y)
4297636928
>>> id({2})
4316700456
>>> x = {2}
>>> id(x)
4316700232
>>> y = {2}
>>> id(y)
4316700456
is的判斷是判別v-storage地址是否一樣循签,而==的判別是判斷v-storage的binary bits是否一樣。
由于binary是8位的疙咸,2^8 =256县匠,所以如果一個(gè)數(shù)大于256,v-storage的地址會(huì)變化撒轮,小于的時(shí)候不變化乞旦,這樣用上文說的is判斷就會(huì)出現(xiàn)下述情況
>>> x = 257
>>> x is 257
False
>>> x = 256
>>> x is 256
True
programming的時(shí)候如果遇到可修改的非基礎(chǔ)類型數(shù)據(jù),一定要小心generate的方式题山。如下:
>>> X = [0] * 3; X
[0, 0, 0]
>>> id(X), id(X[0]), id(X[1]), id(X[2])
(4521957128, 4481604640, 4481604640, 4481604640)
>>> X[0] = 1; X
[1, 0, 0]
>>> id(X), id(X[0]), id(X[1]), id(X[2])
(4521957128, 4481604672, 4481604640, 4481604640)
[0] * 3兰粉,由于0是基本數(shù)據(jù)類型,實(shí)際上產(chǎn)生3次0顶瞳,地址改變玖姑,所以如果對(duì)其中任何一個(gè)進(jìn)行修改愕秫,三者不會(huì)全部變化。
>>> X = [[0]] * 3; X
[[0], [0], [0]]
>>> id(X), id(X[0]), id(X[1]), id(X[2])
(4521981960, 4511587784, 4511587784, 4511587784)
>>> X[0][0] = 1; X
[[1], [1], [1]]
>>> id(X), id(X[0]), id(X[1]), id(X[2])
(4521981960, 4511587784, 4511587784, 4511587784)
[[0]] * 3焰络,由于[0]是可修改的非基礎(chǔ)數(shù)據(jù)類型戴甩,實(shí)際上并沒有產(chǎn)生3次[0],而是給了3個(gè)v-name而已闪彼,地址未變甜孤,所以如果對(duì)其中任何一個(gè)進(jìn)行修改,三者全部變化畏腕。如果想要產(chǎn)生3個(gè)[0]缴川,用下面的方法。
>>> X = [[0] for i in range(3)]; X
[[0], [0], [0]]
>>> id(X), id(X[0]), id(X[1]), id(X[2])
(4521980424, 4521980104, 4521981832, 4521980680)
>>> X[0][0] = 1; X
[[1], [0], [0]]
>>> id(X), id(X[0]), id(X[1]), id(X[2])
(4521980424, 4521980104, 4521981832, 4521980680)
4. Game of Life
游戲規(guī)則:A cell comes into existence at an empty spot when that spot is surrounded by exactly 3 cells. A cell survives if and only if it is surrounded by exactly 2 or 3 cells.
4.1 顯示數(shù)據(jù)
0代表死郊尝,1代表生二跋,有以下兩種方法顯示數(shù)據(jù)。
Method 1:
def print_grid():
for i in range(20):
for j in range(20):
print(grid[i][j], end = ' ')
print()
grid = [[0] * 20] * 20
Method 2:
def print_grid():
for i in range(20):
print(' '.join(str(e) for e in grid[i]))
grid = [[0] * 20] * 20
注意流昏,這里生成grid用到grid = [[0] * 20] * 20是沒有問題的扎即,因?yàn)閇0]中的0是基礎(chǔ)數(shù)據(jù)類型int。如果改成grid = [[[0]] * 20] * 20則會(huì)出問題况凉,因?yàn)閇[0]]中的[0]是非基礎(chǔ)數(shù)據(jù)類型list且可修改谚鄙。如果grid = [[(0)] * 20] * 20則不會(huì)出問題,因?yàn)閇(0)]]中的(0)是非基礎(chǔ)數(shù)據(jù)類型tuple刁绒,但不可修改闷营。
4.2 生成生死規(guī)則
注意全局變量使用和bondary的巧妙處理方式(在原數(shù)據(jù)外層加一圈符合規(guī)則的數(shù)據(jù))
from random import randrange
dim = 20
def print_grid():
for i in range(1, dim + 1):
print(' '.join(str(e) for e in grid[i]))
def initialise_grid():
for i in range(1, dim + 1):
for j in range(1, dim + 1):
if not randrange(0, density):
grid[i][j] = 1
def update_grid():
global grid
#因?yàn)樽詈骻rid =,賦值了知市,grid是local傻盟;如果只是改變grid的值,那么不用global
for i in range(1, dim + 1):
for j in range(1, dim + 1):
nb_of_neighbours = sum((grid[i - 1][j - 1], grid[i - 1][j], grid[i - 1][j + 1],
grid[i][j - 1], grid[i][j + 1],
grid[i + 1][j - 1], grid[i + 1][j], grid[i + 1][j + 1]))
if grid[i][j] and nb_of_neighbours in {2, 3} or\
not grid[i][j] and nb_of_neighbours == 3:
new_grid[i][j] = 1
grid = new_grid
density = 2
grid = [[0] * (dim + 2) for _ in range(dim + 2)]
initialise_grid()
print_grid()
print()
update_grid()
print_grid()
new_grid = [[0] * (dim + 2) for _ in range(dim + 2)]
#周圍加一圈0嫂丙,方便check周圍多少neighbor是1