這篇文章給大家分享的是有關(guān)python如何實(shí)現(xiàn)并查集的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。
為岱岳等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及岱岳網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都做網(wǎng)站、網(wǎng)站建設(shè)、岱岳網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專(zhuān)業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!并查集是一種樹(shù)型的數(shù)據(jù)結(jié)構(gòu),用于處理一些不相交集合的合并及查詢問(wèn)題。常常在使用中以森林來(lái)表示。
并查集有三種基本操作,獲得根節(jié)點(diǎn),判斷兩節(jié)點(diǎn)是否連通,以及將兩不連通的節(jié)點(diǎn)相連(相當(dāng)于將兩節(jié)點(diǎn)各自的集合合并)
用UnionFind類(lèi)來(lái)表示一個(gè)并查集,在構(gòu)造函數(shù)中,初始化一個(gè)數(shù)組parent,parent[i]表示的含義為,索引為i的節(jié)點(diǎn),它的直接父節(jié)點(diǎn)為parent[i]。初始化時(shí)各個(gè)節(jié)點(diǎn)都不相連,因此初始化parent[i]=i,讓自己成為自己的父節(jié)點(diǎn),從而實(shí)現(xiàn)各節(jié)點(diǎn)不互連。
def __init__(self, n): self.parent = list(range(n))
由于parent[i]僅表示自己的直接父節(jié)點(diǎn),查詢兩個(gè)節(jié)點(diǎn)是否相交需要比較它們的根節(jié)點(diǎn)是否相同。因此要封裝一個(gè)查詢自己根節(jié)點(diǎn)的方法。
def get_root(self, i): while i != self.parent[i]: i = self.parent[i] return i
接下來(lái)可以通過(guò)來(lái)比較根節(jié)點(diǎn)是否相同來(lái)判斷兩節(jié)點(diǎn)是否連通。
def is_connected(self, i, j): return self.get_root(i) == self.get_root(j)
當(dāng)要連通兩個(gè)節(jié)點(diǎn)時(shí),我們要將其中一個(gè)節(jié)點(diǎn)的根節(jié)點(diǎn)的parent,設(shè)置為另一個(gè)節(jié)點(diǎn)的根節(jié)點(diǎn)。注意,連通兩個(gè)節(jié)點(diǎn)并非僅僅讓兩節(jié)點(diǎn)自身相連,實(shí)際上是讓它們所屬的集合實(shí)現(xiàn)合并。
def union(self, i, j): i_root = self.get_root(i) j_root = self.get_root(j) self.parent[i_root] = j_root
接下來(lái)我們做兩個(gè)小優(yōu)化。
由于調(diào)用get_root時(shí)需要通過(guò)不斷找自己的直接父節(jié)點(diǎn),來(lái)尋找根節(jié)點(diǎn),如果這棵樹(shù)的層級(jí)過(guò)深,會(huì)導(dǎo)致性能受到嚴(yán)重影響。因此我們需要在union時(shí),盡可能的減小合并后的樹(shù)的高度。
在構(gòu)造函數(shù)中新建一個(gè)數(shù)組rank,rank[i]表示節(jié)點(diǎn)i所在的集合的樹(shù)的高度。
因此,當(dāng)合并樹(shù)時(shí),分別獲得節(jié)點(diǎn)i和節(jié)點(diǎn)j的root i_root和j_root之后,我們通過(guò)訪問(wèn)rank[i_root]和rank[j_root]來(lái)比較兩棵樹(shù)的高度,將高度較小的那棵連到高度較高的那棵上。如果高度相等,則可以隨便,并將rank值加一。
def union(self, i, j): i_root = self.get_root(i) j_root = self.get_root(j) if self.rank[i_root] == self.rank[j_root]: self.parent[i_root] = j_root self.rank[j_root] += 1 elif self.rank[i_root] > self.rank[j_root]: self.parent[j_root] = i_root else: self.parent[i_root] = j_root
通過(guò)對(duì)union操作的改良可以防止樹(shù)的高度過(guò)高。我們還可以對(duì)get_root操作本身進(jìn)行優(yōu)化。
當(dāng)前每次執(zhí)行g(shù)et_root時(shí),需要一層一層的找到自己的父節(jié)點(diǎn),很費(fèi)時(shí)。由于根節(jié)點(diǎn)沒(méi)有父節(jié)點(diǎn),并且文章開(kāi)始處提到過(guò)如果一個(gè)節(jié)點(diǎn)沒(méi)有父節(jié)點(diǎn),那么它的父節(jié)點(diǎn)就是自己,因此可以說(shuō)只有根節(jié)點(diǎn)的父節(jié)點(diǎn)是自己本身。現(xiàn)在我們加上一個(gè)判斷,判斷當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)是否為根節(jié)點(diǎn),如果不為根節(jié)點(diǎn),就遞歸地將自己的父節(jié)點(diǎn)設(shè)置為根節(jié)點(diǎn),最后返回自己的父節(jié)點(diǎn)。
def get_root(self, i): if self.parent[i] != self.parent[self.parent[i]]: self.parent[i] = self.get_root(self.parent[i]) return self.parent[i]
感謝各位的閱讀!關(guān)于“python如何實(shí)現(xiàn)并查集”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。