Miklix

Непересекающийся набор (алгоритм объединения-поиска) в PHP

Опубликовано: 16 февраля 2025 г. в 12:26:57 UTC

В этой статье представлена реализация на PHP структуры данных Disjoint Set, обычно используемой для Union-Find в алгоритмах минимального остовного дерева.


Эта страница была переведена с английского языка для того, чтобы сделать ее доступной как можно большему числу людей. К сожалению, машинный перевод еще не является совершенной технологией, поэтому возможны ошибки. Если вы хотите, вы можете просмотреть оригинальную английскую версию здесь:

Disjoint Set (Union-Find Algorithm) in PHP

Disjoint Set (обычно используется для Union-Find или Disjoint Set Union) — это структура данных, используемая для управления разделением элементов на непересекающиеся (непересекающиеся) наборы. Она эффективно поддерживает две ключевые операции:

  1. Найти : определяет, к какому набору принадлежит элемент.
  2. Объединение : объединяет два множества.

Эта структура особенно полезна в алгоритмах минимального остовного дерева, таких как алгоритм Крускала.

У меня есть реализация алгоритма Крускала, используемая для генерации случайных лабиринтов, которая опирается на приведенную ниже реализацию PHP Disjoint Set для эффективного слияния множеств. Если вам интересно, вы можете увидеть ее в действии здесь: Генератор лабиринтов по алгоритму Крускала

В любом случае, вот моя реализация Disjoint Set на PHP:

class DisjointSet
{
    private $parent = [];
    private $rank   = [];

    public function __construct($size)
    {
        for ($i = 0; $i < $size; $i++)
        {
            $this->parent[$i]   = $i;
            $this->rank[$i]     = 0;
        }
    }

    public function find($x)
    {
        if ($this->parent[$x] != $x)
        {
            $this->parent[$x] = $this->find($this->parent[$x]);
        }

        return $this->parent[$x];
    }

    public function union($x, $y)
    {
        $rootX = $this->find($x);
        $rootY = $this->find($y);

        if ($rootX != $rootY)
        {
            if ($this->rank[$rootX] > $this->rank[$rootY])
            {
                $this->parent[$rootY] = $rootX;
            }
            elseif ($this->rank[$rootX] < $this->rank[$rootY])
            {
                $this->parent[$rootX] = $rootY;
    
            }
            else
            {
                $this->parent[$rootY] = $rootX;
                $this->rank[$rootX]++;
            }
        }
    }
}

Помимо создания лабиринтов для развлечения, структура данных Disjoint Set, безусловно, может быть использована и в реальных жизненных ситуациях.

Представьте себе, например, социальную сеть, которая хотела бы предлагать своим пользователям новых друзей, и предположим, что у нас уже есть шесть человек с такими дружескими отношениями:

  • 1 и 2 — друзья.
  • 2 и 3 — друзья.
  • 4 и 5 — друзья.
  • У 6 нет друзей.

Применив алгоритм Union-Find к этим отдельным группам, мы должны найти следующее:

  • 1, 2 и 3 в одной группе.
  • 4 и 5 во второй группе.
  • 6 в третьей группе.

Исходя из этого, имело бы смысл предположить, что 1 и 3 должны стать друзьями, поскольку у них есть общий человек 2.

Конечно, в таком небольшом примере вы могли бы легко заметить этот факт и сами, но эффективность этого алгоритма позволяет масштабировать его на миллиарды людей и групп друзей.

Поделиться на BlueskyПоделиться на FacebookПоделиться на LinkedInПоделиться на TumblrПоделиться на XПоделиться на LinkedInЗакрепить на Pinterest

Миккель Банг Кристенсен

Об авторе

Миккель Банг Кристенсен
Миккель - создатель и владелец сайта miklix.com. Он имеет более чем 20-летний опыт работы в качестве профессионального программиста/разработчика программного обеспечения и в настоящее время работает на полную ставку в крупной европейской IT-корпорации. Когда он не ведет блог, то тратит свое свободное время на огромное количество интересов, хобби и занятий, что в некоторой степени отражается в разнообразии тем, освещаемых на этом сайте.