【问题标题】:Rotate circular array in place c++就地旋转圆形数组c ++
【发布时间】:2014-05-04 20:22:29
【问题描述】:

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

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

front 和 back 是用作数组索引的整数。 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}。我的打印功能只是从前到后打印(根据需要环绕)所以我需要我的旋转功能以某种方式消除垃圾值。

我想我需要将后面的元素移过来,这样我就有了连续的值,中间没有垃圾。但我不知道该怎么做。

【问题讨论】:

  • 你听说过std::rotate吗? cplusplus.com/reference/algorithm/rotate
  • 我可能是错的,但这不是交换超过所需的最小元素吗?我想交换尽可能少的元素,并利用这是一个循环数组这一事实。
  • 也许你是对的,但这取决于你的“循环数组”是如何实现的。
  • 首先找到要旋转的最小绝对距离(可以向前或向后)。然后像您一样移动索引,但请记住使用std::copy 将留下的部分复制到新发现的区域。顺便说一句,由于 C++ 标准库不提供此功能,因此它与 C++ 几乎没有关系。为什么是 C++ 标签?
  • 我添加了 c++ 标签,因为这是我正在为这个项目工作的内容。 @40two 我的圆形数组被实现为一个常规的旧数组,它跟踪前后,所以我可以在东西被推送和弹出时环绕。

标签: c++ rotation circular-buffer


【解决方案1】:

因此,如果数组未满,您需要移动一些字符。首先,您检查 r 是正数还是负数。如果它是负数,则需要将背面推到与数字 r 的正面齐平,反之亦然。示例:
打印输出:c、b、a、z、f、g 旋转 2
a z f g - c b
0 1 2 3 4 5 6
c(items[5])在前面,g(items[3])在后面。如果我们只是将 r 添加到两者中,它将为空白空间打印垃圾。如果 r 为 2,我们希望将 c 复制到 items[4] 并将 b 复制到 items[5]。然后 items[0] 应该是前面, b 现在 items[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;
}

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-16
      • 2017-05-08
      • 2015-10-03
      • 1970-01-01
      相关资源
      最近更新 更多