为什么在这种情况下,`std::array` 比 `std::vector(10)` 更快?

huangapple go评论83阅读模式
英文:

Why std::array<int, 10> is faster than std::vector<int>(10) in this scenario?

问题

I am given N, where N belongs to [3; 1000000] different numbers X, where X belongs to [0; 18446744073709551616).

How many numbers can be formed by rearranging the digits of a different number in the input ?

Example:

6

25 21 10242 42210 52 24021

Answer:

5

Explanation:

There are 5 different numbers namely {25, 52} and {10242, 42210, 24021}

25 -&gt; 52 and 52 -&gt; 25

10242 -&gt; 42210 and 42210 -&gt; 10242

10242 -&gt; 24021 and 24021 -&gt; 10242

42210 -&gt; 24021 and 24021 -&gt; 42210

lhs -&gt; rhs means that rhs can be formed from the digits of lhs

I solved the task successfully. Here is my solution:

#include <iostream>
#include <string>
#include <vector>
#include <array>
#include <algorithm>
#include <iterator>

namespace Const {
    std::string::size_type constexpr sz_max{ 20 };
}

int main() {
    // 0
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    // 1
    int n;
    std::cin >> n;
    int i;
    std::string x;
    x.reserve(Const::sz_max);
    std::vector<std::array<int, 10>> lut(n);
    for (i = 0; i != n; ++i) {
        std::cin >> x;
        for (auto const& ch : x) {
            ++lut[i][ch - '0'];
        }
    }
    // 2
    std::sort(lut.begin(), lut.end());
    // 3
    auto prev{ lut.cbegin() };
    decltype(prev) curr;
    auto cnt{ 1 }, ans{ 0 };
    for (curr = std::next(prev); curr != lut.cend(); ++curr) {
        if (*curr == *prev) {
            ++cnt;
        }
        else {
            if (cnt != 1) {
                ans += cnt;
            }
            prev = curr;
            cnt = 1;
        }
    }
    if (cnt != 1) {
        ans += cnt;
    }
    prev = curr;
    cnt = 1;
    // 4
    std::cout << ans << '\n';
    return 0;
}

The execution time of this version is 550-600 ms.

If I change the definition of lut in // 1 from

std::vector<std::array<int, 10>> lut(n);

to

std::vector<std::vector<int>> lut(n, std::vector<int>(10));

the execution time increases drastically to 1050-1150 ms.

In both cases heap allocations have to take place but why the first ones are faster than the second ones ?

英文:

The task (from a Bulgarian judge, click on "Език" to change it to English):

I am given N, where N belongs to [3; 1000000] different numbers X, where X belongs to [0; 18446744073709551616).

How many numbers can be formed by rearranging the digits of a different number in the input ?

Example:

6

25 21 10242 42210 52 24021

Answer:

5

Explanation:

There are 5 different numbers namely {25, 52} and {10242, 42210, 24021}

25 -&gt; 52 and 52 -&gt; 25

10242 -&gt; 42210 and 42210 -&gt; 10242

10242 -&gt; 24021 and 24021 -&gt; 10242

42210 -&gt; 24021 and 24021 -&gt; 42210

lhs -&gt; rhs means that rhs can be formed from the digits of lhs

I solved the task successfully. Here is my solution:

#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;array&gt;
#include &lt;algorithm&gt;
#include &lt;iterator&gt;

namespace Const {
	std::string::size_type constexpr sz_max{ 20 };
}

int main() {
	// 0
	std::ios_base::sync_with_stdio(false);
	std::cin.tie(nullptr);
	// 1
	int n;
	std::cin &gt;&gt; n;
	int i;
	std::string x;
	x.reserve(Const::sz_max);
	std::vector&lt;std::array&lt;int, 10&gt;&gt; lut(n);
	for (i = 0; i != n; ++i) {
		std::cin &gt;&gt; x;
		for (auto const&amp; ch : x) {
			++lut[i][ch - &#39;0&#39;];
		}
	}
	// 2
	std::sort(lut.begin(), lut.end());
	// 3
	auto prev{ lut.cbegin() };
	decltype(prev) curr;
	auto cnt{ 1 }, ans{ 0 };
	for (curr = std::next(prev); curr != lut.cend(); ++curr) {
		if (*curr == *prev) {
			++cnt;
		}
		else {
			if (cnt != 1) {
				ans += cnt;
			}
			prev = curr;
			cnt = 1;
		}
	}
	if (cnt != 1) {
		ans += cnt;
	}
	prev = curr;
	cnt = 1;
	// 4
	std::cout &lt;&lt; ans &lt;&lt; &#39;\n&#39;;
	return 0;
}

The execution time of this version is 550-600 ms.

If I change the definition of lut in // 1 from

std::vector&lt;std::array&lt;int, 10&gt;&gt; lut(n);

to

std::vector&lt;std::vector&lt;int&gt;&gt; lut(n, std::vector&lt;int&gt;(10));

the execution time increases drastically to 1050-1150 ms.

In both cases heap allocations have to take place but why the first ones are faster than the second ones ?

答案1

得分: 2

std::array 不像 std::vector 那样为其元素进行单独的堆分配,即

sizeof(std::array<int,16>) == sizeof(int) * 16

所有的元素都直接存储在对象中。因此,vector<array<int,10>> 中的所有数据都存储在相同的连续分配中。

英文:

std::array doesn't make a separate heap allocation for its elements like std::vector does, i.e.,

sizeof(std::array&lt;int,16&gt;) == sizeof(int) * 16

All of the elements are stored directly in the object. Because of this, all the data in a vector&lt;array&lt;int,10&gt;&gt; is stored in the same contiguous allocation.

huangapple
  • 本文由 发表于 2023年7月24日 16:36:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/76752719.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定