這篇文章主要介紹“怎么用一個(gè)整數(shù)來(lái)表示一個(gè)列表”,在日常操作中,相信很多人在怎么用一個(gè)整數(shù)來(lái)表示一個(gè)列表問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”怎么用一個(gè)整數(shù)來(lái)表示一個(gè)列表”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
公司主營(yíng)業(yè)務(wù):成都做網(wǎng)站、成都網(wǎng)站制作、移動(dòng)網(wǎng)站開(kāi)發(fā)等業(yè)務(wù)。幫助企業(yè)客戶(hù)真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)建站是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開(kāi)放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶(hù)帶來(lái)驚喜。創(chuàng)新互聯(lián)建站推出田東免費(fèi)做網(wǎng)站回饋大家。
與 C、Rust 和 Go 不同,Python 默認(rèn)的int
具有任意大小。[注1] 、[注2]
這意味著,一個(gè)整數(shù)可以存儲(chǔ)無(wú)限大的值,只要內(nèi)存足夠。
例如,你可以打開(kāi) Python3 并運(yùn)行以下命令:
>>> import math
>>> math.factorial(2020)
[number omitted] # Python貓注:此處求2020的階乘,結(jié)果是一長(zhǎng)串?dāng)?shù)字,所以省略
>>> math.log2(math.factorial(2020))
19272.453841606068
>>> type(math.factorial(2020))
也就是說(shuō),在 Python 中,平常使用的 int 可以輕松地保存一個(gè)占用 19273 比特的 C 類(lèi)型固定大小無(wú)符號(hào) int 類(lèi)型的值(C-style fixed-size unsigned int )。在 Python 這樣的語(yǔ)言中,便利性高于速度和內(nèi)存效率,這確實(shí)很有用。
這種無(wú)限的精度,也意味著我們可以在單個(gè) int 中存儲(chǔ)任意數(shù)量的信息。只要編碼正確,一整本書(shū)、一整個(gè)數(shù)據(jù)庫(kù)、甚至任何東西,都可以被存入一個(gè)單獨(dú)的 Python int 中。
(Python貓注:這有一篇文章 ,深度剖析了Python整型不會(huì)溢出的實(shí)現(xiàn)原理,可作關(guān)聯(lián)閱讀)
因此,我們可以設(shè)想出一種 Python 的方言,它只有整型,需要用 int 表示其它所有的類(lèi)型(字典、列表、等等)。我們還有一些特殊的函數(shù)和方法,可以將 int 視為 list 、dict 等等。
這將會(huì)是一個(gè)有趣而好玩的練習(xí),而這就是本文想要做的事。
有一個(gè)顯而易見(jiàn)的實(shí)現(xiàn)方法:所有數(shù)據(jù)結(jié)構(gòu)只是內(nèi)存中的位數(shù)組(bit-arrays)。最壞的情況下,它是一組相關(guān)的位數(shù)組(例如,像鏈表或樹(shù)中的每個(gè)節(jié)點(diǎn)),并且它們的集合也只是位數(shù)組。位數(shù)組可以被解釋為二進(jìn)制數(shù)。所以我們必然能這樣做。但這有點(diǎn)無(wú)聊。
在本博文以及本系列的后續(xù)博文中,我將介紹一些用 int 來(lái)表示復(fù)雜數(shù)據(jù)結(jié)構(gòu)的方法。它們不一定是最緊湊、最合理或最有效的,其共同的目標(biāo)是找到這些數(shù)據(jù)結(jié)構(gòu)的有趣的表示方式。[注3]
我們要表示的第一個(gè)數(shù)據(jù)結(jié)構(gòu)是 list。我們將使用以邏輯學(xué)家 KurtG?del 命名的G?del數(shù)。為了方便起見(jiàn),我們僅處理由無(wú)符號(hào)整數(shù)(即自然數(shù))組成的列表。
哥德?tīng)枖?shù)的原理是令每個(gè)大于 1 的自然數(shù)都用唯一的質(zhì)數(shù)分解來(lái)表示。它依據(jù)的是算術(shù)的基本定理。
(Python貓注:質(zhì)數(shù)分解,即 prime factorization,又譯作質(zhì)因數(shù)分解、素因子分解等,指的是把每個(gè)數(shù)都寫(xiě)成用質(zhì)數(shù)相乘的形式)
看一些例子:
一個(gè)數(shù)字可以通過(guò)其質(zhì)因子(prime factors )的指數(shù)列表來(lái)唯一標(biāo)識(shí)(直到其最高位的非零指數(shù))。所以,我們可以用 126 來(lái)表示列表[1, 2, 0, 1] 。列表中的第一個(gè)數(shù)字是 126 作質(zhì)數(shù)分解后 2 的指數(shù),第二個(gè)數(shù)是 3 的指數(shù),依此類(lèi)推。
再來(lái)幾個(gè)例子:
如果列表末尾有 0 ,該怎么辦呢?好吧,基于這樣的編碼,不會(huì)出現(xiàn)這種情況。
在我們的質(zhì)數(shù)分解中,指數(shù)為 0 的質(zhì)數(shù)可能有無(wú)限個(gè),因此我們需要停在某個(gè)地方。[注4] 我們選擇在最后一個(gè)非零指數(shù)處停止。
當(dāng)列表中包含較大的數(shù)字時(shí),這種表示形式也會(huì)使用非常大的數(shù)字。那是因?yàn)榱斜碇械臄?shù)字表示的是指數(shù),所以 int 的大小與它們成指數(shù)增長(zhǎng)。例如,[50, 1000, 250] 需要使用大小為 2266 比特的數(shù)字表示。
另一方面,相比于其它用 int 編碼的列表,那些包含非常多小整數(shù)的長(zhǎng)列表,尤其是大型稀疏列表(即大部分的值都為 0),則擁有非常緊湊的表示形式。
提醒一下,將 list 編碼為 int,這不是很好的編程實(shí)踐,僅僅是一個(gè)好玩的實(shí)驗(yàn)。
讓我們看一下 Python 的實(shí)現(xiàn)。這里有幾點(diǎn)注意事項(xiàng):
我們會(huì)使用帶有 yield 的函數(shù),因?yàn)樗鼧O大地簡(jiǎn)化了操作。[注5]
你會(huì)看到大量的 while 循環(huán)。這是因?yàn)榱斜砩墒?、range 和大多數(shù)你打算在 for 循環(huán)中使用的東西,都被禁止用在只有 int 類(lèi)型的方言中。所有這些都被 while 循環(huán)替代了。
我們要編寫(xiě)的第一個(gè)函數(shù)是一個(gè)迭代器,它將按順序生成質(zhì)數(shù)。它從頭到尾都很關(guān)鍵。這里的實(shí)現(xiàn)是最簡(jiǎn)單可行的版本。
我可能很快會(huì)寫(xiě)一篇完整的關(guān)于生成質(zhì)數(shù)的算法的文章,因?yàn)檫@是一個(gè)很酷的話題,本身也是一個(gè)古老的研究領(lǐng)域。最廣為人知的算法是愛(ài)拉托遜斯篩法(Sieve of Erathosthenes ),但這只是冰山一角。[注6]
在這里,一個(gè)非常幼稚的實(shí)現(xiàn)就夠了:
def primes(starting: int = 2):
"""Yield the primes in order.
Args:
starting: sets the minimum number to consider.
Note: `starting` can be used to get all prime numbers
_larger_ than some number. By default it doesn't skip
any candidate primes.
"""
candidate_prime = starting
while True:
candidate_factor = 2
is_prime = True
# We'll try all the numbers between 2 and
# candidate_prime / 2. If any of them divide
# our candidate_prime, then it's not a prime!
while candidate_factor <= candidate_prime // 2:
if candidate_prime % candidate_factor == 0:
is_prime = False
break
candidate_factor += 1
if is_prime:
yield candidate_prime
candidate_prime += 1
def empty_list() -> int:
"""Create a new empty list."""
# 1 is the empty list. It isn't divisible by any prime.
return 1
def iter_list(l: int):
"""Yields elements in the list, from first to last."""
# We go through each prime in order. The next value of
# the list is equal to the number of times the list is
# divisible by the prime.
for p in primes():
# We decided we will have no trailing 0s, so when
# the list is 1, it's over.
if l <= 1:
break
# Count the number of divisions until the list is
# not divisible by the prime number.
num_divisions = 0
while l % p == 0:
num_divisions += 1
l = l // p # could be / as well
yield num_divisions
def access(l: int, i: int) -> int:
"""Return i-th element of l."""
# First we iterate over all primes until we get to the
# ith prime.
j = 0
for p in primes():
if j == i:
ith_prime = p
break
j += 1
# Now we divide the list by the ith-prime until we
# cant divide it no more.
num_divisions = 0
while l % ith_prime == 0:
num_divisions += 1
l = l // ith_prime
return num_divisions
def append(l: int, elem: int) -> int:
# The first step is finding the largest prime factor.
# We look at all primes until l.
# The next prime after the last prime factor is going
# to be the base we need to use to append.
# E.g. if the list if 18 -> 2**1 * 3**2 -> [1, 2]
# then the largest prime factor is 3, and we will
# multiply by the _next_ prime factor to some power to
# append to the list.
last_prime_factor = 1 # Just a placeholder
for p in primes():
if p > l:
break
if l % p == 0:
last_prime_factor = p
# Now get the _next_ prime after the last in the list.
for p in primes(starting=last_prime_factor + 1):
next_prime = p
break
# Now finally we append an item by multiplying the list
# by the next prime to the `elem` power.
return l * next_prime ** elem
你可以打開(kāi)一個(gè) Python、iPython 或 bPython會(huì)話,并試試這些函數(shù)!
建議列表元素使用從 1 到 10 之間的數(shù)字。如果使用比較大的數(shù)字,則 append 和 access 可能會(huì)花費(fèi)很長(zhǎng)時(shí)間。
從某種程度上說(shuō),使用哥德?tīng)枖?shù)來(lái)表示列表并不實(shí)用,盡管可以通過(guò)優(yōu)化質(zhì)數(shù)生成及分解算法,來(lái)極大地?cái)U(kuò)大可用數(shù)值的范圍。
In [16]: l = empty_list()
In [17]: l = append(l, 2)
In [18]: l = append(l, 5)
In [19]: list(iter_list(l))
Out[19]: [2, 5]
In [20]: access(l, 0)
Out[20]: 2
In [21]: access(l, 1)
Out[21]: 5
In [22]: l
Out[22]: 972 # Python貓注:2^2*3^5=972
我們看到了一種將自然數(shù)列表表示為 int 的方法。還有其它更實(shí)用的方法,這些方法依賴(lài)于將數(shù)字的二進(jìn)制形式細(xì)分為大小不一的塊。我相信你可以提出這樣的建議。
我以后可能會(huì)寫(xiě)其它文章,介紹更好的用于生成和分解質(zhì)數(shù)的算法,以及其它復(fù)雜數(shù)據(jù)結(jié)構(gòu)的 int 表示形式。
到此,關(guān)于“怎么用一個(gè)整數(shù)來(lái)表示一個(gè)列表”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!