您的位置:首页 > 其它

union-find算法——解决连通性一类问题的算法

2014-09-24 19:30 405 查看
最近开始看Algorithm,根据书上讲的终于写了点代码~

package demo;

/*

* 当且仅当id[p]等于id[q]时p和q是连通的

* 该算法无法处理大型问题,对于每对输入都需要扫描整个id数组

* 其中union操作访问数组的次数在(N+3)到(2N+1)之间

*/

public class QuickFind {

/**

* @param args

*/

private int count;

private int[] id;

public QuickFind(int n){

count = n;

id = new int
;

for(int i = 0; i < n; i++){

id[i] = i;

}

}

public boolean connect(int p, int q){

return find(p) == find(q);

}

public int find(int p){

return id[p];

}

public void union(int p, int q){

int pId = find(p);

int qId = find(q);

for(int i = 0; i< id.length; i++){

if(id[i] == pId){

id[i] = qId;

}

}

count--;

}

public static void main(String[] args) {

// TODO Auto-generated method stub

int n = StdIn.readInt();

QuickFind qf = new QuickFind(n);

while(!StdIn.isEmpty()){

int p = StdIn.readInt();

int q = StdIn.readInt();

if(qf.connect(p,q)) continue;

qf.union(p, q);

StdOut.println(p + " " + q);

}

StdOut.println(qf.count + "components");

}

}

package demo;

public class QuickUnion {

/**

*最坏情况下,find算法需要访问2N-1次数组

* @param count 存储当前连通个数

* @param id 以触点为索引的数组

*/

private int count;

private int[] id;

public QuickUnion(int n){

count = n;

id = new int
;

for(int i = 0; i< n; i++){

id[i] = i;

}

}

/*

* 找到根节点的id值

*/

public int find(int p){

while(p != id[p]){

p = id[p];

}

return id[p];

}

/*

* 判断是否连通

*/

public boolean connect(int p, int q){

return find(p) == find(q);

}

/*

* 连接两个节点

*/

public void union(int p, int q){

int pRoot = find(p);

int qRoot = find(q);

if(pRoot == qRoot) return;

//将一个p树连接到q树上

id[pRoot] = qRoot;

count--;

}

public static void main(String[] args) {

// TODO Auto-generated method stub

int n = StdIn.readInt();

while(!StdIn.isEmpty()){

int p = StdIn.readInt();

int q = StdIn.readInt();

QuickUnion qu = new QuickUnion(n);

if(qu.connect(p, q)) continue;

qu.union(p, q);

}

}

}

package demo;

/*

* 加权quick-union算法,能保证像quick-union算法中深度无限制增加的情况不再出现

* 将随意把一棵树连接到另一棵树的策略改变为总是将较小的树连接到较大的树上

*能保证性能在对数级别上

* @param sz记录每个连通量的深度

*/

public class WeightedQuickUnion {

/**

* @param args

*/

private int count;

private int[] id;

private int[] sz;

public WeightedQuickUnion(int n){

count = n;

id = new int
;

for(int i = 0; i < n; i++){

id[i] = i;

}

sz = new int
;

for(int i = 0; i < n; i++){

sz[i] = 1;

}

}

public int find(int p){

while(p != id[p]){

p = id[p];

}

return id[p];

}

public void union(int p, int q){

int pRoot = find(p);

int qRoot = find(q);

if(pRoot == qRoot) return;

//将深度较小的树连接到深度较大的树上

if(sz[pRoot] < sz[qRoot]){

id[pRoot] = id[qRoot];

sz[qRoot] += sz[pRoot];

}

else{

id[qRoot] = id[pRoot];

sz[pRoot] += sz[qRoot];

}

count--;

}

public boolean connect(int p, int q){

return find(p) == find(q);

}

public static void main(String[] args) {

// TODO Auto-generated method stub

int n = StdIn.readInt();

WeightedQuickUnion wqf = new WeightedQuickUnion(n);

while(!StdIn.isEmpty()){

int p = StdIn.readInt();

int q = StdIn.readInt();

if(wqf.connect(p,q)) continue;

wqf.union(p, q);

StdOut.println(p + " " + q);

}

StdOut.println(wqf.count + "components");

}

}

