python數(shù)據(jù)結(jié)構(gòu)之搜索講解
往期學(xué)習(xí):
python數(shù)據(jù)類型: python數(shù)據(jù)結(jié)構(gòu):數(shù)據(jù)類型.
python的輸入輸出: python數(shù)據(jù)結(jié)構(gòu)之輸入輸出及控制和異常.
python面向?qū)ο? python數(shù)據(jù)結(jié)構(gòu)面向?qū)ο?
python算法分析: python數(shù)據(jù)結(jié)構(gòu)之算法分析.
python棧、隊列和雙端隊列:python數(shù)據(jù)結(jié)構(gòu)棧、隊列和雙端隊列.
python遞歸: python數(shù)據(jù)結(jié)構(gòu)之遞歸.
上一期講的遞歸,對于初學(xué)者其實是不太友好的,遞歸需要自己多去接觸,自己多畫畫圖,這樣可以加強理解遞歸的過程,本期我們要講的內(nèi)容是搜索,也可以叫查找。我將講解幾種最為普遍的查找算法。
1. 普通搜索
搜索是指從元素集合中找到某個特定元素的算法過程。搜索過程通常返回 True 或 False, 分別表示元素是否存在。python
中提供了 in 方法可以判斷元素是否存在列表中:
# python提供in函數(shù)進行搜索 a=[3,4,5,8,'t'] 't' in a 9 in a
結(jié)果如下:
2. 順序搜索
順序搜索故名思義:從列表中的第一個元素開始,沿著默認的順序逐個查看, 直到找到目標(biāo)元素或者查完列表。如果查完列表后仍沒有找到目標(biāo)元素,則說明目標(biāo)元素不在列表中。
順序搜索過程:
1.1 無序下的順序查找
無序下的順序搜索很有特點,列表無序,只好一個一個去比較,尋找元素。
#順序查找 def sequentialsearch(testlist,item): pos=0 found=False while pos<len(testlist) and not found: if testlist[pos]==item: found=True else: pos=pos+1 return found
結(jié)果如下:
分析一下這種順序查找,這種查找方式,最好的方式就尋找一次就成功了,最壞的情況的需要查找n次,于是時間復(fù)雜度是O(n)
1.2 有序下的順序查找
有序下的順序查找就是所查找的列表是有序的,
# 有序下的順序搜索 def ordersearch(testlist,item): pos=0 found=False stop=False while pos<len(testlist) and not found and not stop: if testlist[pos]==item: found=True else: if testlist[pos]>item: stop=True else: pos=pos+1 return found
結(jié)果如下:
分析一下這種搜索方法,正常情況下來說,最好情況下,搜索1次就能成功,最差情況只需要n/2次即可搜索完成,但時間復(fù)雜度依舊是O(n),只有當(dāng)列表中不存在目標(biāo)元素時,有序排列的元素才會提高順序搜索的效率。
2.二分查找
二分查找:是利用列表有序的這個原理,從中間的元素著手。如果這個元素就是目標(biāo)元素,那就立即停止搜索;如果不是,則可以利用列表有序的特性,排除一半的元素。如果目標(biāo)元素比中間的元素大,就可以直接排除列表的左半部分和中間的元素。這是因為,如果列表包含目標(biāo)元素,它必定位于右半部分。
在有序整數(shù)列表中進行二分搜索:
二分查找實現(xiàn)方式:
def binarysearch(testlist,item): testlist.sort()#排序 left=0#左指針 right=len(testlist)-1#右指針 found=False while left<=right and not found: mid=(left+right)//2#取中間值 if testlist[mid]==item: found=True else: if testlist[mid]<item: left=mid+1 else: right=mid-1 return found
看看效果:
二分查找遞歸實現(xiàn):
def binarysearch2(testlist,item): if len(testlist) == 0: return False else: mid = len(testlist) // 2 if testlist[mid] == item: return True else: if item < testlist[mid]: return binarysearch2(testlist[:mid], item) else: return binarysearch2(testlist[mid+1:], item)
看看效果:
總結(jié)一下二分查找:在進行二分搜索時,每一次比較都將待考慮的元素減半,。那么,要檢查完整個列表,二分搜索算法最多要比較多少次呢?假設(shè)列表共有 n 個元素,第一次比較后剩下n 個元素,第 2 次比較2后剩下n /4個元素,接下來是n/8 ,然后是n/16 ,依此類推。列表能拆分多少次?
二分搜索算法的表格分:
3.散列查找
散列查找:通過散列構(gòu)建一個時間復(fù)雜度為 O(1)的數(shù)據(jù)結(jié)構(gòu)。我們平常聽的最多哈希表就是散列的一種方式。
散列表:散列表是元素集合,其中的元素以一種便于查找的方式存儲。散列表中的每個位置通常被稱 為槽,其中可以存儲一個元素。槽用一個從 0 開始的整數(shù)標(biāo)記,例如 0 號槽、1 號槽、2 號槽, 等等。初始情形下,散列表中沒有元素,每個槽都是空的??梢杂昧斜韥韺崿F(xiàn)散列表,并將每個元素都初始化為 Python 中的特殊值 None。下圖展示了大小 m 為 11 的散列表。也就是說,表中有 m 個槽,編號從 0 到 10。
有11 個槽的散列表:
:
散列函數(shù):將散列表中的元素與其所屬位置對應(yīng)起來。對散列表中的任一元素,散列函數(shù)返回 一個介于 0 和 m – 1 之間的整數(shù)。假設(shè)有一個由整數(shù)元素 54、26、93、17、77 和 31 構(gòu)成的集 合。首先來看第一個散列函數(shù),它有時被稱作“取余函數(shù)”,即用一個元素除以表的大小,并將 得到的余數(shù)作為散列值(h(item) = item%11)。下圖給出了所有示例元素的散列值。取余函數(shù)是一個很常見的散列函數(shù),這是因為結(jié)果必須在槽編號范圍內(nèi)。
使用余數(shù)作為散列值:
計算出散列值后,就可以將每個元素插入到相應(yīng)的位置,如圖 5-5 所示。注意,在 11 個槽 中,有 6 個被占用了。占用率被稱作載荷因子,記作λ \lambdaλ,定義如下:
有 6 個元素的散列表:
3.1 幾種散列函數(shù)
給定一個元素集合,能將每個元素映射到不同的槽,這種散列函數(shù)稱作完美散列函數(shù)。如果元素已知,并且集合不變,那么構(gòu)建完美散列函數(shù)是可能的。不幸的是,給定任意一個元素集合,沒有系統(tǒng)化方法來保證散列函數(shù)是完美的。所幸,不完美的散列函數(shù)也能有不錯的性能。
- 折疊法:先將元素切成等長的部分(最后一部分的長度可能不同),然后將這些部分相加,得到散列值。假設(shè)元素是電話號碼 436-555-4601,以 2 位為一組進行切分,得到 43、65、55、46 和 01。將這些數(shù)字相加后,得到 210。
- 平方取中法:先將元素取平方,然后提取中間幾位數(shù)。如果元素是 44,先計算 442=1936,然后提取中間兩位 93,繼續(xù)進行取余的步驟。
- 字符編碼:采用python中的ord函數(shù)將單詞“cat”看作序數(shù)值序列,再將這些序數(shù)值相加,并采用取余法得到散列值。
3.2 處理散列表沖突
完美的散列表,一個元素只對應(yīng)著一個卡槽,可是如果當(dāng)2個元素被分配到一個卡槽時,必須通過一種系統(tǒng)化方法在散列表中安置第二個元素。這個過程被稱為處理沖突。
開發(fā)定址法:在散列表中找到另一個空槽,用于放置引起沖突的元素。簡單的做法是從起初的散列值開始,順序遍歷散列表,直到找到一個空槽。注意,為了遍歷散列表,可能需要往回檢查第一個槽。(例如:將(54, 26, 93, 17, 77, 31, 44, 55, 20)放入卡槽中。)
3.3 散列表的實現(xiàn)(加1重復(fù))
哈希散列的實現(xiàn):
#哈希表 class HashTable: def __init__(self): self.size = 11 self.slots = [None] * self.size self.data = [None] * self.size def put(self, key, data): hashvalue = self.hashfunction(key, len(self.slots)) if self.slots[hashvalue] == None: self.slots[hashvalue] = key self.data[hashvalue] = data else: if self.slots[hashvalue] == key: self.data[hashvalue] = data #替換 else: nextslot = self.rehash(hashvalue, len(self.slots)) while self.slots[nextslot] != None and self.slots[nextslot] != key: nextslot = self.rehash(nextslot, len(self.slots)) if self.slots[nextslot] == None: self.slots[nextslot] = key self.data[nextslot] = data else: self.data[nextslot] = data #替換 def hashfunction(self, key, size): return key%size def rehash(self, oldhash, size): return (oldhash + 1)%size #get函數(shù) def get(self, key): startslot = self.hashfunction(key, len(self.slots)) data = None stop = False found = False position = startslot while self.slots[position] != None and not found and not stop: if self.slots[position] == key: found = True data = self.data[position] else: position=self.rehash(position, len(self.slots)) if position == startslot: stop = True return data def __getitem__(self, key): return self.get(key) def __setitem__(self, key, data): self.put(key, data)
結(jié)果如下:
我們分析一下散列查找:在最好情況下,散列搜索算法的時間復(fù)雜度是 O(1),即常數(shù)階。但可能發(fā)生沖突,所以比較次數(shù)通常不會這么簡單。
4.參考資料
- 《python數(shù)據(jù)結(jié)構(gòu)與算法》
- 《大話數(shù)據(jù)結(jié)構(gòu)》
到此這篇關(guān)于python數(shù)據(jù)結(jié)構(gòu)之搜索講解的文章就介紹到這了,更多相關(guān)python搜索講解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺析Python中壓縮zipfile與解壓縮tarfile模塊的使用
Python?提供了兩個標(biāo)準(zhǔn)庫模塊來處理文件的壓縮和解壓縮操作:zipfile和tarfile,本文將分享?這兩個模塊的使用方法,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-10-10Python基于Tkinter開發(fā)一個爬取B站直播彈幕的工具
這篇文章主要介紹了Python Tkinter如何開發(fā)一個爬取B站直播彈幕的工具,幫助大家更好的利用python進行圖形界面的開發(fā)學(xué)習(xí),感興趣的朋友可以了解下2021-05-05Pycharm 2to3配置,python2轉(zhuǎn)python3方式
這篇文章主要介紹了Pycharm 2to3配置,python2轉(zhuǎn)python3方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12解決Windows下PowerShell無法進入Python虛擬環(huán)境問題
這篇文章主要介紹了解決Windows下PowerShell無法進入Python虛擬環(huán)境問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-02-02