I'm trying to implement the merge-sort algorithm. I started with pseudocode that was available in an algorithms book. The pseudocode indicates the first position in the array as 1 and not 0. I am having a very difficult time trying to implement the code.
Here is what I have. I've tried stepping through the recursion by printing out the results at each step but it is very convoluted at this point.
#include <iostream>
#include <deque>
using size_type = std::deque<int>::size_type;
void print(std::deque<int> &v)
{
for(const auto &ref:v)
std::cout << ref << " ";
std::cout << std::endl;
}
void merge(std::deque<int> &vec, size_type p, size_type q, size_type r)
{
int n_1 = q - p;
int n_2 = r - q;
std::deque<int> left, right;
for(auto i = 0; i != n_1; i++)
left.push_back(vec[p + i]);
for(auto j = 0; j != n_2; j++)
right.push_back(vec[q + j]);
int i = 0, j = 0;
std::cout << "left = ";
print(left);
std::cout << "right = ";
print(right);
for(auto k = p; k != r; k++) {
if((i != n_1 && j != n_2) && left[i] <= right[j]) {
vec[k] = left[i];
i++;
}
else if(j != n_2){
vec[k] = right[j];
j++;
}
}
}
void merge_sort(std::deque<int> &A, size_type p, size_type r)
{
int q;
if(p < r - 1) {
q = (p + r)/2;
merge_sort(A, p, q);
merge_sort(A, q + 1, r);
merge(A, p, q, r);
}
}
int main()
{
std::deque<int> small_vec = {1, 6, 2, 10, 5, 2, 12, 6};
std::deque<int> samp_vec = {2, 9, 482, 72, 42, 3, 4, 9, 8, 73, 8, 0, 98, 72, 473, 72, 3, 4, 9, 7, 6, 5, 6953, 583};
print(small_vec);
merge_sort(small_vec, 0, small_vec.size());
print(small_vec);
return 0;
}
I get the following output when I run the program:
left = 1
right = 6
left = 1 6
right = 2 10
left = 2
right = 12 6
left = 1 2 6 10
right = 5 2 12 6
1 2 5 2 6 10 12 6
The error is here: (i != n_1 && j != n_2) && left[i] <= right[j]) when i != n_1 evaluates to false vec[k] = right[j]; is executed - correct.
But if i != n_1 evaluates to true and j != n_2 to false i.e. j = n_2 your program trys to do this vec[k] = right[j]; again i.e. accesing over the bounds of your deque.
Rewrite your for loop as follows:
if (i<n_1 && (j>=n_2 || left[i] <= right[j])
This loop works only due to C++'s short circuiting of the conditions i.e. when j>=n_2 evaluates to true, left[i] <= right[j] is never checked again and you don't access the deque over bounds.
left[i] <= right[j] is being checked only if both i<n_1 is true and j>=n_2 false otherwise the 2nd branch is executed.
After spending a lot of time and getting some valuable help on another post was able to get the algorithm to run correctly.
CORRECT CODE:
#include <iostream>
#include <deque>
using size_type = std::deque<int>::size_type;
void print(std::deque<int> &v)
{
for(const auto &ref:v)
std::cout << ref << " ";
std::cout << std::endl;
}
void print(int arr[], int size)
{
for(int i = 0; i != size; i++)
std::cout << arr[i] << " ";
std::cout << std::endl;
}
void merge(std::deque<int> &vec, size_type p, size_type q, size_type r)
{
int n_1 = q - p + 1;
int n_2 = r - q;
std::deque<int> left, right;
int i = 0, j = 0;
while(i < n_1)
left.push_back(vec[p + i++]);
while(j < n_2)
right.push_back(vec[j++ + q + 1]);
i = 0; j = 0;
//std::cout << "left = ";
//print(left);
//std::cout << "right = ";
//print(right);
for(auto k = p; k <= r; k++) {
if((i < n_1 && left[i] <= right[j]) || j >= n_2) {
vec[k] = left[i++];
}
else if(j < n_2){
vec[k] = right[j++];
}
}
}
void merge_sort(std::deque<int> &A, size_type p, size_type r)
{
int q;
if(p < r) {
q = (r + p) / 2;
std::cout << "q = " << q << std::endl;
//std::cout << "p = " << p << std::endl;
merge_sort(A, p, q);
merge_sort(A, q + 1, r);
merge(A, p, q, r);
}
}
int main()
{
std::deque<int> small_vec = {10, 3, 6, 4, 1, 5, 3, 9, 7, 2, 8};
std::deque<int> samp_vec = {2, 9, 482, 42, 3, 4, 9, 8, 73, 8, 0, 98, 72, 473, 72, 3, 4, 9, 7, 6, 5, 6953, 583};
print(samp_vec);
merge_sort(samp_vec, 0, samp_vec.size() - 1);
print(samp_vec);
return 0;
}
Related
Given 3 numeric sorted arrays:
int[] a;
int[] b;
int[] c;
It is necessary to find three numbers whose difference is minimal:
(a_i- b_j)^2 + (b_j - c_k)^2 + (a_i - c_k)^2 -> min
For examle:
int[] a = {7, 10, 12};
int[] b = {3, 4, 6, 9};
int[] c = {1, 2, 5, 8};
Result should be 7 6 8 (or 7 6 5) because (7 - 6)^2 + (6 - 5)^2 + (7 - 5)^2 = 6 = min
What is the best approach to this problem?
I`ve tried to use 3 variables and increment them depending on the minimum term, but unsuccessfully.
Here is my algorithm written in C++:
void printThreeClosest(int[] a, int[] b, int[] c) {
int64_t diff = (a[0] - b[0]) * (a[0] - b[0]) +
(b[0] - c[0]) * (b[0] - c[0]) +
(a[0] - c[0]) * (a[0] - c[0]);
int i_res = 0, j_res = 0, k_res = 0, i = 0, j = 0, k = 0;
while (i < a.size() && j < b.size() && k < c.size()) {
int first_term = (a[i] - b[j]) * (a[i] - b[j]);
int second_term = (b[j] - c[k]) * (b[j] - c[k]);
int third_term = (a[i] - c[k]) * (a[i] - c[k]);
int min_term = std::min(a[i], std::min(b[j], c[k]));
int64_t current_diff = first_term + second_term + third_term;
if (current_diff < diff) {
diff = current_diff;
i_res = i, j_res = j, k_res = k;
}
if (diff == 0) {
break;
}
if (first_term == min_term) {
++k;
} else if (second_term == min_term) {
++i;
} else {
++j;
}
}
std::cout << a[i_res] << " " << b[j_res] << " " << c[k_res] << "\n";
}
IMO, the straight-forward, but O(n^3) solution may be this:
void printThreeClosest(int[] a, int[] b, int[] c) {
int minVal = -1;
int resa, int resb, int resc;
for(int i=0; i<a.length && minVal != 0; i++) {
int x = a[i];
for(int j=0; j<b.length && minVal != 0; j++) {
int y = b[j];
for(int k=0; k<c.length && minVal != 0; k++) {
int z = c[k];
int sumOfSqr = ( ((x-y)*(x-y)) + ((y-z)*(y-z)) + ((z-x)*(z-x)) );
if (minVal < 0) {
minVal = sumOfSqr;
resa=x; resb=y; resc=z;
} else if (sumOfSqr < minVal) {
minVal = sumOfSqr;
resa=x; resb=y; resc=z;
}
}
}
};
std::cout << resa << ' ' << resb << ' ' << resc << std::endl;
}
This solution implemented in Javascript for quick testing is below:
const a = [7, 10, 12];
const b = [3, 4, 6, 9];
const c = [1, 2, 5, 8];
let minVal = -1;
let result = [];
const sumOfSquares = (x, y, z) => ( ((x-y)*(x-y)) + ((y-z)*(y-z)) + ((x-z)*(x-z)) );
for (let i=0; i < a.length && minVal !== 0; i++) {
for (let j=0; j < b.length && minVal !== 0; j++) {
for (let k=0; k < c.length && minVal !== 0; k++) {
const tempSum = sumOfSquares(a[i], b[j], c[k]);
if (minVal < 0) {
minVal = tempSum;
result = [a[i], b[j], c[k]];
} else if (tempSum < minVal) {
minVal = tempSum;
result = [a[i], b[j], c[k]];
}
}
}
}
console.log('result: ', result);
decompose(11) must return [1,2,4,10].
Note that there are actually two ways to decompose 11², 11² = 121 = 1 + 4 + 16 + 100 = 1² + 2² + 4² + 10².
For decompose(50) don't return [1, 1, 4, 9, 49] but [1, 3, 5, 8, 49] since [1, 1, 4, 9, 49] doesn't form a strictly increasing sequence.
I created a function but in only some cases provides a strictly increasing sequence all of my solutions add up to the correct number, what changes do i have to make to enable the return of a strictly increasing sequence?
vector<ll> Decomp::decompose(ll n){
ll square = n * n, j = 1, nextterm = n - 1, remainder, sum = 0;
float root;
vector<ll> sequence;
do
{
sequence.push_back(nextterm);
sum = sum + (nextterm * nextterm);
remainder = square - sum;
root = sqrt(remainder - 1);
if (root - (int)root > 0)
{
root = (int)root;
}
j = 1;
nextterm = (int)root;
if (remainder == 1)
{
sequence.push_back(1);
}
} while (root > 0);
reverse(sequence.begin(),sequence.end());
for (int i=0; i < sequence.size(); i++)
{
cout << sequence[i] << endl;
}
}
Here is a simple recursive approach, basically exploring all the possibilities.
It stops once a solution is found.
Output:
11 : 1 2 4 10
50 : 1 3 5 8 49
And the code:
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
bool decompose_dp (long long int sum, long long int k, std::vector<long long int> &seq) {
while (k > 0) {
long long int sump = sum - k*k;
if (sump == 0) {
seq.push_back(k);
return true;
}
if (sump < 0) {
k--;
continue;
}
long long int kp = k-1;
while (kp > 0) {
if (decompose_dp(sump, kp, seq)) {
seq.push_back(k);
return true;
}
kp --;
}
k--;
}
return false;
}
std::vector<long long int> decompose(long long int n){
long long int square = n * n, j = 1, nextterm = n - 1, remainder, sum = 0;
float root;
std::vector<long long int> sequence;
auto check = decompose_dp (n*n, n-1, sequence);
return sequence;
}
void pr (long long int n, const std::vector<long long int> &vec) {
std::cout << n << " : ";
for (auto k: vec) {
std::cout << k << " ";
}
std::cout << "\n";
}
int main() {
long long int n = 11;
auto sequence = decompose (n);
pr (n, sequence);
n = 50;
sequence = decompose (n);
pr (n, sequence);
}
Here's BFS, DFS and brute force in Python. BFS seems slow for input 50. Brute force yielded 91020 different combinations for input 50.
from collections import deque
def bfs(n):
target = n * n
queue = deque([(target, [], 1)])
while queue:
t, seq, i = queue.popleft()
if t == 0:
return seq
if (t == target and i*i < t) or (t != target and i*i <= t):
queue.append((t - i*i, seq[:] + [i], i + 1))
queue.append((t, seq, i + 1))
def dfs(n):
target = n * n
stack = [(target, [], 1)]
while stack:
t, seq, i = stack.pop()
if t == 0:
return seq
if (t == target and i*i < t) or (t != target and i*i <= t):
stack.append((t - i*i, seq[:] + [i], i + 1))
stack.append((t, seq, i + 1))
def brute(n):
target = n * n
stack = [(target, [], 1)]
result = []
while stack:
t, seq, i = stack.pop()
if t == 0:
result.append(seq)
if (t == target and i*i < t) or (t != target and i*i <= t):
stack.append((t - i*i, seq[:] + [i], i + 1))
stack.append((t, seq, i + 1))
return result
print bfs(50) # [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20]
print dfs(50) # [30, 40]
#print brute(50)
Suppose I have a vector<int> myVec. Let there be n elements in it. I know that these elements are in sorted order(ascending) and also that they are unique. Let n = 10 and myVec be {2, 4, 6, 8, 10, 12, 14, 16, 18, 20}. I'm given l and r such that 0<=l<=r<=n-1. Now i want to search an element val in the subvector that is defined by the bounds l and rsuch that
if val is found return val
if val is not found then return (if possible) a value in the subvector which is just smaller than val.
Return false(or -1 maybe) if either of the above is not possible.
In the above case if if l = 3 and r = 5. The subvector is {8, 10, 12}. If val = 8 return 8. If val = 7 return false (or -1). If val = 9 return 8.
How do I implement this. I want order comparable to binary search. Also, is it possible to use std::binary_search() present under algorithm header file.
something like this?
int search(int l, int r, int value) {
if (l > vec.Size() || r > vec.Size() || l > r) return -1;
for (int i = r; i >= l; --i) {
int v = vector[i];
if (v <= value) return v;
}
return -1;
}
or does it need to be binary?
int BinarySearch(int l, int r, int value) {
return PrivateBinarySearch(l, r, (l+r)/2, value);
}
int PrivateBinarySearch(int l, int r, int index, int value) {
if (vector[index] == value) return value;
else if (vector[index] > value) {
if (index == l) return -1;
else if (index == r) return -1;
else return PrivateBinarySearch(l, index, (index-1+l)/2, value);
}
else { // vector[index] < value
if (index == l) return vector[index];
else if (index == r) return vector[index];
else return PrivateBinarySearch(index, r, (index+1+r)/2, value);
}
Hope this helps
This should work for you and is pretty extensible and flexible:
template<typename T>
typename vector<T>::const_iterator
find_or_under (typename vector<T>::const_iterator start, typename vector<T>::const_iterator end,
const T& val)
{
auto el = std::lower_bound(start, end, val);
//if not found, propagate
if (el == end)
return el;
//if it's equal, just return the iterator
if ((*el) == val)
return el;
//if there is no value of an equal or smaller size, return the end
if (el == start)
return end;
//otherwise, return the previous element
return el-1;
}
//Functor representing the search
struct CustomSearch
{
//Create a searcher from a subrange
CustomSearch (const vector<int> &v, size_t l, size_t r)
{
start = std::lower_bound(std::begin(v), std::end(v), l);
end = find_or_under(start, std::end(v), r) + 1;
}
//Calling the searcher
//Returns this->end on not found
auto operator() (int val)
{
return find_or_under(start, end, val);
}
vector<int>::const_iterator start;
vector<int>::const_iterator end;
};
int main() {
vector<int> v = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
CustomSearch searcher {v, 3, 8};
cout << *searcher(6);
}
Using traditional binary search with minor modification:
#include <iostream>
#include <vector>
int search(const std::vector<int> &vec, int l, int r, int val)
{
int pivot, xl = l, xr = r, mid;
do {
/* Not exact match, check if the closest lower match is in the
* subvector. */
if (xl > xr) {
return xr >= l ? vec[xr]: -1;
}
mid = (xl + xr) / 2;
pivot = vec[mid];
if (val < pivot) {
xr = mid - 1;
} else if (val > pivot) {
xl = mid + 1;
} else if (val == pivot) {
return val;
}
} while (true);
}
int main()
{
std::vector<int> myVec(10);
myVec[0] = 2;
myVec[1] = 4;
myVec[2] = 6;
myVec[3] = 8;
myVec[4] = 10;
myVec[5] = 12;
myVec[6] = 14;
myVec[7] = 16;
myVec[8] = 18;
myVec[9] = 20;
int l = 3, r = 5;
std::cout << "search(3, 5, 8) = " << search(myVec, 3, 5, 8) << std::endl;
std::cout << "search(3, 5, 7) = " << search(myVec, 3, 5, 7) << std::endl;
std::cout << "search(3, 5, 9) = " << search(myVec, 3, 5, 9) << std::endl;
return 0;
}
enter code here
I am having trouble with trying to implement the merge sort algorithm. I would appreciate it if someone can help me out. Here is what I have.
#include <iostream>
#include <deque>
using size_type = std::deque<int>::size_type;
void print(std::deque<int> &v)
{
for(const auto &ref:v)
std::cout << ref << " ";
std::cout << std::endl;
}
void merge(std::deque<int> &vec, size_type p, size_type q, size_type r)
{
int n_1 = q - p;
int n_2 = r - q;
std::deque<int> left, right;
for(auto i = 0; i != n_1; i++)
left.push_back(vec[p + i]);
for(auto j = 0; j != n_2; j++)
right.push_back(vec[q + j]);
int i = 0, j = 0;
std::cout << "left = ";
print(left);
std::cout << "right = ";
print(right);
for(auto k = p; k != r; k++) {
if(i < n_1 && left[i] <= right[j]) {
vec[k] = left[i];
i++;
}
else if(j < n_2){
vec[k] = right[j];
j++;
}
}
}
void merge_sort(std::deque<int> &A, size_type p, size_type r)
{
int q;
if(p < r) {
q = (p + r)/2;
merge_sort(A, p, q);
merge_sort(A, q + 1, r);
merge(A, p, q, r);
}
}
int main()
{
std::deque<int> small_vec = {1, 6, 2, 10, 5, 2, 12, 6};
std::deque<int> samp_vec = {2, 9, 482, 72, 42, 3, 4, 9, 8, 73, 8, 0, 98, 72, 473, 72, 3, 4, 9, 7, 6, 5, 6953, 583};
print(small_vec);
merge_sort(small_vec, 0, small_vec.size());
print(small_vec);
return 0;
}
The output from the program is:
left =
right = 1
left = 1
right = 6
left =
right = 10
left = 1 6
right = 2 10
left =
right = 2
left =
right = 6
left = 2
right = 12 6
left = 1 2 6 10
right = 5 2 12 6
1 2 5 2 6 10 12 6
There are a few issues with your sort. Firstly the merge step is wrong. Second how you call merge is wrong. Ill suggest a few steps to improve the implementation to a correct solution, and maybe itll help you.
First my code for merge:
void merge(std::deque<int> &vec, size_type p, size_type q, size_type r)
{
std::deque<int> left, right;
int i = p, j = q+1;
while(i <= q) //change 1: to a while loop. expresses it a little simpler but
//you weren't inserting the correct left elements here
left.push_back(vec[i++]);
while(j <= r) //change 2: same thing, lets get the correct right values
right.push_back(vec[j++]);
i = 0; j = 0;
for(auto k = p; k <= r; k++) {
//change 3: alter this case to include the left over left elements! this is the main error
if(i < left.size() && left[i] <= right[j] || j >= right.size())
vec[k] = left[i++];
else if(j < right.size())
vec[k] = right[j++];
}
}
Then to change how you call merge_sort to:
merge_sort(small_vec, 0, small_vec.size()-1); //change 4: initialized r wrong
This made the sort work for me. As a review of the problems I found: 1) not grabbing the correct subarrays of left and right. 2) didn't handle merge correctly - forgot to grab all the left elements after right is gone. 3) didn't call merg_sort correctly, initializing the r parameter incorrectly.
So I'm trying to code Dijkstra's shortest path algorithm in C++. For some reason, it's not adding up the distances correctly...
Here is what I have so far for code. You can ignore the section where I am copying the path to the stack because I know it's not complete yet. Any ideas where I'm going wrong?
#include <fstream>
#include "matrix.h"
#include <list> // STL container
using namespace std;
//---------------------------------------------------------------------------
const int INFIN = 100000;
const int size = 8;
double a[] = {
0, 0, 5, 0, 0, 2, 3, 0, //length matrix ( #9, page 276)
4, 0, 6, 0, 7, 0, 5, 0,
0, 3, 0, 9, 2, 6, 0, 7,
3, 0, 2, 0, 1, 0, 7, 6,
0, 5, 0, 1, 0, 0, 4, 0,
0, 0, 2, 0, 8, 0, 9, 0,
1, 2, 3, 0, 0, 6, 0, 0,
5, 0, 8, 0, 2, 0, 9, 0
};
// Global declarations for L Matrix and begin and end node
Matrix L(size,size,a); //length matrix
int begin, end;
void path(long* D, int* P); //function prototype for shortest path algorithm
Matrix Warshall(Matrix M);
void main()
{
int i, u;
long D [size+1]; //distance functions
int P [size+1]; //prior vertices in path
cout << "\nLength Matrix: " << L;
cout << "\nPaths that exist:" << Warshall(L);
for (i=1; i <= size; i++) {
D[i] = INFIN; //initialize distance functions
P[i] = 0;
}
cout << "\nFind distance from vertex #";
cin >> begin;
cout << " to vertex #";
cin >> end;
if (begin == end) exit(1);
if (begin < 0 || end < 0) exit(1);
if (begin > size || end > size) exit(1);
path(D,P);
cout << "\nShortest distance from \nvertex #"
<< begin << " to vertex #"
<< end << " is " << D[end];
// u = end;
list<int> stack; // work path backwards
while (1) {
stack.push_front(end);
stack.push_front(begin);
break;
}
cout << "\nusing path:\n";
cout << "\t" << stack.front();
stack.pop_front();
while (stack.size()) {
cout << " -> " << stack.front();
stack.pop_front();
}
getch();
}
void path(long* D, int* P) {
int i, u, dist;
int U[size+1];
for (i=1; i <= size; i++)
U[i] = 0;
U[begin] = 1; // add first vertex;
D[begin] = 0;
u = begin;
do { // until find end vertex
for (i = 1; i <= size; i++) {
dist = L.element(u,i); // distance from u to i
if( D[u] + dist < D[i]) {
D[i] = D[u] + dist;
P[i] = u;
}
}
dist = 38000; // reset distance value to large value
int min;
for(i = 1; i <= size; i++) {
if(L.element(u,i) != 0) {
if(L.element(u,i) < dist && U[i] != 1) {
dist = L.element(u,i);
min = i;
}
}
}
u = min;
U[u] = 1;
cout << "Min is " << min << endl;
} while (u != end);
}
if( D[u] + dist < D[i]) {
D[i] = D[u] + dist;
P[i] = u;
}
should be
if( D[u] + dist < D[i] && dist != 0) {
D[i] = D[u] + dist;
P[i] = u;
}