package demo;

/*************************************************************************

* Compilation: javac StdIn.java

* Execution: java StdIn (interactive test of basic functionality)

*

* Reads in data of various types from standard input.

*

*************************************************************************/

import java.util.ArrayList;

import java.util.InputMismatchException;

import java.util.Locale;

import java.util.Scanner;

import java.util.regex.Pattern;

/**

* The <tt>StdIn</tt> class provides static methods for reading strings

* and numbers from standard input. See

* <a href="http://introcs.cs.princeton.edu/15inout">Section 1.5</a> of

* <i>Introduction to Programming in Java: An Interdisciplinary Approach</i>

* by Robert Sedgewick and Kevin Wayne.

* <p>

* For uniformity across platforms, this class uses <tt>Locale.US</tt>

* for the locale and <tt>"UTF-8"</tt> for the character-set encoding.

* The English language locale is consistent with the formatting conventions

* for Java floating-point literals, command-line arguments

* (via {@link Double#parseDouble(String)}) and standard output.

* <p>

* Like {@link Scanner}, reading a <em>token</em> also consumes preceding Java

* whitespace; reading a line consumes the following end-of-line

* delimeter; reading a character consumes nothing extra.

* <p>

* Whitespace is defined in {@link Character#isWhitespace(char)}. Newlines

* consist of \n, \r, \r\n, and Unicode hex code points 0x2028, 0x2029, 0x0085;

* see <tt><a href="http://www.docjar.com/html/api/java/util/Scanner.java.html">

* Scanner.java</a></tt> (NB: Java 6u23 and earlier uses only \r, \r, \r\n).

* <p>

* See {@link In} for a version that handles input from files, URLs,

* and sockets.

* <p>

* Note that Java's UTF-8 encoding does not recognize the optional byte-order

* mask. If the input begins with the optional byte-order mask, <tt>StdIn</tt>

* will have an extra character <tt>uFEFF</tt> at the beginning.

* For details, see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058.
*

* @author David Pritchard

* @author Robert Sedgewick

* @author Kevin Wayne

*/

