I'm learning C++ and am playing around with searching/sorting algorithms.
I am trying to do binary search on an unsorted list of items and return the original array index. I have to sort it first, so to preserve the original indices, I created a 2D array, put the data in the first column and the original indices in the second. (I pared it down a little, which is why I had to put //insert data items here.)
template <class TYPE>
int SomeClass<TYPE>::find(TYPE data)
{
TYPE(*ary)[2] = new TYPE[size()][2];
for (int i = 0; i < size(); i++)
{
ary[i][0] = //insert data items here;
ary[i][1] = i;
}
//reading the data items and indexes into the new 2D array works
someSort(ary, size());
return bsearch(ary, 0, size()-1, data);
}
Assume you have some sorting algorithm. As an example, I'll just put bubble sort below because it doesn't take up much space to write.
template <class DT>
void SomeClass<TYPE>::someSort(TYPE A[][2], int n)
{
int i, j;
for (i = 0; i < n- 1; i++)
{
for (j = 0; j < n- i - 1; j++)
{
if (A[j] > A[j + 1])
swap(&A[j][0], &A[j + 1][0]);
}
}
}
Alright, so my question is how would you modify binary search for a 2D array and return the original value (which is in the second slot of the array)? (Feel free to modify my sorting example, too, in case there are issues there.)
template <class TYPE>
int SomeClass<TYPE>::bsearch(TYPE A[][2], int left, int right, TYPE data)
{
while (right>= left)
{
int mid = left + (right+ left) / 2;
if (A[mid][0] == data)
return A[mid][1];
if (A[mid][0] > data)
right= mid- 1;
else
left= mid+ 1;
}
return -1;
}
You need to check your binary search implementation, as it's not correct. Here's improved version:
template <class TYPE>
int SomeClass<TYPE>::bsearch(TYPE A[][2], int left, int right, TYPE data)
{
while (right>= left)
{
int mid = left + (right - left) / 2; // <== corrected here.
if (A[mid][0] == data)
return A[mid][1];
if (A[mid][0] > data)
right= mid- 1;
else
left= mid+ 1;
}
return -1;
}
While learning it's better to code algorithms manually, but you should know that C++ provides implementation for common algorithms like binary search or quick/merge sort.
For example, you could define your value-pair struct vp that holds value and position in original array:
struct vp
{
TYPE val;
int pos;
bool operator<(const vp& vp) const {
return val < vp.val;
}
static bool cmp(TYPE b, const vp& a) {
return b < a.val;
}
};
then you can sort array of value-pairs using std::sort:
vp *arr = ...
std::sort(arr, arr+size());
then, you can use lower_bound or upper_bound to do binary search in your array of value-pairs:
auto p = std::upper_bound(arr, arr+size(), data, vp::cmp);
But you'll need to interpret properly returned value to figure out if value was found in the array or not.
Related
Looking to implement a function to merge multiple sorted arrays (of the same size) using STL's min heap. Here's what I have so far:
struct node{
int element; // the actual element that is being stored
int index; // array index from where the element was taken
int next; // next index
node(int x, int y, int z){
element = x;
index = y;
next = x;
}
bool operator<( const node & d ) const {
return element < d.element;
}
};
void multiway_merge(vector<vector<int> >& input_lists, vector<int>& output_list){
// n represents the number of unordered sublists and m is the number of integers comprising each sublist
size_t n = input_lists.size();
size_t m = input_lists[0].size();
int element;
vector<node> heap;
heap.reserve(m);
// loading first element of each sub-array into heap: (believe is correct)
for(int i = 0; i < n; i++){
node current(input_lists[i][0], i, 1);
heap.push_back(current);
}
make_heap(heap.begin(), heap.end());
for(int j = 0; j < (n*m); j++){
node root = heap[0];
output_list[j] = root.element;
if(root.next < m){ // if the next element isn't bigger than the array itself...
root.element = input_lists[root.index][root.next];
root.next += 1;
}
else root.element = INT_MAX; // problem is here
heap[0] = root;
make_heap(heap.begin(), heap.end());
}
}
My output is generally one of the inputted numbers and then 2147483647 (INT_MAX) for the rest of the output. I commented where/why this happens above, but overall I'm very confused on how to move within the for loop to the next element and continue going through the vectors to add more elements to the output.
Any help would be greatly appreciated!!
I am trying to compile ORBSLAM2 on Windows with Visual Studio 2015 vc14 x64 compiler. The project was originally developed for GNU GCC. I now have the following issue:
// Compute distances between them
const size_t N = vDescriptors.size();
float aDistances[N][N];
for(size_t i=0;i<N;i++) {
aDistances[i][i]=0;
for(size_t j=i+1;j<N;j++) {
int distij = ORBmatcher::DescriptorDistance(vDescriptors[i],vDescriptors[j]);
aDistances[i][j]=distij;
aDistances[j][i]=distij;
}
}
I get the this error while compiling:
C2131 expression did not evaluate to a constant
... on this line of code:
const size_t N = vDescriptors.size();
Subsequently the two dimensional array definition fails too (float Distances[N][N];).
What's the best way to solve this in Visual-C++ ?
UPDATE: Here's the complete function code:
void MapPoint::ComputeDistinctiveDescriptors() {
// Retrieve all observed descriptors
vector<cv::Mat> vDescriptors;
map<KeyFrame*,size_t> observations;
{
unique_lock<mutex> lock1(mMutexFeatures);
if(mbBad)
return;
observations=mObservations;
}
if(observations.empty())
return;
vDescriptors.reserve(observations.size());
for(map<KeyFrame*,size_t>::iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++) {
KeyFrame* pKF = mit->first;
if(!pKF->isBad())
vDescriptors.push_back(pKF->mDescriptors.row(mit->second));
}
if(vDescriptors.empty())
return;
// Compute distances between them
const size_t N = vDescriptors.size();
float aDistances[N][N];
for(size_t i=0;i<N;i++) {
aDistances[i][i]=0;
for(size_t j=i+1;j<N;j++) {
int distij = ORBmatcher::DescriptorDistance(vDescriptors[i],vDescriptors[j]);
aDistances[i][j]=distij;
aDistances[j][i]=distij;
}
}
// Take the descriptor with least median distance to the rest
int BestMedian = INT_MAX;
int BestIdx = 0;
for(size_t i=0;i<N;i++) {
vector<int> vDists(aDistances[i], aDistances[i]+N);
sort(vDists.begin(),vDists.end());
int median = vDists[0.5*(N-1)];
if(median<BestMedian) {
BestMedian = median;
BestIdx = i;
}
}
{
unique_lock<mutex> lock(mMutexFeatures);
mDescriptor = vDescriptors[BestIdx].clone();
}
}
Your Problem
You tried to create a 2D array on the stack (this is not standard C++, even though it might work on some compilers). For this the size needs to be know at compile time, which is not the case as you call size() on an object which likely is not a constexpr.
QUICK FIX
A quick fix that works out of the box is to just allocate the memory on the heap (do not forget to delete array later on) by doing
float** aDistances = new float[N][N];
The deletion can be done in a function which looks like this
template <typename T>
void delete2DArray(T** ptr, size_t NumRows)
{
for (size_t i = 0; i < NumRows; i++)
{
delete[] ptr[i];
}
delete[] ptr;
}
FIX
You will haveto use dynamic memory allocation. For this you can try the following approach by adding a wrapper class around std::vector (this should be possible as you said the scope is very manageable)
template <typename T>
class Array2D
{
public:
Array2D(size_t numrows, size_t numcols) :
rows(numrows), columns(numcols), array2d(rows * columns)
{}
T& operator()(size_t row, size_t column)
{
return array2d[row * columns + column];
}
const T& operator()(size_t row, size_t column) const
{
return array2d[row * columns + column];
}
T* getRow(size_t row)
{
return &array2d[row * columns];
}
private:
size_t rows;
size_t columns;
std::vector<T> array2d;
};
Than you have to modify your code like this:
// Compute distances between them
const size_t N = vDescriptors.size();
Array2D<float> aDistances(N,N);
for (size_t i = 0; i < N; i++) {
aDistances(i,i) = 0;
for (size_t j = i + 1; j < N; j++) {
int distij = ORBmatcher::DescriptorDistance(vDescriptors[i], vDescriptors[j]);
aDistances(i,j) = distij ;
aDistances(j,i) = distij ;
}
}
As you can see the syntax to access elements has slightly changed [x][y] -> (x,y).
EDIT
As the OP has modified the question, I have noticed that the Distances is used a second time which needs attention as well. For this you will have to add a getColumn method (see above) to the Array2D class. Than you further have to modify
// Take the descriptor with least median distance to the rest
int BestMedian = INT_MAX;
int BestIdx = 0;
for(size_t i=0;i<N;i++) {
vector<int> vDists(aDistances.getRow()[i], aDistances.getRow()[i]+N);
sort(vDists.begin(),vDists.end());
int median = vDists[0.5*(N-1)];
if(median<BestMedian) {
BestMedian = median;
BestIdx = i;
}
}
NOTE: I am not perfectly sure if I got it right -- maybe you have to get a
columns instead of a rows (too late to think straight). If this is the case you should also change the memory layout of the Array2D class, i.e. sorting the elements differently in the underlaying 1D-Vector.
Trying to understand the insertion sort algorithm..
My algorithm looks like this currently:
void insertionSort(int *array, int N) {
int value;
int hole;
int *array2;
for (int i = 1; i < N - 1; i++) {
value = array[i]; //next item to be inserted in array 2
hole = i;
while (hole > 0 && array[hole - 1] > value) {
array[hole] = array[hole - 1];
hole = hole - 1;
}
array[hole] = value;
}
}
My algorithm works for sorting arrays, however I now need to change it so that I build up a new sorted array (array2) one element at a time, rather than just working with the original array.
Is there a simple way to implement this given my completed algorithm?
Thanks.
You can use the following method:
int *array2 = calloc(N, sizeof(int));
for(var index = 0; index < N; index++)
{
array2[index] = array[index];
}
and after that use array2 instead of array
then just change the prototype of your function to int *insertionSort
All remaining is to return array2 at the end of task
But be aware of memory leak: https://en.wikipedia.org/wiki/Memory_leak
I have an array transpose function that mirrors arrays like so:
[1][2][3] [1][4][7]
[4][5][6] ===> [2][5][8]
[7][8][9] [3][6][9]
Here is the concept of the algorithm I came up:
size_t numvars = variables.size(), numsegs = segments.size();
for (int v = 0; v < numvars; ++v) {
for (int s = 0; s < numsegs; ++s) {
float * row = in + (s * numvars);
out[v][s] = *(row + v);
}
}
When proceeding through the algorithm by hand, all works as expected. I would like to implement the function such that it takes two pointers to two-dimensional arrays, one with the source array and the second to a memory buffer that will hold the transposed array. When I try to implement the algorithm in C++ in a function I get the following error:
void transposeArray(float * in, float * out) throw()
{
size_t numvars = variables.size(), numsegs = segments.size();
for (int v = 0; v < numvars; ++v) {
for (int s = 0; s < numsegs; ++s) {
float * row = in + (s * numvars);
out[v][s] = *(row + v);
}
}
}
out[v][s] = *(row + v);
invalid types ‘float[int]’ for array subscript
Is this because the compiler does not know that it should treat the second float * out as a 2-dimensional array? If so, what's the fix?
Well, your out variable is a pointer to a float, so derefencing it in out[v] yields a float value. And you can't subscript a float value.
What you need to do, is to calculate the array index for the out 2D array the same way you calculated it for the in 2D array:
void transposeArray(float * in, float * out) throw() {
size_t numvars = variables.size(), numsegs = segments.size();
for (int v = 0; v < numvars; ++v) {
for (int s = 0; s < numsegs; ++s) {
out[v*numsegs + s] = in[s*numvars + v];
}
}
}
Note:
It's a pity that you are apparently writing this code in C++, and not in C. Because in C, you can do this in a quite nice way:
void transposeArray(int numvars, int numsegs, float (*in)[numvars], float (*out)[numsegs]) {
for (int v = 0; v < numvars; ++v) {
for (int s = 0; s < numsegs; ++s) {
out[v][s] = in[s][v];
}
}
}
The trick here is that the in and out arguments are declared to be pointers to line arrays, which allows the language to invoke the same pointer arithmetic magic that it uses when you declare an array with float myArray[numvars][numsegs];. This pointer arithmetic boils down to do the same thing implicitly which v*numsegs + s does explicitly.
The advantage of C is, that it allows for array types with run time sizes, something C++ does not do. Of course, if numvars and numsegs are compile time constants, you can do the equivalent in C++.
Here is how you can write your function if you want to use the same function signature as the one you gave in the question:
void transposeArray(float * in, float * out) throw() {
size_t numvars = variables.size(), numsegs = segments.size();
float (*in2D)[numvars] = (void*)in;
float (*out2D)[numsegs] = (void*)out;
for (int v = 0; v < numvars; ++v) {
for (int s = 0; s < numsegs; ++s) {
out2D[v][s] = in2D[s][v];
}
}
}
The problem is already solved but I wanted to post a C++-ish solution to your 2D array handling problem. If you want to treat a pointer (basically a 1 dimensional array) as a 2D array whose size is known only at runtime then you could employ one of the following helper templates. They not only make your code look much nicer but they also help you to catch wrong out-of-range indexes in debug mode and in release they compile basically to the same code as your hand-written harder-to-read code. Today's C++ compilers are extremely good at optimizing away such simple methods/functions:
#include <assert.h>
#include <stdio.h>
// An implementation that performs range checking on both dimension and
// has nice array subscript syntax. This has some performance overhead
// in debug mode but in release the compiler does the optimization magic.
template <typename T>
class PtrArray2D
{
public:
class SubDim
{
public:
SubDim(T* p, int d1) : m_Ptr(p), m_D1(d1) {}
T& operator[](int d1)
{
assert(d1>=0 && d1<m_D1);
return m_Ptr[d1];
}
const T& operator[](int d1) const
{
assert(d1>=0 && d1<m_D1);
return m_Ptr[d1];
}
private:
T* m_Ptr;
int m_D1;
};
PtrArray2D(T* p, int d0, int d1) : m_Ptr(p), m_D0(d0), m_D1(d1) {}
SubDim operator[](int d0)
{
assert(d0>=0 && d0<m_D0);
return SubDim(m_Ptr + m_D1*d0, m_D1);
}
const SubDim operator[](int d0) const
{
assert(d0>=0 && d0<m_D0);
return SubDim(m_Ptr + m_D1*d0, m_D1);
}
int GetD0() const { return m_D0; }
int GetD1() const { return m_D1; }
private:
T* m_Ptr;
int m_D0;
int m_D1;
};
template <typename T>
inline PtrArray2D<T> MakePtrArray2D(T* p, int d0, int d1)
{
return PtrArray2D<T>(p, d0, d1);
}
template <typename T>
void Transpose(const PtrArray2D<T>& src, PtrArray2D<T>& dest)
{
assert(src.GetD0() == dest.GetD1() && src.GetD1() == dest.GetD0());
for (int i=0,i_e=src.GetD0(); i<i_e; ++i)
{
for (int j=0,j_e=src.GetD1(); j<j_e; ++j)
{
dest[j][i] = src[i][j];
}
}
}
int test()
{
const int DIMENSION0 = 5;
const int DIMENSION1 = 2;
const int ARRAY_SIZE = DIMENSION0*DIMENSION1;
float* p = new float[ARRAY_SIZE];
for (int i=0; i<ARRAY_SIZE; ++i)
p[i] = (float)i;
PtrArray2D<float> arr0(p, DIMENSION0, DIMENSION1);
printf("%f, %f, %f\n", arr0[0][0], arr0[0][1], arr0[1][0]);
arr0[1][0] = 8;
// The statement below will cause an assert as the second dimension is out of range.
//arr0[0][2];
float* q = new float[ARRAY_SIZE];
PtrArray2D<float> arr1(q, DIMENSION1, DIMENSION0);
Transpose(arr0, arr1);
// OR if you want to create helper array object on-the fly only for the time of execution of Transpose():
//Transpose(MakePtrArray2D(p, DIMENSION0, DIMENSION1), MakePtrArray2D(q, DIMENSION1, DIMENSION0));
printf("%f, %f, %f\n", arr1[0][0], arr1[0][1], arr1[1][0]);
return 0;
}
The compiler doesn't know the dimensions of the array.
So if you keep your simple pointers then you need to do the same addressing arithmetic for out as you currently do for in.
Namely, calculate a row pointer, use an offset into that row, instead of out[v][s].
Technically,
the expression out[v] produces a reference to a float, and
if the float is denoted f, the expression f[s] is then just invalid: you can't index a float value.
As general advice, unless you're using some framework that uses float everywhere, such as SFML, then just use double. That's the default floating point type in C and C++. E.g., the literal 3.14 is of type double, not float.
How can I make an inset method that will add a number into the array in the correct order?
void addElement(int table[], int element, int length) {
int x = 0;
int temporary=0;
cout<<length<<endl;
if(length == 1) {
table[0] = element;
}
else {
if(length == 2) {
if (table[0] > element) {
int temp = table[0];
table[0] = element;
table[1] = temp;
}
else {
table[1] = element;
}
}
else {
for(int i = 0; i< length && x == 0; i++) {
if(element<table[i] && element>=table[i-1]) {
for(int y = i; y<length; y++) {
temporary = table[y+2];
int temp = table[y];
table[y] = element;
table[y+1] = table
}
}
}
}
}
}
This is as far as I have gotten. In my main class I have worked it out so that array is increased by 1. So there is one open space at the end of the array for everything to be pushed back by 1.
You can scan the array from back to front, moving values up until you find the correct insertion point.
void addElement(int *table, int element, int length)
{
int i = length - 1;
for (; i > 0 && table[i-1] > element; --i)
{
table[i] = table[i-1];
}
table[i] = element;
}
Write a shiftElements function, write a findIndexOfFirstGreaterThan function, then in addElement - find the index, if -1 then put in last slot, else shift elements using index, then a[index]=elem;
Draw yourself an example, then work out a list of very simple steps required to do what you want.
Then write code that does those steps.
Im not sure if this is what your looking for, but I think you want something that adds an element depending on its integer value. Also, I do not have access to a compiler at this moment so there might be a couple of errors. The code below is just written to give you a brief idea of what you could do, but probably not a perfect solution to your problem.
int addElement (int element, int array [], int length)
{
vector <int> vectorOfInts; //vector to store current order of ints
vector <int> vectorOfArrangedInts; //vector to store arranged order
for (int counter = 0; counter < length; counter ++) //loop to fill the array with values
{
vectorOfInts.push_back (array [counter]);
}
for (int counter = 0; counter < vectorOfInts.length(); counter ++) //loop through all elements
{
int temp = 0; //stores temp value of biggest number found at a specific moment
int elementIndex; //stores indexes
for (int counterTwo = 0; counterTwo < vectorOfInts.length(); counterTwo ++) //loop through all elements to find the biggest array
{
if (vectorOfInts.at (counterTwo) >= temp) //if value is bigger than current biggest number
{
temp = vectorOfInts.at (counterTwo); //change temp value
elementIndex = counterTwo; //remember index
}
}
vectorOfArrangedInts.push_back (vectorOfInts.at(elementIndex)); //add the biggest number to the arranged values
vectorOfInts.erase (vectorOfInts.begin() + elementIndex); //remove the biggest element
}