Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added make_root in DSU #342

Merged
merged 3 commits into from
Mar 13, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions pydatastructs/miscellaneous_data_structures/disjoint_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ class DisjointSetForest(object):
>>> dst.union(1, 2)
>>> dst.find_root(2).key
1
>>> dst.make_root(2)
>>> dst.find_root(2).key
2

References
==========
Expand Down Expand Up @@ -74,3 +77,18 @@ def union(self, key1, key2):

y_root.parent = x_root
x_root.size += y_root.size

def make_root(self, key):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The feature looks good. Could you share an example (book/lecture notes examples will work) where this is used/required?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presently, I don't remember the exact the example but, we can consider this example https://cp-algorithms.com/data_structures/disjoint_set_union.html#toc-tgt-10 wherein we generally make root which Is largest element in set

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. That's great. Could you solve one such problem using DSU API in pydatastructs and show the code here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will trying finding the exact problem I solved using this method and show that

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, this is the problem where I used the above method: https://codeforces.com/contest/1133/problem/F2, and the submission of mine can be found at: https://codeforces.com/contest/1133/submission/109674863

"""
Finds the set to which the key belongs
and makes it as the root of the set.
"""
if self.tree.get(key, None) is None:
raise KeyError("Invalid key, %s"%(key))

current_root = self.find_root(key)
if current_root.key != key:
key_set = self.tree[key]
current_root.parent = key_set
key_set.size = current_root.size
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the size of current_root should change. Just take the following example,

>>> from pydatastructs import *
>>> dst = DisjointSetForest()
>>> dst.make_set(1)
>>> dst.make_set(2)
>>> dst.make_set(3)
>>> dst.tree[1].size
1
>>> dst.tree[2].size
1
>>> dst.tree[3].size
1
>>> dst.union(2, 3)
>>> dst.tree[1].size
1
>>> dst.tree[2].size
2
>>> dst.tree[3].size
1
>>> dst.make_root(3)
>>> dst.tree[1].size
1
>>> dst.tree[2].size # should have been 1 because now 2 is pointing to 3
2
>>> dst.tree[3].size
2

I think this inconsistency can cause problems when root is shifted a lot of times to different elements of set. We should keep things correct wherever possible.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this inconsistency can cause problems when root is shifted a lot of times to different elements of set. We should keep things correct wherever possible.

This can be recitifed using re-rooting technique: https://wiki.algo.is/Rerooting%20technique. Actually while changing the root I didn't tried to maintain tree/subtree structure and just focused on the size of total elements belonging to that set. However using above technique we can re-root by maintaing tree/subtree structure too

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should have it. We may need to track the nodes whose size will change due to change of root. It may or not be that tricky. Try to do it by just using the parent pointers.

key_set.parent = key_set
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,11 @@ def test_DisjointSetForest():
assert raises(KeyError, lambda: dst.find_root(9))
dst.union(3, 1)
assert dst.find_root(3).key == 1
assert dst.find_root(5).key == 1
dst.make_root(6)
assert dst.find_root(3).key == 6
assert dst.find_root(5).key == 6
dst.make_root(5)
assert dst.find_root(1).key == 5
assert dst.find_root(5).key == 5
assert raises(KeyError, lambda: dst.make_root(9))