将圆形数组旋转到位c ++

时间:2014-05-04 20:22:30

标签: c++ rotation circular-buffer

我在编写旋转圆形数组的函数时遇到问题。我需要将它旋转到位(没有临时数组),我需要移动尽可能少的元素。对于背景信息,“Quack”类只是一个与堆栈混合的队列。因此,可以从圆形阵列的两端推出和弹出项目。以下是我到目前为止的情况:

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

正面和背面是作为数组索引的整数。 r是要旋转的量。 capacity是数组的最大大小。

问题是如果数组中有“垃圾”值,我最终将它们旋转到数组中。例如,假设ACTUAL字符数组是{a,b,c,d,e,f,g},前面是5,后面是3.如果我打印圆形数组,我会看到{f,g,a ,b,c,d}。由于前面是5而后面是3,因此索引4是一个“垃圾”值(它在某个时刻被弹出)。所以我现在的旋转功能有一个问题,即索引4被“旋入”。如果我将数组旋转2,那么ACTUAL数组仍然是{a,b,c,d,e,f,g},除非现在我将它打印出来,因为前后不同我得到{a,b,c ,d,e,f}。我想看到的是{a,b,c,d,f,g}。我的打印功能只是从前到后打印(根据需要包裹)所以我需要我的旋转功能以某种方式消除垃圾值。

我想我需要移动后面的元素,所以我有连续的值,中间没有垃圾。但我不知道该怎么做。

2 个答案:

答案 0 :(得分:1)

使用循环迭代器和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 

答案 1 :(得分:1)

因此,如果数组未满,则需要移动一些char。首先检查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(项目[3])在后面。如果我们只是将r添加到两者,它将为空白区域打印垃圾。如果r是2,我们想要将c复制到项目[4],将b复制到项目[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;
}