From 96185eed8edbae82c9dcff70ee1991176a383a05 Mon Sep 17 00:00:00 2001 From: norangebit Date: Sat, 23 Mar 2019 10:09:09 +0100 Subject: [PATCH] union-find - implement quick find - implement quick union - implement quick union with optimization --- .../datastructures/unionfind/QuickFind.kt | 46 +++++++++++++++ .../datastructures/unionfind/QuickUnion.kt | 48 +++++++++++++++ .../unionfind/QuickUnionCompressionPath.kt | 50 ++++++++++++++++ .../unionfind/QuickUnionWithSize.kt | 58 +++++++++++++++++++ .../datastructures/unionfind/UnionFind.kt | 32 ++++++++++ .../datastructures/unionfind/QuickFindTest.kt | 54 +++++++++++++++++ .../QuickUnionCompressionPathTest.kt | 54 +++++++++++++++++ .../unionfind/QuickUnionTest.kt | 54 +++++++++++++++++ .../unionfind/QuickUnionWithSizeTest.kt | 54 +++++++++++++++++ 9 files changed, 450 insertions(+) create mode 100644 src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickFind.kt create mode 100644 src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnion.kt create mode 100644 src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionCompressionPath.kt create mode 100644 src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionWithSize.kt create mode 100644 src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/UnionFind.kt create mode 100644 src/test/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickFindTest.kt create mode 100644 src/test/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionCompressionPathTest.kt create mode 100644 src/test/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionTest.kt create mode 100644 src/test/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionWithSizeTest.kt diff --git a/src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickFind.kt b/src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickFind.kt new file mode 100644 index 0000000..079ae4e --- /dev/null +++ b/src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickFind.kt @@ -0,0 +1,46 @@ +/* + * MIT License + * + * Copyright (c) 2019 norangebit + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, tryMerge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package it.norangeb.algorithms.datastructures.unionfind + +class QuickFind(private val capacity: Int) : UnionFind { + private val ids = IntArray(capacity) { it } + + override fun find(element: Int): Int { + return ids[element] + } + + override fun union(first: Int, second: Int) { + val firstId = find(first) + val secondId = find(second) + + if (firstId == secondId) + return + + for (i in 0 until capacity) + if (ids[i] == firstId) + ids[i] = secondId + } +} \ No newline at end of file diff --git a/src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnion.kt b/src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnion.kt new file mode 100644 index 0000000..37b34ef --- /dev/null +++ b/src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnion.kt @@ -0,0 +1,48 @@ +/* + * MIT License + * + * Copyright (c) 2019 norangebit + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, tryMerge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package it.norangeb.algorithms.datastructures.unionfind + +class QuickUnion(capacity: Int) : UnionFind { + private val ids = IntArray(capacity) { it } + + override fun find(element: Int): Int { + var i = element + while (i != ids[i]) + i = ids[i] + + return i + } + + override fun union(first: Int, second: Int) { + val firstId = find(first) + val secondId = find(second) + + if (firstId == secondId) + return + + ids[firstId] = secondId + } +} \ No newline at end of file diff --git a/src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionCompressionPath.kt b/src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionCompressionPath.kt new file mode 100644 index 0000000..c71606e --- /dev/null +++ b/src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionCompressionPath.kt @@ -0,0 +1,50 @@ +/* + * MIT License + * + * Copyright (c) 2019 norangebit + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package it.norangeb.algorithms.datastructures.unionfind + +class QuickUnionCompressionPath(capacity: Int) : UnionFind { + private val ids = IntArray(capacity) { it } + + override fun find(element: Int): Int { + var i = element + while (i != ids[i]) { + ids[i] = ids[ids[i]] + i = ids[i] + } + + return i + } + + override fun union(first: Int, second: Int) { + val firstId = find(first) + val secondId = find(second) + + if (firstId == secondId) + return + + ids[firstId] = secondId + } +} \ No newline at end of file diff --git a/src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionWithSize.kt b/src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionWithSize.kt new file mode 100644 index 0000000..8c36c09 --- /dev/null +++ b/src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionWithSize.kt @@ -0,0 +1,58 @@ +/* + * MIT License + * + * Copyright (c) 2019 norangebit + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package it.norangeb.algorithms.datastructures.unionfind + +class QuickUnionWithSize(capacity: Int) : UnionFind { + private val ids = IntArray(capacity) { it } + private val size = IntArray(capacity) { 0 } + + override fun find(element: Int): Int { + var i = element + while (i != ids[i]) + i = ids[i] + + return i + } + + override fun union(first: Int, second: Int) { + val firstId = find(first) + val secondId = find(second) + + if (firstId == secondId) + return + + when { + size[first] < size[second] -> { + ids[firstId] = secondId + size[secondId] += size[firstId] + } + else -> { + ids[secondId] = firstId + size[firstId] += size[secondId] + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/UnionFind.kt b/src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/UnionFind.kt new file mode 100644 index 0000000..6ab6178 --- /dev/null +++ b/src/main/kotlin/it/norangeb/algorithms/datastructures/unionfind/UnionFind.kt @@ -0,0 +1,32 @@ +/* + * MIT License + * + * Copyright (c) 2019 norangebit + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, tryMerge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package it.norangeb.algorithms.datastructures.unionfind + +interface UnionFind { + fun find(element: Int): Int + fun union(first: Int, second: Int) + fun connected(first: Int, second: Int): Boolean = find(first) == find(second) +} \ No newline at end of file diff --git a/src/test/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickFindTest.kt b/src/test/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickFindTest.kt new file mode 100644 index 0000000..948f1a9 --- /dev/null +++ b/src/test/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickFindTest.kt @@ -0,0 +1,54 @@ +/* + * MIT License + * + * Copyright (c) 2019 norangebit + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, tryMerge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package it.norangeb.algorithms.datastructures.unionfind + +import org.amshove.kluent.`should be equal to` +import org.junit.Before +import org.junit.jupiter.api.Test + +class QuickFindTest { + private var unionFind = QuickFind(10) + + @Before + fun init() { + unionFind = QuickFind(10) + } + + @Test + fun testUnion() { + unionFind.connected(1, 2) `should be equal to` false + unionFind.union(1, 2) + unionFind.connected(1, 2) `should be equal to` true + } + + @Test + fun testTransitiveUnion() { + unionFind.connected(1, 3) `should be equal to` false + unionFind.union(1, 2) + unionFind.union(2, 3) + unionFind.connected(1, 3) `should be equal to` true + } +} \ No newline at end of file diff --git a/src/test/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionCompressionPathTest.kt b/src/test/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionCompressionPathTest.kt new file mode 100644 index 0000000..082f897 --- /dev/null +++ b/src/test/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionCompressionPathTest.kt @@ -0,0 +1,54 @@ +/* + * MIT License + * + * Copyright (c) 2019 norangebit + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package it.norangeb.algorithms.datastructures.unionfind + +import org.amshove.kluent.`should be equal to` +import org.junit.Before +import org.junit.jupiter.api.Test + +class QuickUnionCompressionPathTest { + private var unionFind = QuickUnion(10) + + @Before + fun init() { + unionFind = QuickUnion(10) + } + + @Test + fun testUnion() { + unionFind.connected(1, 2) `should be equal to` false + unionFind.union(1, 2) + unionFind.connected(1, 2) `should be equal to` true + } + + @Test + fun testTransitiveUnion() { + unionFind.connected(1, 3) `should be equal to` false + unionFind.union(1, 2) + unionFind.union(2, 3) + unionFind.connected(1, 3) `should be equal to` true + } +} \ No newline at end of file diff --git a/src/test/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionTest.kt b/src/test/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionTest.kt new file mode 100644 index 0000000..cd0c51f --- /dev/null +++ b/src/test/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionTest.kt @@ -0,0 +1,54 @@ +/* + * MIT License + * + * Copyright (c) 2019 norangebit + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, tryMerge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package it.norangeb.algorithms.datastructures.unionfind + +import org.amshove.kluent.`should be equal to` +import org.junit.Before +import org.junit.jupiter.api.Test + +class QuickUnionTest { + private var unionFind = QuickUnion(10) + + @Before + fun init() { + unionFind = QuickUnion(10) + } + + @Test + fun testUnion() { + unionFind.connected(1, 2) `should be equal to` false + unionFind.union(1, 2) + unionFind.connected(1, 2) `should be equal to` true + } + + @Test + fun testTransitiveUnion() { + unionFind.connected(1, 3) `should be equal to` false + unionFind.union(1, 2) + unionFind.union(2, 3) + unionFind.connected(1, 3) `should be equal to` true + } +} \ No newline at end of file diff --git a/src/test/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionWithSizeTest.kt b/src/test/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionWithSizeTest.kt new file mode 100644 index 0000000..dcf811b --- /dev/null +++ b/src/test/kotlin/it/norangeb/algorithms/datastructures/unionfind/QuickUnionWithSizeTest.kt @@ -0,0 +1,54 @@ +/* + * MIT License + * + * Copyright (c) 2019 norangebit + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package it.norangeb.algorithms.datastructures.unionfind + +import org.amshove.kluent.`should be equal to` +import org.junit.Before +import org.junit.jupiter.api.Test + +class QuickUnionWithSizeTest { + private var unionFind = QuickUnionWithSize(10) + + @Before + fun init() { + unionFind = QuickUnionWithSize(10) + } + + @Test + fun testUnion() { + unionFind.connected(1, 2) `should be equal to` false + unionFind.union(1, 2) + unionFind.connected(1, 2) `should be equal to` true + } + + @Test + fun testTransitiveUnion() { + unionFind.connected(1, 3) `should be equal to` false + unionFind.union(1, 2) + unionFind.union(2, 3) + unionFind.connected(1, 3) `should be equal to` true + } +} \ No newline at end of file