Find runs of consecutive values in int array - c++

Let's say I have this integer array of separate integer elements:
111100010011010
I'd like to find out if there exists 0000 in this array, which obviously does not, but 000 exists. Same goes for other lengths of consecutive runs.
I know this is easily done with strings, there are built in functions for this, but is there something built in which accomplishes what I want to do?
Or is there another easy method I overlooked? All I can come up with are complicated non efficient algorithms going through the array and saving values in a temporary other array.

No need to save values to a temporary array.
All you need to do is keep track of the largest length found (initially zero) and the location of its first element (initially NULL if you use a pointer to indicate that).
Then walk through the array until you find the value of interest. Count the number of consecutive occurrences. If that number exceeds the maximum length found, set the location to point at the first one found.
Repeat until end of array is reached.
Done. If the largest length found is zero, it means there were no occurrences of the value sought.
No, I'm not going to write code for the above. The description of the approach is enough.
There are also plenty of alternative options using standard algorithms

Just for the record, another way is to use use std::search.
#include <algorithm>
using namespace std;
const int elements[] = { 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0 };
const int test1[] = { 0, 0, 0, 0 };
const int test2[] = { 0, 0, 0 };
auto it1 = std::search(begin(elements), end(elements), begin(test1), end(test1));
auto it2 = std::search(begin(elements), end(elements), begin(test2), end(test2));
std::cout << "Test 0000: " << (it1 == end(elements) ? "no" : "yes") << "\n";
std::cout << "Test 000: " << (it2 == end(elements) ? "no" : "yes") << "\n";
Prints out:
Test 0000: no
Test 000: yes
Even easier if your array is a standard container, like std::array or vector.

Related

Difference between for loop and the range based loop in C++

I am confused as to what what the difference is between for loop and for each loop in C++.
I read tutorials and some books but I am yet to see how for each loop is different.
With arrays, examples I have seen seem to suggest for each loop loops through the whole elements at a go. Could that be the special advantage range based loop has?
The main difference is that the ordinary for-loop uses an additional variable used as an index inside the array and has the scope of the loop and you can yourself write the condition of the for loop.
For example let's assume that you need to output either all even elements of an array or until an element with a zero value is encountered. You can write
#include <iostream>
int main()
{
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 11, 12 };
const size_t N = sizeof( a ) / sizeof( *a );
for ( size_t i = 0; i < N && a[i] != 0; i++ )
{
if ( a[i] % 2 == 0 ) std::cout << i << ": " << a[i] << '\n';
}
return 0;
}
The program output is
1: 2
3: 4
5: 6
7: 8
How to do this with the range-based for loop? For starters before the loop you need to declare a variable that will play the role of the index. One drawback of this is the variable is not declared in the scope where it is used.
Also to stop the iterations of the loop you need to use a break statement within the loop. That also makes the code more complicated.
Compare the above program with this
#include <iostream>
int main()
{
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 11, 12 };
const size_t N = sizeof( a ) / sizeof( *a );
size_t i = 0;
for ( const auto &item : a )
{
if ( item == 0 )
{
break;
}
else if ( item % 2 == 0 )
{
std::cout << i << ": " << item << '\n';
}
++i;
}
return 0;
}
In general to use the range based for loop the used container either shall have member functions begin and end or the general functions begin and end shall support the container. For arrays begin and end mean expressions a and a + N.
The difference between a for loop and a range based for loop is roughly analogous to the difference between goto and a for loop. Former is a more generic control flow, while the latter is more structured. Every range based loop can be written as a for loop and every for loop can be written as a goto. But the reverse is not true.
Goto encapsulates the idea of jumping elsewhere. Loop encapsulates the idea of repetition (which involves jumping back). Range based loop encapsulates the idea of iterating over a range from begin until end (which involves repetition).
If your intention is to iterate over an entire range, then the range based loop is typically syntactically simpler, and easier to understand than a for loop. Likewise, a for loop is easier to understand than a goto loop. This is what makes structured approach superior. Compare for example the following, and consider which one is easier to understand:
for (auto it = list.begin(), end = list.end(); it != end; ++it) {
auto& element = *it;
// do stuff with element
}
for (auto& element : list) {
// do stuff with element
}
loops through the whole elements at a go. Could that be the special advantage range based loop has?
Looping through an entire range is what range based loop can do. A for loop can do that too. But a for loop can do much more: it can iterate indices, it can iterate indefinitely, it can iterate until a terminator etc.

