我在编写旋转圆形数组的函数时遇到问题。我需要将它旋转到位(没有临时数组),我需要移动尽可能少的元素。对于背景信息,“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}。我的打印功能只是从前到后打印(根据需要包裹)所以我需要我的旋转功能以某种方式消除垃圾值。
我想我需要移动后面的元素,所以我有连续的值,中间没有垃圾。但我不知道该怎么做。
答案 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;
}