Questions →
Dynamic Connectivity: when the program reads an integer pair p Q from the input, if all the known pairs of integers do not indicate that P and q are connected, then the pair of integers are written to the Output. If the known data can explain the P and Q
is connected, then the program should ignore p Q for this pair of integers and continue processing the next pair of integers in the Input.
Application of the problem →
network, variable name equivalence, numeric collections, and so On.
Design api→
public class UF
|
UF (int N) |
Initialize n contacts with integer identifier (0 to N-1) |
void |
Union (int p, int Q) |
Add a connection between P and Q |
Int |
Find (int P) |
Identifier of the component where P (0 to N-1) resides |
Boolean |
Connected (int p, int Q) |
Returns True if P and Q are present in the same component |
Int |
Count () |
Number of connected components |
The task of designing algorithms for solving the dynamic connectivity problem is translated in order to implement this Api.
Quick-find algorithm →
public classQuickfinduf {Private int[] id;//Component ID (with contact as Index) Private intCount//Number of components publicQuickfinduf (intN) {//Initialize component ID arrayCount =N; ID=New int[N]; for(inti = 0; I < N; i++) {id[i]=i; } } public intCount () {returncount; } public BooleanConnectedintPintQ) {returnFind (p) = =Find (q); } public intFindintP) {returnid[p]; } public voidUnionintPintQ) {//merge P and q into the same component intPID =Find (p); intQID =Find (q); //if P and Q are already in the same component, no action is Required. if(pID = = QID)return; //Rename the component of p to the name of Q for(inti = 0; I < id.length; i++) { if(id[i] = = PID) id[i] =qID; } Count--; } public Static voidMain (string[] Args) {//Solving the dynamic connectivity problems obtained by stdin intN = Stdin.readint ();//number of Read contact pointsUF UF =NewUF (N);//Initialize N Components while(!Stdin.isempty ()) { intp =Stdin.readint (); intQ = Stdin.readint ();//reads an integer pair if(uf.connected (p, Q))Continue;//if the general rules are ignoredUf.union (p, q);//Merge ComponentStdout.println (p + "" + q);//Print Link} stdout.println (uf.count ()+ "components"); }}
Quickfinduf
Analysis:
· Each time the Find () call requires only one access to the array, and the Union () that merges the two components accesses the array in the number of (N + 3) to (2N + 1).
· Assuming that there is only one connected component at the end, this calls for at least n-1 union (), i.e. at least (n + 3) (N-1) ~ N ^ 2-time array access.
· The Quick-find algorithm is square-level.
Quick-union algorithm →
public classQuickunionuf {Private int[] id;//Component ID (with contact as Index) Private intCount//Number of components publicQuickunionuf (intN) {//Initialize component ID arrayCount =N; ID=New int[N]; for(inti = 0; I < N; i++) {id[i]=i; } } public intCount () {returncount; } public BooleanConnectedintPintQ) {returnFind (p) = =Find (q); } public intFindintP) {//return id[p]; while(p! = Id[p]) p =id[p]; returnp; } public voidUnionintPintQ) {intProot =Find (p); intQroot =Find (q); if(proot = = Qroot)return; id[proot]=qroot; Count--; } public Static voidMain (string[] Args) {//Solving the dynamic connectivity problems obtained by stdin intN = Stdin.readint ();//number of Read contact pointsUF UF =NewUF (N);//Initialize N Components while(!Stdin.isempty ()) { intp =Stdin.readint (); intQ = Stdin.readint ();//reads an integer pair if(uf.connected (p, Q))Continue;//if the general rules are ignoredUf.union (p, q);//Merge ComponentStdout.println (p + "" + q);//Print Link} stdout.println (uf.count ()+ "components"); }}
Quickunionuf
Analysis:
· The best case input, the run time of the use case is a linear level.
· Worst case input, The run time of the use case is the square level.
Weighted quick-union algorithm →
public classWeightedquickunionuf {Private int[] id; Private int[] sz; Private intcount; publicWeightedquickunionuf (intN) {count=N; ID=New int[N]; for(inti = 0; I < N; I++) id[i] =i; SZ=New int[N]; for(inti = 0; I < N; I++) sz[i] = 1; } public intCount () {returncount; } public BooleanConnectedintPintQ) {returnFind (p) = =Find (q); } public intFindintP) {//follow the link to find the root node while(p! = Id[p]) p =id[p]; returnp; } public voidUnionintPintQ) {inti =Find (p); intj =Find (q); if(i = = J)return; //connect the root node of the small tree to the root node of the tree if(sz[i] <Sz[j]) {id[i]=j; sz[j]+=sz[i]; } Else{id[j]=i; sz[i]+=sz[j]; } Count--; } public Static voidMain (string[] Args) {//Solving the dynamic connectivity problems obtained by stdin intN = Stdin.readint ();//number of Read contact pointsUF UF =NewUF (N);//Initialize N Components while(!Stdin.isempty ()) { intp =Stdin.readint (); intQ = Stdin.readint ();//reads an integer pair if(uf.connected (p, Q))Continue;//if the general rules are ignoredUf.union (p, q);//Merge ComponentStdout.println (p + "" + q);//Print Link} stdout.println (uf.count ()+ "components"); } }
Weightedquickunionuf
Analysis:
· Record the size of each tree and always connect the smaller tree to the larger tree.
· The weighted quick-union algorithm is for a number of levels.
optimal algorithm →
The weighted quick-union algorithm for path compression is the optimal algorithm, but not all operations can be done in constant Time.
Cost-averaging images →
· For the Quick-find algorithm: the cumulative average starts high and then starts to decline, but remains relatively high.
· For the quick-union algorithm: the cumulative mean is lower in the initial stage and the later growth is Obvious.
· For the weighted quick-union algorithm: there is no expensive operation, and the cost of averaging is low.
Outlook →
Basic steps when discussing a problem:
· Define the problem in full and detail, identify the basic abstractions necessary to solve the problem, and define an Api.
· Simply implement a primary algorithm, give a well-organized development use case and use the actual data as Input.
· Decide whether to improve or give up when the maximum size of the problem that can be solved is not up to Expectations.
· Gradually improve the implementation, through empirical analysis or (and) mathematical analysis to verify the improved Effect.
· Design more advanced, improved versions with higher-level abstractions that represent data structures or algorithms.
· If the worst-case performance can be guaranteed as much as possible, there is good performance when dealing with normal Data.
· At the right time, more detailed in-depth research is left to experienced researchers and continues to solve the next Problem.
Algorithm (4th edition)-1.5 case study: Union-find algorithm