Завъртете кръгъл масив на място c++

Имам проблем с писането на функция за завъртане на кръгъл масив. Трябва да го завъртя на място (без временни масиви) и трябва да преместя възможно най-малко елементи. За основна информация класът "Quack" е просто опашка, смесена със стек. Така елементите могат да се избутват и изскачат от двата края на кръговия масив. Ето какво имам досега:

void Quack::rotate(int r)
{
    front = (front + capacity + r) % capacity;
    back = (back + capacity + r) % capacity;
}

front и back са int, които действат като индекси за масива. r е количеството за ротация. капацитетът е максималният размер на масива.

Проблемът е, че ако масивът има "боклук" стойности в него, в крайна сметка ги завъртам в масива. Например да кажем, че ДЕЙСТВИТЕЛНИЯТ масив от знаци е {a, b, c, d, e, f, g}, а предната част е 5, а задната част е 3. Ако отпечатам кръговия масив, ще видя {f, g, a , b, c, d}. Тъй като отпред е 5, а отзад е 3, индексът 4 е "боклук" стойност (изскочи в някакъв момент). Така че моята функция за завъртане, както е сега, има проблем в това, че индекс 4 се "завърта". Ако завъртя масива с 2, ДЕЙСТВИТЕЛНИЯТ масив все още е {a, b, c, d, e, f, g}, освен сега, когато го отпечатам, тъй като предната и задната част са различни, получавам {a, b, c , d, e, f}. Това, което искам да видя, е {a, b, c, d, f, g}. Моята функция за печат просто отпечатва отпред назад (обвивайки, ако е необходимо), така че имам нужда от моята функция за завъртане, за да премахна по някакъв начин стойността на боклука.

Мисля, че трябва да преместя задните елементи, за да имам последователни стойности без боклук в средата. Но не съм сигурен как да го направя.


person chillpenguin    schedule 04.05.2014    source източник
comment
Чували ли сте за std::rotate? cplusplus.com/reference/algorithm/rotate   -  person 101010    schedule 05.05.2014
comment
Може и да греша, но това не разменя ли повече от необходимия минимум елементи? Искам да разменя възможно най-малко елементи и да се възползвам от факта, че това е кръгъл масив.   -  person chillpenguin    schedule 05.05.2014
comment
Може би сте прав, но зависи от това как е реализиран вашият кръгъл масив.   -  person 101010    schedule 05.05.2014
comment
започнете с намиране на минималното абсолютно разстояние за завъртане (може да бъде напред или назад). след това преместете индексите, както правите, но не забравяйте да използвате std::copy, за да копирате останалата част в новооткритата територия. между другото, тъй като стандартната библиотека на C++ не предлага тази функционалност, тя има много малко или нищо общо със C++. защо тагът C++?   -  person Cheers and hth. - Alf    schedule 05.05.2014
comment
Добавих тага c++, защото това е, в което работя за този проект. @40two моят кръгов масив е реализиран просто като обикновен стар масив, който следи предната и задната част, така че да мога да се увивам, когато нещата се бутат и изскачат.   -  person chillpenguin    schedule 05.05.2014
comment
@Cheersandhth.-Алф, това има смисъл, но ми е трудно да разбера как да го направя. Не съм сигурен как да изчисля какво е останало. Мога да видя какво трябва да се случи в отделни случаи, но не мога да разбера как да напиша кода, за да се справи с всяка ротация.   -  person chillpenguin    schedule 05.05.2014


Отговори (2)


Така че, ако масивът не е пълен, трябва да преместите някои символи наоколо. Първо проверявате дали r е положително или отрицателно. Ако е отрицателно, трябва да натиснете задната част, за да се изравни с предната част за числото r или обратното. пример:
разпечатайте: c, b, a, z, f, g завъртете 2
a z f g - c b
0 1 2 3 4 5 6
c (елементи[5 ]) е отпред, а g (items[3]) е отзад. Ако просто добавим r към двете, това ще отпечата боклук за празното пространство. Ако r е 2, искаме да копираме c в items[4] и b в items[5]. Тогава елементи [0] трябва да са отпред и b сега елементи [5] трябва да са отзад.

