python的heap
『壹』 python堆和棧的區別有哪些
堆(Heap)與棧(Stack)是開發人員必須面對的兩個概念,在理解這兩個概念時,需要放到具體的場景下,因為不同場景下,堆與棧代表不同的含義。一般情況下,有兩層含義:
(1)程序內存布局場景下,堆與棧表示的是兩種內存管理方式;
(2)數據結構場景下,堆與棧表示兩種常用的數據結構。
相關推薦:《Python教程》
堆與棧實際上是操作系統對進程佔用的內存空間的兩種管理方式,主要有如下幾種區別:
(1)管理方式不同。棧由操作系統自動分配釋放,無需我們手動控制;堆的申請和釋放工作由程序員控制,容易產生內存泄漏;
(2)空間大小不同。每個進程擁有的棧的大小要遠遠小於堆的大小。理論上,程序員可申請的堆大小為虛擬內存的大小,進程棧的大小 64bits 的 Windows 默認 1MB,64bits 的 Linux 默認 10MB;
(3)生長方向不同。堆的生長方向向上,內存地址由低到高;棧的生長方向向下,內存地址由高到低。
(4)分配方式不同。堆都是動態分配的,沒有靜態分配的堆。棧有2種分配方式:靜態分配和動態分配。靜態分配是由操作系統完成的,比如局部變數的分配。動態分配由alloca函數進行分配,但是棧的動態分配和堆是不同的,他的動態分配是由操作系統進行釋放,無需我們手工實現。
(5)分配效率不同。棧由操作系統自動分配,會在硬體層級對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是由C/C++提供的庫函數或運算符來完成申請與管理,實現機制較為復雜,頻繁的內存申請容易產生內存碎片。顯然,堆的效率比棧要低得多。
(6)存放內容不同。棧存放的內容,函數返回地址、相關參數、局部變數和寄存器內容等。當主函數調用另外一個函數的時候,要對當前函數執行斷點進行保存,需要使用棧來實現,首先入棧的是主函數下一條語句的地址,即擴展指針寄存器的內容(EIP),然後是當前棧幀的底部地址,即擴展基址指針寄存器內容(EBP),再然後是被調函數的實參等,一般情況下是按照從右向左的順序入棧,之後是被調函數的局部變數,注意靜態變數是存放在數據段或者BSS段,是不入棧的。出棧的順序正好相反,最終棧頂指向主函數下一條語句的地址,主程序又從該地址開始執行。堆,一般情況堆頂使用一個位元組的空間來存放堆的大小,而堆中具體存放內容是由程序員來填充的。
從以上可以看到,堆和棧相比,由於大量malloc()/free()或new/delete的使用,容易造成大量的內存碎片,並且可能引發用戶態和核心態的切換,效率較低。棧相比於堆,在程序中應用較為廣泛,最常見的是函數的調用過程由棧來實現,函數返回地址、EBP、實參和局部變數都採用棧的方式存放。雖然棧有眾多的好處,但是由於和堆相比不是那麼靈活,有時候分配大量的內存空間,主要還是用堆。
無論是堆還是棧,在內存使用時都要防止非法越界,越界導致的非法內存訪問可能會摧毀程序的堆、棧數據,輕則導致程序運行處於不確定狀態,獲取不到預期結果,重則導致程序異常崩潰,這些都是我們編程時與內存打交道時應該注意的問題。
『貳』 Python對數據進行排序-中英文
sort_values(by,axis=0,ascending=True,inplace=False,kind='quicksort',na_position='last')
參數說明:
by: 可以填入字元串或者字元串組成的列表。也就是說, 如果axis=0,那麼by="列名";如果axis=1,那麼by="行名"。
axis: {0 or 『index』, 1 or 『columns』}, default 0,意思就是如果 axis=0,就按照索引排序,即縱向排序;如果axis=1,則按列排序,即橫向排序。默認是axis=0 。
ascending: 輸入布爾型, True是升序 , False是降序 ,也可以可以是[True,False],即第一個欄位升序,第二個欄位降序 。
inplace : 輸入布爾型,是否用排序後的數據框替換現有的數據框
kind: 排序的方法,{『quicksort』, 『mergesort』, 『heapsort』},默認是使用『quicksort』。這個參數用的比較少,大家可以試一試。
na_position : {『first』, 『last』}, 缺失值的排序 ,也就說決定將缺失值放在數據的最前面還是最後面 。first是排在前面,last是排在後面,默認是用last 。
例子:
scores= pd.DataFrame([[87,56,85],[46,87,97],[34,65,86]],columns=['jack', 'rose', 'mike'])
scores
1.對『rose』這一列進行降序排序:
df_sc=scores.sort_values(by='rose',ascending=False)
df_sc
2.對第0行進行升序排序:
scores.sort_values(by=0,axis=1,ascending=True)
3.第1行進行升序,第0行進行降序:
scores.sort_values(by=[1,0],axis=1,ascending=[True,False]
4.觀察數據
data.head:
查看數據的前五行。
data.tail:
查看數據的後五行。
data.shape :
查看矩陣或數組的維數,或者是說數據表的結構(有幾行幾列)。
data.info :
查看數據的基本信息,如:數據類型、缺失值數量等。
#brand目標:中文-中英-英文
2.1 包含中文,純英文
for i in range(0,len(file1)):
result = re.compile(u'[\u4e00-\u9fa5]')
contents = file1['brand'][i]
match = result.search(contents)
if match:
file1.loc[i,['index1']]=0 #0為包含中文
else:
file1.loc[i,['index1']]=1 #1為純英文
2.1 包含英文,純中文
for i in range(0,len(file1)):
file1.loc[i,['index2']]=len(re.findall('[a-zA-Z]+', file1['brand'][i]) ) #0為純中文,1為包含英文
『叄』 python中有哪些簡單的演算法
你好:
跟你詳細說一下python的常用8大演算法:
1、插入排序
插入排序的基本操作就是將一個數據插入到已經排好序的有序數據中,從而得到一個新的、個數加一的有序數據,演算法適用於少量數據的排序,時間復雜度為O(n^2)。是穩定的排序方法。插入演算法把要排序的數組分成兩部分:第一部分包含了這個數組的所有元素,但將最後一個元素除外(讓數組多一個空間才有插入的位置),而第二部分就只包含這一個元素(即待插入元素)。在第一部分排序完成後,再將這個最後元素插入到已排好序的第一部分中。
2、希爾排序
希爾排序(Shell Sort)是插入排序的一種。也稱縮小增量排序,是直接插入排序演算法的一種更高效的改進版本。希爾排序是非穩定排序演算法。該方法因DL.Shell於1959年提出而得名。 希爾排序是把記錄按下標的一定增量分組,對每組使用直接插入排序演算法排序;隨著增量逐漸減少,每組包含的關鍵詞越來越多,當增量減至1時,整個文件恰被分成一組,演算法便終止。
3、冒泡排序
它重復地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重復地進行直到沒有再需要交換,也就是說該數列已經排序完成。
4、快速排序
通過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的所有數據都比另外一部分的所有數據都要小,然後再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。
5、直接選擇排序
基本思想:第1趟,在待排序記錄r1 ~ r[n]中選出最小的記錄,將它與r1交換;第2趟,在待排序記錄r2 ~ r[n]中選出最小的記錄,將它與r2交換;以此類推,第i趟在待排序記錄r[i] ~ r[n]中選出最小的記錄,將它與r[i]交換,使有序序列不斷增長直到全部排序完畢。
6、堆排序
堆排序(Heapsort)是指利用堆積樹(堆)這種數據結構所設計的一種排序演算法,它是選擇排序的一種。可以利用數組的特點快速定位指定索引的元素。堆分為大根堆和小根堆,是完全二叉樹。大根堆的要求是每個節點的值都不大於其父節點的值,即A[PARENT[i]] >= A[i]。在數組的非降序排序中,需要使用的就是大根堆,因為根據大根堆的要求可知,最大的值一定在堆頂。
7、歸並排序
歸並排序是建立在歸並操作上的一種有效的排序演算法,該演算法是採用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合並,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合並成一個有序表,稱為二路歸並。
歸並過程為:比較a[i]和a[j]的大小,若a[i]≤a[j],則將第一個有序表中的元素a[i]復制到r[k]中,並令i和k分別加上1;否則將第二個有序表中的元素a[j]復制到r[k]中,並令j和k分別加上1,如此循環下去,直到其中一個有序表取完,然後再將另一個有序表中剩餘的元素復制到r中從下標k到下標t的單元。歸並排序的演算法我們通常用遞歸實現,先把待排序區間[s,t]以中點二分,接著把左邊子區間排序,再把右邊子區間排序,最後把左區間和右區間用一次歸並操作合並成有序的區間[s,t]。
8、基數排序
基數排序(radix sort)屬於「分配式排序」(distribution sort),又稱「桶子法」(bucket sort)或bin sort,顧名思義,它是透過鍵值的部分資訊,將要排序的元素分配至某些「桶」中,藉以達到排序的作用,基數排序法是屬於穩定性的排序,其時間復雜度為O (nlog(r)m),其中r為所採取的基數,而m為堆數,在某些時候,基數排序法的效率高於其它的穩定性排序法。
『肆』 Python headq模塊淺析
參考:
heapq Documentation
淺析Python heapq模塊 堆數據結構
在Python中也對堆這種數據結構進行了模塊化,我們可以通過調用heapq模塊來建立堆這種數據結構,同時heapq模塊也提供了相應的方法來對堆做操作。
heap = [] #創建了一個空堆
item = heap[0] #查看堆中最小值,不彈出
heappush(heap,item) #往堆中插入一條新的值
item = heappop(heap) #從堆中彈出最小值, 如果堆為空報 IndexError 異常
heappushpop() #1.將值插入到堆中 2.彈出堆中的最小值。
P.S. 1. 可以保證彈出最小元素 2. 效率比先heappush再heappop快
heapify(x) #以線性時間講一個列表轉化為堆
item = heapreplace(heap,item) #彈出並返回最小值,然後將heapqreplace方法中item的值插入到堆中,堆的整體結構不會發生改變。如果堆為空報 IndexError 異常。 在需要保證堆大小不變的適合使用 。
P.S. 1. 彈出的元素可能比加入的item大 2. 效率比先heappop再heappush快
merge(*iterables, key=None, reverse=False) #合並多個堆然後輸出
nlargest(n , iterbale, key=None) #從堆中找出做大的N個數,key的作用和sorted( )方法裡面的key類似,用列表元素的某個屬性和函數作為關鍵字
nsmallest(n, iterable, key=None) #找到堆中最小的N個數用法同上
該段為heapq Documentation里節選的翻譯
堆作為數據結構在內存和二級緩存中充當了重要的角色。優先隊列中也會經常使用堆,這也就給堆數據結構提出了很多挑戰。例如內存中存放了數多個計劃任務的時候我們可以定義一個數列list(priority,task)來保存在堆結構中。但是這樣就出現了很多問題 :
1.排序的穩定性:當任務加入到堆中時,如果兩個任務有同等的優先順序,兩個任務實際上在列表裡是沒什麼區別的,那我怎麼得到返回值?
2.在Python3以後的版本中,如果元組(priority,task)priority是一樣的,而且task沒有一個默認的比較參照值,那這樣我們其實是沒有辦法來比較的。
3.如果一個任務的優先順序發生了改變,那麼我們如何來處理該任務在相應堆中優先順序的變化,堆中位置肯定會改變。
4.如果一個任務因為要等待其他的任務(最簡單的比方,等待父進程)而照成懸掛狀態,我們如何在堆中去找到它並且做相應的操作(降低優先順序或者刪除該任務)
解決前兩個問題的方法我們可以採用三元數組的方法。設置一個優先順序,一個條目值,一個任務值。即使當兩個任務有相同優先順序的時候,因為條目值不一樣可以幫助cpu來裁決它們被載入的順序。
剩下需要解決的問題是如何找到被懸掛而推遲的任務,然後嘗試去修改優先順序或者永久刪除這個任務。我們可以使用字典,來指向堆中某個任務的條目值。
最後就是刪除操作,刪除會改變堆的結構。為了保證堆結構的特性,我們可以標記已有將被刪除的任務的條目值,然後將該任務重新打標加入到堆中。
『伍』 Python高級數據結構——堆
在一個 最小堆 (min heap) 中,如果 P 是 C 的一個父級節點,那麼 P 的 key(或 value) 應小於或等於 C 的對應值。 正因為此,堆頂元素一定是最小的,我們會利用這個特點求最小值或者第 k 小的值。
在一個 最大堆 (max heap) 中,P 的 key(或 value) 大於或等於 C 的對應值。
以python為例,說明堆的幾個常見操作,這里需要用到一個內置的包:heapq
python中使用堆是通過傳入一個數組,然後調用一個函數,在原地讓傳入的數據具備堆的特性
需要注意的是,heapify默認構造的是小頂堆(min heap),如果要構造大頂堆,思路是把所有的數值倒轉,既* -1,例如:
使用heapq提供的函數: heappop 來實現
具體使用方式參考 初始化Heapify
使用heapq提供的函數: heappush 來實現
同時heapq還提供另外一個函數: heappushpop ,能夠在一個函數實現push&pop兩個操作;順序是:先push再pop
根據官方文檔的描述,這個函數會比先在外圍先調用heappush,再調用heappop,效率更高
先pop數據再push數據,和heappushpop的順序是反著的; 同樣的,這樣調用的性能也會比先調用heappop再調用heappush更好
如果pop的時候隊列是空的,會拋出一個異常
可以通過 heapq.merge 將多個 已排序 的輸入合並為一個已排序的輸出,這個本質上不是堆;其實就是用兩個指針迭代
對於這個問題,有一個演算法題可以實現相同的功能
從 iterable 所定義的數據集中返回前 n 個最大/小元素組成的列表。
函數為: heapq.nlargest() | heapq.nsmallest()
heapq - Heap queue algorithm - Python 3.10.4 documentation