我想展示一个使用 C++ 语言元素的解决方案。
我在这里看到的一切(除了 std::cout 的用法)都是纯 C 代码。很遗憾,因为 C++ 更强大,并且有很多“外壳”可用的算法。
所以,作为第一个注释。您不应该在 C++ 中使用 C 样式数组。没有理由不使用 std::array 代替。或者,对于具有动态内存管理的用例,std::vector。使用std::vector 几乎总是更好的解决方案。
无论如何。 C++ 也仍然适用于 C 样式的数组。在下面的示例中,我大量使用了 C++ 功能,并且仍然可以使用 C 样式数组。由于这种编程风格,我以后可以将 C-Style 数组与现代 C++ STL 容器交换,并且程序仍然可以运行。
但是让我们先看看代码,我稍后会解释。
#include <iostream>
#include <iterator>
#include <algorithm>
#include <functional>
// Test data
int arr[] = { 2, 3, -1, -1, -1, 4, -1, -1 };
unsigned int result[(sizeof(arr) / sizeof(arr[0]))/2];
// A predicate function that checks for 2 elements to be -1
bool twoMinusOnes(const int i, const int j) {
return i == -1 && j == -1;
}
// Test program
int main() {
// Here we count, how many contiguos blocks of -1 are available
unsigned int blockCounter = 0;
// Some iterator to the begin and end of a -1 block in a source data
decltype(std::begin(arr)) beginOfBlock{};
decltype(std::begin(arr)) endOfBlock{};
// Find all blocks with contiguos -1 in a simple for loop
for ( beginOfBlock = std::adjacent_find(std::begin(arr), std::end(arr), twoMinusOnes); // Initial value. Start searching from beginning
beginOfBlock != std::end(arr); // Check end condition
beginOfBlock = std::adjacent_find(endOfBlock, std::end(arr), twoMinusOnes)) { // find next block
// Ok. std::adjacent_found a block with at lease 2 repeating -1 for us
// Now, find the position, where this block ends
endOfBlock = std::adjacent_find(beginOfBlock, std::end(arr), std::not_equal_to<int>());
// Set iterator to past the end of the contiguous -1 block (if we are not at the end)
if (endOfBlock != std::end(arr)) std::advance(endOfBlock, 1);
// Store number of elements in this block
result[blockCounter++] = std::distance(beginOfBlock, endOfBlock);
}
// Show result to user. Number of blocks and number of elements in each block
for (unsigned int i{}; i < blockCounter; ++i)
std::cout << "Block " << i + 1 << " has " << result[i] << " elements\n";
return 0;
}
好的,我们在这里做什么?
首先,我们定义一个包含要检查的源数据的数组。
其次,我们还定义了一个“结果”数组,具有固定的最大大小,等于第一个数组元素数量的一半。这是因为不能有更多连续的 -1 块。
好的,然后我们定义一个所谓的谓词函数,它只是检查两个给定元素是否都是-1。这就是我们在源数组中寻找的内容。然后可以在 C++ 标准算法中使用谓词函数。
在 main 中,我们初始化一个 blockCounter,它将显示找到的连续 -1 块的数量。
然后我们看到:
decltype(std::begin(arr)) beginOfBlock{};
decltype(std::begin(arr)) endOfBlock{};
这将定义一个迭代器,与使用的 C++ STL 容器无关。对于我们的int[] 数组,它将是一个int*(所以,我们也可以写成int *beginOfBlock;。
这是一种非常灵活的方法,可以让我们以后使用不同的容器。
接下来我们开始一个 for 循环,查找所有连续的 -1 块。
为此,我们使用了一个专用函数,该函数旨在查找具有特定属性的相邻元素:std::adjacent:find。参考说明请见here。标准是找到相等的元素。但是我们使用我们的谓词函数来找到 2 个连续的 -1。
所以,for-loop 的 init 语句从容器的开始开始寻找这样的块。 for 的“条件”检查是否可以找到一个块。
“迭代表达式”在第一个块被评估后寻找下一个块。
这是一个普通的 for 循环,相当直接。
在循环体中,我们只有 3 条语句:
- 搜索当前找到的-1块的结尾
- 因为该函数将返回一对的第一个元素,它将指向找到的块的最后一个-1。我们将增加位置以指向找到的 -1 块之后的下一个元素(但前提是我们尚未位于数组的末尾)
- 我们将生成的元素数量存储在一个块中
就是这样。非常简单紧凑的代码。
最后,我们在控制台上显示收集的结果。
基本上就是这样。由于重用了标准 C++ 库中的现有函数,因此只需要几条语句。
为了向您展示,这样的功能是多么通用,您可以 include 标头 vector 然后简单地替换您的 C 样式数组:
// Test data
std::vector arr{ 2, 3, -1, -1, -1, 4, -1, -1 };
std::vector<size_t> result(arr.size()/2);
并且程序将像以前一样运行。
如果你想学习 C++,我强烈建议你开始使用 C++ 语言元素
如有疑问,请提出。