void Quack::rotate(int r)
{
    if (nItems < capacity) { //if it's not full
        if (r < 0) { // if r is negative
            int r2 = r*(-1); //find absolute value
            for (int i = 0; i < r2; i++) { 
                items[(back + 1 - i) % (capacity)] = items[(back - i < 0) ? capacity + back - i : back - i]; //push back the back chars up to the front r times
            }
        }
        else {
            for (int i = 0; i < r; i++){
                items[(back + 1 + i)% capacity] = items[(front + i) % capacity];
            }
        }
    }
    front = ((front + r > 0) ? (front + r)%capacity : front + r + capacity); //if front + r is negative add capacity to it
    back = (back + r) % capacity;
}
person Murphpdx    schedule 29.10.2014

С цикличен итератор и std::rotate:

#include <algorithm>
#include <iterator>

template <typename Iterator>
class cyclic_range
{
    public:
    typedef Iterator iterator;

    cyclic_range(iterator first, iterator middle, iterator last)
    :   m_first(first), m_middle(middle), m_last(last)
    {
        if(m_middle == m_last) m_middle = m_first;
    }

    iterator first() const { return m_first; }
    iterator middle() const { return m_middle; }
    iterator last() const { return m_last; }

    private:
    iterator m_first;
    iterator m_middle;
    iterator m_last;

};

template <typename Iterator>
inline cyclic_range<Iterator>
make_cyclic_range(Iterator first, Iterator middle, Iterator last) {
    return cyclic_range<Iterator>(first, middle, last);
}


/// A cyclic random access iterator operating on a iterator range [first, last).
/// If an iterator reaches the last (or is at last) position of the range the iterator
/// becomes equal to the first position of the range.
template <
    typename RandomAccessIterator,
    typename CyclicRange = cyclic_range<RandomAccessIterator> >
class cyclic_iterator
{
    public:
    typedef RandomAccessIterator inner_iterator;
    typedef std::iterator_traits<inner_iterator> inner_iterator_traits;

    typedef typename std::random_access_iterator_tag iterator_category;
    typedef typename inner_iterator_traits::value_type value_type;
    typedef typename inner_iterator_traits::difference_type difference_type;
    typedef typename inner_iterator_traits::reference reference;
    typedef typename inner_iterator_traits::pointer pointer;
    typedef CyclicRange range_type;

    public:
    cyclic_iterator(inner_iterator pos, range_type range, bool at_end = false)
    :   m_pos(pos), m_range(range), m_at_end(at_end)
    {
        if(m_pos == range.last()) {
            m_pos = range.first();
        }
    if(m_range.first() == m_range.last()) m_at_end = true;
    }

    const range_type& range() const { return m_range; }

    /// True if the incremented or decremented iterator is at the middle of
    /// the circular range.
    bool at_end() const { return m_at_end; }

    reference operator * () const noexcept {
        return *m_pos;
    }
    pointer operator -> () const noexcept { return &*m_pos; }

    cyclic_iterator& operator ++ () noexcept {
        if(++m_pos == m_range.last()) m_pos = m_range.first();
        m_at_end = (m_pos == m_range.middle());
        return *this;
    }

    cyclic_iterator operator ++ (int) noexcept {
        return ++cyclic_iterator(*this);
    }

    cyclic_iterator& operator += (difference_type n) noexcept {
        if(n) {
            if(n < 0) *this -= -n;
            else {
                n %= (m_range.last() - m_range.first());
                difference_type avail = m_range.last() - m_pos;
                if(n < avail) m_pos += n;
                else {
                    m_pos = m_range.first();
                    n -= avail;
                    m_pos += n;
                }
                m_at_end = (m_pos == m_range.middle());
            }
        }
        return *this;
    }

    cyclic_iterator operator + (difference_type n) const noexcept {
        return cyclic_iterator(*this) += n;
    }

