Вы можете сделать это безумно быстро, используя алгоритм поиска объединения.
Идея состоит в том, чтобы иметь лес из деревьев, где каждое дерево представляет элементы "равные". Вы представляете это дерево как простой массив, где a [i] может быть родительским для i, -1, если i является корнем, или сказать -2, если i еще нет в дереве.
В вашем случае вы бы начали с простого дерева:
1
\
5
Следующее, что вы хотите, чтобы это присоединилось к 6 и 8. Однако они оба не назначены, поэтому вы добавляете новое дерево. (То есть [6] = - 1, a [8] = 6):
1 6
\ \
5 8
Теперь вы хотите присоединиться к 6 и 1. Вы узнаете, к каким наборам они принадлежат, следуя за своими родителями наверх. По совпадению они оба корни. В этом случае мы делаем самое маленькое дерево дочерним по отношению к другому дереву. (А [6] = 1)
1
/ \
6 5
\
8
Наконец, мы хотим объединить 9 и 3, они оба не назначены, поэтому мы создаем новое дерево. (a [3] = - 1, a [9] = 3)
1 9
/ \ \
6 5 3
\
8
Скажите, у вас также есть 5 = 3? Следуйте за своими родителями, пока не дойдете до корней. Вы обнаружите, что они уже не равны, поэтому вы сливаете деревья. Поскольку 9 управляет менее высоким деревом, мы добавляем его к своему дереву, чтобы получить:
.1.
/ | \
6 9 5
\ \
8 3
Как видите, теперь легко проверить, находятся ли два элемента в одном наборе. Скажи, хочешь проверить, равны ли 8 и 3? Просто следуйте по их путям вверх, и вы увидите, что 8 в наборе, представленном одним, и три в наборе, представленном 9. Следовательно, они неравны.
Использование эвристики всегда помещая меньшее дерево под большее, дает вам log (n) среднее время поиска или слияния. Статья в Википедии объясняет дополнительный трюк, который сделает его в основном постоянным.