Python-like range
题目描述
实现类似 Python 中的 range
函数。
具体而言,range(start, stop, step = 1);
生成一个范围;这个范围内的元素都是整数;从 start
(含)开始,stop
(不含)结束,每个元素之间以 step
为差递增。比如 for(int i : range(0, 5)) /*...*/
会让 i
在每次循环中取值为 0, 1, 2, 3, 4。
本题目只要求 range
函数能在基于范围的 for 循环中工作,不做更多要求。
关于输入
无
关于输出
见样例输出
练习目标
- 了解“基于范围的 for 循环”的工作原理:通过
begin
end
和迭代器来确定范围及范围元素; - 尝试自己编写一个范围。
我们期望同学们定义的是“抽象”的范围概念,即在“迭代器”的迭代中实现步进递增。有的同学使用“动态数组”的做法,在构造范围时将所有元素填充好,随后返回数组的范围定义。这样做是满足题目要求的,但是不好:如果这道题改成到 INT_MAX
的范围并由循环体决定何时 break
,那么实现生成“动态数组”的做法就会超时、超内存。
参考答案
#include <iostream>
class IotaSentinel {
private:
int value;
friend class IotaIterator;
public:
IotaSentinel(int value) : value{value} {}
};
class IotaIterator {
private:
int value, step;
public:
IotaIterator(int value, int step) : value{value}, step{step} {}
int operator*() const {
return value;
}
IotaIterator& operator++() {
value += step;
return *this;
}
bool operator!=(const IotaSentinel& rhs) {
if (step > 0) {
return value < rhs.value;
} else {
return value > rhs.value;
}
}
};
class IotaRange {
int start, stop, step;
public:
IotaRange(int start, int stop, int step) : start{start}, stop{stop}, step{step} {}
IotaIterator begin() const {
return IotaIterator(start, step);
}
IotaSentinel end() const {
return IotaSentinel(stop);
}
};
IotaRange range(int start, int stop, int step = 1) {
return IotaRange(start, stop, step);
}
int main() {
for (int i : range(0, 10)) {
std::cout << i << " ";
}
std::cout << std::endl;
for (int i : range(1, 20, 2)) {
std::cout << i << " ";
}
std::cout << std::endl;
for (int i : range(10, 0, -3)) {
std::cout << i << " ";
}
std::cout << std::endl;
for (int i : range(10, 0)) {
std::cout << i << " ";
}
std::cout << std::endl;
}
// 请不要使用任何标准库容器。
#if defined(_GLIBCXX_VECTOR) || defined(_GLIBCXX_DEQUE) || defined(_GLIBCXX_FORWARD_LIST) || \
defined(_GLIBCXX_LIST)
#error Do not use standard library containers.
#endif
#include <iostream>
class IotaRange {
int* data;
int size;
public:
IotaRange(int start, int stop, int step) {
size = 1 + (stop - start - 1) / step;
if (size <= 0) {
size = 0;
}
data = new int[size];
for (int i = 0; i < size; i++) {
data[i] = start + i * step;
}
}
int* begin() {
return data;
}
int* end() {
return data + size;
}
~IotaRange() {
delete[] data;
}
};
IotaRange range(int start, int stop, int step = 1) {
return IotaRange(start, stop, step);
}
int main() {
for (int i : range(0, 10)) {
std::cout << i << " ";
}
std::cout << std::endl;
for (int i : range(1, 20, 2)) {
std::cout << i << " ";
}
std::cout << std::endl;
for (int i : range(10, 0, -3)) {
std::cout << i << " ";
}
std::cout << std::endl;
for (int i : range(10, 0)) {
std::cout << i << " ";
}
std::cout << std::endl;
}
// 请不要使用任何标准库容器。
#if defined(_GLIBCXX_VECTOR) || defined(_GLIBCXX_DEQUE) || defined(_GLIBCXX_FORWARD_LIST) || \
defined(_GLIBCXX_LIST)
#error Do not use standard library containers.
#endif