python實(shí)現(xiàn)一個(gè)簡(jiǎ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)表示一個(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)是自己本身?,F(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]
以上是python實(shí)現(xiàn)一個(gè)簡(jiǎn)單的并查集的方式。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Django 設(shè)置多環(huán)境配置文件載入問(wèn)題
這篇文章主要介紹了Django 設(shè)置多環(huán)境配置文件載入問(wèn)題,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02基于Python和PyYAML讀取yaml配置文件數(shù)據(jù)
這篇文章主要介紹了基于Python和PyYAML讀取yaml配置文件數(shù)據(jù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01NDArray 與 numpy.ndarray 互相轉(zhuǎn)換方式
這篇文章主要介紹了NDArray 與 numpy.ndarray 互相轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05Python使用post及get方式提交數(shù)據(jù)的實(shí)例
今天小編就為大家分享一篇關(guān)于Python使用post及get方式提交數(shù)據(jù)的實(shí)例,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-01-01opencv函數(shù)threshold、adaptiveThreshold、Otsu二值化的實(shí)現(xiàn)
這篇文章主要介紹了opencv函數(shù)threshold、adaptiveThreshold、Otsu二值化的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03python正則表達(dá)式re.sub各個(gè)參數(shù)的超詳細(xì)講解
Python 的 re 模塊提供了re.sub用于替換字符串中的匹配項(xiàng),下面這篇文章主要給大家介紹了關(guān)于python正則表達(dá)式re.sub各個(gè)參數(shù)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07