c++ - 链表的基于范围的for循环

标签 c++ c++11 for-loop linked-list iterator

我有一个对嵌套链表进行操作的函数。函数如下:

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/

相关文章:

c++ - 强制QWebView在单独的线程中下载网页内容?

c++ - 不使用 for、while 或 goto 的循环

c++ - 在 ubuntu 上安装 npm 期间,使用 C++ 17 编译 native Node 插件失败

c++ - 无法在我的代码中使用 std::unordered_map

r - 使用 R 根据输入返回某些内容的函数

Java 错误 : Issue with for loop which should convert every content of a string array to a float array

c++ - 移动分配是否会破坏引用?

c++ - 如何将可变参数模板函数声明为友元?

c++ - 如果 block 无法访问错误

javascript for 循环在输出中产生错误