我有一个对嵌套链表进行操作的函数。函数如下:
void DoLiana(void) {
PlotPointer plot;
TreePointer tree;
plot = FirstPlot;
while (plot != nullptr) {
tree = plot->FirstTree;
while (tree != nullptr) {
if (tree->isLiana) {
if (tree->attachedTree == nullptr && TestForLianaAttach(plot, tree))
DoLianaAttachement(plot, tree);
}
tree = tree->next;
}
plot = plot->next;
}
}
因为这种类型的迭代在我的代码中发生了多次,所以我正在寻找一种方法来使迭代更紧凑和更具表现力。我读到在 C++11 中有基于范围的 for 循环迭代一个集合。这种构造是否适用于这种情况?还是有其他可能的方法来执行这些迭代?
最佳答案
是的,您可以为此定义适当的函数。
因为 oyu 提供的细节很少。让我们做一些假设。
struct Tree
{
bool isLiana;
void* attachedTree;
Tree* next;
};
using TreePointer = Tree*;
struct Plot
{
TreePointer FirstTree;
Plot* next;
};
using PlotPointer = Plot*;
bool TestForLianaAttach(PlotPointer, TreePointer);
void DoLianaAttachement(PlotPointer, TreePointer);
PlotPointer FirstPlot;
要使它与指针一起工作,您需要为指针定义适当的 begin()
和 end()
方法。
NextIterator<Plot> begin(PlotPointer ptr) {return make_NextIterator(ptr);}
NextIterator<Plot> end(PlotPointer) {return make_NextIterator<Plot>();}
NextIterator<Tree> begin(TreePointer ptr) {return make_NextIterator(ptr);}
NextIterator<Tree> end(TreePointer) {return make_NextIterator<Tree>();}
基于 for 的范围查找可与您的类型一起使用的 begin()
和 end()
函数。现在标准有默认的 std::begin()
和 std::end()
调用 begin()
和 end ()
传递的对象上的方法。但是您可以提供自己的(如上)来为您的类型/指针做一个特殊情况。
现在,由于您的指针使用 p = p->next;
来推进,我们需要一个迭代器对象来完成这部分工作。在上面的代码中,我调用了这个 NextIterator
。它相对容易定义。
template<typename T>
struct NextIterator
{
T* p;
NextIterator(): p(nullptr) {}
NextIterator(T* ptr): p(ptr) {}
NextIterator& operator++(){p = p->next;return *this;}
T const& operator*() const {return *p;}
T& operator*() {return *p;}
T const* operator->() const {return p;}
T* operator->() {return p;}
bool operator==(NextIterator const& rhs) const {return p == rhs.p;}
bool operator!=(NextIterator const& rhs) const {return p != rhs.p;}
};
template<typename T>
NextIterator<T> make_NextIterator(T* val) {return NextIterator<T>(val);}
template<typename T>
NextIterator<T> make_NextIterator() {return NextIterator<T>{};}
现在我们可以使用基于 for 的范围重写您的循环。
void DoLianaRange(void) {
for(auto& plot: FirstPlot) {
for(auto& tree: plot.FirstTree) {
if (tree.isLiana) {
if (tree.attachedTree == nullptr && TestForLianaAttach(&plot, &tree))
DoLianaAttachement(&plot, &tree);
}
}
}
}
用于比较的原始版本。
void DoLiana(void) {
PlotPointer plot;
TreePointer tree;
plot = FirstPlot;
while (plot != nullptr) {
tree = plot->FirstTree;
while (tree != nullptr) {
if (tree->isLiana) {
if (tree->attachedTree == nullptr && TestForLianaAttach(plot, tree))
DoLianaAttachement(plot, tree);
}
tree = tree->next;
}
plot = plot->next;
}
}
或者您可以简单地使用标准的 for 循环!!
void DoLianaForLoop(void) {
for (PlotPointer plot = FirstPlot; plot != nullptr; plot = plot->next) {
for (TreePointer tree= plot->FirstTree; tree != nullptr; tree = tree->next) {
if (tree->isLiana) {
if (tree->attachedTree == nullptr && TestForLianaAttach(plot, tree))
DoLianaAttachement(plot, tree);
}
}
}
}
所有代码都集中在一个地方(按照正确的编译顺序)。
struct Tree
{
bool isLiana;
void* attachedTree;
Tree* next;
};
using TreePointer = Tree*;
struct Plot
{
TreePointer FirstTree;
Plot* next;
};
using PlotPointer = Plot*;
template<typename T>
struct NextIterator
{
T* p;
NextIterator(): p(nullptr) {}
NextIterator(T* ptr): p(ptr) {}
NextIterator& operator++(){p = p->next;return *this;}
T const& operator*() const {return *p;}
T& operator*() {return *p;}
T const* operator->() const {return p;}
T* operator->() {return p;}
bool operator==(NextIterator const& rhs) const {return p == rhs.p;}
bool operator!=(NextIterator const& rhs) const {return p != rhs.p;}
};
template<typename T>
NextIterator<T> make_NextIterator(T* val) {return NextIterator<T>(val);}
template<typename T>
NextIterator<T> make_NextIterator() {return NextIterator<T>{};}
NextIterator<Plot> begin(PlotPointer ptr) {return make_NextIterator(ptr);}
NextIterator<Plot> end(PlotPointer) {return make_NextIterator<Plot>();}
NextIterator<Tree> begin(TreePointer ptr) {return make_NextIterator(ptr);}
NextIterator<Tree> end(TreePointer) {return make_NextIterator<Tree>();}
bool TestForLianaAttach(PlotPointer, TreePointer);
void DoLianaAttachement(PlotPointer, TreePointer);
PlotPointer FirstPlot;
void DoLianaRange(void) {
for(auto& plot: FirstPlot) {
for(auto& tree: plot.FirstTree) {
if (tree.isLiana) {
if (tree.attachedTree == nullptr && TestForLianaAttach(&plot, &tree))
DoLianaAttachement(&plot, &tree);
}
}
}
}
void DoLiana(void) {
PlotPointer plot;
TreePointer tree;
plot = FirstPlot;
while (plot != nullptr) {
tree = plot->FirstTree;
while (tree != nullptr) {
if (tree->isLiana) {
if (tree->attachedTree == nullptr && TestForLianaAttach(plot, tree))
DoLianaAttachement(plot, tree);
}
tree = tree->next;
}
plot = plot->next;
}
}
关于c++ - 链表的基于范围的for循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52609854/