将循环算法与动作分开

时间:2013-09-15 20:44:31

标签: c++ algorithm data-structures

假设我们有一个单独的整数列表,我们给出了以下要求:

  1. 对于给定节点,菜单选项1应显示节点的数据字段以及控制台输出中的任何后续节点。
  2. 对于给定节点,菜单选项2应仅在数据为2的倍数时显示节点的数据字段以及控制台输出中的任何后续节点。
  3. 对于给定节点,菜单选项3应仅在数据为3的倍数时显示节点的数据字段以及控制台输出中的任何后续节点。
  4. 可能的解决方案如下:

    struct node {
        int data;
        node *next;
    };
    
    void insertBeginning(node **list, int data)
    {
        node *n = new node;
        n->data = data;
        n->next = *list;
        *list = n;
    }
    
    void option1(node *node)
    {
        if (node != NULL) {
        cout << node->data << endl;
        option1(node->next);
        }
    }
    
    void option2(node *node)
    {
        if (node != NULL) {
        if (node->data % 2 == 0)
            cout << node->data << endl;
        option2(node->next);
        }
    }
    
    void option3(node *node)
    {
        if (node != NULL) {
        if (node->data % 3 == 0)
            cout << node->data << endl;
        option3(node->next);
        }
    }
    
    void main()
    {
        node *root = new node;
        root->data = 5;
        root->next = NULL;
        insertBeginning(&root, 4);
        insertBeginning(&root, 3);
        insertBeginning(&root, 2);
        insertBeginning(&root, 1);
        cout << "OPTION 1" << endl;
        option1(root);
        cout << endl;
        cout << "OPTION 2" << endl;
        option2(root);
        cout << endl;
        cout << "OPTION 3" << endl;
        option3(root);
    }
    

    但仔细观察发现,在每个菜单选项中都有一个循环遍历节点的算法,在所有选项中都是相同的,然后是特定的操作。因此,将循环算法与动作分开可能是件好事。你会怎么做?

    在这种情况下,循环算法以及操作非常简单,因此进行分离将是杀手锏,但在我的情况下,循环算法和操作更复杂,我想避免复制和粘贴循环算法。此外,这种情况使用单链表,但它可能是一棵树。无论如何,我不想用这些细节分散你的注意力。

    最后考虑第四种选择:

    1. 对于给定节点,菜单选项4应显示节点的数据字段与控制台输出中任何后续节点的总和。
    2. 可能的解决方案如下:

      void loopNodes(node * n, void action(node * n))
      {
          if (n != NULL) {
          action(n);
          loopNodes(n->next, action);
          }
      }
      
      void option1(node * node)
      {
          cout << node->data << endl;
      }
      
      void option2(node * node)
      {
          if (node->data % 2 == 0)
          cout << node->data << endl;
      }
      
      void option3(node * node)
      {
          if (node->data % 3 == 0)
          cout << node->data << endl;
      }
      
      int sum;
      void option4(node * node)
      {
          sum += node->data;
      }
      
      void main()
      {
          node *root = new node;
          root->data = 5;
          root->next = NULL;
          insertBeginning(&root, 4);
          insertBeginning(&root, 3);
          insertBeginning(&root, 2);
          insertBeginning(&root, 1);
          cout << "OPTION 1" << endl;
          loopNodes(root, option1);
          cout << endl;
          cout << "OPTION 2" << endl;
          loopNodes(root, option2);
          cout << endl;
          cout << "OPTION 3" << endl;
          loopNodes(root, option3);
          cout << endl;
          cout << "OPTION 4" << endl;
          sum = 0;
          loopNodes(root, option4);
          cout << "SUM = " << sum << endl;
      }
      

      选项4引入了挑战;需要保持状态。我使用了一个带有文件范围的变量,但另一种选择可能是(这是我的最终解决方案):

      void loopNodes(node * n, void action(node * n, void *state), void *state)
      {
          if (n != NULL) {
          action(n, state);
          loopNodes(n->next, action, state);
          }
      }
      
      void option1(node * node, void *state)
      {
          cout << node->data << endl;
      }
      
      void option2(node * node, void *state)
      {
          if (node->data % 2 == 0)
          cout << node->data << endl;
      }
      
      void option3(node * node, void *state)
      {
          if (node->data % 3 == 0)
          cout << node->data << endl;
      }
      
      void option4(node * node, void *state)
      {
          *(int *) state += node->data;
      }
      
      void main()
      {
          node *root = new node;
          root->data = 5;
          root->next = NULL;
          insertBeginning(&root, 4);
          insertBeginning(&root, 3);
          insertBeginning(&root, 2);
          insertBeginning(&root, 1);
          cout << "OPTION 1" << endl;
          loopNodes(root, option1, NULL);
          cout << endl;
          cout << "OPTION 2" << endl;
          loopNodes(root, option2, NULL);
          cout << endl;
          cout << "OPTION 3" << endl;
          loopNodes(root, option3, NULL);
          cout << endl;
          cout << "OPTION 4" << endl;
          int *sum = new int;
          *sum = 0;
          loopNodes(root, option4, sum);
          cout << "SUM = " << *sum << endl;
      }
      

      您怎么看?

      非常感谢任何反馈!

      注意:我必须使用核心语言工具(我不能使用标准库,提升等)。

2 个答案:

答案 0 :(得分:0)

就OOP而言,您的选项机制取决于绑定到每个选项输入的某些特定处理,在这种情况下是正整数。您可以考虑使用Handle类在构造期间接受两个输入,一个是选项号(即整数),第二个是lambda函数或应用逻辑的函数指针。然后,您的链接列表可以使用AssignHandles()方法自动构建菜单行为。

答案 1 :(得分:0)

您可以将模板化版本用于循环功能。这可以与函数或函数对象一起使用,它们实现operator():

#include <iostream>

int list[] = {1, 2, 3, 4, 5};

template<class Option>
void loop(Option & option) {
    for (size_t i = 0; i < sizeof(list)/sizeof(list[0]); ++i) {
        option(list[i]);
    }
}

void print(int e) {
    std::cout << e << std::endl;
}

struct Sum {
    int sum = 0;
    void operator () (int e) {
        sum += e;
    }
};

int main(int argc, char** argv) {
    loop(print);
    Sum s;
    loop(s);
    std::cout << s.sum << std::endl;
    return 0;
}