I can iterate over the subsets of size 1
for( int a = 0; a < size; a++ ) {
or subsets of size 2
for( int a1 = 0; a1 < size; a1++ ) {
for( int a2 = a1+1; a2 < size; a2++ ) {
or 3
for( int a1 = 0; a1 < size; a1++ ) {
for( int a2 = a1+1; a2 < size; a2++ ) {
for( int a3 = a2+1; a3 < size; a3++ ) {
But how to do this for subsets of size n?
This does the job, based on an answer by Adam Rosenfield
void iterate(int *a, int i, int size, int n)
{
int start = 0;
if( i > 0 ) start = a[i-1]+1;
for(a[i] = start; a[i] < n; a[i]++) {
if(i == n-1) {
// a is the array of indices of size n
for( int k = 0; k < size; k++ ) {
printf("%d ",a[k]);
}
printf("\n");
}
else
iterate(a, i+1, size, n);
}
}
You can use recursion:
void iterate(int *a, int i, int size, int n)
{
for(a[i] = 0; a[i] < size; a[i]++)
{
if(i == n-1)
DoStuff(a, n); // a is the array of indices of size n
else
iterate(a, i+1, size, n);
}
}
...
// Equivalent to 4 nested for loops
int a[4];
iterate(a, 0, size, 4);
You likely could do this with some recursion.
Here is something I used for a similar problem. It does not use recursion; rather, it uses a vector of indexes.
#include <vector>
template<class T>
class MultiForVar {
std::vector<T> _begin, _end, _vars;
inline int dim(){return _vars.size();}
public:
MultiForVar(std::vector<T> begin, std::vector<T> end) : _begin(begin), _end(end), _vars(_begin)
{
assert(begin.size() == end.size() and "Starting and ending vector<T> not the same size!" );
}
MultiForVar& operator ++()
{
++_vars[dim()-1];
for(int d = dim()-1; d > 0; --d)
{
if( _vars[d] >= _end[d] )
{
_vars[d] = _begin[d];
++_vars[d-1];
}
}
return *this;
}
bool done()
{
/*for(int d = 0; d < dim(); ++d)
if( _vars[d] < _end[d] )
return false;
return true;*/
return (_vars[0] >= _end[0]);
}
T operator[](int d)
{
return _vars.at(d);
}
int numDimensions(){
return dim();
}
std::vector<T>& getRaw(){
return _vars;
}
};
If I understand what you're asking correctly, another way to do it is to use bit-wise operators:
for(int i = 0; i < 1<<size; i++) {
for(int j = 0; j < size; j++) {
if(i & 1<<j) printf("%d ", a[j]);
}
printf("\n");
}
You need something the constructs the powerset of the original set. It's been a while since I've written that, but the psuedocode looks like
Powerset(a, size)
{
if(size == 0) return emptyset
subseta = Powerset(a, size-1) // Powerset of everything except last element
subsetb = appendToAll(a[size-1], subseta) // appends the last element to every set in subseta
return union(subseta, subsetb)
}
Related
I am solving the problem-->
Given an array of integers, find out whether there are two distinct indices i and j in the array such that the absolute difference between nums[i] and nums[j] is at most t and the absolute difference between i and j is at most k.
and the error I get is Line 16: Char 17: runtime error: index 3 out of bounds for type 'int [n - 1]' (solution.cpp)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior prog_joined.cpp:25:17
The line 16 is indice[i][j] = abs(i-j);
class Solution {
public:
bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
int n = nums.size();
int indice[n-1][n-1];
int total[n-1][n-1];
for(int i = 0;i<n;i++)
{
for(int j=0;j<n;j++)
{
indice[i][j]= abs(i-j);
total[i][j] = abs(nums[i]-nums[j]);
}
}
for(int i = 0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(indice[i][j]<=k && total[i][j]<=t)
{
return true;
}
}
}
return false;
}
};
for the test case [1,2,3,1] 3 0
The code works fine on my device and other compiler but not on leetcode's compiler.
Please help
This would fix your bug, however there is a problem with your algorithm, does not pass all the test cases:
class Solution {
public:
bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
int n = nums.size();
int indice[n][n];
int total[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
indice[i][j] = abs(i - j);
total[i][j] = abs(nums[i] - nums[j]);
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (indice[i][j] <= k && total[i][j] <= t) {
return true;
}
}
}
return false;
}
};
This solution would pass using std::lower_bound:
// The following block might trivially improve the exec time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(NULL);
std::cout.tie(NULL);
return 0;
}();
// Most of headers are already included;
// Can be removed;
#include <cstdint>
#include <vector>
#include <set>
#include <algorithm>
using ValueType = std::int_fast64_t;
static const struct Solution {
static const bool containsNearbyAlmostDuplicate(
const std::vector<int>& nums,
const int k,
const int t
) {
std::set<ValueType> window;
ValueType len = std::size(nums);
for (auto index = 0; index < len; ++index) {
if (index > k && index - k - 1 < len ) {
window.erase(nums[index - k - 1]);
}
const auto it = window.lower_bound((ValueType)nums[index] - t);
if (it != std::cend(window) && *it - nums[index] <= t) {
return true;
}
window.insert(nums[index]);
}
return false;
}
};
I already managed to implement most of what I planned to do correctly, but somehow I struggle with the unique and cut method.
The unique method should sort the vector and delete all entries that appear more than once and the original vector should be overwritten with the shortened on. The cut method should delete all entries < cMin or > cMax.
Here is my try so far:
#include <cassert>
#include <iostream>
using std::cout;
using std::endl;
class Vector {
private:
int n;
double* coeff;
public:
Vector(int, double = 0);
~Vector();
Vector(const Vector&);
Vector& operator=(const Vector&);
int size() const;
double& operator()(int);
const double& operator()(int) const;
double max() const;
void sort();
void unique();
void cut(double Cmin, double Cmax);
void print() const;
};
Vector::Vector(int n, double init)
{
assert(n >= 0);
this->n = n;
if (n == 0) {
coeff = (double*)0;
}
else {
coeff = new double[n];
}
for (int i = 0; i < n; i++) {
coeff[i] = init;
}
}
Vector::Vector(const Vector& rhs)
{
n = rhs.n;
if (n > 0) {
coeff = new double[n];
}
else {
coeff = (double*)0;
}
for (int i = 0; i < n; i++) {
coeff[i] = rhs.coeff[i];
}
}
Vector::~Vector()
{
if (n > 0) {
delete[] coeff;
}
}
Vector& Vector::operator=(const Vector& rhs)
{
if (this != &rhs) {
if (n != rhs.n) {
if (n > 0) {
delete[] coeff;
}
n = rhs.n;
if (n > 0) {
coeff = new double[n];
}
else {
coeff = (double*)0;
}
}
for (int i = 0; i < n; i++) {
coeff[i] = rhs.coeff[i];
}
}
return *this;
}
int Vector::size() const
{
return n;
}
double& Vector::operator()(int j)
{
assert(j >= 1 && j <= n);
return coeff[j - 1];
}
const double& Vector::operator()(int j) const
{
assert(j >= 1 && j <= n);
return coeff[j - 1];
}
double Vector::max() const
{
double max = coeff[0];
for (int i = 1; i < n; i++) {
if (coeff[i] > max) {
max = coeff[i];
}
}
return max;
}
void Vector::sort()
{ //bubble-sort
double tmp = 0;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - 1; j++) {
if (coeff[j] > coeff[j + 1]) {
tmp = coeff[j];
coeff[j] = coeff[j + 1];
coeff[j + 1] = tmp;
}
}
}
}
void Vector::unique()
{
sort();
int counter = 0;
Vector kopie = *this;
for (int i = 0; i < n; i++) {
if (i == 0 && coeff[i] != coeff[i + 1]) {
counter++;
}
if (i == n - 1 && coeff[i] != coeff[i - 1]) {
counter++;
}
if (i != 0 && i != n - 1 && coeff[i] != coeff[i - 1] && coeff[i] != coeff[i + 1]) {
counter++;
}
}
delete[] coeff;
coeff = new double[counter];
//to be continued...
}
void Vector::cut(double Cmin, double Cmax)
{
sort();
int counter = 0;
int j = 0;
Vector kopie = *this;
for (int i = 0; i < n; i++) {
if (coeff[i] >= Cmin && coeff[i] <= Cmax) {
counter++;
}
}
delete[] coeff;
coeff = new double[counter];
for (int i = 0; i < n; i++) {
if (kopie.coeff[i] >= Cmin && kopie.coeff[i] <= Cmax) {
coeff[j] = kopie.coeff[i];
j++;
if (j == n) {
break;
}
}
}
}
void Vector::print() const
{
for (int i = 0; i < n; i++) {
cout << coeff[i] << " ";
}
}
int main()
{
Vector X(8);
X.print();
cout << endl;
X(1) = 1.;
X(2) = 7.;
X(3) = 2.;
X(4) = 5.;
X(5) = 6.;
X(6) = 5.;
X(7) = 9.;
X(8) = 6.;
X.print();
cout << endl;
X.sort();
X.print();
cout << endl;
//X.unique();
//X.print();
//cout << endl;
X.cut(2, 6);
X.print();
cout << endl;
return 0;
}
For the unique function, rather than checking if it's legal to move the counter forward, I would just check if your current element and the next element aren't the same. If they are, set the next element's pointer to skip over the duplicate element.
Pseduocode:
For(int i = 0; i < n-1; i++) {
if(coef[i] == coef[i+1]) {
//Keep moving next element pointer until not equal. Probably use a while loop
}
}
The simplest solution that I can think of is something like this:
void Vector::unique()
{
size_t counter = 0;
double* copy = new double[n];
copy[counter++] = coeff[0]; // The first element is guaranteed to be unique
// Since coeff is sorted, copy will be sorted as well.
// Therefore, its enough to check only the last element of copy to
// the current element of coeff
for (size_t i = 1; i < n; i++)
{
if (coeff[i] != copy[counter])
{
copy[counter++] = coeff[i];
}
}
// copy already contains the data in the format that you want,
// but the reserved memory size may be larger than necessary.
// Reserve the correct amount of memory and copy the data there
delete[] coeff;
coeff = new double[counter];
std::memcpy(coeff, copy, counter*sizeof(double));
}
For cut() you can use a similar algorithm:
void Vector::cut(double Cmin, double Cmax)
{
size_t counter = 0;
double* copy = new double[n];
for (size_t i = 0; i < n; i++)
{
if (coeff[i] > Cmin && coeff[i] < Cmax)
{
copy[counter++] = coeff[i];
}
}
// Same story with memory size here as well
delete[] coeff;
coeff = new double[counter];
std::memcpy(coeff, copy, counter*sizeof(double));
}
Is there any reason why you can't use the standard library?
void Vector::unique() {
std::sort(coeff, std::next(coeff, n));
auto it = std::unique(coeff, std::next(coeff, n));
double* tmp = new double[n = std::distance(coeff, it)];
std::copy(coeff, it, tmp);
delete[] std::exchange(coeff, tmp);
}
void Vector::cut(double Cmin, double Cmax) {
auto it = std::remove_if(coeff, std::next(coeff, n),
[=] (double d) { return d < Cmin || d > Cmax; });
double* tmp = new double[n = std::distance(coeff, it)];
std::copy(coeff, it, tmp);
delete[] std::exchange(coeff, tmp);
}
To remove duplicates and sort, you can achieve it in three ways
Just using vector, sort + unique
sort( vec.begin(), vec.end() );
vec.erase( unique( vec.begin(), vec.end() ), vec.end() );
Convert to set (manually)
set<int> s;
unsigned size = vec.size();
for( unsigned i = 0; i < size; ++i )
s.insert( vec[i] ); vec.assign( s.begin(), s.end() );
Convert to set (using a constructor)
set<int> s( vec.begin(), vec.end() );
vec.assign( s.begin(), s.end() );
All three has different performance. You can use one depending upon your size and number of duplicates present.
To cut you can use algorithm library
std::remove, std::remove_if
Syntax
template< class ForwardIt, class T >
constexpr ForwardIt remove( ForwardIt first, ForwardIt last, const T& value );
Possible implementation
First version
template< class ForwardIt, class T > ForwardIt remove(ForwardIt first, ForwardIt last, const T& value)
{ first = std::find(first, last, value);
if (first != last)
for(ForwardIt i = first; ++i != last; )
if (!(*i == value))
*first++ = std::move(*i); return first; }
Second version
template<class ForwardIt, class UnaryPredicate> ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate p)
{ first = std::find_if(first, last, p);
if (first != last)
for(ForwardIt i = first; ++i != last; )
if (!p(*i)) *first++ = std::move(*i);
return first; }
Examples
The following code removes all spaces from a string by shifting all non-space characters to the left and then erasing the extra. This is an example of erase-remove idiom.
Run this code
#include <algorithm>
#include <string>
#include <iostream>
#include <cctype>
int main()
{ std::string str1 = "Text with some spaces"; str1.erase(std::remove(str1.begin(), str1.end(), ' '), str1.end());
std::cout << str1 << '\n';
std::string str2 = "Text\n with\tsome \t whitespaces\n\n"; str2.erase(std::remove_if(str2.begin(), str2.end(), [](unsigned char x)
{return std::isspace(x);}), str2.end());
std::cout << str2 << '\n'; }
Output:
Textwithsomespaces
Textwithsomewhitespaces
Hello I am looking for a way to write this C++ Code in a general way, so that if a want 20 columns I will not have to write 20 for loops:
for(int i=1; i<6; i++) {
for(int j=i; j<6; j++) {
for(int k=j; k<6; k++) {
for(int m=k; m<6; m++) {
std::cout << i << j << k << m << std::endl;
}
}
}
}
It is important that my numbers follow a >= Order.
I am very grateful for any help.
This recursive function should work:
#include <iostream>
bool inc( int *indexes, int limit, int n )
{
if( ++indexes[n] < limit )
return true;
if( n == 0 ) return false;
if( inc( indexes, limit, n-1 ) ) {
indexes[n] = indexes[n-1];
return true;
}
return false;
}
int main()
{
const size_t N=3;
int indexes[N];
for( size_t i = 0; i < N; ++i ) indexes[i] = 1;
do {
for( size_t i = 0; i < N; ++i ) std::cout << indexes[i] << ' ';
std::cout << std::endl;
} while( inc( indexes, 6, N-1 ) );
return 0;
}
live example
The design here is simple. We take a std::vector each containing a dimension count and a std::vector containing a current index at each dimension.
advance advances the current bundle of dimension indexes by amt (default 1).
void advance( std::vector<size_t>& indexes, std::vector<size_t> const& counts, size_t amt=1 ) {
if (indexes.size() < counts.size())
indexes.resize(counts.size());
for (size_t i = 0; i < counts.size(); ++i ) {
indexes[i]+=amt;
if (indexes[i] < counts[i])
return;
assert(counts[i]!=0);
amt = indexes[i]/counts[i];
indexes[i] = indexes[i]%counts[i];
}
// past the end, don't advance:
indexes = counts;
}
which gives us an advance function for generic n dimensional coordinates.
Next, a filter that tests the restriction you want:
bool vector_ascending( std::vector<size_t> const& v ) {
for (size_t i = 1; (i < v.size()); ++i) {
if (v[i-1] < v[i]) {
return false;
}
}
return true;
}
then a for loop that uses the above:
void print_a_lot( std::vector<size_t> counts ) {
for( std::vector<size_t> v(counts.size()); v < counts; advance(v,counts)) {
// check validity
if (!vector_ascending(v))
continue;
for (size_t x : v)
std::cout << (x+1);
std::cout << std::endl;
}
}
live example.
No recursion needed.
The downside to the above is that it generates 6^20 elements, and then filters. We don't want to make that many elements.
void advance( std::vector<size_t>& indexes, std::vector<size_t> const& counts, size_t amt=1 ) {
if (indexes.size() < counts.size())
indexes.resize(counts.size());
for (size_t i = 0; i < counts.size(); ++i ) {
indexes[i]+=amt;
if (indexes[i] < counts[i])
{
size_t min = indexes[i];
// enforce <= ordering:
for (size_t j = i+i; j < counts.size(); ++j) {
if (indexes[j]<min)
indexes[j]=min;
else
break; // other elements already follow <= transitively
}
assert(vector_ascending(indexes));
return;
}
assert(counts[i]!=0);
amt = indexes[i]/counts[i];
indexes[i] = indexes[i]%counts[i];
}
// past the end, don't advance:
indexes = counts;
}
which should do it without the vector_ascending check in the previous version. (I left the assert in to do testing).
This function works for me, but do not call it with 20 if you want it to finish.
#include <list>
#include <iostream>
std::list<std::list<int>> fun (std::list<std::list<int>> inputlist, int counter)
{
if(counter == 0)
{
return inputlist;
}
else
{
std::list<std::list<int>> outputlist;
for(std::list<int> oldlist : inputlist)
{
for(int i = 1; i<6; i++)
{
std::list<int> newlist = oldlist;
newlist.push_back(i);
outputlist.push_back(newlist);
}
}
return fun(outputlist, counter - 1);
}
}
int main()
{
std::list<int> somelist;
std::list<std::list<int>> listlist;
listlist.push_back(somelist);
std::list<std::list<int>> manynumbers = fun (listlist,5);
for (std::list<int> somenumbers : manynumbers)
{
for(int k : somenumbers)
{
std::cout<<k;
}
std::cout<<std::endl;
}
return 0;
}
Same with Processing (java) here :
void loopFunction(int targetLevel, int actualLevel, int min, int max, String prefix){
/*
targetLevel is the wanted level (20 in your case)
actualLevel starts from 1
min starts from 1
max is the max number displayed (6 in your case)
prefix starts from blank
see usage bellow (in setup function)
*/
for(int m=min; m<max; m++) {
if(targetLevel==actualLevel)
{
println(prefix+ " " + m);
}
else
{
loopFunction(targetLevel, actualLevel+1,m,max,prefix+ " " + m);
}
}
}
void setup(){
loopFunction(10,1,1,6,"");
}
Well, I am not the fastest in writing answer... when I started there was no other answer. Anyhow, here is my version:
#include <iostream>
#include <vector>
using namespace std;
class Multiindex {
public:
typedef std::vector<int> Index;
Multiindex(int dims,int size) :
dims(dims),size(size),index(Index(dims,0)){}
void next(){
int j=dims-1;
while (nextAt(j) && j >= 0){j--;}
}
Index index;
bool hasNext(){return !(index[0]==size-1);}
private:
bool nextAt(int j){
index[j] = index[j]+1;
bool overflow = (index[j]==size);
if (!overflow && j < dims-1){std::fill(index.begin() + j + 1,index.end(),index[j]);}
return overflow;
}
int dims;
int size;
};
int main() {
Multiindex m(4,6);
while (m.hasNext()){
cout << m.index[0] << m.index[1] << m.index[2] << m.index[3] << endl;
m.next();
}
cout << m.index[0] << m.index[1] << m.index[2] << m.index[3] << endl;
return 0;
}
Here is some working code that implements a modified version of the Quicksort algorithm that uses Insertion Sort for array size n > 8. My test array isn't sorting exactly right, and I think it must be with my implementation of Insertionsort and Insert.
The general form of the recursive Insertionsort algorithm is:
void Insertionsort(int S[], int n)
{
if(n>1)
Insertionsort(S,n-1);
Insert(S,n-1);
}
void Insert(int *S, int k)
{
int key = S[k];
int j = k-1;
while(j>=0 && S[j] > key)
{
S[j+1] = S[j];
j--;
}
S[j+1] = key;
}
Here is my complete working code that does not sort quite exactly right:
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
int comparisons = 0;
int compare_qs_m3_ins[12];
// Function prototypes
int partition(int *S,int l, int u);
void exchange(int list[], int p, int q);
void Insert(int S[], int k);
void Insertionsort(int S[], int low, int hi);
void Quicksort_Insert_M3(int S[], int n, int p, int r);
int main()
{
srand (time(NULL));
// Declare all arrays used for testing
int S1_500[500];
int S2_500[500];
int S3_500[500];
int S1_300[300];
int S2_300[300];
int S3_300[300];
int S1_100[100];
int S2_100[100];
int S3_100[100];
int S1_8[8];
int S2_8[8];
int S3_8[8];
// Fill arrays with random integers
for(int i=0; i<500; i++)
{
S1_500[i] = rand()%1000;
S2_500[i] = rand()%1000;
S3_500[i] = rand()%1000;
}
for(int i=0; i<300; i++)
{
S1_300[i] = rand()%1000;
S2_300[i] = rand()%1000;
S3_300[i] = rand()%1000;
}
for(int i=0; i<100; i++)
{
S1_100[i] = rand()%500;
S2_100[i] = rand()%500;
S3_100[i] = rand()%500;
}
for(int i=0; i<8; i++)
{
S1_8[i] = rand()%100;
S2_8[i] = rand()%100;
S3_8[i] = rand()%100;
}
Quicksort_Insert_M3(S1_500,500,0,499);
compare_qs_m3_ins[0] = comparisons;
comparisons = 0;
Quicksort_Insert_M3(S2_500,500,0,499);
compare_qs_m3_ins[1] = comparisons;
comparisons = 0;
Quicksort_Insert_M3(S3_500,500,0,499);
compare_qs_m3_ins[2] = comparisons;
comparisons = 0;
Quicksort_Insert_M3(S1_300,300,0,299);
compare_qs_m3_ins[3] = comparisons;
comparisons = 0;
Quicksort_Insert_M3(S2_300,300,0,299);
compare_qs_m3_ins[4] = comparisons;
comparisons = 0;
Quicksort_Insert_M3(S3_300,300,0,299);
compare_qs_m3_ins[5] = comparisons;
comparisons = 0;
Quicksort_Insert_M3(S1_100,100,0,99);
compare_qs_m3_ins[6] = comparisons;
comparisons = 0;
Quicksort_Insert_M3(S2_100,100,0,99);
compare_qs_m3_ins[7] = comparisons;
comparisons = 0;
Quicksort_Insert_M3(S3_100,100,0,99);
compare_qs_m3_ins[8] = comparisons;
comparisons = 0;
Quicksort_Insert_M3(S1_8,8,0,7);
compare_qs_m3_ins[9] = comparisons;
comparisons = 0;
Quicksort_Insert_M3(S2_8,8,0,7);
compare_qs_m3_ins[10] = comparisons;
comparisons = 0;
Quicksort_Insert_M3(S3_8,8,0,7);
compare_qs_m3_ins[11] = comparisons;
comparisons = 0;
//for(int i=0; i<12; i++)
//cout << compare_qs_m3_ins[i] << endl;
for(int i=0;i<499;i++)
cout << S1_500[i] << endl;
}
int partition(int *S,int l, int u)
{
int x = S[l];
int j = l;
for(int i=l+1; i<=u; i++)
{
comparisons++;
if(S[i] < x)
{
j++;
swap(S[i],S[j]);
}
}
int p = j;
swap(S[l],S[p]);
return p;
}
void swap(int &val1, int &val2)
{
int temp = val1;
val1 = val2;
val2 = temp;
}
void exchange(int list[], int p, int q)
{
int temp = list[p];
list[p] = list[q];
list[q] = temp;
}
int Sort3(int list[], int p, int r)
{
int median = (p + r) / 2;
comparisons++;
if(list[p] <= list[median])
{
comparisons++;
if(list[median]>list[r])
{
comparisons++;
if(list[p]<list[r])
{
int temp = list[p];
list[p] = list[r];
list[r] = list[median];
list[median] = temp;
}
else
{
exchange(list,median,r);
}
}
else
;
}
else
{
comparisons++;
if(list[p] > list[r])
{
comparisons++;
if(list[median] < list[r])
{
int temp = list[p];
list[p] = list[median];
list[median] = list[r];
list[r] = temp;
}
else
{
exchange(list,p,r);
}
}
else
{
exchange(list,p,median);
}
}
return list[r];
}
void Insert(int *S, int k)
{
int key = S[k];
int j = k-1;
while(j>=0 && S[j] > key)
{
S[j+1] = S[j];
j--;
comparisons++;
}
comparisons++;
S[j+1] = key;
}
void Insertionsort(int S[], int low, int hi)
{
if((hi-low)+1>1)
Insertionsort(S,low+1,hi);
Insert(S,hi-low);
}
void Quicksort_Insert_M3(int S[], int n, int low, int hi)
{
if((hi-low)<=8)
Insertionsort(S,low,hi);
else
{
if(low < hi)
{
if((low+1) == hi)
{
comparisons++;
if(S[low] > S[hi])
swap(S[low],S[hi]);
}
else
{
Sort3(S,low,hi);
if((low+2)<hi)
{
swap(S[low+1],S[(low+hi)/2]);
int q = partition(S, low+1, hi-1);
Quicksort_Insert_M3(S, n, low, q-1);
Quicksort_Insert_M3(S, n, q+1, hi);
}
}
}
}
}
The function supposed to sort three array elements in ascending order doesn't:
int Sort3(int list[], int p, int r)
{
called only for p + 2 <= r, so
int median = (p + r) / 2;
p < median < r here. Let a = list[p], b = list[median] and c = list[r].
comparisons++;
if(list[p] <= list[median])
{
comparisons++;
if(list[median]>list[r])
{
comparisons++;
if(list[p]<list[r])
{
So here we have a <= b, c < b and a < c, together a < c < b
int temp = list[p];
list[p] = list[r];
list[r] = list[median];
list[median] = temp;
but you place them in order c, a, b. Probably you intended to use if (list[r] < list[p]) there.
}
else
c <= a <= b
{
exchange(list,median,r);
so that arranges them in order a, c, b.
}
}
else
;
}
else
Here, b < a.
{
comparisons++;
if(list[p] > list[r])
{
c < a
comparisons++;
if(list[median] < list[r])
{
Then b < c < a
int temp = list[p];
list[p] = list[median];
list[median] = list[r];
list[r] = temp;
Yup, that's correct.
}
else
c <= b < a
{
exchange(list,p,r);
}
Okedoke.
}
else
{
b < a <= c
exchange(list,p,median);
Okay.
}
}
return list[r];
}
Why does this function return anything? You don't use the return value anyway.
"The general form of the recursive Insertionsort algorithm is" - if you need to have a head-recursive algorithm, yes, otherwise a better version is:
void Insertionsort(int S[], int i, int n)
{
Insert(S, i, n);
if(i < n)
Insertionsort(S, i+1, n);
}
which is much more understandable. Also, you might as well have put the body of Insert into Insertionsort.
I'm not going to try and figure out your overly complicated version of quicksort. A decent quicksort is around 20 lines or less (like this - www.algolist.net/Algorithms/Sorting/Quicksort) (and add another 10 or less for insertion sort). I suggest getting a better understanding by looking at another implementation and rewriting yours.
I believe this could've been asked as an extension of your previous question.
I implemented the Damerau–Levenshtein distance in c++ but it does not give correct o/p for the input (pantera,aorta) the correct o/p is 4 but my code gives 5.....
int editdist(string s,string t,int n,int m)
{
int d1,d2,d3,cost;
int i,j;
for(i=0;i<=n;i++)
{
for(j=0;j<=m;j++)
{
if(s[i+1]==t[j+1])
cost=0;
else
cost=1;
d1=d[i][j+1]+1;
d2=d[i+1][j]+1;
d3=d[i][j]+cost;
d[i+1][j+1]=minimum(d1,d2,d3);
if(i>0 && j>0 && s[i+1]==t[j] && s[i]==t[j+1] ) //transposition
{
d[i+1][j+1]=min(d[i+1][j+1],d[i-1][j-1]+cost);
}
}
}
return d[n+1][m+1];
}
I don't see any errors. Can someone find a problem with the code?
The algorithm in the post does not compute Damerau-Levenshtein distance. In a wikipedia article this algorithm is defined as the Optimal String Alignment Distance.
A java implementation of DL distance algorithm can be found in another SO post.
To get the correct values of OSA distance please change the lines marked with - below with the lines marked with +
int editdist(string s,string t,int n,int m)
{
int d1,d2,d3,cost;
int i,j;
for(i=0;i<=n;i++)
{
for(j=0;j<=m;j++)
{
- if(s[i+1]==t[j+1])
+ if(s[i+1]==t[j+1])
cost=0;
else
cost=1;
d1=d[i][j+1]+1;
d2=d[i+1][j]+1;
d3=d[i][j]+cost;
d[i+1][j+1]=minimum(d1,d2,d3);
- if(i>0 && j>0 && s[i+1]==t[j] && s[i]==t[j+1] ) //transposition
+ if(i>0 && j>0 && s[i]==t[j-1] && s[i-1]==t[j] ) //transposition
{
d[i+1][j+1]=min(d[i+1][j+1],d[i-1][j-1]+cost);
}
}
}
return d[n+1][m+1];
}
It looks as if the code was copied from a program written in a programming language where array indices start at 1 by default. Therefore all references to the elements of the distance array d were incremented. However the references to the characters within the strings are references to 0-based arrays, therefore they should not be updated.
To compute the distance the distance array has to be properly initialized:
for( i = 0; i < n + 1; i++)
d[i][0] = i;
for( j = 1; j < m + 1; j++)
d[0][j] = j;
Since you have got the answer 5, you probably have your distance array already initialized correctly.
Since the above algorithm does not compute the DL distance, here is a sketch of a C implementation of the DL algorithm (derived from the SO post with a java impl. derived from an ActionScript impl. in the Wikipedia article).
#define d(i,j) dd[(i) * (m+2) + (j) ]
#define min(x,y) ((x) < (y) ? (x) : (y))
#define min3(a,b,c) ((a)< (b) ? min((a),(c)) : min((b),(c)))
#define min4(a,b,c,d) ((a)< (b) ? min3((a),(c),(d)) : min3((b),(c),(d)))
int dprint(int* dd, int n,int m){
int i,j;
for (i=0; i < n+2;i++){
for (j=0;j < m+2; j++){
printf("%02d ",d(i,j));
}
printf("\n");
}
printf("\n");
return 0;
}
int dldist2(char *s, char* t, int n, int m) {
int *dd;
int i, j, cost, i1,j1,DB;
int INFINITY = n + m;
int DA[256 * sizeof(int)];
memset(DA, 0, sizeof(DA));
if (!(dd = (int*) malloc((n+2)*(m+2)*sizeof(int)))) {
return -1;
}
d(0,0) = INFINITY;
for(i = 0; i < n+1; i++) {
d(i+1,1) = i ;
d(i+1,0) = INFINITY;
}
for(j = 0; j<m+1; j++) {
d(1,j+1) = j ;
d(0,j+1) = INFINITY;
}
dprint(dd,n,m);
for(i = 1; i< n+1; i++) {
DB = 0;
for(j = 1; j< m+1; j++) {
i1 = DA[t[j-1]];
j1 = DB;
cost = ((s[i-1]==t[j-1])?0:1);
if(cost==0) DB = j;
d(i+1,j+1) =
min4(d(i,j)+cost,
d(i+1,j) + 1,
d(i,j+1)+1,
d(i1,j1) + (i-i1-1) + 1 + (j-j1-1));
}
DA[s[i-1]] = i;
dprint(dd,n,m);
}
cost = d(n+1,m+1);
free(dd);
return cost;
}
Here is my C++ version of this algorithm:
int damerau_levenshtein_distance(std::string p_string1, std::string p_string2)
{
int l_string_length1 = p_string1.length();
int l_string_length2 = p_string2.length();
int d[l_string_length1+1][l_string_length2+1];
int i;
int j;
int l_cost;
for (i = 0;i <= l_string_length1;i++)
{
d[i][0] = i;
}
for(j = 0; j<= l_string_length2; j++)
{
d[0][j] = j;
}
for (i = 1;i <= l_string_length1;i++)
{
for(j = 1; j<= l_string_length2; j++)
{
if( p_string1[i-1] == p_string2[j-1] )
{
l_cost = 0;
}
else
{
l_cost = 1;
}
d[i][j] = std::min(
d[i-1][j] + 1, // delete
std::min(d[i][j-1] + 1, // insert
d[i-1][j-1] + l_cost) // substitution
);
if( (i > 1) &&
(j > 1) &&
(p_string1[i-1] == p_string2[j-2]) &&
(p_string1[i-2] == p_string2[j-1])
)
{
d[i][j] = std::min(
d[i][j],
d[i-2][j-2] + l_cost // transposition
);
}
}
}
return d[l_string_length1][l_string_length2];
}