(вид) вращение и нарезка элементов контейнера в C ++ - PullRequest
2 голосов
/ 08 июля 2010

У меня есть 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, но потом понял, что это не то, что я искалfor.

У меня проблемы с реализацией.Лучшее, что я получил, это нерабочая версия на 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                                                       
    }
}

Есть ли способ сделать это?Я знаю, что могу реализовать это с помощью множества вложенных циклов, но я стараюсь избегать этого, ища что-то более элегантное (если слово подходит).

Заранее спасибо.

Ответы [ 5 ]

5 голосов
/ 08 июля 2010

Если вы хотите использовать больше места, вы можете сначала добавить 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;

    } 
}

Возможно, цикл for можно было бы записать лучше, с точки зрения начала и конца (или dernier) вместо переменной цикла i.1007 * Для добавления вы, вероятно, можете использовать std :: copy (предостережение: я ржавый в C ++).

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

(back_inserter, предложенный Luc)

3 голосов
/ 08 июля 2010

Что именно не так с использованием 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() раз, вы получите пять векторов, которые у вас есть в вопросе.

0 голосов
/ 08 июля 2010

Все приведенные выше ответы требуют изменения контейнера.Это можно решить, не делая этого, и по-прежнему использовать алгоритмы 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

0 голосов
/ 08 июля 2010

В значительной степени то, что Джеймс написал выше:

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());
}

Проверено, и это работает.

0 голосов
/ 08 июля 2010

Не могли бы вы сделать что-то вроде:

// vector = (a,b,c,d,e);

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

повторите любое количество раз.однако может быть неэффективным с точки зрения перестановки памяти

...