This is just a small question, more aimed at understanding the usage of arrays than at solving a difficult problem.
I currently have an array of four integers (Neighbors) that I'd like to compare against a set of other arrays (which don't exist anywhere else - I have no need to store them). I want to know which of the four arrays Neighbors is identical to. As somebody who doesn't know any better, my first attempt was to do this:
if (Neighbors == {1, 1, 0, 0})
{
//code...
}
else if (Neighbors == {0, 1, 1, 0})
{
//code...
}
else if (Neighbors == {0, 0, 1, 1})
{
//code...
}
else if (Neighbors == {1, 0, 0, 1})
{
//code...
}
As you can see, the order of the integers is important. However, the above returned compiler errors about expecting primary expressions before curly-brace tokens.
So instead, I tried this:
int Sets[4][4] = { {1, 1, 0, 0}, {0, 1, 1, 0}, {0, 0, 1, 1}, {1, 0, 0, 1} };
if (Neighbors == Sets[0])
{
//code...
}
else if (Neighbors == Sets[1])
{
//code...
}
else if (Neighbors == Sets[2])
{
//code...
}
else if (Neighbors == Sets[3])
{
//code...
}
What happens here is that even when Neighbors = {0, 1, 1, 0} (for example), Neighbors == Sets[1] returns false.
Now, after doing this and wondering why, I remembered that the array variable is basically a pointer to the first element in a sequence. Right? So I think I get why the above code doesn't work - I'm comparing two memory addresses, rather than two arrays. So instead I wrote this code, which works fine:
for (int ii = 0; ii < 4; ++ii)
{
bool Same = true;
for (int jj = 0; jj < 4; ++jj)
{
if (Neighbors[jj] != Set[ii][jj])
{
Same = false;
}
}
if (Same == true)
{
//code...
}
}
What I want to know is whether there is a way to compare arrays like this without going through two for-loops. It seems like something that ought to be simpler than this. I know a for-loop isn't especially intensive when you've only got 4 values, but I still would have thought it'd be easier to determine whether two arrays contain identical information. If each array is a contiguous block of memory, I would have thought you could just look at those two blocks and check whether they are identical (which is basically what the for-loops are doing, although that requires doing it manually).
So is there a way to compare the content of arrays directly, preferably with a single line of code? If not, why not? I'd like to understand the science behind this issue.
You have tagged the question C++. Which means you should be using std::vector. It has overloaded operator== that does what you want (for two vectors).
You can also use std::equal or std::lexicographical_compare for anything you have iterators for, which includes primitive arrays.
Of course you can also overload the operator== for other things. Unfortunately you can't overload it for primitive arrays, because overloading operators is only allowed if at least one argument is a class (or struct) type. But you could override it to compare vector with array. Something like:
template<typename T, typename Alloc, size_t S>
bool operator==(std::vector<T, Alloc> v, const T (&a)[S])
{
return v.size() == S && std::equal(v.begin(), v.end(), a);
}
(this takes reference to array not degraded to pointer to check it's declared size first and is therefore safe)
Of course all these methods have a loop hidden inside that compares the elements one by one. But you don't have to write it.
The C++iest way to do this is with std::equal :
#include <algorithm>
With C++11:
if (std::equal(begin(Neighbors), end(Neighbors), begin(Sets[0]))
{ /* then they're equal */ }
With C++03:
if (std::equal(Neighbors, Neighbors + 4, Sets[0]))
{ /* then they're equal */ }
You can use memcmp function. If arrays are equal it returns 0. Here is a description: http://www.cplusplus.com/reference/clibrary/cstring/memcmp/
Related
class Solution
{
public:
void sort012(int a[], int n)
{
// code here
int low = 0;
int high = n-1;
int mid = 0;
while(mid<high)
{
int high = n-1;
if(a[mid]==0 && mid<=high)
{ swap(a[mid++],a[low++]);
}
else if(a[mid]==2 && mid<=high)
{ swap(a[mid],a[high--]);
}
else if(a[mid]==1 && mid<=high)
{
mid++;
}
}
}
};
Problem number one is you are redefining the int high = n - 1 inside of the while loop, at each iteration it's reset to this value, so high-- has no effect, and you're getting inside an infinite loop.
Problem number two is that potentially if you pass an array a which has a single value that is not a 0, 1 or 2, you are 100% getting into an infinite loop as well.
Check out this compiler explorer link for an interactive demo: https://godbolt.org/z/EbKPqrxz4
For what it's worth, you program looks like bad C instead of being C++. Non exhaustive list of issues:
The sort012 is an instance method on a class while it doesn't use the instance state. It's probably better as a free function, or at worse a static method on that class.
You're using C arrays.
As a result, you're also not using the algorithms provided by the STL.
I'm assuming this is a kind of coding exercise, but anyways, for the sake of completeness you could achieve the same thing (and more, it'd work with several containers, and regardless of your values/types) with fewer lines of code with this (Compiler Explorer):
#include <fmt/format.h>
#include <algorithm>
#include <array>
int main() {
std::array<int, 10> a{1, 2, 0, 1, 2, 1, 2, 1, 0, 2};
// Could also be a vector: `std::vector<int> a{1, 2, 0, 1, 2, 1, 2, 1, 0, 2};`
std::sort(a.begin(), a.end());
fmt::print("sorted a=");
for (auto x: a) {
fmt::print("{}, ", x);
}
}
I have a block allocation function that takes in an array and then searches through it to find values 0 which indicates the free space, and then allocates blocks to the available free space. I am trying to use unordered map to improve the speed of searching for 0s. In my function, all the elements in the array are inserted into the unordered map. I was wondering if implementing unordered map like below even improves the searching speed compared to just using arrays?
int arr[] = {15, 11, 0, 0, 0, 27, 0, 0}; // example array
int n = sizeof(arr)/sizeof(arr[0]);
unordered_map<int, int> hash;
for(i=n;i>=0;i--)
{
hash[i+1] = arr[i];
}
for(auto v : hash)
{
if(v.second==0)
{
return v.second;
}
}
int arr[] = {15, 11, 0, 0, 0, 27, 0, 0};
int n = sizeof(arr)/sizeof(arr[0]);
for(i=0;i<n;i++)
{
if(arr[i]==0)
{
return arr[i];
}
}
First, note that both functions as you've written them always return zero, which is not what you want.
Now, to answer the main question: No, this approach doesn't help. In both cases you're just iterating over the values in the array until you hit on one that's a zero. This is an O(n) operation in the worst case, and introducing an unordered_map here is just slowing things down.
The most similar thing you could do here that would actually help would be something like
std::unordered_map<int, std::vector<int>> lookup;
for(int i = 0; i < n; i++)
{
lookup[arr[i]].push_back(i);
}
Now if you want to find a block with a zero in it you just an element from lookup[0].
However, given that we only need to track the blocks with zeroes in them, and not immediately look up the blocks with, say, a 13 in them, we may as well just do:
std::vector<int> emptyBlocks;
for(int i = 0; i < n; i++)
{
if(arr[i] == 0) { emptyBlocks.push_back(i); }
}
and then we can just grab empty blocks as we need them.
Note that you should take blocks from the back of emptyBlocks so that deleting them from the list doesn't require us to shift everything over. If you need to take the smallest indices first for some reason, traverse arr backwards when building the list of empty blocks.
That said, when you're allocating blocks typically you're trying to find a range of consecutive empty blocks. If that's the case, what you likely want is a way to look up the starting point of blocks of a given size. And you probably want it to be ordered, too, so that you can ask for "the smallest block at least this large."
#include <iostream>
using namespace std;
int main()
{
int *array1 = new int [5]();
int *array2 = new int [7]();
array1[2] = 3;// or anychange
array2[2] = 3;// to both arrays
if (array1==array2)
{
//if all values of the both arrays are equal
}
else
{
//if all values of the both arrays are not equal
}
return 0;
}
I have two dynamically allocated array using new (the size may or may not be same). Now I want to compare all elements of array (if size and elements are same, then true, if not either of these then false).
How to do in C++? (not interested using vector in my problem scenario)
First off, I would like to encourage you to use std::vector for dynamically allocated arrays. They will free the allocated memory safely and automatically and you can always retrieve their size without extra manual book-keeping.
Once you have that, you can compare the two arrays in the following way:
#include <vector>
int main()
{
std::vector<int> v1 = { 1, 2, 3 };
std::vector<int> v2 = { 1, 2, 3, 4 };
const bool theyAreEqual = v1 == v2;
}
Comparing two pointers as you did, only compares the addresses of the first elements and not the sizes and the contents of the dynamic arrays elementwise. That's one of the reasons, that it's much safer to use std::vector instead of C-style arrays.
array1 == array2 compares pointers. They will never be equal. Furthermore, you can't know how many elements is in a dynamically allocated array, unless you're:
having its size stored separately
using sentinel value to determine its end - you choose a value (e.g. -1) to represent end of the array (like c-style strings usually use \0)
Then you'll be able to know how many elements to iterate over, comparing the elements of both arrays.
Here is a way to resolve it, but I highly recommend vectors, in cases like this.
You need the length and a bool for checking. check is true for default and arrays should be allocated with length1 and length2.
//...
if (length1 != length2) check = false;
else for (int i = 0; i < length1; i++)
{
if (array1[i] != array2[i])
{
check = false;
break;
}
}
if (check)
//...
I followed up on Ralph comment, because I also wanted to see what std::equal did, and the == operator of std::vector does the right thing, and surprisingly simpler to use than the std::equal operator. If you use the latter, you will need to make sure to user begin()/end() for both arrays (It is a C++14 version of std::equal), or add v1.size() == v2.size() &&...
#include <algorithm>
#include <vector>
int main()
{
std::vector<int> v1 = { 1, 2, 3 };
std::vector<int> v2 = { 1, 2, 3, 4 };
std::vector<int> v3 = { 1, 2, 3 };
const bool theyAreEqualv1v2 = v1 == v2;
const bool theyAreEqualv1v3 = v1 == v3;
const bool theyAreEqualStdv1v2 = std::equal(v1.begin(),v1.end(), v2.begin(),v2.end());
const bool theyAreEqualStdv1v2bad = std::equal(v1.begin(),v1.end(), v2.begin());
const bool theyAreEqualStdv1v3 = std::equal(v1.begin(),v1.end(), v3.begin(),v3.end());
// std::equal according to http://en.cppreference.com/w/cpp/algorithm/equal actually
// only compares the first range thus you would really need begin()/end() for both arrays
printf("equal v1v2: %d\n",theyAreEqualv1v2);
printf("equal v1v3: %d\n",theyAreEqualv1v3);
printf("std::equal v1v2: %d\n",theyAreEqualStdv1v2);
printf("std::equal v1v2 bad: %d\n",theyAreEqualStdv1v2bad);
printf("std::equal v1v3: %d\n",theyAreEqualStdv1v3);
return 0;
}
clang++ -std=c++14 -stdlib=libc++ c.cpp
output:
equal v1v2: 0
equal v1v3: 1
std::equal v1v2: 0
std::equal v1v2 bad: 1
std::equal v1v3: 1
I had an interview for a Jr. development job and he asked me to write a procedure that takes an array of ints and shoves the zeroes to the back. Here are the constraints (which he didn't tell me at the beginning .... As often happens in programming interviews, I learned the constraints of the problem while I solved it lol):
Have to do it in-place; no creating temporary arrays, new arrays, etc.
Don't have to preserve the order of the nonzero numbers (I wish he would've told me this at the beginning)
Setup:
int arr[] = {0, -2, 4, 0, 19, 69};
/* Transform arr to {-2, 4, 19, 69, 0, 0} or {69, 4, -2, 19, 0, 0}
or anything that pushes all the nonzeros to the back and keeps
all the nonzeros in front */
My answer:
bool f (int a, int b) {return a == 0;}
std::sort(arr, arr+sizeof(arr)/sizeof(int), f);
What are some other good answers?
Maybe the interviewer was looking for this answer:
#include <algorithm>
//...
std::partition(std::begin(arr), std::end(arr), [](int n) { return n != 0; });
If the order needs to be preserved, then std::stable_partition should be used:
#include <algorithm>
//...
std::stable_partition(std::begin(arr), std::end(arr), [](int n) { return n != 0; });
For pre C++11:
#include <functional>
#include <algorithm>
//...
std::partition(arr, arr + sizeof(arr)/sizeof(int),
std::bind1st(std::not_equal_to<int>(), 0));
Live Example
Basically, if the situation is that you need to move items that satisfy a condition to "one side" of a container, then the partition algorithm functions should be high up on the list of solutions to choose (if not the solution to use).
An approach that sorts is O(N*Log2N). There is a linear solution that goes like this:
Set up two pointers - readPtr and writePtr, initially pointing to the beginning of the array
Make a loop that walks readPtr up the array to the end. If *readPtr is not zero, copy to *writePtr, and advance both pointers; otherwise, advance only readPtr.
Once readPtr is at the end of the array, walk writePtr to the end of the array, while writing zeros to the remaining elements.
This is O(n) so it may be what he's looking for:
auto arrBegin = begin(arr);
const auto arrEnd = end(arr);
for(int i = 0; arrBegin < arrEnd - i; ++arrBegin){
if(*arrBegin == 0){
i++;
*arrBegin = *(arrEnd - i);
}
}
std::fill(arrBegin, arrEnd, 0);
Sorry for my potential nOOb'ness but have been trying to get this for hours and cant seem to find an elegant solution for c++ 98.
My question is, say i have a vector of strings { a,b,c,d,e,f } and i want to move 'e' to the 2nd element how would i do so? Obviously the expected output would now print out { a,e,b,c,d,f }
Ideally looking for a single operation that lets me do this just for efficiency reasons but would love to hear some suggestions on how to achieve this.
Thanks.
It's not possible to do this "efficiently" with std::vector<>, because it is stored in contiguous memory and you must therefore move everything between the old and new locations by one element. So it's linear time in the length of the vector (or at least the distance moved).
The naive solution would be to insert() then erase(), but that requires moving everything after the rightmost location you modified, twice! So instead you can do it "by hand", by copying b through d one position to the right (e.g. with std::copy(), then overwriting b. At least then you avoid shifting anything outside the modified range. It looks like you may be able to make std::rotate() do this, as #WhozCraig mentioned in a comment.
I'd try with std::rotate first and only try other manual stuff (or a container other than vector) if that turns out not be efficient enough:
#include <vector>
#include <iostream>
#include <algorithm>
int main()
{
// move 5 from 4th to 1st index
std::vector<int> v {1,2,3,4,5,6};
// position: 0 1 2 3 4 5
std::size_t i_old = 4;
std::size_t i_new = 1;
auto it = v.begin();
std::rotate( it + i_new, it + i_old, it + i_old + 1);
for (int i : v) std::cout << i << ' ';
}
Live demo.
EDIT As noted in the comments, the below code actually mimics std::rotate, which is of course preferred above my hand-rolled code in all cases.
You can accomplish this with K swaps where K is the distance between the elements:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string v = "abcdef"; // use string here so output is trivial
string::size_type insert_index = 1; // at the location of 'b'
string::size_type move_index = 4; // at the location of 'e'
while(move_index > insert_index)
{
std::swap(v[move_index], v[move_index-1]);
--move_index;
}
std::cout << v;
}
Live demo here. Note I used std::string, but the algorithm remains the same for std::vector. The same can be done with iterators, so you can generalize to containers that don't have operator[].
Expanding on jrok's answer, here's a wrapper around std::rotate() for moving a single element around. This is more general than jrok's example, in that it supports moving an element forward in the vector too (rather than only backward).
See the comments within rotate_single() explaining how you have to swap the logic around when moving the element forward versus back.
#include <vector>
#include <stdexcept> // for std::domain_error in range-checking assertion
#include <algorithm> // for std::rotate()
template<class ContiguousContainer>
void assert_valid_idx(ContiguousContainer & v, size_t index)
{
// You probably have a preferred assertion mechanism in your code base...
// This is just a sample.
if(index >= v.size())
{
throw std::domain_error("Invalid index");
}
}
template<class ContiguousContainer>
void rotate_single(ContiguousContainer & v, size_t from_index, size_t to_index)
{
assert_valid_idx(v, from_index);
assert_valid_idx(v, to_index);
const auto from_it = v.begin() + from_index;
const auto to_it = v.begin() + to_index;
if(from_index < to_index)
{
// We're rotating the element toward the back, so we want the new
// front of our range to be the element just after the "from" iterator
// (thereby making our "from" iterator the new end of the range).
std::rotate(from_it, from_it + 1, to_it + 1);
}
else if(to_index < from_index)
{
// We're rotating the element toward the front,
// so we want the new front of the range to be the "from" iterator.
std::rotate(to_it, from_it, from_it + 1);
}
// else the indices were equal, no rotate necessary
}
You can play with this in Compiler Explorer—there are (extensive) unit tests there, but here's an illustrative sample:
TEST_CASE("Handful of elements in the vector")
{
std::vector<int> v{1, 2, 3, 4, 5, 6}; // Note: this gets recreated for each SECTION() below
// position: 0 1 2 3 4 5
SECTION("Interior moves")
{
SECTION("Move 5 from 4th to 1st index")
{
rotate_single(v, 4, 1);
CHECK(v == std::vector<int>{1, 5, 2, 3, 4, 6});
}
SECTION("Move 2 from 1st to 4th index")
{
rotate_single(v, 1, 4);
CHECK(v == std::vector<int>{1, 3, 4, 5, 2, 6});
}
}
SECTION("Swap adjacent")
{
rotate_single(v, 4, 5);
rotate_single(v, 0, 1);
CHECK(v == std::vector<int>{2, 1, 3, 4, 6, 5});
}
}