Related
I am required to find the address of a matching value in an array, as stated in the following question:
This function searches length elements of array list for the value target. It returns the index where target was found, or -1 if the value is not present.
int find(int target, int list[], int length) {
for (int i = 0; i < length; ++i) {
if (list[i] == target) return i;
}
return -1;
}
Rewrite the function using pointers to indicate the search range. The search should begin by examining the element at start and end at stop without examining that value. The return value should be a pointer to the location of the target value or a null pointer if the values is not present.
The code I have is here, but I can't seem to get it to work:
#include <cstdlib>
#include <iostream>
using namespace std;
int* find(int target, int* start, int* stop)
{
while(start <= stop)
{
if (*start == target)
{
return start;
}
start++;
}
return nullptr;
}
int main()
{
int someArray[] = {3,10,19,7,3,45,123,4,9,89};
int start = *someArray[0];
int stop = *someArray[9];
cout << *find(19, start, stop);
return 0;
}
The start and stop pointers should be initialized appropriately:
int* start = &someArray[0];
int* stop = &someArray[9];
You also want to know the index of the array where the target is at (and not the target itself), so you have to change the line:
cout << *find(19, start, stop);
to
cout << find(19, start, stop) - someArray ;
In this way, you will not be in the danger of accessing the nullptr.
If a negative value is printed, it would mean that the target is not in someArray.
I would use std::find and std::distance, to get the index of the value.
#include <iostream>
#include <algorithm>
int main() {
const int someArray [] = {3,10,19,7,3,45,123,4,9,89};
const int len = sizeof(someArray) / sizeof(int);
const auto it = std::find(&someArray[0], &someArray[len], 19);
std::cout << std::distance(&someArray[0], it);
return 0;
}
or if you use std::array or another std container you can use .begin() and .end().
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
const std::array<int,10> someArray = {3,10,19,7,3,45,123,4,9,89};
const auto it = std::find(someArray.begin(), someArray.end(), 19);
std::cout << std::distance(someArray.begin(),it);
return 0;
}
You can use
const auto start = someArray.begin() + value;
and likewise stop to norrow the search area of someArray.
Your function find() requires the 'addresses' of the start/end of the array, but you're assigning the 'value' of the start/end of the array.
Your start and stop variables need to be pointers. For example:
int *start = &someArray[0];
int *stop = &someArray[9];
And be careful by using the line
cout << *find(19, start, stop);
with another value that is not in the array. This results in an access violation because you try to derefence a nullptr.
An asterisk (*) dereferences a pointer. That is, it gives you the value at the address. An ampersand (&) gets the pointer to a value. The start and stop pointers should be the addresses of the first and last values.
If you turn on more warnings, the compiler might tell you that you are dereferencing something that is not a pointer and you are passing int values to the function where pointers are expected.
int *start = &someArray[0];
int *stop = &someArray[9];
If you have C++11 (which you should), then std::end is specialized for arrays.
You can avoid either having to hard-code the array size as the magic number 9, or writing out the sizeof(someArray)/sizeof(someArray[0]) incantation (which is itself at least better than hardcoding the type in your sizeof expression).
#include <iostream>
#include <iterator>
#include <algorithm>
int main() {
const int someArray [] = {3,10,19,7,3,45,123,4,9,89};
const auto it = std::find(std::begin(someArray), std::end(someArray), 19);
std::cout << std::distance(std::begin(someArray), it);
return 0;
}
If you do want to use your custom find function, note that begin and end just return pointers in this case anyway, and it will also be a pointer in the code above.
As other answers have stated, your start and stop variables need to be int* pointers, and you need to use the & address operator instead of the * dereference operator to obtain those pointers:
int *start = &someArray[0];
int *stop = &someArray[9];
However, there is another, more subtle, bug in your code. As the documented requirement states:
The search should begin by examining the element at start and end at stop without examining that value.
But your code is examining the value at stop. This is because you are using the <= operator, when you should be using the < operator instead:
//while (start <= stop)
while (start < stop)
Making this change then creates a new bug in your main() code. someArray[9] is the last element in the array (89). After making the above change, this element will no longer be compared when using someArray[9] for the stop pointer. So, if you were to call find(89, start, stop), it would return nullptr instead of the address of someArray[9]. As such, you need to set stop to the address of someArray[10] instead:
int *stop = &someArray[10];
This is on par with how STL algorithms works with iterator ranges (and raw pointers are also iterators). The ending iterator always represents "1-past-the-end" and is never dereferenced, only used for comparing when the starting iterator reaches the ending iterator. The C++ standard also explicitly allows obtaining a pointer to "1-past-the-end" of an array, for similar reasons.
With that said, try something like this:
#include <iostream>
#include <cstddef>
int* find(int target, int* start, int* stop)
{
while (start < stop)
{
if (*start == target)
{
return start;
}
++start;
}
return nullptr;
}
int main()
{
int someArray[] = {3,10,19,7,3,45,123,4,9,89};
int *start = &someArray[0];
int *stop = &someArray[10];
std::cout << "Enter a number to find: ";
int num;
std::cin >> num;
int *found = find(num, start, stop);
if (found)
std::cout << "Found at index " << static_cast<ptrdiff_t>(found - start);
else
std::cout << "Not found";
return 0;
}
Live Demo
im studying c++ primer, and in one exercise, i have to do a recursive function that prints the elements on a vector.
I did this:
void printVector(vector<int>::iterator it1, vector<int>::iterator it2) {
cout << *it1 << " ";
if (it1 != it2-1)
printVector((it1 + 1), it2);
}
is there another form to declare it, without the
if(it1!= ***IT2-1***)
i feel like its a mediocre solution couse i cant find another way.
thanks!!
Your function does not accept empty range, which it should, and it is a good idea to put exit condition into begin of a recursive function:
void printVector(vector<int>::iterator it1, vector<int>::iterator it2)
{
if( it1 == it2 ) return;
cout << *it1++ << " ";
printVector(it1, it2);
}
Yes.
void printVector(vector<int>::iterator begin, vector<int>::iterator end)
{
if (begin != end) {
cout << *begin << " ";
printVector(++begin, end)(;
}
}
Yes, you probably want to go at it in another way. It is pretty silly to do recursion when a simple loop will do. Instead, recursion is a tool to use in a more divide an conquer style. I.e. divide into two parts, then apply the same function to the first part and then to the second part.
Usually you then have some kind of cutoff point as to when you can actually do whatever it is you want to do, say for instance that you have less than N number of elements to work with or similar. This example is pretty contrived, because it only brings overhead to do it recursively.
template<class Iter>
void printVector(Iter begin, Iter end)
{
const auto dist = std::distance(begin, end);
if (0 == dist) {
return;
} else if (1 == dist) {
std::cout << *begin;
} else {
// Find the middle
auto pivot = begin + dist/2;
// Apply to first part
printVector(begin, pivot);
// Print separator
std::cout << " ";
// Apply to second part
printVector(pivot, end);
}
}
Please forgive any typos and other issues. Oh, I made it a template as well so that it accepts any random access iterators. That was mostly because it felt annoying to type vector<int>::iterator twice. That should probably be vector<int>::const_iterator by the way.
So I got a methode inside my class, and what this class is supposed to do is, check if the vector i have in the .h file have values bewtween double low & double high and then delete those and at last return how many "spaces" got removed
So I tried a few things and i always get runtime errors, it seems to be in the for loop, but i can´t figure out why.
Here is what i tried,
First I tried to just do it the way I felt like it would work:
int datastorage::eraseDataPointsBetween(double low,double high)
{
int antal = 0;
for (vector<double>::iterator i = data_.begin(); i !=data_.end();i++)
{
if (*i >=low && *i <=high)
{
data_.erase(i);
antal++;
}
}
return antal;
}
But then I tried to do some debugging and I could see that it actually doesn´t make sence to have it like that as when something gets deleted it still gets incremented(so if we delete "space 2" it would actually check space 4 next time(as spot 3 get to be spot 2 after erase)))
So I tried to change it to this
int datastorage::eraseDataPointsBetween(double low,double high)
{
int antal = 0;
for (vector<double>::iterator i = data_.begin(); i !=data_.end();)
{
if (*i >=low && *i <=high)
{
data_.erase(i);
antal++;
}
else
i++;
}
return antal;
}
Where it only increment the i whenever i do not remove a space(so if I delete "space 2", it will check the new "space 2" next run)
This also gives me a syntax error expression: vector iterators incompatible
Hope you can help because I'm pretty lost
vector::erase invalidates iterator so you cannot use it after call to erase.
You should erase from a vector this way:
int datastorage::eraseDataPointsBetween( double low, double high) {
int antal = 0;
for( vector<double>::iterator i = data_.begin(); i !=data_.end())
{
if( (*i >= low) && (*i <= high))
{
i = data_.erase( i); // new (valid) iterator is returned
++antal;
}
else
{
++i;
}
return antal;
}
You should use the remove_if() and erase. The reason why this is somewhat more stable than writing your own loops is simple -- you can't get into trouble using invalid iterators.
#include <algorithm>
#include <vector>
struct IsBetween
{
double low, high;
IsBetween(double l, double h) : low(l), high(h) {}
bool operator()(double d) const { return d >= low && d <= high; }
};
void datastorage::eraseDataPointsBetween(double low,double high)
{
std::vector<double>::iterator it = std::remove_if(data.begin(), data.end(), IsBetween(low, high));
data.erase(it, data.end());
}
There are no loops, and note the use of remove_if() with a function object IsBetween.
The bottom line is that you should minimize the attempt to write loops that erase items in a container while you're looping over the container. There is remove_if(), remove(), partition(), etc. that moves the data you want to focus on to one end of the container.
As much as you'll see answers that erase an iterator while looping, and it seems safe, how many will remember the rules of what is returned, or rather simply, write the loop incorrectly? (even experienced C++ programmers could have written the loop incorrectly on the first cut). So use the algorithms to do this work for you.
For remove_if(), the "bad" data is moved to the end, where you can now easily erase them.
I am reading on tail recursion as below
Tail recursion refers to a recursive call at the last line. Tail
recursion can be mechanically eliminated by enclosing the body in a
while loop and replacing the recursive call with one assignment per
function argument.
For example
void print(Iterator start, Iterator end, ostream& out=cout) {
if(start == end)
return;
out << *start++ << endl;
print(start, end, out);
}
is converted to iterative by above specification as
void print(Iterator start, Iterator end, ostream& out=cout) {
while(true) {
if(start == end)
return;
out << *start++ << endl;
}
}
In above passage it is mentioned that "replacing recursive call with one assignment per function argument, but in given example we didn't have any assignment?
Can any one explain and provide example for above explanation about how to translate recursive to iterative function?
The assignment is hidden in the increment operator:
start++;
is in fact an assignment:
start = start+1;
Actually, the example (part one) is not very good.
out << *start++ << endl;
print(start, end, out);
should be
out << *start << endl;
print( start+1, end, out);
I don't think, whatever passage you are referring is important; just focus on the main problem, where you want to convert a recursive function to a normal iterative function, which can be done (effortlessly) as,
void print(Iterator start, Iterator end, ostream& out=cout) {
while(start != end) {
out << *start++ << endl;
}
}
It is hidden a little in C++, but start++ is assigning a new value to each time in the loop.
What they are talking about is, that you assign the arguments of the tail function call to the parameter variables of this function invocation, but in this case it is not neccessary, as you are calling the function with the exact same arguments (because like others said, the change to the first argument start happened before the function call).
Actually, if done precisely, the iterative function should look like
void print(Iterator start, Iterator end, ostream& out=cout) {
while(true) {
if(start == end)
return;
out << *start++ << endl;
start = start;
end = end;
out = out;
}
}
But these assignments are completely unneccessary, even if conpectually correct.
The general conversion of recursive to iterative would look like this.
Original code:
void print(Iterator start, Iterator end, ostream& out=cout) {
if(start == end)
return;
out << *start++ << endl;
print(start, end, out);
}
Converted code:
void print(Iterator start, Iterator end, ostream& out=cout) {
while(true) {
if(start == end)
return;
out << *start << endl;
// One assignment per function argument for 'general' tail recursion
start = start + 1; // (1)
end = end; // (2)
out = out; // (3)
}
}
The three assignments as in the explanation are included. Assignment (1) is embedded in the start++, assignments (2) and (3) are optimized away.
Given a sorted vector with a number of values, as in the following example:
std::vector<double> f;
f.pushback(10);
f.pushback(100);
f.pushback(1000);
f.pushback(10000);
I'm looking for the most elegant way to retrieve for any double d the two values that are immediately adjacent to it. For example, given the value "45", I'd like this to return "10" and "100".
I was looking at lower_bound and upper_bound, but they don't do what I want. Can you help?
EDIT: I've decided to post my own anser, as it is somewhat a composite of all the helpful answers that I got in this thread. I've voted up those answers which I thought were most helpful.
Thanks everyone,
Dave
You can grab both values (if they exist) in one call with equal_range(). It returns a std::pair of iterators, with first being the first location and second being the last location in which you could insert the value passed without violating ordering. To strictly meet your criteria, you'd have to decrement the iterator in first, after verifying that it wasn't equal to the vector's begin().
You can use STL's lower_bound to get want you want in a few lines of code. lower_bound uses binary search under the hood, so your runtime is O(log n).
double val = 45;
double lower, upper;
std::vector<double>::iterator it;
it = lower_bound(f.begin(), f.end(), val);
if (it == f.begin()) upper = *it; // no smaller value than val in vector
else if (it == f.end()) lower = *(it-1); // no bigger value than val in vector
else {
lower = *(it-1);
upper = *it;
}
You could simply use a binary search, which will run in O(log(n)).
Here is a Lua snippet (I don't have time to do it in C++, sorry) which does what you want, except for limit conditions (that you did not define anyway) :
function search(value, list, first, last)
if not first then first = 1; last = #list end
if last - first < 2 then
return list[first], list[last]
end
local median = math.ceil(first + (last - first)/2)
if list[median] > value then
return search(value, list, first, median)
else
return search(value, list, median, last)
end
end
local list = {1,10,100,1000}
print(search(arg[1] + 0, list))
It takes the value to search from the command line :
$ lua search.lua 10 # didn't know what to do in this case
10 100
$ lua search.lua 101
100 1000
$ lua search.lua 99
10 100
I'm going to post my own anser, and vote anyone up that helped me to reach it, since this is what I'll use in the end, and you've all helped me reach this conclusion. Comments are welcome.
std::pair<value_type, value_type> GetDivisions(const value_type& from) const
{
if (m_divisions.empty())
throw 0; // Can't help you if we're empty.
std::vector<value_type>::const_iterator it =
std::lower_bound(m_divisions.begin(), m_divisions.end(), from);
if (it == m_divisions.end())
return std::make_pair(m_divisions.back(), m_divisions.back());
else if (it == m_divisions.begin())
return std::make_pair(m_divisions.front(), m_divisions.front());
else
return std::make_pair(*(it - 1), *(it));
}
What if (in your case) d is less than the first element or more than the last? And how to deal with negative values? By the way: guaranteeing that your "d" lives between the first and the last value of your vector you can do like that:
// Your initializations
std::vector<double>::const_iterator sit = f.begin();
double upper, lower;
Here is the rest:
while ( *sit < d ) // if the element is still less than your d
++sit; // increase your iterator
upper = *sit; // here you get the upper value
lower = *(--sit); // and here your lower
Elegant enough? :/
You could do a search in your vector for your value (which would tell you where your value would be if it were in the vector) and then return the value before and after that location. So searching for 45 would tell you it should be at index=1 and then you would return 0 and 1 (depending on your implementation of the search, you'll either get the index of the smaller value or the index of the larger value, but this is easy to check with a couple boundary conditions). This should be able to run in O(log n) where n is the number of elements in your vector.
I would write something like this, didn't test if this compiles, but you get the idea:
template <typename Iterator>
std::pair<Iterator, Iterator> find_best_pair(Iterator first, Iterator last, const typename Iterator::value_type & val)
{
std::pair<Iterator, Iterator> result(last, last);
typename Iterator::difference_type size = std::distance(first, last);
if (size == 2)
{
// if the container is of size 2, the answer is the two elements
result.first = first;
result.first = first;
++result.first;
}
else
{
// must be of at lease size 3
if (size > 2)
{
Iterator second = first;
++second;
Iterator prev_last = last;
--prev_last;
Iterator it(std::lower_bound(second, last, val));
if (it != last)
{
result.first = it;
result.second = it;
if (it != prev_last)
{
// if this is not the previous last
// then the answer is (it, it + 1)
++result.second;
}
else
{
// if this the previous last
// then the answer is (it - 1, it)
--result.first;
}
}
}
}
return result;
}
I wrote up this little function, which seems to fit the more general case you wanted. I haven't tested it totally, but I did write a little test code (included).
#include <algorithm>
#include <iostream>
#include <vector>
template <class RandomAccessIt, class Container, class T>
std::pair<RandomAccessIt, RandomAccessIt> bracket_range(RandomAccessIt begin, RandomAccessIt end, Container& c, T val)
{
typename Container::iterator first;
typename Container::iterator second;
first = std::find(begin, end, val);
//Find the first value after this by iteration
second = first;
if (first == begin){ // Found the first element, so set this to end to indicate no lower values
first = end;
}
else if (first != end && first != begin) --first; //Set this to the first value before the found one, if the value was found
while (second != end && *second == val) ++second;
return std::make_pair(first,second);
}
int main(int argc, _TCHAR* argv[])
{
std::vector<int> values;
std::pair<std::vector<int>::iterator, std::vector<int>::iterator> vals;
for (int i = 1; i < 9; ++i) values.push_back(i);
for (int i = 0; i < 10; ++i){
vals = bracket_range(values.begin(), values.end(),values, i);
if (vals.first == values.end() && vals.second == values.end()){ // Not found at all
std::cout << i << " is not in the container." << std::endl;
}
else if (vals.first == values.end()){ // No value lower
std::cout << i << ": " << "None Lower," << *(vals.second) << std::endl;
}
else if (vals.second == values.end()) { // No value higher
std::cout << i << ": " << *(vals.first) << ", None Higher" << std::endl;
}
else{
std::cout << i << ": " << *(vals.first) << "," << *(vals.second) << std::endl;
}
}
return 0;
}
Based on the code that tunnuz posted, here you have some improvements regarding bound checking:
template<typename T>
void find_enclosing_values(const std::vector<T> &vec, const T &value, T &lower, T &upper, const T &invalid_value)
{
std::vector<T>::const_iterator it = vec.begin();
while (it != vec.end() && *it < value)
++it;
if(it != vec.end())
upper = *it;
else
upper = invalid_value;
if(it == vec.begin())
lower = invalid_value;
else
lower = *(--it);
}
Example of usage:
std::vector<int> v;
v.push_back(3);
v.push_back(7);
v.push_back(10);
int lower, upper;
find_enclosing_values(v, 4, lower, upper, -1);
std::cout<<"lower "<<lower<<" upper "<<upper<<std::endl;
If you have the ability to use some other data structure (not a vector), I'd suggest a B-tree. If you data is unchanging, I believe you can retrieve the result in constant time (logarithmic time at the worst).