The original: A daily walkthrough of the classic Algorithm--the 15th question and the search set
This article we look at the classic and magical and look-up, as the name implies is and up to check, can be used to deal with some disjoint collection of seconds to kill.
One: Scene
Sometimes we will encounter such a scenario, such as: m={1,4,6,8},n={2,4,5,7}, my need is to determine whether {is} belongs to the same collection, of course, the implementation method
There are many, in general, ordinary youth will make O (MN) complexity, then there is no more lightweight complexity? Hey, and check set is used to solve the problem.
Two: Operation
From the name can come out, and check the set actually only two operations, and (Union) and check (find), and check set is an algorithm, so we have to choose a good data structure,
Usually we use a tree as its underlying implementation.
1. Node definition
1 #region tree Node 2// <summary> 3// tree node 4// </summary> 5 Public class node 6 {7
///<summary> 8// Parent Node 9// </summary>10 public char parent;11// <summary>13 /// </summary>15 public int rank;16 }17 #endregion
2.Union operation
<1> Original plan
First we break all the elements of the collection, and finally each element is a single tree, and then we union one of the two elements and let them become a collection,
The worst case scenario where we do m union will exist such a list.
We can see that the worst is happening in union, and this is relatively easy to come by, resulting in a rather shabby, hard-to-Find, O (N).
<2> Merge by rank
We find that the reason for this is that when we union, we have the merged tree as a child node of the small tree, so can we judge in Union,
The small tree as a child of the tree nodes exist, and ultimately reduce the depth of the new tree, compared to the Union (d,{e,f}) when the following changes can be made.
As can be seen, we effectively reduce the depth of the tree, in the set of n elements, the depth of the build tree will not exceed the LOGN layer. The complexity of M operations is O (MLOGN), from generation
On the code, we use rank to count the rank of the tree, which can be understood as the height of the tree, when the tree is rank=0, when the rank of the two trees at the same time, you can choose to merge at random, in the new
The rank++ in the root will be all right.
1 #region Merge two disjoint sets 2// <summary> 3// merge two disjoint sets 4// </summary> 5// <param name= "ro Ot1 "></param> 6// <param name=" Root2 "></param> 7// <returns></returns> 8 Public void Union (char root1, char root2) 9 {Ten char x1 = Find (ROOT1), one char y1 = find (Root2); 13
//If the root node is the same, the description is the same collection if (x1 = = y1) return;16 //Description left set Depth < right collection if (Dic[x1].rank < dic [Y1].rank] + //Set the left set to the right set of dic[x1].parent = y1;22 }23 else24 { //If the rank is equal, The Y1 is incorporated into X1 and x1++26 if (Dic[x1].rank = = Dic[y1].rank), dic[x1].rank++;28 dic[y1].parent = x1;30< c25/>}31 }32 #endregion
3.Find operation
We learn the algorithm, all want to be able to optimize a problem to the Earth people can not optimize the point, for the level of LOGN, we can also optimize it? Of course.
<1> path Compression
In the two operations of Union and find, it is clear that we have achieved the ultimate in the union above, let's consider on find above, whether it can be used on find
The idea of stretching the tree, this stretching idea is the compression path.
As we can see, when I find the "f", we start to backtrack and, in the process of backtracking, point the parent of the node to the root node. Eventually
We'll form a compressed tree, and when we find (F) again, as long as O (1) is available, here's a note of rank, when we're on the road
Diameter compression, the height of the last tree may be reduced, you may realize that the original rank needs to be modified, so I would say that when the path is compressed, rank saves
is the upper bound of the height of the tree, not just the height of the tree, can be understood as "telescopic chair" extension of the length.
1 #region Find the collection that x belongs to 2// <summary> 3// find the collection that x belongs to 4// </summary> 5// <param name= "X" ></param> 6 //<returns></returns> 7 public Char Find (char x) 8 {9 //if equal, Then the root node is returned, the root node element, if (dic[x].parent = = x), return x;12 //Path compression (the final value is the "X" returned above, That is, all of a path has been modified) return dic[x].parent = Find (dic[x].parent); }16 #endregion
We notice that after the path is compressed, we reduce the complexity of LOGN to Alpha (n), and Alpha (n) can be understood as a smaller constant than the hash function, hehe, which
Is the charm of the algorithm.
Finally, the total running code:
Using system;using system.collections.generic;using system.linq;using system.text;namespace ConsoleApplication1{ Class Program {static void Main (string[] args) {//define 6 nodes char[] c = new char[] {' A ', ' B ', ' C ', ' D ', ' E ', ' F '}; Disjointset set = new Disjointset (); Set. Init (c); Set. Union (' E ', ' F '); Set. Union (' C ', ' D '); Set. Union (' C ', ' E '); var B = set. Issameset (' C ', ' E '); Console.WriteLine ("C,e is in the same set: {0}", b); b = Set. Issameset (' A ', ' C '); Console.WriteLine ("A,c is in the same set: {0}", b); Console.read (); }}///<summary>//And check set//</summary> public class Disjointset {#region tree node <summary>//tree node///</summary> public class Node {//<summ Ary>///parent node///</summary> public char parent; <summary>////node rank///</summary> public int rank; } #endregion Dictionary<char, node> dic = new Dictionary<char, node> (); #region do a single set of initialization operations///<summary>///do a single set initialization operation////</summary> public void Init ( Char[] c) {//Default parent node that does not want to cross the collection points to itself for (int i = 0; i < c.length; i++) { Dic. ADD (C[i], new Node () {parent = C[i], rank = 0}); }} #endregion #region determine whether the two elements belong to the same collection///<summary>///Determine whether the two elements belong to the same collection </summary>//<param name= "ROOT1" ></param>//<param name= "Root2" ></p aram>//<returns></returns> public bool Issameset (char Root1, char Root2) { return Find (ROOT1) = = Find (ROOT2); #endregion #region Find the collection that x belongs to///<summary>//Find the collection that x belongs to//</summary> <param name= "x" ></param>///<returns></returns> public char Find (char x {//If equal, then the root node is returned, and the root node element if (dic[x].parent = = x) return x; Path compression (when backtracking is assigned, the final value is the "X" returned above, which means that all of the paths have been modified) return dic[x].parent = Find (dic[x].parent); #endregion #region Merge two disjoint sets///<summary>///Merge two disjoint sets///</summary> <param name= "ROOT1" ></param>//<param name= "Root2" ></param>//<retu rns></returns> public void Union (char root1, char root2) {char x1 = Find (ROOT1); Char y1 = Find (Root2); If the root node is the same, then the same set if (x1 = = y1) return; Describes the depth < right set of the left collection if (Dic[x1].ranK < Dic[y1].rank) {//sets the left collection to the right set dic[x1].parent = y1; } else {//If the rank is equal, the Y1 is incorporated into X1 and x1++ if (Dic[x1].rank = = DIC[Y1].R Ank) dic[x1].rank++; Dic[y1].parent = x1; }} #endregion}}
The daily walkthrough of the classic Algorithm question--the 15th question and check set