views:

95

answers:

3

Had 3 questions regarding a hw assignment for C++. The goal was to create a simple palindrome method. Here is my template for that:

#ifndef PALINDROME_H
#define PALINDROME_H

#include <vector>
#include <iostream>
#include <cmath>

template <class T>
static bool palindrome(const std::vector<T> &input)
{
    std::vector<T>::const_iterator it = input.begin();
    std::vector<T>::const_reverse_iterator rit = input.rbegin();

    for (int i = 0; i < input.size()/2; i++, it++, rit++)
    {
        if (!(*it == *rit)) {
            return false;   
        }
    }
    return true;
}

template <class T>
static void showVector(const std::vector<T> &input)
{

    for (std::vector<T>::const_iterator it = input.begin(); it != input.end(); it++) {
        std::cout << *it << " ";
    }
}

#endif

Regarding the above code, can you have more than one iterator declared in the first part of the for loop? I tried defining both the "it" and "rit" in the palindrome() method, and I kept on getting an error about needing a "," before rit. But when I cut and paste outside the for loop, no errors from the compiler. (I'm using VS 2008).

Second question, I pretty much just brain farted on this one. But is the way I have my return statements in the palindrome() method ok? In my head, I think it works like, once the *it and *rit do not equal each other, then the function returns false, and the method exits at this point. Otherwise if it goes all the way through the for loop, then it returns true at the end. I totally brain farted on how return statements work in if blocks and I tried looking up a good example in my book and I couldn't find one.

Finally, I get this warnings:

\palindrome.h(14) : warning C4018: '<' : signed/unsigned mismatch

Now is that because I run my for loop until (i < input.size()/2) and the compiler is telling me that input can be negative? Thanks!

+4  A: 

can you have more than one iterator declared in the first part of the for loop?

Yes, but they both have to be of the same type, so you can't declare both a const_iterator and a const_reverse_iterator.

is the way I have my return statements in the palindrome() method ok?

Yes, though why not just compare *it != *rit?

palindrome.h(14) : warning C4018: '<' : signed/unsigned mismatch

i is signed; std::vector::size() returns an unsigned value. If i was unsigned, you would not get this warning.

As a suggestion, though: it might be simpler to use two forward iterators. Initialize one to .begin() and the other to .end() - 1. You can then increment the first and decrement the second and your loop test simply becomes it1 < it2. Something like the following (completely untested) for-loop:

for (iterator it1(v.begin()), it2(v.end() - 1); it1 < it2; ++it1, --it2)

This way you no longer need the separate i counter and comparisons; everything is done with iterators.

James McNellis
Your last suggestion will only work for random access iterators as only those support subtraction.
Tomek
@Tomek: True. The OP is using `std::vector`, which utilizes random access iterators. You can also use `std::prev()` (C++0x addition, but trivial to implement) to obtain an iterator to the last element; then the requirement is reduced to bidirectional iterators.
James McNellis
@James McNellis: you cannot compare bidirectional iterators with anything but equality (`==` and `!=` are ok, but not `<`), so the requirement would still be a random access iterator. It could be rewritten to only use equality comparisons, but that would require moving the increments/decrements (at least one) inside the loop body and checking to avoid both iterators crossing in containers with an even number of elements.
David Rodríguez - dribeas
@David: You're right; I wasn't paying attention when I posted that comment. Thanks for the correction. That said, I still think that would be a better solution than any solution using `size()`, since `size()` _might_ have linear complexity (e.g. for some implementations of `std::list`).
James McNellis
I agree, the code has one less requirement (does not use 'size'), is smaller and cleaner.
David Rodríguez - dribeas
A: 

The for loop works for me when iterators are of the same type, I haven't figured out other way yet - apart from initializing them outside like what you did:

typedef vector<char>::const_iterator IT;

for (IT it(vchars.begin()), end(vchars.end()); it != end; ++it)
{
    cout << *it << endl;
}

Regarding the return statement, your reasoning is correct but you start with those 2 iterators not being the same, one starts from front the other from the end. So on the first iteration they are not equal and you return false - I believe.

And last, the warning points to the fact that size() returns unsigned type (size can't be negative) but you are compare with signed value i, which in most cases is not a real problem - but to be neat you can declare your i as unsigned.

This will fix that:

for (unsigned int i = 0; i < input.size()/2; ...)
stefanB
+7  A: 

Are iterators a requirement of the homework assignment? This task can be reduced to a call to std::equal:

template <class T>
bool palindrome(const std::vector<T> &input)
{
        return equal(input.begin(), input.begin()+input.size()/2, input.rbegin());
}
Cubbi
Cheater ;-) (and +1... very nice solution)
James McNellis