diff --git a/samples/blackmisc/main.cpp b/samples/blackmisc/main.cpp index 94d9dfd49..f78b071c6 100644 --- a/samples/blackmisc/main.cpp +++ b/samples/blackmisc/main.cpp @@ -14,6 +14,7 @@ #include "samplesjson.h" #include "samplesvariant.h" #include "samplesperformance.h" +#include "samplesalgorithm.h" #include "blackmisc/blackmiscfreefunctions.h" #include "blackmisc/pqallquantities.h" @@ -40,6 +41,7 @@ int main(int argc, char *argv[]) qDebug() << "4 .. Metadata"; qDebug() << "5 .. Variant"; qDebug() << "6 .. Performance"; + qDebug() << "7 .. Algorithms"; qDebug() << "-----"; qDebug() << "x .. Bye"; QTextStream qtin(stdin); @@ -51,6 +53,7 @@ int main(int argc, char *argv[]) else if (s.startsWith("4")) { CSamplesMetadata::samples(); } else if (s.startsWith("5")) { CSamplesVariant::samples(); } else if (s.startsWith("6")) { CSamplesPerformance::samples(); } + else if (s.startsWith("7")) { CSamplesAlgorithm::samples(); } else if (s.startsWith("x")) { break; } } while (true); diff --git a/samples/blackmisc/samplesalgorithm.cpp b/samples/blackmisc/samplesalgorithm.cpp new file mode 100644 index 000000000..b6b82ac24 --- /dev/null +++ b/samples/blackmisc/samplesalgorithm.cpp @@ -0,0 +1,42 @@ +/* Copyright (C) 2014 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +#include "samplesalgorithm.h" +#include "blackmisc/algorithm.h" +#include +#include + +namespace BlackMiscTest +{ + + /* + * Samples + */ + int CSamplesAlgorithm::samples() + { + QStringList src { "a1", "a2", "a3", "b1", "b2", "b3", "c1", "c2", "c3" }; + std::random_shuffle(src.begin(), src.end()); + qDebug() << src; + qDebug() << "topologicallySortedInsert"; + QStringList dst; + int count = 0; + auto cmp = [ & ](const QString &a, const QString &b) { count++; return a[0] == b[0] && a[1] < b[1]; }; + for (const auto &s : src) { BlackMisc::topologicallySortedInsert(dst, s, cmp); } + qDebug() << count << "comparisons"; + qDebug() << dst; + qDebug() << "topologicalSort"; + count = 0; + BlackMisc::topologicalSort(dst.begin(), dst.end(), cmp); + qDebug() << count << "comparisons"; + qDebug() << dst; + + return 0; + } + +} // namespace diff --git a/samples/blackmisc/samplesalgorithm.h b/samples/blackmisc/samplesalgorithm.h new file mode 100644 index 000000000..1cbc3b890 --- /dev/null +++ b/samples/blackmisc/samplesalgorithm.h @@ -0,0 +1,26 @@ +/* Copyright (C) 2014 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKMISCTEST_SAMPLESALGORITHM_H +#define BLACKMISCTEST_SAMPLESALGORITHM_H + +namespace BlackMiscTest +{ + //! Samples for our algorithms + class CSamplesAlgorithm + { + public: + //! Run the samples + static int samples(); + }; +} // namespace + +#endif diff --git a/src/blackmisc/algorithm.h b/src/blackmisc/algorithm.h new file mode 100644 index 000000000..7fbd36100 --- /dev/null +++ b/src/blackmisc/algorithm.h @@ -0,0 +1,79 @@ +/* Copyright (C) 2014 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKMISC_ALGORITHM_H +#define BLACKMISC_ALGORITHM_H + +#include +#include +#include + +namespace BlackMisc +{ + /*! + * Topological sorting algorithm. + * + * \param begin Begin iterator of the range to sort. + * \param end End iterator of the range to sort. + * \param comparator A binary function which defines a less-than relation between elements of the range. + * The ordering it induces must be a partial ordering, which is a more relaxed requirement + * than the strict weak ordering required by most standard sorting algorithms. + * + * \see https://en.wikipedia.org/wiki/Topological_sorting + * \see https://en.wikipedia.org/wiki/Partial_ordering + */ + template + void topologicalSort(I begin, I end, F comparator) + { + using value_type = typename std::iterator_traits::value_type; + auto part = begin; + while (part != end) + { + auto newPart = std::partition(part, end, [ = ](const value_type &a) + { + return std::none_of(part, end, [ =, &a ](const value_type &b) + { + return comparator(b, a); + }); + }); + Q_ASSERT_X(newPart != part, "BlackMisc::topologicalSort", "Cyclic less-than relation detected (not a partial ordering)"); + part = newPart; + } + } + + /*! + * Insert an element into a sequential container while preserving the topological ordering of the container. + * + * \param container A sequential container. + * \param value The value to insert. + * \param comparator A binary function which defines a less-than relation between elements of the container. + * The ordering it induces must be a partial ordering, which is a more relaxed requirement + * than the strict weak ordering required by most standard sorting algorithms. + * + * \see https://en.wikipedia.org/wiki/Topological_sorting + * \see https://en.wikipedia.org/wiki/Partial_ordering + */ + template + void topologicallySortedInsert(C &container, T &&value, F comparator) + { + using value_type = typename C::value_type; + using reverse = std::reverse_iterator; + auto rit = std::find_if(reverse(container.end()), reverse(container.begin()), [ =, &value ](const value_type &lhs) + { + return comparator(lhs, value); + }); + Q_ASSERT_X(std::none_of(rit, reverse(container.begin()), [ =, &value ](const value_type &rhs) { return comparator(value, rhs); }), + "BlackMisc::topologicallySortedInsert", "Cyclic less-than relation detected (not a partial ordering)"); + container.insert(rit.base(), std::forward(value)); + } +} + +#endif