代码之家  ›  专栏  ›  技术社区  ›  Tom

(类)C++中容器的旋转和切片元素

  •  2
  • Tom  · 技术社区  · 14 年前

    我有一个 std::vector 持有 Point struct (X、Y、Z和其他一些非指针类型)。

    这些点是绘制bspline曲线的控制点。我在绘制曲线时没有遇到困难,但是当我必须关闭曲线时会出现复杂情况,这涉及到按一定顺序添加控制点(容器中已经存在)。

    例如,如果我有5个控制点

    A B C D E
    

    我必须得到5个这样的序列:

    A B C D  //curve is drawn from B to C
    B C D E  //curve is drawn from C to D
    C D E A  //curve is drawn from D to E 
    D E A B  //curve is drawn from E to A
    E A B C  //curve is drawn from A to B
    

    起初,我和 std::rotate 但后来意识到这不是我要找的。

    我在执行这项任务时遇到了困难。我得到的最好的是C++中的非工作版本(失败的原因不是问题,这里是一个片段)。

    static char letters = 'A';
    typedef struct Point{
            float x,y,z;
            char name;
    
            Point(float x,float y,float z=0):name(letters++){}
    
    }Point;
    typedef std::vector<Point> lpoints;
    
    void
    rotate(lpoints& points)
    {
        for (unsigned int i =0;i<5;i++){
                    lpoints::iterator beg =   lista.begin() + (i%5);
                    lpoints::iterator dernier=lista.begin()+(4+i)%6; 
    
                    lpoints subseq(beg,dernier); //4 points in subseq
    
                    //do stuff with subseq                                                       
        }
    }
    

    有办法吗?我知道我可以用许多嵌套的for循环来实现它,但是我试图避免这种情况,寻找更优雅的东西(如果这个词合适的话)。

    事先谢谢。

    5 回复  |  直到 14 年前
        1
  •  3
  •   James McNellis    14 年前

    到底是什么用错了 std::rotate() ?例如,

    std::vector<int> v(5);
    
    std::rotate(v.begin(), v.begin() + 1, v.end());
    std::vector<int> firstFour(v.begin(), v.begin() + 4);
    

    firstFour 然后包含旋转向量的前四个元素。如果在循环中使用它并运行它 v.size() 有时,你会得到你在问题中的五个向量。

        2
  •  5
  •   Aryabhatta    14 年前

    如果您愿意使用更多的空间,可以先将lpoints附加到自身,然后在需要时获取subseq时增加迭代器。这也可以满足您的“5个不同的向量或一个长向量”,因为您可以使用双向量的迭代器,而不是创建新的向量。

    对不起,我暂时还没有编写C++,所以这里是C++类伪代码。

    void 
    rotate(lpoints& points) 
    { 
        pointsDouble = Append(points,points); // Do your own implementation
                                     // if points is A B C D E
                                     // pointsDouble is A B C D E A B C D E
    
        pointsDouble::iterator beg =   lista.begin(); 
        pointsDouble::iterator dernier=lista.begin()+4;  
    
        for (unsigned int i =0;i<5;i++){ 
    
            lpoints subseq(beg,dernier); //4 points in subseq 
    
            //do stuff with subseq
    
           ++beg; ++dernier;
    
        } 
    }
    

    对于循环变量i的开始和结束(或Dernier),for循环也可以写得更好。

    对于一个附件,您可能使用STD::复制(告诫:我在C++中生锈)。

    lpoints pointsDouble(points);
    std::copy(points.begin(), points.end(), std::back_inserter(pointsDouble));
    

    (Luc建议的背部插入器)

        3
  •  0
  •   Anycorn    14 年前

    你能做点什么吗?

    // vector = (a,b,c,d,e);
    
    front = vector.front();
    vector.pop_front();
    vector.push_back(front);
    // now you have (b,c,d,e,a);
    

    重复任何次数。 但是,在内存混乱方面可能效率低下

        4
  •  0
  •   bits    14 年前

    正如詹姆斯在上面写的:

    vector <char> newv[5];
    
    for(int i=0; i<5; i++)
    {
        newv[i].insert(newv[i].begin(),v.begin(), v.begin()+4);
        std::rotate(v.begin(), v.begin()+1, v.end());
    }
    

    经过测试,一切正常。

        5
  •  0
  •   bradgonesurfing    14 年前

    以上所有的答案都需要改变容器。不这样做就可以解决这个问题,并且仍然可以使用stl/boost算法。如果下面的应用程序没有完全编译,因为我没有测试过它。

    std::vector<int> v;
    v.push_back(0);
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    
    for(int i = 0; i < 5; i ++)
    {
        using boost::join;
        using boost::adaptors::sliced;
        using std::ostream_iterator;
        using std::cout;
        using boost::copy;
    
        copy
            ( join(v | sliced(i,4), v | sliced(0, (4 + i) % 5))
            , ostream_iterator<int>(cout, " ") 
            )
        }
        cout << std::endl;
    
    }
    

    Boost::Sliced的医生在

    http://www.boost.org/doc/libs/1_43_0/libs/range/doc/html/range/reference/adaptors/reference/sliced.html#range.reference.adaptors.reference.sliced.sliced_example