public final class StdIn {

// it doesn't make sense to instantiate this class

private StdIn() { }

private static Scanner scanner;

/*** begin: section (1 of 2) of code duplicated from In to StdIn */

// assume Unicode UTF-8 encoding

private static final String CHARSET_NAME = "UTF-8";

// assume language = English, country = US for consistency with System.out.

private static final Locale LOCALE = Locale.US;

// the default token separator; we maintain the invariant that this value

// is held by the scanner's delimiter between calls

private static final Pattern WHITESPACE_PATTERN = Pattern.compile("\\p{javaWhitespace}+");

// makes whitespace characters significant

private static final Pattern EMPTY_PATTERN = Pattern.compile("");

// used to read the entire input

private static final Pattern EVERYTHING_PATTERN = Pattern.compile("\\A");

/*** end: section (1 of 2) of code duplicated from In to StdIn */

/*** begin: section (2 of 2) of code duplicated from In to StdIn,

* with all methods changed from "public" to "public static" ***/

/**

* Is the input empty (except possibly for whitespace)? Use this

* to know whether the next call to {@link #readString()},

* {@link #readDouble()}, etc will succeed.

* @return true if standard input is empty (except possibly

* for whitespae), and false otherwise

*/

public static boolean isEmpty() {

return !scanner.hasNext();

}

/**

* Does the input have a next line? Use this to know whether the

* next call to {@link #readLine()} will succeed. <p> Functionally

* equivalent to {@link #hasNextChar()}.

* @return true if standard input is empty, and false otherwise

*/

public static boolean hasNextLine() {

return scanner.hasNextLine();

}

/**

* Is the input empty (including whitespace)? Use this to know

* whether the next call to {@link #readChar()} will succeed.

* <p>Functionally equivalent to {@link #hasNextLine()}.

* @return true if standard input is empty, and false otherwise

*/

public static boolean hasNextChar() {

scanner.useDelimiter(EMPTY_PATTERN);

boolean result = scanner.hasNext();

scanner.useDelimiter(WHITESPACE_PATTERN);

return result;

}

/**

* Reads and returns the next line, excluding the line separator if present.

* @return the next line, excluding the line separator if present

*/

public static String readLine() {

String line;

try { line = scanner.nextLine(); }

catch (Exception e) { line = null; }

return line;

}

/**

* Reads and returns the next character.

* @return the next character

*/

public static char readChar() {

scanner.useDelimiter(EMPTY_PATTERN);

String ch = scanner.next();

assert (ch.length() == 1) : "Internal (Std)In.readChar() error!"

+ " Please contact the authors.";

scanner.useDelimiter(WHITESPACE_PATTERN);

return ch.charAt(0);

}

/**

* Reads and returns the remainder of the input, as a string.

* @return the remainder of the input, as a string

*/

public static String readAll() {

if (!scanner.hasNextLine())

return "";

String result = scanner.useDelimiter(EVERYTHING_PATTERN).next();

// not that important to reset delimeter, since now scanner is empty

scanner.useDelimiter(WHITESPACE_PATTERN); // but let's do it anyway

return result;

}

/**

* Reads the next token and returns the <tt>String</tt>.

* @return the next <tt>String</tt>

*/

public static String readString() {

return scanner.next();

}

/**

* Reads the next token from standard input, parses it as an integer, and returns the integer.

* @return the next integer on standard input

* @throws InputMismatchException if the next token cannot be parsed as an <tt>int</tt>

*/

public static int readInt() {

return scanner.nextInt();

}

/**

* Reads the next token from standard input, parses it as a double, and returns the double.

* @return the next double on standard input

* @throws InputMismatchException if the next token cannot be parsed as a <tt>double</tt>

*/

public static double readDouble() {

return scanner.nextDouble();

}

/**

* Reads the next token from standard input, parses it as a float, and returns the float.

* @return the next float on standard input

* @throws InputMismatchException if the next token cannot be parsed as a <tt>float</tt>

*/

public static float readFloat() {

return scanner.nextFloat();

}

/**

* Reads the next token from standard input, parses it as a long integer, and returns the long integer.

* @return the next long integer on standard input

* @throws InputMismatchException if the next token cannot be parsed as a <tt>long</tt>

*/

public static long readLong() {

return scanner.nextLong();

}

/**

* Reads the next token from standard input, parses it as a short integer, and returns the short integer.

* @return the next short integer on standard input

* @throws InputMismatchException if the next token cannot be parsed as a <tt>short</tt>

*/

public static short readShort() {

return scanner.nextShort();

}

/**

* Reads the next token from standard input, parses it as a byte, and returns the byte.

* @return the next byte on standard input

* @throws InputMismatchException if the next token cannot be parsed as a <tt>byte</tt>

*/

public static byte readByte() {

return scanner.nextByte();

}

/**

* Reads the next token from standard input, parses it as a boolean,

* and returns the boolean.

* @return the next boolean on standard input

* @throws InputMismatchException if the next token cannot be parsed as a <tt>boolean</tt>:

* <tt>true</tt> or <tt>1</tt> for true, and <tt>false</tt> or <tt>0</tt> for false,

* ignoring case

*/

public static boolean readBoolean() {

String s = readString();

if (s.equalsIgnoreCase("true")) return true;

if (s.equalsIgnoreCase("false")) return false;

if (s.equals("1")) return true;

if (s.equals("0")) return false;

throw new InputMismatchException();

}

/**

* Reads all remaining tokens from standard input and returns them as an array of strings.

* @return all remaining tokens on standard input, as an array of strings

*/

public static String[] readAllStrings() {

// we could use readAll.trim().split(), but that's not consistent

// because trim() uses characters 0x00..0x20 as whitespace

String[] tokens = WHITESPACE_PATTERN.split(readAll());

if (tokens.length == 0 || tokens[0].length() > 0)

return tokens;

// don't include first token if it is leading whitespace

String[] decapitokens = new String[tokens.length-1];

for (int i = 0; i < tokens.length - 1; i++)

decapitokens[i] = tokens[i+1];

return decapitokens;

}

/**

* Reads all remaining lines from standard input and returns them as an array of strings.

* @return all remaining lines on standard input, as an array of strings

*/

public static String[] readAllLines() {

ArrayList<String> lines = new ArrayList<String>();

while (hasNextLine()) {

lines.add(readLine());

}

return lines.toArray(new String[0]);

}

/**

* Reads all remaining tokens from standard input, parses them as integers, and returns

* them as an array of integers.

* @return all remaining integers on standard input, as an array

* @throws InputMismatchException if any token cannot be parsed as an <tt>int</tt>

*/

public static int[] readAllInts() {

String[] fields = readAllStrings();

int[] vals = new int[fields.length];

for (int i = 0; i < fields.length; i++)

vals[i] = Integer.parseInt(fields[i]);

return vals;

}

/**

* Reads all remaining tokens from standard input, parses them as doubles, and returns

* them as an array of doubles.

* @return all remaining doubles on standard input, as an array

* @throws InputMismatchException if any token cannot be parsed as a <tt>double</tt>

*/

public static double[] readAllDoubles() {

String[] fields = readAllStrings();

double[] vals = new double[fields.length];

for (int i = 0; i < fields.length; i++)

vals[i] = Double.parseDouble(fields[i]);

return vals;

}

/*** end: section (2 of 2) of code duplicated from In to StdIn */

// do this once when StdIn is initialized

static {

resync();

}

/**

* If StdIn changes, use this to reinitialize the scanner.

*/

private static void resync() {

setScanner(new Scanner(new java.io.BufferedInputStream(System.in), CHARSET_NAME));

}

private static void setScanner(Scanner scanner) {

StdIn.scanner = scanner;

StdIn.scanner.useLocale(LOCALE);

}

/**

* Reads all remaining tokens, parses them as integers, and returns

* them as an array of integers.

* @return all remaining integers, as an array

* @throws InputMismatchException if any token cannot be parsed as an <tt>int</tt>

* @deprecated For more consistency, use {@link #readAllInts()}

*/

public static int[] readInts() {

return readAllInts();

}

/**

* Reads all remaining tokens, parses them as doubles, and returns

* them as an array of doubles.

* @return all remaining doubles, as an array

* @throws InputMismatchException if any token cannot be parsed as a <tt>double</tt>

* @deprecated For more consistency, use {@link #readAllDoubles()}

*/

public static double[] readDoubles() {

return readAllDoubles();

}

/**

* Reads all remaining tokens and returns them as an array of strings.

* @return all remaining tokens, as an array of strings

* @deprecated For more consistency, use {@link #readAllStrings()}

*/

public static String[] readStrings() {

return readAllStrings();

}

/**

* Interactive test of basic functionality.

*/

public static void main(String[] args) {

System.out.println("Type a string: ");

String s = StdIn.readString();

System.out.println("Your string was: " + s);

System.out.println();

System.out.println("Type an int: ");

int a = StdIn.readInt();

System.out.println("Your int was: " + a);

System.out.println();

System.out.println("Type a boolean: ");

boolean b = StdIn.readBoolean();

System.out.println("Your boolean was: " + b);

System.out.println();

System.out.println("Type a double: ");

double c = StdIn.readDouble();

System.out.println("Your double was: " + c);

System.out.println();

}

}

