I've written a program that counts the number of inversions using a Divide and Conquer algorithm, written in C++11.
#include <iostream>
#include <tuple>
#include <vector>
using IntVec = std::vector<int>;
std::tuple<IntVec, long long> count_inv(IntVec xs);
std::tuple<IntVec, long long> count_split_inv(IntVec xs, IntVec ys);
std::tuple<IntVec, long long> count_inv(IntVec xs) {
int n = xs.size();
if (n < 2) return std::make_tuple(xs, 0);
IntVec::iterator middle = xs.begin() + (n / 2);
IntVec left(xs.begin(), middle);
IntVec right(middle, xs.end());
long long left_inv, right_inv, split_inv;
IntVec as, bs, cs;
std::tie(as, left_inv) = count_inv(left);
std::tie(bs, right_inv) = count_inv(right);
std::tie(cs, split_inv) = count_split_inv(as, bs);
return std::make_tuple(cs, left_inv + right_inv + split_inv);
}
std::tuple<IntVec, long long> count_split_inv(IntVec xs, IntVec ys) {
int n = xs.size() + ys.size();
IntVec zs(n);
long long split_inv = 0;
int i = 0, j = 0, k = 0;
for (; k < n && i < xs.size() && j < ys.size(); ++k) {
if (xs[i] <= ys[j]) {
zs[k] = xs[i];
++i;
} else {
zs[k] = ys[j];
++j;
split_inv += xs.size() - i;
}
}
for (; i < xs.size(); ++k, ++i)
zs[k] = xs[i];
for (; j < ys.size(); ++k, ++j)
zs[k] = ys[j];
return std::make_tuple(zs, split_inv);
}
int main() {
std::vector<int> xs;
int x;
while (std::cin >> x) {
xs.push_back(x);
}
IntVec ys;
long long inv;
std::tie(ys, inv) = count_inv(xs);
std::cout << inv << std::endl;
return 0;
}
I find that the code is very verbose in some areas, such as specifying the type of the tuple. Also, parts of it are confusing. How could I rewrite this code such that it is more concise and clearer?
(i,j)
wherei < j && array[i] > array[j]
. At least, this is what would make sense, because this program is using the "mergesort method" of counting the number of inversions in an array. See this link, for example. \$\endgroup\$ – JS1 Oct 27 '15 at 20:12