    cyclic_iterator& operator -- () noexcept {
        if(m_pos == m_range.first()) m_pos = m_range.last();
        --m_pos;
        m_at_end = (m_pos == m_range.middle());
        return *this;
    }

    cyclic_iterator operator -- (int) noexcept {
        return --cyclic_iterator(*this);
    }

    cyclic_iterator& operator -= (difference_type n) noexcept {
        if(n) {
            if(n < 0) *this += -n;
            else {
                n %= (m_range.last() - m_range.first());
                difference_type avail = m_pos - m_range.first();
                if(avail < n) {
                    m_pos = m_range.last();
                    n -= avail;
                }
                m_pos -= n;
                m_at_end = (m_pos == m_range.middle());
            }
        }
        return *this;
    }

    cyclic_iterator operator - (difference_type n) const noexcept {
        return cyclic_iterator(*this) -= n;
    }

    difference_type operator - (const cyclic_iterator& other) const noexcept {
        return index() - other.index();
    }

    bool operator == (const cyclic_iterator& other) noexcept {
        return (index() == other.index());
    }

    bool operator != (const cyclic_iterator& other) noexcept {
        return ! (*this == other);
    }

    bool operator <  (const cyclic_iterator& other) noexcept {
        return index < other.index();
    }

    bool operator <= (const cyclic_iterator& other) noexcept {
        return ! (other < this);
    }

    bool operator >  (const cyclic_iterator& other) noexcept {
        return (other < this);
    }

    bool operator >= (const cyclic_iterator& other) noexcept {
        return ! (this < other);
    }

    private:
    /// The index of the iterator position.
    typedef std::size_t size_type;
    size_type index() const noexcept {
        size_type n = m_range.last() - m_range.first();
        if( ! m_at_end) {
            if(m_range.middle() <= m_pos) {
                n = m_pos - m_range.middle();
            }
            else {
                n = (m_pos - m_range.first()) + (m_range.last() - m_range.middle());
            }
        }
        return n;
    }

    private:
    inner_iterator m_pos;
    range_type m_range;
    bool m_at_end;
};

template <typename Iterator>
cyclic_iterator<Iterator> begin(const cyclic_range<Iterator>& range) {
    return cyclic_iterator<Iterator>(range.middle(), range);
}

template <typename Iterator>
cyclic_iterator<Iterator> end(const cyclic_range<Iterator>& range) {
    return cyclic_iterator<Iterator>(range.middle(), range, true);
}

// Test
// ====

#include <iostream>
#include <vector>

template <typename Iterator>
void print_cyclic_range(Iterator first, Iterator last) {
    std::cout << "Cyclic Range: ";
    for( ; first != last; ++first) {
        std::cout << *first << ' ';
    }
    std::cout << '\n';
}

template <typename Iterator>
void print_range(Iterator first, Iterator last) {
    std::cout << "       Range: ";
    for( ; first != last; ++first) {
        std::cout << *first << ' ';
    }
    std::cout << '\n';
}

int main()
{
    typedef cyclic_iterator<char*> cyclic_iterator;

    char v[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g'};
    print_range(v, v + sizeof(v));

    // The cyclic range from 'f' to (including) 'e'
    cyclic_iterator::range_type range(v, v + 5, v + sizeof(v));
    // The cyclic iterator pointing to 'f'
    cyclic_iterator first = begin(range);
    // The cyclic iterator pointing to 'e'
    cyclic_iterator last = end(range) - 1;
    print_cyclic_range(first, last);

    // Rotate the cyclic range from 'f' to (including) 'd', excluding 'e'
    std::rotate(first, first + 2, last);
    print_range(v, v + sizeof(v));
    print_cyclic_range(first, last);
    return 0;
}

даване:

       Range: a b c d e f g 
Cyclic Range: f g a b c d 
       Range: c d f g e a b 
Cyclic Range: a b c d f g 
person Community    schedule 05.05.2014