package demo;

/*************************************************************************

* Compilation: javac StdOut.java

* Execution: java StdOut

*

* Writes data of various types to standard output.

*

*************************************************************************/

import java.io.OutputStreamWriter;

import java.io.PrintWriter;

import java.io.UnsupportedEncodingException;

import java.util.Locale;

/**

* <i>Standard output</i>. This class provides methods for writing strings

* and numbers to standard output.

* <p>

* For additional documentation, see <a href="http://introcs.cs.princeton.edu/15inout">Section 1.5</a> of

* <i>Introduction to Programming in Java: An Interdisciplinary Approach</i> by Robert Sedgewick and Kevin Wayne.

*

* @author Robert Sedgewick

* @author Kevin Wayne

*/

public final class StdOut {

// force Unicode UTF-8 encoding; otherwise it's system dependent

private static final String CHARSET_NAME = "UTF-8";

// assume language = English, country = US for consistency with StdIn

private static final Locale LOCALE = Locale.US;

// send output here

private static PrintWriter out;

// this is called before invoking any methods

static {

try {

out = new PrintWriter(new OutputStreamWriter(System.out, CHARSET_NAME), true);

}

catch (UnsupportedEncodingException e) { System.out.println(e); }

}

// don't instantiate

private StdOut() { }

// close the output stream (not required)

/**

* Close standard output.

*/

public static void close() {

out.close();

}

/**

* Terminate the current line by printing the line separator string.

*/

public static void println() {

out.println();

}

/**

* Print an object to standard output and then terminate the line.

*/

public static void println(Object x) {

out.println(x);

}

/**

* Print a boolean to standard output and then terminate the line.

*/

public static void println(boolean x) {

out.println(x);

}

/**

* Print a char to standard output and then terminate the line.

*/

public static void println(char x) {

out.println(x);

}

/**

* Print a double to standard output and then terminate the line.

*/

public static void println(double x) {

out.println(x);

}

/**

* Print a float to standard output and then terminate the line.

*/

public static void println(float x) {

out.println(x);

}

/**

* Print an int to standard output and then terminate the line.

*/

public static void println(int x) {

out.println(x);

}

/**

* Print a long to standard output and then terminate the line.

*/

public static void println(long x) {

out.println(x);

}

/**

* Print a short to standard output and then terminate the line.

*/

public static void println(short x) {

out.println(x);

}

/**

* Print a byte to standard output and then terminate the line.

*/

public static void println(byte x) {

out.println(x);

}

/**

* Flush standard output.

*/

public static void print() {

out.flush();

}

/**

* Print an Object to standard output and flush standard output.

*/

public static void print(Object x) {

out.print(x);

out.flush();

}

/**

* Print a boolean to standard output and flush standard output.

*/

public static void print(boolean x) {

out.print(x);

out.flush();

}

/**

* Print a char to standard output and flush standard output.

*/

public static void print(char x) {

out.print(x);

out.flush();

}

/**

* Print a double to standard output and flush standard output.

*/

public static void print(double x) {

out.print(x);

out.flush();

}

/**

* Print a float to standard output and flush standard output.

*/

public static void print(float x) {

out.print(x);

out.flush();

}

/**

* Print an int to standard output and flush standard output.

*/

public static void print(int x) {

out.print(x);

out.flush();

}

/**

* Print a long to standard output and flush standard output.

*/

public static void print(long x) {

out.print(x);

out.flush();

}

/**

* Print a short to standard output and flush standard output.

*/

public static void print(short x) {

out.print(x);

out.flush();

}

/**

* Print a byte to standard output and flush standard output.

*/

public static void print(byte x) {

out.print(x);

out.flush();

}

/**

* Print a formatted string to standard output using the specified

* format string and arguments, and flush standard output.

*/

public static void printf(String format, Object... args) {

out.printf(LOCALE, format, args);

out.flush();

}

/**

* Print a formatted string to standard output using the specified

* locale, format string, and arguments, and flush standard output.

*/

public static void printf(Locale locale, String format, Object... args) {

out.printf(locale, format, args);

out.flush();

}

// This method is just here to test the class

public static void main(String[] args) {

// write to stdout

StdOut.println("Test");

StdOut.println(17);

StdOut.println(true);

StdOut.printf("%.6f\n", 1.0/7.0);

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: