您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關python中搜索的示例分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
搜索是指從元素集合中找到某個特定元素的算法過程。搜索過程通常返回 True 或 False, 分別表示元素是否存在。python
中提供了 in 方法可以判斷元素是否存在列表中:
# python提供in函數(shù)進行搜索 a=[3,4,5,8,'t'] 't' in a 9 in a
結果如下:
順序搜索故名思義:從列表中的第一個元素開始,沿著默認的順序逐個查看, 直到找到目標元素或者查完列表。如果查完列表后仍沒有找到目標元素,則說明目標元素不在列表中。
順序搜索過程:
無序下的順序搜索很有特點,列表無序,只好一個一個去比較,尋找元素。
#順序查找 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
結果如下:
分析一下這種順序查找,這種查找方式,最好的方式就尋找一次就成功了,最壞的情況的需要查找n次,于是時間復雜度是O(n)
有序下的順序查找就是所查找的列表是有序的,
# 有序下的順序搜索 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
結果如下:
分析一下這種搜索方法,正常情況下來說,最好情況下,搜索1次就能成功,最差情況只需要n/2次即可搜索完成,但時間復雜度依舊是O(n),只有當列表中不存在目標元素時,有序排列的元素才會提高順序搜索的效率。
二分查找:是利用列表有序的這個原理,從中間的元素著手。如果這個元素就是目標元素,那就立即停止搜索;如果不是,則可以利用列表有序的特性,排除一半的元素。如果目標元素比中間的元素大,就可以直接排除列表的左半部分和中間的元素。這是因為,如果列表包含目標元素,它必定位于右半部分。
在有序整數(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 binarysearch3(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 binarysearch3(testlist[:mid], item) else: return binarysearch3(testlist[mid+1:], item)
看看效果:
總結一下二分查找:在進行二分搜索時,每一次比較都將待考慮的元素減半,。那么,要檢查完整個列表,二分搜索算法最多要比較多少次呢?假設列表共有 n 個元素,第一次比較后剩下n 個元素,第 2 次比較2后剩下n /4個元素,接下來是n/8 ,然后是n/16 ,依此類推。列表能拆分多少次?
二分搜索算法的表格分:
拆分足夠多次后,會得到只含一個元素的列表。這個元素要么就是目標元素,要么不是。無論是哪種情況,計算工作都已完成。要走到這一步,需要比較 i 次,其中n 2 i {n}\over{2^i}
2
i
n
=1 。由此可得比較次數(shù)的最大值與列表的元素個數(shù)是對數(shù)關系。所以,二分搜索算法的時間復雜度是O ( l o g 2 n ) O(log_2 n)O(log
2
n)。
散列查找:通過散列構建一個時間復雜度為 O(1)的數(shù)據(jù)結構。我們平常聽的最多哈希表就是散列的一種方式。
散列表:散列表是元素集合,其中的元素以一種便于查找的方式存儲。散列表中的每個位置通常被稱 為槽,其中可以存儲一個元素。槽用一個從 0 開始的整數(shù)標記,例如 0 號槽、1 號槽、2 號槽, 等等。初始情形下,散列表中沒有元素,每個槽都是空的??梢杂昧斜韥韺崿F(xiàn)散列表,并將每個元素都初始化為 Python 中的特殊值 None。下圖展示了大小 m 為 11 的散列表。也就是說,表中有 m 個槽,編號從 0 到 10。
有11 個槽的散列表:
:
散列函數(shù):將散列表中的元素與其所屬位置對應起來。對散列表中的任一元素,散列函數(shù)返回 一個介于 0 和 m – 1 之間的整數(shù)。假設有一個由整數(shù)元素 54、26、93、17、77 和 31 構成的集 合。首先來看第一個散列函數(shù),它有時被稱作“取余函數(shù)”,即用一個元素除以表的大小,并將 得到的余數(shù)作為散列值(h(item) = item%11)。下圖給出了所有示例元素的散列值。取余函數(shù)是一個很常見的散列函數(shù),這是因為結果必須在槽編號范圍內(nèi)。
使用余數(shù)作為散列值:
計算出散列值后,就可以將每個元素插入到相應的位置,如圖 5-5 所示。注意,在 11 個槽 中,有 6 個被占用了。占用率被稱作載荷因子,記作λ \lambdaλ,定義如下:
有 6 個元素的散列表:
給定一個元素集合,能將每個元素映射到不同的槽,這種散列函數(shù)稱作完美散列函數(shù)。如果元素已知,并且集合不變,那么構建完美散列函數(shù)是可能的。不幸的是,給定任意一個元素集合,沒有系統(tǒng)化方法來保證散列函數(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ù)值相加,并采用取余法得到散列值。
完美的散列表,一個元素只對應著一個卡槽,可是如果當2個元素被分配到一個卡槽時,必須通過一種系統(tǒng)化方法在散列表中安置第二個元素。這個過程被稱為處理沖突。
開發(fā)定址法:在散列表中找到另一個空槽,用于放置引起沖突的元素。簡單的做法是從起初的散列值開始,順序遍歷散列表,直到找到一個空槽。注意,為了遍歷散列表,可能需要往回檢查第一個槽。(例如:將(54, 26, 93, 17, 77, 31, 44, 55, 20)放入卡槽中。)
再散列:采用“加 3”探測策略處理沖突后的元素分布情況。發(fā)生沖突時,為了找到空槽,該策略每次跳兩個槽。
平方探測:線性探測的一個變體,它不采用固定的跨步大小,而是通過再散列函數(shù)遞增散列 值。如果第一個散列值是 h,后續(xù)的散列值就是 h+1、h+4、h+9、h+16,等等。換句話說,平方探測的跨步大小是一系列完全平方。
鏈接法:允許散列 表中的同一個位置上存在多個元素。發(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)
結果如下:
我們分析一下散列查找:在最好情況下,散列搜索算法的時間復雜度是 O(1),即常數(shù)階。但可能發(fā)生沖突,所以比較次數(shù)通常不會這么簡單。
關于“python中搜索的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。