Inserting to set in a "Fixed" Size Loop

So I wanted to insert the double of all the elements in my set back into the set. But obviously I need to grab the end iterator so that I don't keep iterating over new elements. (Don't worry, I checked, set::insert doesn't invalidate iterators: http://www.cplusplus.com/reference/set/set/insert/#validity) So given the input, set<int> foo = { 1, 2, 3 }, here's what I did:
for(auto it = begin(foo), finish = end(foo); it != finish; ++it) {
foo.insert(*it * 2);
}
I expected my set to contain:
1, 2, 3, 4, 6
Surprise! It contains:
-2147483648, -1073741824, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152, 65536, 98304, 131072, 196608, 262144, 393216, 524288, 786432, 1048576, 1572864, 2097152, 3145728, 4194304, 6291456, 8388608, 12582912, 16777216, 25165824, 33554432, 50331648, 67108864, 100663296, 134217728, 201326592, 268435456, 402653184, 536870912, 805306368, 1073741824, 1610612736
Live Example
Clearly end(foo) doesn't work as I thought it did. So... if I want to save the loops size and count to that?
Iterators are still valid, but as a std::set is a node-based container, the elements are always sorted, using std::less<Key> by default
See how iterators are jumping to lower values, making it to struggle for finish
Code snippet:
for( ; it != finish; ++it)
{
auto t = *it ;
std::cout << "At " << t << "\n";
foo.insert( t * 2 ) ;
std::cout << "Inserted " << t*2 << "\n";
}
At 1
Inserted 2
At 2
Inserted 4 <----+
At 3 |
Inserted 6 | <---+
At 4 // jumped back -----+ |
Inserted 8 |
At 6 // Jumped back -----------+
Inserted 12
At 8
.....
A typical method of doing this would be to iterate through your source set, and perform your function on each value, adding the result into a second set.
Once you are finished with the iteration process and have fully generated the second set, union the two sets together.
If you truly want to save the loops size and count to that, you can do something like this:
set<int> foo = { 1, 2, 3 };
int setSize = foo.size();
auto it = foo.begin();
for(int i = 0; i < setSize; ++i) {
foo.insert(*it * 2);
++it;
}
copy(cbegin(foo), cend(foo), ostream_iterator<int>(cout, " "));
This will give you the output: 1 2 3 4 6
This is obviously circular. The size is increasing in every step, making the loop never reach the end.
It's like saying: Take this list, start from the first element, and keep doing this for every element, and when you're done, add one more element to the same list.
Why would this ever end?
EDIT:
Answering: "So... if I want to save the loops size and count to that?":
int size = foo.size();
std::set<int> bar;
for(auto it = begin(foo); it != end(foo); ++it) {
bar.insert(*it * 2);
}
foo.insert(bar.begin(), bar.end());
I believe that your assumption is that a set is allocated into a contiguous container with the presumption that it initially had enough space that reallocation of the contiguous container was not necessary; in this assumed case I would also expect to see your behavior. (It should be noted though that even in a situation where this were a contiguous container, the container's capacity would need to be validated for this assumption to avoid undefined behavior.)
But even in your question you point out that insert doesn't invalidate iterators, which means that the container cannot be contiguous. In fact sets:
Are typically implemented as binary search trees
Understanding this you're really just continuing your loop till your iterator ends pointing to the last leaf node. Your compilers set implementation caused that to happen when you inserted the -2147483648 element, but that's implementation dependent, and thus may behave differently on another compiler.
You're looking for a behavior that is defined and compiler independent. Depending upon you're knowledge of the set contents you could reverse iterate over the set:
for(auto it = rbegin(foo); it != rend(foo); ++it) {
foo.insert(*it * 2);
}
This is only a good solution if the insertion creates elements that are sorted after those being iterated over. For example if foo contains negative numbers this won't work. You could evaluate this by checking: if(*cbegin(foo) < 0) in the else-block you could do the reverse iteration loop suggested above, but in the otherwise you'd need to do a temporary set allocation described in The Quantum Physicist's answer.

Randomly pick a number between 0 and 8 one by one until there is no number left to pick, then start over

I'm not really a programmer. I'm learning as a I go.
I'm not familiar enough with C++ to know exactly how to do it so I ask here:
I want a logic that will pick a number from 0 to 8 randomly.
Once a number has been picked, it shouldn't be picked again until the program goes through all the numbers from 0 to 8.
Then, once all the number have been eliminated, the program "resets" the list of numbers and restarts the same process endlessly.
I know I'll probably have to do an enum (as I will match other variables to those numbers) but I'm not sure how I'll set up this program.
What you are looking for is to randomly shuffle a list of numbers from 0 to 8, print it out in order, then do it all again. For example:
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
while (true) {
std::vector<int> nums {0, 1, 2, 3, 4, 5, 6, 7, 8};
std::random_shuffle(nums.begin(), nums.end());
for (auto num : nums) {
std::cout << num << " ";
}
std::cout << "\n";
// some kind of continuation detection
}
return 0;
}
You can create a vector with the values : {0,1,2,3,4,5,6,7,8}
Then if a for loop {
Select a random number N between 1 and vector.length() (or size, I don't remember the name)
Pick vector[N-1] and remove the N-1 th element from the vector.
}

For loop with the length of array that has values

Say I have an integer array called abc[100]. abc only has values in the first 5 "slots". How can I write a for loop for this where the loop goes up until the last value in abc that isnt empty?
int abc[100] = {1, 2, 3, 4, 5};
In C++ arrays, there is no concept of an array element being "empty".
That idea simply doesn't exist. Erase it from your mind.
Each array element always exists.
In C & C++, when part of an array is explicitly initialized, and part is not explicitly initialized, the part that you didn't specify defaults to zero.
So, you effectively wrote:
int abc[100] = {1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0....};
If you want, you can treat value 0 as a marker for values that aren't set.
int i;
for(i=0; abc[i] != 0; ++i)
{
cout << "[" <<i<< "] : " << abc[i] <<endl;
}
In C++ if you declare an array and initialize only the first few elements, the remaining elements will be value initialize, meaning basically that the "default constructor" will be called.
For built-in types such as int value initializing sets the value to zero. So if you fix the problems with your array, and only initialize the first five elements the remaining will be initialized to zero.

How does an index increment work in c++

My tutor told me to use an index to keep track of which character in the line the program is at. How does an index work exactly? I know its similar to count but other than that I am not sure.
At a high level, an index works on a collection. It simply says "I want the nth element of that collection" (where n is your index).
So if you have:
int foo[] = {2, 3, 5, 8, 13}; // array of 5 integers
Using 0 as the index will give you 2, using 1 will give you 3, using 2 will give you 5, using 3 will give you 8 and using 4 will give you 13.
All these are constant indices, so they will always give you the same result. However, if you use a variable as an index, that means you can retrieve a varying element from your collection.
In the case of an array, that collection is simply a block of contiguous memory. The array itself is a memory address, and by adding the index to that memory address, you find the element you're looking for.
By index he just means a pointer to the specific character. This can simply be an integer keeping track of the characters position or an actual pointer type.
string test = "Hello";
const int sLength = 5;
int index = 0;
for ( ; index < sLength ; index++ )
{
cout << "Character at index " << index << " = " << test[index];
}
In the beginning, it helped me to think of indexes as bookmarks. The bookmark keeps track of the last thing at which I was looking.
However, to really understand indexes, you should investigate pointers. You need to understand how structures are stored in memory, what addresses are, and how to sanely move from one address to another.