Python如何實現(xiàn)動態(tài)數(shù)組
Python序列類型
在本博客中,我們將學習探討Python的各種“序列”類,內(nèi)置的三大常用數(shù)據(jù)結構——列表類(list)、元組類(tuple)和字符串類(str)。
不知道你發(fā)現(xiàn)沒有,這些類都有一個很明顯的共性,都可以用來保存多個數(shù)據(jù)元素,最主要的功能是:每個類都支持下標(索引)訪問該序列的元素,比如使用語法 Seq[i]。其實上面每個類都是使用 數(shù)組 這種簡單的數(shù)據(jù)結構表示。
但是熟悉Python的讀者可能知道這3種數(shù)據(jù)結構又有一些不同:比如元組和字符串是不能修改的,列表可以修改。
計算機內(nèi)存中的數(shù)組結構
計算機體系結構中,我們知道計算機主存由位信息組成,這些位通常被歸類成更大的單元,這些單元則取決于精準的系統(tǒng)架構。一個典型的單元就是一個字節(jié),相當于8位。
計算機系統(tǒng)擁有龐大數(shù)量的存儲字節(jié),那么如何才能找到我們的信息存在哪個字節(jié)呢?答案就是大家平時熟知的 存儲地址 。基于存儲地址,主存中的任何字節(jié)都能被有效的訪問。實際上,每個存儲字節(jié)都和一個作為其地址的唯一二進制數(shù)字相關聯(lián)。如下圖中,每個字節(jié)均被指定了存儲地址:
一般來說,編程語言記錄標識符和其關聯(lián)值所存儲的地址之間的關系。比如,當我們聲明標識符 xx 就有可能和存儲器中的某一值相關聯(lián),而標識符 yy就可能和其他的值相關聯(lián)。一組相關的變量能夠一個接一個地存儲在計算機存儲器的一塊連續(xù)區(qū)域內(nèi)。我們將這種方式稱為 數(shù)組。
我們來看Python中的例子,一個文本字符串 HELLO 是以一列有序字符的形式存儲的,假定該字符串的每個Unicode字符需要兩個字節(jié)的存儲空間。最下面的數(shù)字就是該字符串的索引值。
我們可以看到,數(shù)組可以存儲多個值而無需構造具有特定索引的多個變量來指定其中的每個項目,并且?guī)缀踉谒芯幊陶Z言(例如C、Java、C#、C++)中使用,但是Python更具有優(yōu)勢。Python在構建列表時,熟悉的讀者可能知道,不需要預先定義數(shù)組或列表的大小,相反,在Python中,列表具有動態(tài)性質(zhì),我們可以不斷的往列表中添加我們想要的數(shù)據(jù)元素。接下來,讓我們看看Python列表的知識(已經(jīng)熟悉的讀者可以快速瀏覽或者跳過)。
Python列表
Python列表的操作
創(chuàng)建列表的語法格式:
[ele1, ele2, ele3, ele4, ...]
創(chuàng)建元組的語法格式:
(ele1, ele2, ele3, ele4, ...)
元組比列表的內(nèi)存空間利用率更高,因為元組是固定不變的,所以沒有必要創(chuàng)建擁有剩余空間的動態(tài)數(shù)組。
我們先在Python的IDE中創(chuàng)建一個列表,然后大致了解一下列表部分內(nèi)置操作,我們先創(chuàng)建了一個名為test_list的列表,然后修改(插入或刪除)元素,反轉(zhuǎn)或清空列表,具體如下:
>>> test_list = [] # 創(chuàng)建名為test_list的空列表 >>> test_list.append("Hello") >>> test_list.append("World") >>> test_list ['Hello', 'World'] >>> test_list = ["Hello", "Array", 2019, "easy learning", "DataStructure"] # 重新給test_list賦值 >>> len(test_list) # 求列表的長度 5 >>> test_list[2] = 1024 # 修改列表元素 >>> test_list ['Hello', 'Array', 1024, 'easy learning', 'DataStructure'] >>> >>> test_list.insert(1, "I love") # 向列表中指定位置中插入一個元素 >>> test_list ['Hello', 'I love', 'Array', 1024, 'easy learning', 'DataStructure'] >>> test_list.append(2020) # 向列表末尾增加一個元素 >>> test_list ['Hello', 'I love', 'Array', 1024, 'easy learning', 'DataStructure', 2020] >>> >>> test_list.pop(1) # 刪除指定位置的元素 'I love' >>> test_list.remove(2020) # 刪除指定元素 >>> >>> test_list.index('Hello') # 查找某個元素的索引值 0 >>> test_list.index('hello') # 如果查找某個元素不在列表中,返回ValueError錯誤 Traceback (most recent call last): File "<pyshell#11>", line 1, in <module> test_list.index('hello') ValueError: 'hello' is not in list >>> >>> test_list.reverse() # 反轉(zhuǎn)整個列表 >>> test_list ['DataStructure', 'easy learning', 2019, 'Array', 'Hello'] >>> test_list.clear() # 清空列表 >>> test_list []
我們看上面的代碼,可以看到list的相關操作——增刪改查,已經(jīng)很強大了,還有一些內(nèi)置方法這里并沒有做展示,留給讀者自己去發(fā)現(xiàn)并體驗。
那么Python內(nèi)置的list類是如何被實現(xiàn)的呢?
好吧,答案是動態(tài)數(shù)組。說到這里,不知道大家學Python列表的時候是不是這樣想的——列表很簡單嘛,就是list()類、用中括號[]括起來,然后指導書籍或文檔上的各類方法append、insert、pop...在IDE或者Pycharm一頓操作過后,是的我學會了。
但其實真的很不簡單,比如我舉個例子:A[-1]這個操作怎么實現(xiàn)?列表切片功能怎么實現(xiàn)?如何自己寫pop()默認刪除列表最右邊的元素(popleft刪除最左邊簡單)?...這些功能用起來爽,但真的自己實現(xiàn)太難了(我也還在學習中,大佬們請輕噴?。┤绻覀兡軐W習并理解,肯定可以加強我們對數(shù)組這一結構的理解。
動態(tài)數(shù)組
什么是動態(tài)數(shù)組
動態(tài)數(shù)組是內(nèi)存的連續(xù)區(qū)域,其大小隨著插入新數(shù)據(jù)而動態(tài)增長。在靜態(tài)數(shù)組中,我們需要在分配時指定大小。在定義數(shù)組的時候,其實計算機已經(jīng)幫我們分配好了內(nèi)存來存儲,實際上我們不能擴展數(shù)組,因為它的大小是固定的。比如:我們分配一個大小為10的數(shù)組,則不能插入超過10個項目。
但是動態(tài)數(shù)組會在需要的時候自動調(diào)整其大小。這一點有點像我們使用的Python列表,可以存儲任意數(shù)量的項目,而無需在分配時指定大小。
所以實現(xiàn)一個動態(tài)數(shù)組的實現(xiàn)的關鍵是——如何擴展數(shù)組?當列表list1的大小已滿時,而此時有新的元素要添加進列表,我們會執(zhí)行一下步驟來克服其大小限制的缺點:
- 分配具有更大容量的新數(shù)組 list2
- 設置 list2[i] = list1[i] (i=0,1,2,...,n-1),其中n是該項目的當前編號
- 設置list1 = list2,也就是說,list2正在作為新的數(shù)組來引用我們的新列表。
- 然后,只要將新的元素插入(添加)到我們的列表list1即可。
接下來要思考的問題是,新數(shù)組應該多大?通常我們得做法是:新數(shù)組的大小是已滿的舊數(shù)組的2倍。我們將在Python中編程實現(xiàn)動態(tài)數(shù)組的概念,并創(chuàng)建一個簡單的代碼,很多功能不及Python強大。
實現(xiàn)動態(tài)數(shù)組Python代碼
在Python中,我們利用ctypes的內(nèi)置庫來創(chuàng)建自己的動態(tài)數(shù)組類,因為ctypes模塊提供對原始數(shù)組的支持,為了更快的對數(shù)組進行學習,所以對ctypes的知識可以查看官方文檔進行學習。關于Python的公有方法與私有方法,我們在方法名稱前使用雙下劃線**__**使其保持隱藏狀態(tài),代碼如下:
# -*- coding: utf-8 -*- # @Time : 2019-11-01 17:10 # @Author : yuzhou_1su # @ContactMe : https://blog.csdn.net/yuzhou_1shu # @File : DynamicArray.py # @Software : PyCharm import ctypes class DynamicArray: """A dynamic array class akin to a simplified Python list.""" def __init__(self): """Create an empty array.""" self.n = 0 # count actual elements self.capacity = 1 # default array capacity self.A = self._make_array(self.capacity) # low-level array def is_empty(self): """ Return True if array is empty""" return self.n == 0 def __len__(self): """Return numbers of elements stored in the array.""" return self.n def __getitem__(self, i): """Return element at index i.""" if not 0 <= i < self.n: # Check it i index is in bounds of array raise ValueError('invalid index') return self.A[i] def append(self, obj): """Add object to end of the array.""" if self.n == self.capacity: # Double capacity if not enough room self._resize(2 * self.capacity) self.A[self.n] = obj # Set self.n index to obj self.n += 1 def _resize(self, c): """Resize internal array to capacity c.""" B = self._make_array(c) # New bigger array for k in range(self.n): # Reference all existing values B[k] = self.A[k] self.A = B # Call A the new bigger array self.capacity = c # Reset the capacity @staticmethod def _make_array(c): """Return new array with capacity c.""" return (c * ctypes.py_object)() def insert(self, k, value): """Insert value at position k.""" if self.n == self.capacity: self._resize(2 * self.capacity) for j in range(self.n, k, -1): self.A[j] = self.A[j-1] self.A[k] = value self.n += 1 def pop(self, index=0): """Remove item at index (default first).""" if index >= self.n or index < 0: raise ValueError('invalid index') for i in range(index, self.n-1): self.A[i] = self.A[i+1] self.A[self.n - 1] = None self.n -= 1 def remove(self, value): """Remove the first occurrence of a value in the array.""" for k in range(self.n): if self.A[k] == value: for j in range(k, self.n - 1): self.A[j] = self.A[j+1] self.A[self.n - 1] = None self.n -= 1 return raise ValueError('value not found') def _print(self): """Print the array.""" for i in range(self.n): print(self.A[i], end=' ') print()
測試動態(tài)數(shù)組Python代碼
上面我們已經(jīng)實現(xiàn)了一個動態(tài)數(shù)組的類,相信都很激動,接下來讓我們來測試一下,看能不能成功呢?在同一個文件下,寫的測試代碼如下:
def main(): # Instantiate mylist = DynamicArray() # Append new element mylist.append(10) mylist.append(9) mylist.append(8) # Insert new element in given position mylist.insert(1, 1024) mylist.insert(2, 2019) # Check length print('The array length is: ', mylist.__len__()) # Print the array print('Print the array:') mylist._print() # Index print('The element at index 1 is :', mylist[1]) # Remove element print('Remove 2019 in array:') mylist.remove(2019) mylist._print() # Pop element in given position print('Pop pos 2 in array:') # mylist.pop() mylist.pop(2) mylist._print() if __name__ == '__main__': main()
測試結果
激動人心的時刻揭曉,測試結果如下。請結合測試代碼和數(shù)組的結構進行理解,如果由疏漏,歡迎大家指出。
The array length is: 5 Print the array: 10 1024 2019 9 8 The element at index 1 is : 1024 Remove 2019 in array: 10 1024 9 8 Pop pos 2 in array: 10 1024 8
總結
通過以上的介紹,我們知道了數(shù)組存在靜態(tài)和動態(tài)類型。而在本博客中,我們著重介紹了什么是動態(tài)數(shù)組,并通過Python代碼進行實現(xiàn)。希望你能從此以復雜的方式學會數(shù)組。
總結發(fā)言,其實越是簡單的操作,背后實現(xiàn)原理可能很復雜。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
- python實現(xiàn)動態(tài)數(shù)組的示例代碼
- Python動態(tài)生成多維數(shù)組的方法示例
- Python 取numpy數(shù)組的某幾行某幾列方法
- 詳細整理python 字符串(str)與列表(list)以及數(shù)組(array)之間的轉(zhuǎn)換方法
- Python3之字節(jié)串bytes與字節(jié)數(shù)組bytearray的使用詳解
- python數(shù)組循環(huán)處理方法
- 對Python 中矩陣或者數(shù)組相減的法則詳解
- python切片(獲取一個子列表(數(shù)組))詳解
- 詳解Python Matplotlib解決繪圖X軸值不按數(shù)組排序問題
相關文章
Python3中條件控制、循環(huán)與函數(shù)的簡易教程
這篇文章主要給大家介紹了關于Python3中條件控制、循環(huán)與函數(shù)的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。2017-11-11Python實現(xiàn)將Excel內(nèi)容插入到Word模版中
前段時間因為需要處理一大堆驗收單,都是一些簡單的復制粘貼替換工作,于是就想到用python進行處理。本文分享了用python將excel文件單元格內(nèi)容插入到word模版中并保存為新文件的辦法,希望對大家有所幫助2023-03-03

python seaborn heatmap可視化相關性矩陣實例

利用python實現(xiàn)詞頻統(tǒng)計分析的代碼示例