基于范围的链表的循环
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于范围的链表的循环相关的知识,希望对你有一定的参考价值。
我有一个在嵌套链表上运行的函数。功能如下:
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中,有一些基于范围的循环迭代一组。这种结构是否适用于这种情况?或者是否有其他可能的方法来执行这些迭代?
答案
是的,您可以为此定义适当的功能。
由于您提供的细节很少。让我们做一些假设。
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>();}
该范围基于查找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;
}
}
或者您可以简单地使用标准循环!!
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;
}
}
另一答案
要跟进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的兼容性,如果这是一个优势。
以上是关于基于范围的链表的循环的主要内容,如果未能解决你的问题,请参考以下文章