列表的紛爭之二進(jìn)制編碼
小美:最近數(shù)學(xué)老師給我們玩了有趣的猜年齡游戲棚贾,他顯示了6張表格逞力,你只要觀察這6張表格锅论,然后回答“是”與“不是”就可以了祈纯。老師可以根據(jù)你的回答猜出你的年齡是多少令宿。
阿福:真有這么厲害?我也想玩玩看腕窥。
小美:好的粒没。請看下圖的6張表格,然后回答“是”與“不是”簇爆。準(zhǔn)備好了嗎癞松?
阿福:準(zhǔn)備好了。
小美:第1張表格中是否包含了你的年齡入蛆?
阿福:不是响蓉。
小美:第2張表格中是否包含了你的年齡?
阿福:不是安寺。
小美:第3張表格中是否包含了你的年齡厕妖?
阿福:不是。
小美:第4張表格中是否包含了你的年齡挑庶?
阿福:是言秸。
小美:第5張表格中是否包含了你的年齡?
阿福:不是迎捺。
小美:第6張表格中是否包含了你的年齡举畸?
阿福:是。
小美:你今年40歲凳枝。不對抄沮,你虛報(bào)年齡跋核。這應(yīng)該是你老爸的年齡才對。
阿福:沒錯叛买,這就是我老爸的年齡砂代。我不讓你猜我的歲數(shù),還不是因?yàn)槟惚緛砭椭牢叶啻舐收酰遗履阕鞅茁铩?/p>
小美:作弊刻伊?本小姐是這種人嗎?我告訴你椒功,這是科學(xué)捶箱!科學(xué),你懂嗎动漾?
阿福:對對對丁屎,科學(xué),科學(xué)旱眯。開個玩笑嘛晨川。不過你這科學(xué)的力量挺強(qiáng)大的,還真猜出我心里想的數(shù)字了键思。能告訴我這背后有什么原理嗎础爬?
小美:這個嘛。吼鳞。看蚜。。赔桌。供炎。我先不告訴你,給你一張圖疾党,看你能不能找出規(guī)律來音诫。
阿福:二進(jìn)制數(shù)。
小美:沒錯雪位,就是二進(jìn)制數(shù)竭钝。你看出這些二進(jìn)制數(shù)有什么規(guī)律了嗎?
阿福:看出來了雹洗,圖2表格中的每一個二進(jìn)制數(shù)都跟圖1表格中的十進(jìn)制數(shù)一一對應(yīng)香罐。
小美:還有呢?
阿福:還有时肿?暫時沒看出來庇茫。
小美:這都看不出來?眼睛白長了螃成。我再給你點(diǎn)提示吧旦签,看看每個表格中所有的二進(jìn)制數(shù)符號1的位置和表格編號的關(guān)系查坪。
阿福:符號1的位置,表格編號宁炫。偿曙。。淋淀。遥昧。覆醇。它們有什么關(guān)系呢朵纷?再讓我想想。永脓。袍辞。。常摧。搅吁。看到了落午!表格1中所有二進(jìn)制數(shù)的第1位(從右往左數(shù))都是1谎懦,表格2中所有二進(jìn)制數(shù)的第2位(從右往左數(shù))都是1,一直到表格6中所有二進(jìn)制數(shù)的第6位(從右往左數(shù))都是1溃斋。
小美:沒錯界拦,正是這樣!孺子可教也梗劫!
阿福:可是這樣的規(guī)律又有什么用呢享甸?
小美:有什么用?你個榆木腦袋梳侨。這樣就可以計(jì)算你的年齡了啊蛉威。你剛才不是說了嗎,第幾張表格就對應(yīng)二進(jìn)制數(shù)的第幾位走哺,這個位上面是符號1蚯嫌,就代表你的年齡出現(xiàn)在了這張表格中啊。哪幾張表格出現(xiàn)了你的年齡丙躏,就代表你的年齡對應(yīng)的二進(jìn)制數(shù)在這幾個位上的符號是1择示,否則就代表這個位上的符號是0。
阿福:原來是這樣彼哼。我明白了对妄,剛才你是根據(jù)二進(jìn)制數(shù)各個位的情況,轉(zhuǎn)化成十進(jìn)制數(shù)以后得到我的年齡的啊敢朱。讓我算一算剪菱,0*2^0 + 0*2^1 + 0*2^2 + 1*2^3 + 0*2^4 + 1*2^5 = 40摩瞎,完全正確。
小美:這回搞懂了吧孝常?
阿福:總算明白了旗们。沒想到這里還隱藏著二進(jìn)制編碼的奧秘。不錯构灸,有點(diǎn)意思上渴。對了,小美喜颁,我覺得這是一個編程的好素材啊稠氮。你不是擅長海龜作圖嗎,能不能用turtle把上面那兩張圖畫出來啊半开。
小美:這有什么難的隔披,不就是畫幾張表格嗎?我只需要用一個二維列表table存儲每一個表格中的數(shù)字就行了寂拆。例如table[0] = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63]奢米,表示table[0]存儲了表1中的所有數(shù)字。我只要寫一個函數(shù)依次把表格編號纠永,表格線和數(shù)字畫出來就行了鬓长。
題目1:
函數(shù)功能:根據(jù)輸入的表格內(nèi)容,畫len(table)個4行col列的二維表格
函數(shù)名:draw_table(x0,y0, h, w, table)
參數(shù)表:x0, y0 -- 存儲了第一張表格的左上角坐標(biāo)
??????? h, w --分別表示表格的高度和寬度
??????? table --存儲了表格內(nèi)容的二維列表尝江。
返回值:沒有返回值涉波。
代碼1:
def draw_table(x0,y0, h, w, table):
??? n = len(table)
??? col = len(table[0]) // 4 #每張表均分成4行col列
??? for i in range(n):#從上到下依次排列共n張4行col列的二維表格
??????? y0 -= h * 5
??????? for command in ('編號', '畫線', '寫字'):
??????????? if command == '編號':
??????????????? tt.penup()
??????????????? tt.goto(x0-40, y0-h*2)
??????????????? tt.pendown()
??????????????? num = ''.join(['表', str(i+1),':'])
??????????????? tt.write(num,align="center", font=("黑體", 16,"normal"))
??????????? elif command == '畫線':
??????????????? for j in range(5):#畫5條橫線
??????????????????? x, y = x0, y0 - j * h
??????????????????? tt.penup()
??????????????????? tt.goto(x, y)
??????????????????? tt.pendown()
??????????????????? tt.forward(col * w)
??????????????? tt.right(90)
??????????????? for j in range(col+1):#畫col+1條豎線
??????????????????? x, y = x0 + j * w, y0
??????????????????? tt.penup()
??????????????????? tt.goto(x, y)
??????????????????? tt.pendown()
??????????????????? tt.forward(4 * h)
??????????????? tt.right(-90)
??????????? else:
??????????????? for r in range(4):
??????????????????? x, y = x0, y0 - r * h - h /2
??????????????????? for c in range(col):
????????? ??????????????tt.penup()
??????????????????????? tt.goto(x+w/2, y-h*2/5)
??????????????????????? tt.pendown()
???????????????????????tt.write(table[i][r*col+c], align="center", font=("黑體", 12,"normal"))
??????????????????????? x += w
import turtle as tt
tt.TurtleScreen._RUNNING= True? #啟動繪圖,在IDE中運(yùn)行加這句可避免報(bào)錯
tt.speed(0)
tt.ht()#隱藏筆頭
table = [[1, 3, 5,7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45,47, 49, 51, 53, 55, 57, 59, 61, 63],
???????? [2, 3, 6, 7, 10, 11, 14, 15, 18, 19,22, 23, 26, 27, 30, 31, 34, 35, 38, 39, 42, 43, 46, 47, 50, 51, 54, 55, 58, 59,62, 63],
???????? [4, 5, 6, 7, 12, 13, 14, 15, 20, 21,22, 23, 28, 29, 30, 31, 36, 37, 38, 39, 44, 45, 46, 47, 52, 53, 54, 55, 60, 61,62, 63],
???????? [8, 9, 10, 11, 12, 13, 14, 15, 24, 25,26, 27, 28, 29, 30, 31, 40, 41, 42, 43, 44, 45, 46, 47, 56, 57, 58, 59, 60, 61,62, 63],
???????? [16, 17, 18, 19, 20, 21, 22, 23, 24,25, 26, 27, 28, 29, 30, 31, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,61, 62, 63],
????? ???[32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,63]]
x0, y0, h, w = -400, 600, 25, 60 #分別存儲了第一張表格的左上角坐標(biāo)茂装、高度和寬度
draw_table(x0, y0,h, w, table)
tt.done()
古老師:嗯怠蹂,不錯,小美的海龜作圖是畫得越來越溜了少态〕遣啵可美中不足的是這個存儲表格信息的二維列表還是手動生成的,可惜彼妻,可惜跋佑印!
小美:可惜侨歉?不手動生成屋摇,難道還可以自動生成?
阿福:當(dāng)然可以啦幽邓。難道你沒有學(xué)過列表生成式嗎炮温?
小美:列表生成式?什么是列表生成式牵舵?
古老師:列表生成式是Python內(nèi)置的非常簡單卻強(qiáng)大的功能柒啤,它可以用來快速創(chuàng)建一個列表倦挂。例如我們要生成一個列表a = [1, 4, 9, 16, 25, 36, 49, 64, 81, 100],只需寫做a = [x * x for x in range(1, 11)]担巩。寫列表生成式時方援,把要生成的元素x * x放到前面,后面跟for循環(huán)涛癌,就可以把list創(chuàng)建出來犯戏,非常簡單方便。
阿福:for循環(huán)后面還可以加上if判斷拳话,這樣我們就可以篩選出僅奇數(shù)的平方:a = [x * x for x in range(1, 11) if x % 2 == 1]先匪。
小美:哦,原來是這樣假颇。我知道了胚鸯,我們可以生成一個二維列表,該列表的每一個元素都是一個列表笨鸡,我們可以使用列表生成式生成每一個列表元素。例如table[0] = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63]坦冠,它是表1中的數(shù)字形耗,其特征是轉(zhuǎn)化成二進(jìn)制數(shù)后第1位(從右往左數(shù))都是1,我可以使用內(nèi)置函數(shù)bin()把十進(jìn)制數(shù)轉(zhuǎn)換成二進(jìn)制數(shù)辙浑,然后判斷它的第1位是不是1激涤,從而生成table[0]的值。以此類推可以生成所有的table[i]判呕。
阿福:沒錯倦踢,就是這樣。還可以不使用bin()函數(shù)侠草,而是利用按位與運(yùn)算來判斷某個二進(jìn)制數(shù)的第i位是不是1辱挥。
古老師:阿福思維很開闊,我們確實(shí)可以用多種方法來判斷二進(jìn)制數(shù)的某個位是1還是0边涕。這樣吧晤碘,我來分配一下任務(wù),小美用bin()函數(shù)做功蜓,阿福用位運(yùn)算做园爷,最后看看效果是否相同。
知識小貼士:
Python bin() 函數(shù):bin() 返回一個整數(shù)的二進(jìn)制表示式撼,其語法為bin(x)童社,其中x是int或者long int數(shù)字,返回值是一個字符串著隆。例如bin(10)返回'0b1010'扰楼,bin(-6)返回'-0b110'甘改。
代碼2:
n = 6
table = [[x for xin range(2**i, 2**n+1) if x & 2**i != 0] for i in range(n)]
代碼3:
n = 6
table = [[x for xin range(2**i, 2**n+1) if bin(x)[-i-1] == '1'] for i in range(n)]
table2 =[[bin(x)[2:] for x in range(2**i, 2**n+1) if bin(x)[-i-1] == '1'] for i inrange(n)]
古老師:非常好!都抓住了列表生成式的精髓灭抑,其中小美還把十進(jìn)制和二進(jìn)制數(shù)兩個列表都生成了十艾,很有創(chuàng)造性。阿福的位運(yùn)算代碼也很簡潔腾节,值得表揚(yáng)忘嫉!
對了,上次我在公園里看到一個猜姓氏的游戲案腺,界面如下圖所示庆冕。你們看看它背后的原理是什么?
小美:這不就是剛才我們玩的猜年齡游戲嗎劈榨?只不過它把數(shù)字改成了姓氏访递,道理是一樣一樣的。
阿福:沒錯同辣,又是一個二進(jìn)制編碼的游戲拷姿。
古老師:眼睛夠亮的啊旱函!既然你們都看出來了响巢,那就用turtle把它畫出來吧。
這是要用到的百家姓前128種姓氏:李王張劉陳楊趙黃周吳徐孫胡朱高林何郭馬羅梁宋鄭謝韓唐馮于董蕭程曹袁鄧許傅沈曾彭呂蘇盧蔣蔡賈丁魏薛葉閻余潘杜戴夏鐘汪田任姜范方石姚譚廖鄒熊金陸郝孔白崔康毛邱秦江史顧侯邵孟龍萬段漕錢湯尹黎易常武喬賀賴龔文龐樊蘭殷施陶洪翟安顏倪嚴(yán)牛溫蘆季俞章魯葛伍韋申尤畢聶叢焦棒妨。
我還有點(diǎn)事踪古,就先走了,回頭見啊券腔。
彩蛋:
阿福:這個好像可以直接調(diào)用你前面寫的draw_table()函數(shù)伏穆,只要修改一下table列表的值就行了。
小美:那當(dāng)然了纷纫,這就叫做函數(shù)的通用性枕扫。還不錯吧?
阿福:看你嘚瑟的涛酗,這不應(yīng)該是編寫函數(shù)的基本要求嗎铡原?對了,代碼寫好了嗎商叹?
小美:早就寫好了燕刻。因?yàn)榭梢灾苯诱{(diào)用draw_table()函數(shù),所以我只寫了主函數(shù)部分剖笙。
代碼4:
import turtle as tt
tt.TurtleScreen._RUNNING= True? #啟動繪圖卵洗,在IDE中運(yùn)行加這句可避免報(bào)錯
tt.speed(0)
tt.ht()#隱藏筆頭
xing = '李王張劉陳楊趙黃周吳徐孫胡朱高林何郭馬羅梁宋鄭謝韓唐馮于董蕭程曹袁鄧許傅沈曾彭呂蘇盧蔣蔡賈丁魏薛葉閻余潘杜戴夏鐘汪田任姜范方石姚譚廖鄒熊金陸郝孔白崔康毛邱秦江史顧侯邵孟龍萬段漕錢湯尹黎易常武喬賀賴龔文龐樊蘭殷施陶洪翟安顏倪嚴(yán)牛溫蘆季俞章魯葛伍韋申尤畢聶叢焦'
n = 7
table =[[xing[x-1] for x in range(2**i, 2**n+1) if x & 2**i != 0] for i inrange(n)]
x0, y0, h, w = -400, 600, 25, 60 #分別存儲了第一張表格的左上角坐標(biāo)、高度和寬度
draw_table(x0, y0,h, w, table)
num = input('輸入二進(jìn)制編碼:')
print(f'{xing[int(num[::-1],2)-1]}先生/女士,你好过蹂!')
tt.done()