blob: 81aca2db1a3d179f9970e0ad8d789239698ebc03 [file] [log] [blame]
/*
* Copyright (C) 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef UnionFind_h
#define UnionFind_h
#include <wtf/Assertions.h>
namespace WTF {
// A UnionFind class can be used to compute disjoint sets using the
// disjoint-set forest data structure. Each UnionFind instance is a
// node in the forest. Typically you use it by using UnionFind as a
// superclass:
//
// class MemberOfSet : public UnionFind<MemberOfSet> { ... }
//
// Calling x->find() gives you a MemberOfSet* that represents the
// disjoint set that x belongs to. Calling x->unify(y) unifies x's
// set with y's set, and ensures that:
//
// x->find() == y->find()
//
// and that:
//
// a->find() == b->find()
//
// for any a, b if prior to the call to x->unify(y), we would have
// had:
//
// a->find() == x
// b->find() == y
//
// This implementation is almost amortized O(1), but could be worse
// in unlikely pathological cases. It favors having a non-recursive
// single pass implementation of unify() and find() over ensuring the
// theoretical O(InverseAckermann[n]) amortized bound, which is much
// closer to amortized O(1).
template<typename T>
class UnionFind {
public:
UnionFind()
: m_parent(0)
{
}
bool isRoot() const
{
bool result = !m_parent;
ASSERT(result == (const_cast<UnionFind<T>*>(this)->find() == this));
return result;
}
T* find()
{
T* result = static_cast<T*>(this);
T* next = result->m_parent;
while (next) {
result = next;
next = result->m_parent;
}
ASSERT(result);
if (result != this)
m_parent = result;
return result;
}
void unify(T* other)
{
T* a = static_cast<T*>(this)->find();
T* b = other->find();
ASSERT(!a->m_parent);
ASSERT(!b->m_parent);
if (a == b)
return;
a->m_parent = b;
}
private:
T* m_parent;
};
} // namespace WTF
using WTF::UnionFind;
#endif // UnionFind_h