Python implements a simple sample code for querying sets, and python implements sample code
The query set is a tree-type data structure used to process the merge and query of some non-intersecting sets. Forest is often used.
The query set has three basic operations: Get the root node, judge whether two nodes are connected, and connect two nodes that are not connected (equivalent to merging the two nodes in their respective sets)
The UnionFind class is used to represent and query a set. In the constructor, initialize an array parent. parent [I] indicates the node whose index is I, its direct parent node is parent [I]. Each node is not connected during initialization. Therefore, you can initialize parent [I] = I to make yourself a parent node, so that each node is not interconnected.
def __init__(self, n): self.parent = list(range(n))
Since parent [I] only represents its own direct parent node, it is necessary to check whether the two nodes are intersecting and whether their root nodes are the same. Therefore, You Need To encapsulate a method to query your own root node.
def get_root(self, i): while i != self.parent[i]: i = self.parent[i] return i
Next, we can determine whether two nodes are connected by comparing whether the root nodes are the same.
def is_connected(self, i, j): return self.get_root(i) == self.get_root(j)
To connect two nodes, we need to set the parent of the root node of one node as the root node of the other node. Note that connecting two nodes not only connects the two nodes themselves, but actually merges the set to which they belong.
def union(self, i, j): i_root = self.get_root(i) j_root = self.get_root(j) self.parent[i_root] = j_root
Next we will make two small optimizations.
When calling get_root, You need to constantly find your own direct parent node to find the root node. If the hierarchy of this tree is too deep, the performance will be seriously affected. Therefore, we need to minimize the height of the merged tree in union.
Create an array rank in the constructor. rank [I] indicates the height of the tree in the set where node I is located.
Therefore, after the root I _root and j_root of node I and node j are obtained respectively when the tree is merged, we can compare the height of the two trees by accessing rank [I _root] and rank [j_root, connect the small one to the tall one. If the height is equal, you can add the rank value to one.
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
The improvement of the union operation can prevent the tree height from being too high. We can also optimize the get_root operation itself.
Each time get_root is executed, it takes a long time to find its parent node layer by layer. Because the root node does not have a parent node, and the article mentioned at the beginning that if a node does not have a parent node, its parent node is itself, so it can be said that only the parent node of the root node is itself. Now let's add a judgment to determine whether the parent node of the current node is the root node. If it is not the root node, it will recursively set its parent node as the root node, and finally return its parent node.
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]
The above is a simple method for implementing and querying sets in python. I hope it will be helpful for everyone's learning, and I hope you can support the house of helping customers more.