我有一个对嵌套链表进行操作的函数。该函数如下:
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中,有一个基于范围的迭代循环。这种构造在这种情况下是否适用?还是还有其他可能的方式来执行这些迭代?
答案 0 :(得分:1)
是的,您可以为此定义适当的功能。
由于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>{};}
现在,我们可以使用基于的范围重新编写循环。
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;
}
}
答案 1 :(得分:0)
要继续关注Serge Ballesta's comment,您可以在此处立即使用普通for
循环,代替while
循环。因此,您的示例代码将变为:
void DoLiana(void) {
for (PlotPointer plot = FirstPlot; plot; plot = plot->next) {
for (TreePointer tree = plot->FirstTree; tree; tree = tree->next) {
if (tree->isLiana && !tree->attachedTree && TestForLianaAttach(plot, tree)) {
DoLianaAttachement(plot, tree);
}
}
}
}
这样可以缩短代码,并增加本地性和可读性。如果有好处的话,还可以保持与C的兼容性。