I am trying to implement build_max_heap function that creates the heap( as it is written in Cormen's "introduction do algorithms" ). But I am getting strange error and i could not localize it. My program successfully give random numbers to table, show them but after build_max_heap() I am getting strange numbers, that are probably because somewhere my program reached something out of the table, but I can not find this error. I will be glad for any help.
For example I get the table:
0 13 18 0 22 15 24 19 5 23
And my output is:
24 7 5844920 5 22 15 18 19 0 23
My code:
#include <iostream>
#include <ctime>
#include <stdlib.h>
const int n = 12; // the length of my table, i will onyl use indexes 1...n-1
struct heap
{
int *tab;
int heap_size;
};
void complete_with_random(heap &heap2)
{
srand(time(NULL));
for (int i = 1; i <= heap2.heap_size; i++)
{
heap2.tab[i] = rand() % 25;
}
heap2.tab[0] = 0;
}
void show(heap &heap2)
{
for (int i = 1; i < heap2.heap_size; i++)
{
std::cout << heap2.tab[i] << " ";
}
}
int parent(int i)
{
return i / 2;
}
int left(int i)
{
return 2 * i;
}
int right(int i)
{
return 2 * i + 1;
}
void max_heapify(heap &heap2, int i)
{
if (i >= heap2.heap_size || i == 0)
{
return;
}
int l = left(i);
int r = right(i);
int largest;
if (l <= heap2.heap_size || heap2.tab[l] > heap2.tab[i])
{
largest = l;
}
else
{
largest = i;
}
if (r <= heap2.heap_size || heap2.tab[r] > heap2.tab[i])
{
largest = r;
}
if (largest != i)
{
std::swap(heap2.tab[i], heap2.tab[largest]);
max_heapify(heap2, largest);
}
}
void build_max_heap(heap &heap2)
{
for (int i = heap2.heap_size / 2; i >= 1; i--)
{
max_heapify(heap2, i);
}
}
int main()
{
heap heap1;
heap1.tab = new int[n];
heap1.heap_size = n - 1;
complete_with_random(heap1);
show(heap1);
std::cout << std::endl;
build_max_heap(heap1);
show(heap1);
}
Indeed, the table is accessed with out-of-bounds indexes.
if (l <= heap2.heap_size || heap2.tab[l] > heap2.tab[i])
^^
I think you meant && in this condition.
The same for the next branch with r.
In case you're still having problems, below is my own implementation that you might use for reference. It was also based on Cormen et al. book, so it's using more or less the same terminology. It may have arbitrary types for the actual container, the comparison and the swap functions. It provides a public queue-like interface, including key incrementing.
Because it's part of a larger software collection, it's using a few entities that are not defined here, but I hope the algorithms are still clear. CHECK is only an assertion mechanism, you can ignore it. You may also ignore the swap member and just use std::swap.
Some parts of the code are using 1-based offsets, others 0-based, and conversion is necessary. The comments above each method indicate this.
template <
typename T,
typename ARRAY = array <T>,
typename COMP = fun::lt,
typename SWAP = fun::swap
>
class binary_heap_base
{
protected:
ARRAY a;
size_t heap_size;
SWAP swap_def;
SWAP* swap;
// 1-based
size_t parent(const size_t n) { return n / 2; }
size_t left (const size_t n) { return n * 2; }
size_t right (const size_t n) { return n * 2 + 1; }
// 1-based
void heapify(const size_t n = 1)
{
T& x = a[n - 1];
size_t l = left(n);
size_t r = right(n);
size_t select =
(l <= heap_size && COMP()(x, a[l - 1])) ?
l : n;
if (r <= heap_size && COMP()(a[select - 1], a[r - 1]))
select = r;
if (select != n)
{
(*swap)(x, a[select - 1]);
heapify(select);
}
}
// 1-based
void build()
{
heap_size = a.length();
for (size_t n = heap_size / 2; n > 0; n--)
heapify(n);
}
// 1-based
size_t advance(const size_t k)
{
size_t n = k;
while (n > 1)
{
size_t pn = parent(n);
T& p = a[pn - 1];
T& x = a[n - 1];
if (!COMP()(p, x)) break;
(*swap)(p, x);
n = pn;
}
return n;
}
public:
binary_heap_base() { init(); set_swap(); }
binary_heap_base(SWAP& s) { init(); set_swap(s); }
binary_heap_base(const ARRAY& a) { init(a); set_swap(); }
binary_heap_base(const ARRAY& a, SWAP& s) { init(a); set_swap(s); }
void init() { a.init(); build(); }
void init(const ARRAY& a) { this->a = a; build(); }
void set_swap() { swap = &swap_def; }
void set_swap(SWAP& s) { swap = &s; }
bool empty() { return heap_size == 0; }
size_t size() { return heap_size; }
size_t length() { return heap_size; }
void reserve(const size_t len) { a.reserve(len); }
const T& top()
{
CHECK (heap_size != 0, eshape());
return a[0];
}
T pop()
{
CHECK (heap_size != 0, eshape());
T x = a[0];
(*swap)(a[0], a[heap_size - 1]);
heap_size--;
heapify();
return x;
}
// 0-based
size_t up(size_t n, const T& x)
{
CHECK (n < heap_size, erange());
CHECK (!COMP()(x, a[n]), ecomp());
a[n] = x;
return advance(n + 1) - 1;
}
// 0-based
size_t push(const T& x)
{
if (heap_size == a.length())
a.push_back(x);
else
a[heap_size] = x;
return advance(++heap_size) - 1;
}
};
Related
With an array consisting of integers where each integer occurs at most 2 times in the array, I have to count the number of beautiful permutations.
A permutation is beautiful if there is no index i such that Pi = Pi+1 where i belongs to [0, n-1).
struct hashFunction
{
size_t operator()(const vector<int>& myVector) const
{
std::hash<int> hasher;
size_t answer = 0;
for (int i : myVector)
{
answer ^= hasher(i) + 0x9e3779b9 +
(answer << 6) + (answer >> 2);
}
return answer;
}
};
bool beautiful(vector<int>& ds)
{
for (int i = 0; i < ds.size(); i++)
{
if (ds[i] == ds[i + 1])
{
return false;
}
}
return true;
}
void permutation(vector<int>& arr, int index,
unordered_set<vector<int>, hashFunction>& unorderedsetOfVectors)
{
if (unorderedsetOfVectors.find(arr) != unorderedsetOfVectors.end()) return;
if (index == arr.size())
{
if (beautiful(arr) == true)
{
unorderedsetOfVectors.insert(arr);
return;
}
}
for (int i = index; i < arr.size(); i++)
{
swap(arr[index], arr[i]);
permutation(arr, index + 1, unorderedsetOfVectors);
swap(arr[index], arr[i]);
}
}
int permutations(vector<int> arr)
{
unordered_set<vector<int>, hashFunction> unorderedsetOfVectors;
permutation(arr, 0, unorderedsetOfVectors);
return unorderedsetOfVectors.size() % 1000000007;
}
How can I optimize this code?
I have this B-Tree implementation, which I'm testing using search() and insert(). Testing is basically this:
void function(){
BTree b16(16);
// do lots of inserts and searchs on b16
}
for(many_times){
function();
}
If I understand correctly, after each iteration of function(), b16 should get destroyed. However, after ~250 iterations, I get a bad_alloc error, which means I have a memory leak.
Is there a problem with the destructors? Here's the implementation:
#include <iostream>
#include <vector>
using namespace std;
typedef unsigned int uint;
class BNode{
private:
uint *keys;
int B;
BNode **C;
int n;
bool leaf;
public:
BNode(int temp, bool bool_leaf);
~BNode();
void insertNonFull(uint k);
void splitChild(int i, BNode *y);
void traverse();
BNode *search(uint k);
friend class BTree;
};
class BTree{
private:
BNode *root;
int B;
public:
BTree(int temp);
~BTree();
BNode *search(uint k);
int search_bool(uint k);
void insert(uint k);
};
BNode::BNode(int t1, bool leaf1) {
B = t1;
leaf = leaf1;
keys = new uint[2*B - 1];
C = new BNode *[2*B];
n = 0;
}
BNode::~BNode(){
delete[] keys;
delete[] C;
}
BNode *BNode::search(uint k){
int i = 0;
while (i < n && k > keys[i]){
i++;
}
if(keys[i] == k){
return this;
}
if (leaf == true){
return NULL;
}
return C[i]->search(k);
}
void BTree::insert(uint k){
if (root == NULL) {
root = new BNode(B, true);
root->keys[0] = k;
root->n = 1;
}
else{
if (root->n == 2*B - 1){
BNode *s = new BNode(B, false);
s->C[0] = root;
s->splitChild(0, root);
int i = 0;
if (s->keys[0] < k){
i++;
}
s->C[i]->insertNonFull(k);
root = s;
}
else{
root->insertNonFull(k);
}
}
}
void BNode::insertNonFull(uint k) {
int i = n - 1;
if (leaf == true) {
while (i>=0 && keys[i] > k) {
keys[i+1] = keys[i];
i--;
}
keys[i+1] = k;
n = n + 1;
}
else {
while (i>=0 && keys[i] > k){
i--;
}
if (C[i+1]->n == 2*B-1) {
splitChild(i+1, C[i+1]);
if (keys[i + 1] < k){
i++;
}
}
C[i+1]->insertNonFull(k);
}
}
void BNode::splitChild(int i, BNode *y) {
BNode *z = new BNode(y->B, y->leaf);
z->n = B - 1;
for (int j = 0; j < B - 1; j++){
z->keys[j] = y->keys[j+B];
}
if (!y->leaf){
for (int j = 0; j < B; j++)
z->C[j] = y->C[j + B];
}
y->n = B - 1;
for(int j=n; j >= i+1; j--){
C[j+1] = C[j];
}
C[i + 1] = z;
for (int j = n - 1; j >= i; j--){
keys[j+1] = keys[j];
}
keys[i] = y->keys[B - 1];
n = n + 1;
}
BTree::BTree(int temp){
root = NULL;
B = temp;
}
BTree::~BTree(){
delete root;
}
BNode *BTree::search(uint k){
return (root == NULL) ? NULL : root->search(k);
}
int BTree::search_bool(uint k){
if(search(k) != NULL){
return true;
}
else{
return false;
}
}
Thanks in advance.
So, the simple diagnosis is that
delete[] C;
deletes only the array, not the nodes contained by it. So, (a) make sure they're properlu zero-initialized (b) delete them as well:
BNode** C = new BNode* [2 * B] { 0 };
// in the destructor:
for (int i = 0; i < 2 * B; ++i)
delete C[i];
delete[] C;
HOWEVER.
This doesn't work well because nodes can be split. After you moved some nodes from one node's C to another node's C, you run into double-free. So, when you split nodes, you have to make sure you set the moved-from C elemeent to NULL again:
z->C[j] = y->C[j + B];
y->C[j + B] = nullptr;
Now, this program runs clean under valgrind, ubsan and asan and without leaks:
Live On Coliru
#include <iostream>
#include <vector>
using uint = unsigned;
class BNode {
private:
int B;
bool leaf;
uint* keys = new uint[2 * B - 1]{0};
BNode** C = new BNode* [2 * B] { 0 };
int n = 0;
public:
BNode(int t1, bool leaf1) : B(t1), leaf(leaf1) {}
~BNode()
{
delete[] keys;
for (int i = 0; i < 2 * B; ++i)
delete C[i];
delete[] C;
}
BNode const* search(uint k) const
{
int i = 0;
while (i < n && k > keys[i]) {
i++;
}
if (keys[i] == k) {
return this;
}
return leaf ? nullptr : C[i]->search(k);
}
void insertNonFull(uint k)
{
int i = n - 1;
if (leaf == true) {
while (i >= 0 && keys[i] > k) {
keys[i + 1] = keys[i];
i--;
}
keys[i + 1] = k;
n = n + 1;
} else {
while (i >= 0 && keys[i] > k) {
i--;
}
if (C[i + 1]->n == 2 * B - 1) {
splitChild(i + 1, C[i + 1]);
if (keys[i + 1] < k) {
i++;
}
}
C[i + 1]->insertNonFull(k);
}
}
void splitChild(int i, BNode* y)
{
BNode* z = new BNode(y->B, y->leaf);
z->n = B - 1;
for (int j = 0; j < B - 1; j++) {
z->keys[j] = y->keys[j + B];
}
if (!y->leaf) {
for (int j = 0; j < B; j++) {
z->C[j] = y->C[j + B];
y->C[j + B] = nullptr;
}
}
y->n = B - 1;
for (int j = n; j >= i + 1; j--) {
C[j + 1] = C[j];
}
C[i + 1] = z;
for (int j = n - 1; j >= i; j--) {
keys[j + 1] = keys[j];
}
keys[i] = y->keys[B - 1];
n = n + 1;
}
friend class BTree;
};
class BTree {
private:
BNode* root = nullptr;
int B;
public:
BTree(int temp)
{
root = nullptr;
B = temp;
}
~BTree() { delete root; }
BNode const* search(uint k) const
{
return (root == nullptr) ? nullptr : root->search(k);
}
bool search_bool(uint k) const { return search(k) != nullptr; }
void insert(uint k)
{
if (!root) {
root = new BNode(B, true);
root->keys[0] = k;
root->n = 1;
} else {
if (root->n == 2 * B - 1) {
BNode* s = new BNode(B, false);
s->C[0] = root;
s->splitChild(0, root);
int i = 0;
if (s->keys[0] < k) {
i++;
}
s->C[i]->insertNonFull(k);
root = s;
} else {
root->insertNonFull(k);
}
}
}
};
int main()
{
for (int b = 8; b < 17; ++b) {
BTree tree(b);
for (int i = 0; i < 100'000; ++i)
tree.insert(rand() % 1000);
}
}
In Closing
Kudos for getting the algorithmics largely right here. That's not easy.
As you can see in my cleanup/review I hardened a lot of stuff, mainly around initialization. This is an important habit. I can't actually rule out that not having that would have exposed other sleeping bugs.
Also note the increased const-correctness.
Also, like other said, prefer smart pointers and modern C++ techniques. It will be amazing how much less error prone just using std::array, unique_ptr and so will be. For example, the bug with moving nodes in splitChild would never have compiled because you have to explcitly move-assign unique_ptr
Bonus
Example in more modern C++:
without any new/delete
without any raw pointer
no more manual destructors (even no constructors required, really)
compiler checked move semantics, NICE!
statically known B factor, so everything becomes 10x more performant, while still being tunable
generic key (element) type, so you can now store std::string, double, whatnot
generic comparator, so you sort your keys in alternative orders (e.g. Btree<std::string, 16, std::greater<> > to store the keys in descending order instead of ascending).
No leaks!
Live On Coliru
#include <array>
#include <algorithm>
#include <memory>
#include <iostream>
template <typename T, unsigned B = 16, typename Cmp = std::less<T>>
class BTree {
private:
static constexpr unsigned MaxKeys = 2 * B - 1;
static constexpr unsigned MaxChildren = 2 * B;
struct BNode;
using NodePtr = std::unique_ptr<BNode>;
struct BNode {
bool _leaf;
int _n = 0;
std::array<T, MaxKeys> _keys{};
std::array<NodePtr, MaxChildren> _children{};
BNode(bool leaf1) : _leaf(leaf1) {}
BNode const* search(T k, Cmp cmp) const
{
int i = 0;
while (i < _n && cmp(_keys[i], k)) {
i++;
}
if (_keys[i] == k) {
return this;
}
return _leaf ? nullptr : _children[i]->search(k, cmp);
}
void insertNonFull(T k, Cmp cmp)
{
int i = _n - 1;
if (_leaf == true) {
while (i >= 0 && cmp(k, _keys[i])) {
_keys[i + 1] = _keys[i];
i--;
}
_keys[i + 1] = k;
_n = _n + 1;
} else {
while (i >= 0 && cmp(k, _keys[i])) {
i--;
}
if (_children[i + 1]->_n == MaxKeys) {
splitChild(i + 1, *_children[i + 1]);
if (cmp(_keys[i + 1], k)) {
i++;
}
}
_children[i + 1]->insertNonFull(k, cmp);
}
}
void splitChild(int i, BNode& y)
{
NodePtr z = std::make_unique<BNode>(y._leaf);
z->_n = B - 1;
for (unsigned j = 0; j < B - 1; j++) {
z->_keys[j] = y._keys[j + B];
}
if (!y._leaf) {
for (unsigned j = 0; j < B; j++) {
z->_children[j] = std::move(y._children[j + B]);
}
}
y._n = B - 1;
for (int j = _n; j >= i + 1; j--) {
_children[j + 1] = std::move(_children[j]);
}
_children[i + 1] = std::move(z);
for (int j = _n - 1; j >= i; j--) {
_keys[j + 1] = _keys[j];
}
_keys[i] = y._keys[B - 1];
_n = _n + 1;
}
};
NodePtr root = nullptr;
Cmp _cmp{};
public:
BTree(Cmp cmp = {}) : _cmp(std::move(cmp)) {}
BNode const* search(T k) const {
return root ? root->search(k, _cmp) : nullptr;
}
bool search_bool(T k) const { return search(k) != nullptr; }
void insert(T k)
{
if (!root) {
root = std::make_unique<BNode>(true);
root->_keys[0] = k;
root->_n = 1;
} else {
if (root->_n == MaxKeys) {
NodePtr s = std::make_unique<BNode>(false);
s->splitChild(0, *root);
s->_children[0] = std::move(root);
int i = 0;
if (_cmp(s->_keys[0], k)) {
i++;
}
s->_children[i]->insertNonFull(k, _cmp);
root = std::move(s);
} else {
root->insertNonFull(k, _cmp);
}
}
}
};
int main()
{
using Asc = std::less<>;
using Desc = std::greater<>;
BTree<double, 8, Asc> b8;
BTree<int, 9, Desc> b9;
BTree<unsigned, 10, Asc> b10;
BTree<size_t, 11, Desc> b11;
BTree<double, 12, Asc> b12;
BTree<int, 13, Desc> b13;
BTree<unsigned, 14, Asc> b14;
BTree<size_t, 15, Desc> b15;
BTree<int, 16> b16; // default is ascending
for (int i = 0; i < 100'000; ++i) {
b8.insert(rand() % 10000);
b9.insert(rand() % 10000);
b10.insert(rand() % 10000);
b11.insert(rand() % 10000);
b12.insert(rand() % 10000);
b13.insert(rand() % 10000);
b14.insert(rand() % 10000);
b15.insert(rand() % 10000);
b16.insert(rand() % 10000);
}
{
struct NC {
int v;
bool operator==(NC const& o) const { return v == o.v; }
};
struct CMP {
bool operator()(NC const& a, NC const& b) const { return a.v < b.v; }
};
BTree<NC, 8, CMP> b8;
b8.insert({42});
bool ok = b8.search_bool({42});
}
}
The question is described above. Basically, the input is vector<stack<int>>& piles and n, output is the max value for all n coins from any of the piles.
The only solution I can think of is to use backtracking for each pile, i.e. piles[0] is chosen i coins, then recursively call functions on piles[1...m-1] and n - i. And record max value for all possible combinations. I feel like this can be solved by dynamic-programming, however, due the constrain n, it's hard for me to build a dp equation.
Any better solution than backtracking?
There are m piles. Every pile p offers n+1 contributions of
(label, gain, cost):
for i from 0 upto n have ("pile {p}, {i} taken", sum of top i values, i).
The sum of costs must be equal (or less when negative numbers) to n, gain maximal.
The rest is up to the algorithm: whether you sort descending by ((double)gain)/cost or whatever.
This is definately nHr combination.
I would use some code like this.. p = number of piles, n = coins taken.
calc_sum is a function to record maximum value.
nHr h(p, n);
while(h.next()) {
for(int i=0; i<h.size(); i++) take_coins_from_a_pile(h[i]);
calc_sum();
}
And this is nHr library of my own.
#pragma once
#include <exception>
class NRexception : public std::exception
{
public:
virtual const char* what() const throw() {
return "Combination : N, R should be positive integer!!";
}
};
class Combination
{
public:
Combination(int n, int r);
virtual ~Combination() { delete [] ar;}
int& operator[](unsigned i) {return ar[i];}
bool next();
int size() {return r;}
static int factorial(int n);
protected:
int* ar;
int n, r;
};
class nCr : public Combination
{
public:
nCr(int n, int r);
bool next();
int count() const;
};
class nTr : public Combination
{
public:
nTr(int n, int r);
bool next();
int count() const;
};
class nHr : public nTr
{
public:
nHr(int n, int r) : nTr(n,r) {}
bool next();
int count() const;
};
class nPr : public Combination
{
public:
nPr(int n, int r);
virtual ~nPr() {delete [] on;}
bool next();
void rewind();
int count() const;
private:
bool* on;
void inc_ar(int i);
};
#include "combi.h"
#include <set>
#include<cmath>
Combination::Combination(int n, int r)
{
//if(n < 1 || r < 1) throw NRexception();
ar = new int[r];
this->n = n;
this->r = r;
}
int Combination::factorial(int n)
{
return n == 1 ? n : n * factorial(n-1);
}
int nPr::count() const
{
return factorial(n)/factorial(n-r);
}
int nCr::count() const
{
return factorial(n)/factorial(n-r)/factorial(r);
}
int nTr::count() const
{
return pow(n, r);
}
int nHr::count() const
{
return factorial(n+r-1)/factorial(n-1)/factorial(r);
}
nCr::nCr(int n, int r) : Combination(n, r)
{
if(r == 0) return;
for(int i=0; i<r-1; i++) ar[i] = i + 1;
ar[r-1] = r-1;
}
nTr::nTr(int n, int r) : Combination(n, r)
{
for(int i=0; i<r-1; i++) ar[i] = 1;
ar[r-1] = 0;
}
bool nCr::next()
{
if(r == 0) return false;
ar[r-1]++;
int i = r-1;
while(ar[i] == n-r+2+i) {
if(--i == -1) return false;
ar[i]++;
}
while(i < r-1) ar[i+1] = ar[i++] + 1;
return true;
}
bool nTr::next()
{
ar[r-1]++;
int i = r-1;
while(ar[i] == n+1) {
ar[i] = 1;
if(--i == -1) return false;
ar[i]++;
}
return true;
}
bool nHr::next()
{
ar[r-1]++;
int i = r-1;
while(ar[i] == n+1) {
if(--i == -1) return false;
ar[i]++;
}
while(i < r-1) ar[i+1] = ar[i++];
return true;
}
nPr::nPr(int n, int r) : Combination(n, r)
{
on = new bool[n+2];
for(int i=0; i<n+2; i++) on[i] = false;
for(int i=0; i<r; i++) {
ar[i] = i + 1;
on[i] = true;
}
ar[r-1] = 0;
}
void nPr::rewind()
{
for(int i=0; i<r; i++) {
ar[i] = i + 1;
on[i] = true;
}
ar[r-1] = 0;
}
bool nPr::next()
{
inc_ar(r-1);
int i = r-1;
while(ar[i] == n+1) {
if(--i == -1) return false;
inc_ar(i);
}
while(i < r-1) {
ar[++i] = 0;
inc_ar(i);
}
return true;
}
void nPr::inc_ar(int i)
{
on[ar[i]] = false;
while(on[++ar[i]]);
if(ar[i] != n+1) on[ar[i]] = true;
}
There are a lot of links on http://stackoverflow.com for how to do combinations: Generating combinations in c++ But these links presume to draw from an infinite set without repetition. When given a finite collection which does have repetition, these algorithms construct duplicates. For example you can see the accepted solution to the linked question failing on a test case I constructed here: http://ideone.com/M7CyFc
Given the input set: vector<int> row {40, 40, 40, 50, 50, 60, 100};
I expect to see:
40 40 40
40 40 50
40 40 60
40 40 100
40 50 50
40 50 60
40 50 100
40 60 100
50 50 60
50 50 100
50 60 100
Obviously I can use the old method store the output and check for duplicates as I generate, but this requires a lot of extra memory and processing power. Is there an alternative that C++ provides me?
Combinations by definition do not respect order. This frees us to arrange the numbers in any order we see fit. Most notably we can rely on to provide a combination rank. Certainly the most logical way to rank combinations is in sorted order, so we'll be depending upon our inputs being sorted.
There is already precedent for this in the standard library. For example lower_bound which we will actually use in this solution. When used generally this may however require the user to sort before passing.
The function we will write to do this will take in iterators to the sorted collection which the next combination is to be drawn from, and iterators to the current combination. We'd also need the size but that can be derived from the distance between the combination's iterators.
template <typename InputIt, typename OutputIt>
bool next_combination(InputIt inFirst, InputIt inLast, OutputIt outFirst, OutputIt outLast) {
assert(distance(inFirst, inLast) >= distance(outFirst, outLast));
const auto front = make_reverse_iterator(outFirst);
const auto back = make_reverse_iterator(outLast);
auto it = mismatch(back, front, make_reverse_iterator(inLast)).first;
const auto result = it != front;
if (result) {
auto ub = upper_bound(inFirst, inLast, *it);
copy(ub, next(ub, distance(back, it) + 1), next(it).base());
}
return result;
}
This function is written in the format of the other algorithm functions, so any container that supports bidirectional iterators can be used with it. For our example though we'll use: const vector<unsigned int> row{ 40U, 40U, 40U, 50U, 50U, 60U, 100U }; which is, necessarily, sorted:
vector<unsigned int> it{ row.cbegin(), next(row.cbegin(), 3) };
do {
copy(it.cbegin(), it.cend(), ostream_iterator<unsigned int>(cout, " "));
cout << endl;
} while(next_combination(row.cbegin(), row.cend(), it.begin(), it.end()));
Live Example
After writing this answer I've done a bit more research and found N2639 which proposes a standardized next_combination, which was:
Actively under consideration for a future TR, when work on TR2 was deferred pending
Viewed positively at the time
Due at least one more revision before any adoption
Needed some reworking to reflect the addition of C++11 language facilities
[Source]
Using N2639's reference implementation requires mutability, so we'll use: vector<unsigned int> row{ 40U, 40U, 40U, 50U, 50U, 60U, 100U };. And our example code becomes:
vector<unsigned int>::iterator it = next(row.begin(), 3);
do {
copy(row.begin(), it, ostream_iterator<unsigned int>(cout, " "));
cout << endl;
} while(next_combination(row.begin(), it, row.end()));
Live Example
You can do something like this (maybe avoiding the recursion):
#include <iostream>
#include <vector>
#include <algorithm>
using std::cout;
using std::vector;
void perm( const vector<int> &v, vector<vector<int>> &p, vector<int> &t, int k, int d) {
for ( int i = k; i < v.size(); ++i ) {
// skip the repeted value
if ( i != k && v[i] == v[i-1]) continue;
t.push_back(v[i]);
if ( d > 0 ) perm(v,p,t,i+1,d-1);
else p.push_back(t);
t.pop_back();
}
}
int main() {
int r = 3;
vector<int> row {40, 40, 40, 50, 50, 60, 100};
vector<vector<int>> pp;
vector<int> pe;
std::sort(row.begin(),row.end()); // that's necessary
perm(row,pp,pe,0,r-1);
cout << pp.size() << '\n';
for ( auto & v : pp ) {
for ( int i : v ) {
cout << ' ' << i;
}
cout << '\n';
}
return 0;
}
Which outputs:
11
40 40 40
40 40 50
40 40 60
40 40 100
40 50 50
40 50 60
40 50 100
40 60 100
50 50 60
50 50 100
50 60 100
I know, it's far from efficient, but if you get the idea you may come out with a better implementation.
Here is a class I once wrote in my university times to handle bosons. It's quite long, but it's generally usable and seems to work well. Additionally, it also gives ranking and unranking functionality. Hope that helps -- but don't ever ask me what I was doing back then ... ;-)
struct SymmetricIndex
{
using StateType = std::vector<int>;
using IntegerType = int;
int M;
int N;
StateType Nmax;
StateType Nmin;
IntegerType _size;
std::vector<IntegerType> store;
StateType state;
IntegerType _index;
SymmetricIndex() = default;
SymmetricIndex(int _M, int _N, int _Nmax = std::numeric_limits<int>::max(), int _Nmin = 0)
: SymmetricIndex(_M, _N, std::vector<int>(_M + 1, std::min(_Nmax, _N)), StateType(_M + 1, std::max(_Nmin, 0)))
{}
SymmetricIndex(int _M, int _N, StateType const& _Nmax, StateType const& _Nmin)
: N(_N)
, M(_M)
, Nmax(_Nmax)
, Nmin(_Nmin)
, store(addressArray())
, state(M)
, _index(0)
{
reset();
_size = W(M, N);
}
friend std::ostream& operator<<(std::ostream& os, SymmetricIndex const& sym);
SymmetricIndex& reset()
{
return setBegin();
}
bool setBegin(StateType& state, StateType const& Nmax, StateType const& Nmin) const
{
int n = N;
for (int i = 0; i<M; ++i)
{
state[i] = Nmin[i];
n -= Nmin[i];
}
for (int i = 0; i<M; ++i)
{
state[i] = std::min(n + Nmin[i], Nmax[i]);
n -= Nmax[i] - Nmin[i];
if (n <= 0)
break;
}
return true;
}
SymmetricIndex& setBegin()
{
setBegin(state, Nmax, Nmin);
_index = 0;
return *this;
}
bool isBegin() const
{
return _index==0;
}
bool setEnd(StateType& state, StateType const& Nmax, StateType const& Nmin) const
{
int n = N;
for (int i = 0; i < M; ++i)
{
state[i] = Nmin[i];
n -= Nmin[i];
}
for (int i = M - 1; i >= 0; --i)
{
state[i] = std::min(n + Nmin[i], Nmax[i]);
n -= Nmax[i] - Nmin[i];
if (n <= 0)
break;
}
return true;
}
SymmetricIndex& setEnd()
{
setEnd(state, Nmax, Nmin);
_index = _size - 1;
return *this;
}
bool isEnd() const
{
return _index == _size-1;
}
IntegerType index() const
{
return _index;
}
IntegerType rank(StateType const& state) const
{
IntegerType ret = 0;
int n = 0;
for (int i = 0; i < M; ++i)
{
n += state[i];
for (int k = Nmin[i]; k < state[i]; ++k)
ret += store[(n - k) * M + i];
}
return ret;
}
IntegerType rank() const
{
return rank(state);
}
StateType unrank(IntegerType rank) const
{
StateType ret(M);
int n = N;
for (int i = M-1; i >= 0; --i)
{
int ad = 0;
int k = std::min(Nmax[i] - 1, n);
for (int j = Nmin[i]; j <= k; ++j)
ad+=store[(n - j) * M + i];
while (ad > rank && k >= Nmin[i])
{
ad -= store[(n - k) * M + i];
--k;
}
rank -= ad;
ret[i] = k+1;
n -= ret[i];
if (n <= 0)
{
return ret;
}
}
return ret;
}
IntegerType size() const
{
return _size;
}
operator StateType& ()
{
return state;
}
auto operator[](int i) -> StateType::value_type& { return state[i]; }
operator StateType const& () const
{
return state;
}
auto operator[](int i) const -> StateType::value_type const& { return state[i]; }
bool nextState(StateType& state, StateType const& Nmax, StateType const& Nmin) const
{
//co-lexicographical ordering with Nmin and Nmax:
// (1) find first position which can be decreased
// then we have state[k] = Nmin[k] for k in [0,pos]
int pos = M - 1;
for (int k = 0; k < M - 1; ++k)
{
if (state[k] > Nmin[k])
{
pos = k;
break;
}
}
// if nothing found to decrease, return
if (pos == M - 1)
{
return false;
}
// (2) find first position after pos which can be increased
// then we have state[k] = Nmin[k] for k in [0,pos]
int next = 0;
for (int k = pos + 1; k < M; ++k)
{
if (state[k] < Nmax[k])
{
next = k;
break;
}
}
if (next == 0)
{
return false;
}
--state[pos];
++state[next];
// (3) get occupation in [pos,next-1] and set to Nmin[k]
int n = 0;
for (int k = pos; k < next; ++k)
{
n += state[k] - Nmin[k];
state[k] = Nmin[k];
}
// (4) fill up from the start
for (int i = 0; i<M; ++i)
{
if (n <= 0)
break;
int add = std::min(n, Nmax[i] - state[i]);
state[i] += add;
n -= add;
}
return true;
}
SymmetricIndex& operator++()
{
bool inc = nextState(state, Nmax, Nmin);
if (inc) ++_index;
return *this;
}
SymmetricIndex operator++(int)
{
auto ret = *this;
this->operator++();
return ret;
}
bool previousState(StateType& state, StateType const& Nmax, StateType const& Nmin) const
{
////co-lexicographical ordering with Nmin and Nmax:
// (1) find first position which can be increased
// then we have state[k] = Nmax[k] for k in [0,pos-1]
int pos = M - 1;
for (int k = 0; k < M - 1; ++k)
{
if (state[k] < Nmax[k])
{
pos = k;
break;
}
}
// if nothing found to increase, return
if (pos == M - 1)
{
return false;
}
// (2) find first position after pos which can be decreased
// then we have state[k] = Nmin[k] for k in [pos+1,next]
int next = 0;
for (int k = pos + 1; k < M; ++k)
{
if (state[k] > Nmin[k])
{
next = k;
break;
}
}
if (next == 0)
{
return false;
}
++state[pos];
--state[next];
int n = 0;
for (int k = 0; k <= pos; ++k)
{
n += state[k] - Nmin[k];
state[k] = Nmin[k];
}
if (n == 0)
{
return true;
}
for (int i = next-1; i>=0; --i)
{
int add = std::min(n, Nmax[i] - state[i]);
state[i] += add;
n -= add;
if (n <= 0)
break;
}
return true;
}
SymmetricIndex operator--()
{
bool dec = previousState(state, Nmax, Nmin);
if (dec) --_index;
return *this;
}
SymmetricIndex operator--(int)
{
auto ret = *this;
this->operator--();
return ret;
}
int multinomial() const
{
auto v = const_cast<std::remove_reference<decltype(state)>::type&>(state);
return multinomial(v);
}
int multinomial(StateType& state) const
{
int ret = 1;
int n = state[0];
for (int i = 1; i < M; ++i)
{
n += state[i];
ret *= binomial(n, state[i]);
}
return ret;
}
SymmetricIndex& random(StateType const& _Nmin)
{
static std::mt19937 rng;
state = _Nmin;
int n = std::accumulate(std::begin(state), std::end(state), 0);
auto weight = [&](int i) { return state[i] < Nmax[i] ? 1 : 0; };
for (int i = n; i < N; ++i)
{
std::discrete_distribution<int> d(N, 0, N, weight);
++state[d(rng)];
}
_index = rank();
return *this;
}
SymmetricIndex& random()
{
return random(Nmin);
}
private:
IntegerType W(int m, int n) const
{
if (m < 0 || n < 0) return 0;
else if (m == 0 && n == 0) return 1;
else if (m == 0 && n > 0) return 0;
//else if (m > 0 && n < Nmin[m-1]) return 0;
else
{
//static std::map<std::tuple<int, int>, IntegerType> memo;
//auto it = memo.find(std::make_tuple(k, m));
//if (it != std::end(memo))
//{
// return it->second;
//}
IntegerType ret = 0;
for (int i = Nmin[m-1]; i <= std::min(Nmax[m-1], n); ++i)
ret += W(m - 1, n - i);
//memo[std::make_tuple(k, m)] = ret;
return ret;
}
}
IntegerType binomial(int m, int n) const
{
static std::vector<int> store;
if (store.empty())
{
std::function<IntegerType(int, int)> bin = [](int n, int k)
{
int res = 1;
if (k > n - k)
k = n - k;
for (int i = 0; i < k; ++i)
{
res *= (n - i);
res /= (i + 1);
}
return res;
};
store.resize(M*M);
for (int i = 0; i < M; ++i)
{
for (int j = 0; j < M; ++j)
{
store[i*M + j] = bin(i, j);
}
}
}
return store[m*M + n];
}
auto addressArray() const -> std::vector<int>
{
std::vector<int> ret((N + 1) * M);
for (int n = 0; n <= N; ++n)
{
for (int m = 0; m < M; ++m)
{
ret[n*M + m] = W(m, n);
}
}
return ret;
}
};
std::ostream& operator<<(std::ostream& os, SymmetricIndex const& sym)
{
for (auto const& i : sym.state)
{
os << i << " ";
}
return os;
}
Use it like
int main()
{
int M=4;
int N=3;
std::vector<int> Nmax(M, N);
std::vector<int> Nmin(M, 0);
Nmax[0]=3;
Nmax[1]=2;
Nmax[2]=1;
Nmax[3]=1;
SymmetricIndex sym(M, N, Nmax, Nmin);
while(!sym.isEnd())
{
std::cout<<sym<<" "<<sym.rank()<<std::endl;
++sym;
}
std::cout<<sym<<" "<<sym.rank()<<std::endl;
}
This will output
3 0 0 0 0 (corresponds to {40,40,40})
2 1 0 0 1 (-> {40,40,50})
1 2 0 0 2 (-> {40,50,50})
2 0 1 0 3 ...
1 1 1 0 4
0 2 1 0 5
2 0 0 1 6
1 1 0 1 7
0 2 0 1 8
1 0 1 1 9
0 1 1 1 10 (-> {50,60,100})
DEMO
Note that I assumed here an ascending mapping of your set elements (i.e. the number 40's is given by index 0, the number of 50's by index 1, and so on).
More precisely: Turn your list into a map<std::vector<int>, int> like
std::vector<int> v{40,40,40,50,50,60,100};
std::map<int, int> m;
for(auto i : v)
{
++m[i];
}
Then use
int N = 3;
int M = m.size();
std::vector<int> Nmin(M,0);
std::vector<int> Nmax;
std::vector<int> val;
for(auto i : m)
{
Nmax.push_back(m.second);
val.push_back(m.first);
}
SymmetricIndex sym(M, N, Nmax, Nmin);
as input to the SymmetricIndex class.
To print the output, use
while(!sym.isEnd())
{
for(int i=0; i<M; ++i)
{
for(int j = 0; j<sym[i]; ++j)
{
std::cout<<val[i]<<" ";
}
}
std::cout<<std::endl;
}
for(int i=0; i<M; ++i)
{
for(int j = 0; j<sym[i]; ++j)
{
std::cout<<val[i]<<" ";
}
}
std::cout<<std::endl;
All untested, but it should give the idea.
I have the code to build a max heap, but it keeps on returning the same array I give it. I'm sure its a minor error, but I cant seem to figure it out. Any help is appreciated.
Compilable sample code:
#include <iostream>
#include <cmath>
class Heaparr {
public:
Heaparr();
void insert(int da);
int getLeft(int i) { return 2 * i; }
int getRight(int i) { return (2 * i) + 1; }
int getParent(int i) { return i / 2; }
int getMax() { return maxHeap[0]; }
void print();
void reheap(int num);
void makeArray();
void Build_Max_Heap(int maxHeap[], int heap_size);
void Max_Heapify(int heapArray[], int i, int heap_size);
void heapSort(int heapArray[]);
private:
int size;
int* maxHeap;
int index;
int i;
};
Heaparr::Heaparr() {
maxHeap = nullptr;
size = 0;
}
void Heaparr::insert(int da) {
size++;
int* tmp = new int[size];
for (int i = 0; i < size - 1; i++) {
tmp[i] = maxHeap[i];
}
tmp[size - 1] = da;
delete[] maxHeap;
maxHeap = tmp;
}
void Heaparr::heapSort(int maxHeap[]) {
int heap_size = size;
int n = size;
int temp;
Build_Max_Heap(maxHeap, heap_size);
for (int i = n - 1; i >= 1; i--) {
temp = maxHeap[0];
maxHeap[0] = maxHeap[i];
maxHeap[i] = temp;
heap_size = heap_size - 1;
Max_Heapify(maxHeap, 0, heap_size);
}
for (int i = 0; i < 8; i++) {
std::cout << maxHeap[i] << std::endl;
}
}
void Heaparr::Build_Max_Heap(int maxHeap[], int heap_size) {
int n = size;
for (int i = floor((n - 1) / 2); i >= 0; i--) {
Max_Heapify(maxHeap, i, heap_size);
}
return;
}
void Heaparr::Max_Heapify(int heapArray[], int i, int heap_size) {
// int n = size;
int largest = 0;
int l = getLeft(i);
int r = getRight(i);
if ((l <= heap_size) && (heapArray[l] > heapArray[i])) {
largest = l;
} else {
largest = i;
}
if ((r <= heap_size) && (heapArray[r] > heapArray[largest])) {
largest = r;
}
int temp;
if (largest != i) {
temp = heapArray[i];
heapArray[i] = heapArray[largest];
heapArray[largest] = temp;
Max_Heapify(heapArray, largest, heap_size);
}
return;
}
int main(int argc, char* argv[]) {
int hArray[8] = {5, 99, 32, 4, 1, 12, 15, 8};
Heaparr t;
t.heapSort(hArray);
for (auto v : hArray) {
std::cout << v << ", ";
}
std::cout << std::endl;
}
I made some fixed to the code (i try not to changed much the original code):
The getLeft, getRight and getParent formulas were wrong (ex: when i == 0 children must be 1 and 2 and with your code are 0 and 1. The return type was also wrong, should be int (array index).
Do you receive in all methods a int[] except in insert and the member variable that are double[], changed all to int[], if you need changed back all to double
Using std::swap for swap values in the array.
Adding the length of the array to heapSort (inside the method this info is lost, need to be passed by parameter).
Notes:
I dont see where you use the member variable maxHeap, because all methods except getMax and insert use the array passed by parameter and not the member variable (perhaps you should initialized in the constructor or in heapSort method.
Try to use std::vector instead of C Array
Code:
#include <iostream>
#include <cmath>
class Heaparr {
public:
Heaparr();
void insert(int da);
int getLeft(int i) { return 2 * i + 1; }
int getRight(int i) { return 2 * i + 2; }
int getParent(int i) { return (i - 1) / 2; }
int getMax() { return maxHeap[0]; }
void print();
void reheap(int num);
void makeArray();
void Build_Max_Heap(int heapArray[], int heap_size);
void Max_Heapify(int heapArray[], int i, int heap_size);
void heapSort(int heapArray[], int heap_size);
private:
int size;
int* maxHeap;
int index;
int i;
};
Heaparr::Heaparr() {
maxHeap = nullptr;
size = 0;
}
void Heaparr::insert(int da) {
size++;
int* tmp = new int[size];
for (int i = 0; i < size - 1; i++) {
tmp[i] = maxHeap[i];
}
tmp[size - 1] = da;
delete[] maxHeap;
maxHeap = tmp;
}
void Heaparr::heapSort(int heapArray[], int heap_size) {
size = heap_size;
int n = size;
Build_Max_Heap(heapArray, heap_size);
for (int i = n - 1; i >= 1; i--) {
std::swap(heapArray[0], heapArray[i]);
heap_size = heap_size - 1;
Max_Heapify(heapArray, 0, heap_size);
}
}
void Heaparr::Build_Max_Heap(int heapArray[], int heap_size) {
int n = size;
for (int i = floor((n - 1) / 2); i >= 0; i--) {
Max_Heapify(heapArray, i, heap_size);
}
return;
}
void Heaparr::Max_Heapify(int heapArray[], int i, int heap_size) {
// int n = size;
int largest = 0;
int l = getLeft(i);
int r = getRight(i);
if ((l < heap_size) && (heapArray[l] < heapArray[i])) {
largest = l;
} else {
largest = i;
}
if ((r < heap_size) && (heapArray[r] < heapArray[largest])) {
largest = r;
}
if (largest != i) {
std::swap(heapArray[i], heapArray[largest]);
Max_Heapify(heapArray, largest, heap_size);
}
return;
}
int main(int argc, char* argv[]) {
int hArray[8] = {5, 99, 32, 4, 1, 12, 15, 8};
Heaparr t;
t.heapSort(hArray, sizeof(hArray)/sizeof(hArray[0]));
for (auto v : hArray) {
std::cout << v << ", ";
}
std::cout << std::endl;
return 0;
}
Output:
99, 32, 15, 12, 8, 5, 4, 1,
Tested in GCC 4.9.0 with C++11
If you're willing to consider alternative implementations, then here is one:
#define MIN_TYPE 0
#define MAX_TYPE ~0
template<int TYPE,typename ITEM>
class Heap
{
public:
Heap(int iMaxNumOfItems);
virtual ~Heap();
public:
bool AddItem(ITEM* pItem);
bool GetBest(ITEM** pItem);
protected:
int BestOfTwo(int i,int j);
void SwapItems(int i,int j);
protected:
ITEM** m_aItems;
int m_iMaxNumOfItems;
int m_iCurrNumOfItems;
};
template<int TYPE,typename ITEM>
Heap<TYPE,ITEM>::Heap(int iMaxNumOfItems)
{
m_iCurrNumOfItems = 0;
m_iMaxNumOfItems = iMaxNumOfItems;
m_aItems = new ITEM*[m_iMaxNumOfItems];
if (!m_aItems)
throw "Insufficient Memory";
}
template<int TYPE,typename ITEM>
Heap<TYPE,ITEM>::~Heap()
{
delete[] m_aItems;
}
template<int TYPE,typename ITEM>
bool Heap<TYPE,ITEM>::AddItem(ITEM* pItem)
{
if (m_iCurrNumOfItems == m_iMaxNumOfItems)
return false;
m_aItems[m_iCurrNumOfItems] = pItem;
for (int i=m_iCurrNumOfItems,j=(i+1)/2-1; j>=0; i=j,j=(i+1)/2-1)
{
if (BestOfTwo(i,j) == i)
SwapItems(i,j);
else
break;
}
m_iCurrNumOfItems++;
return true;
}
template<int TYPE,typename ITEM>
bool Heap<TYPE,ITEM>::GetBest(ITEM** pItem)
{
if (m_iCurrNumOfItems == 0)
return false;
m_iCurrNumOfItems--;
*pItem = m_aItems[0];
m_aItems[0] = m_aItems[m_iCurrNumOfItems];
for (int i=0,j=(i+1)*2-1; j<m_iCurrNumOfItems; i=j,j=(i+1)*2-1)
{
if (j+1 < m_iCurrNumOfItems)
j = BestOfTwo(j,j+1);
if (BestOfTwo(i,j) == j)
SwapItems(i,j);
else
break;
}
return true;
}
template<int TYPE,typename ITEM>
int Heap<TYPE,ITEM>::BestOfTwo(int i,int j)
{
switch (TYPE)
{
case MIN_TYPE: return *m_aItems[i]<*m_aItems[j]? i:j;
case MAX_TYPE: return *m_aItems[i]>*m_aItems[j]? i:j;
}
throw "Illegal Type";
}
template<int TYPE,typename ITEM>
void Heap<TYPE,ITEM>::SwapItems(int i,int j)
{
ITEM* pItem = m_aItems[i];
m_aItems[i] = m_aItems[j];
m_aItems[j] = pItem;
}
And here is a usage example:
typedef int ITEM;
#define SIZE 1000
#define RANGE 100
void test()
{
ITEM* pItem;
ITEM aArray[SIZE];
Heap<MIN_TYPE,ITEM> cHeap(SIZE);
srand((unsigned int)time(NULL));
for (int i=0; i<SIZE; i++)
{
aArray[i] = rand()%RANGE;
cHeap.AddItem(aArray+i);
}
for (int i=0; i<SIZE; i++)
{
cHeap.GetBest(&pItem);
printf("%d\n",*pItem);
}
}
Description:
This class stores up to N items of type T
It allows adding an item or extracting the best item
Supported operations are accomplished at O(log(n)), where n is the current number of items
Remarks:
T is determined at declaration and N is determined at initialization
The meaning of "best", either minimal or maximal, is determined at declaration
In order to support Heap<MIN,T> and Heap<MAX,T>, one of the following options must be viable:
bool operator<(T,T) and bool operator>(T,T)
bool T::operator<(T) and bool T::operator>(T)
T::operator P(), where P is a type, for which, one of the above options is viable