I have a task where I have to make a class depending on std::multiset. The idea is that it gets 2 multisets in its constructor, they then have to be sorted and put back in those variables while the class is in scope.To provide an example:
std::multiset<int> a;
std::multiset<int> b;
a.insert(4); a.insert(3); a.insert(1); a.insert(10); // a={1,3,4,10}
b.insert(3); b.insert(2); // b={2,3}
if(true){
multisets_merge_view<int>(a,b);
// sorts them and makes it, so that:
// a={1,2,3,3}
// b={4,10}
}
// and here, the multisets need to go back to their original state:
// a={1,3,4,10}
// b={2,3}
We have to work with g++ 9.3.0 under Ubuntu 20.04, with the following flags: -fsanitize=address,leak,undefined -O3 -Wall -Wextra -WerrorThe code - that was given and I cannot touch - to check if everything works correctly:
#include <iostream>
#include <numeric>
#include "msmview.h"
#include <set>
#include <iterator>
#include <string>
#include <algorithm>
#include "msmview.h"
struct string_size_less
{
bool operator()( const std::string& lhs,
const std::string& rhs ) const
{
return lhs.size() < rhs.size();
}
};
const int max = 1000;
bool check()
{
std::multiset<int> a;
std::multiset<int> b;
a.insert( 1 );
a.insert( 7 );
a.insert( 4 );
b.insert( 4 );
b.insert( 3 );
std::multiset<std::string> s;
std::multiset<std::string> t;
s.insert( "C++" );
s.insert( "Pascal" );
s.insert( "Haskell" );
t.insert( "C" );
t.insert( "Ada" );
std::multiset<int> x;
std::multiset<int> y;
for( int i = 0 ; i < max; ++i )
{
x.insert( i );
y.insert( i );
}
bool c = x.count( max / 3 ) == 2;
if ( !c )
{
multisets_merge_view<int> mvi( a, b );
multisets_merge_view<int> mvm( x, y );
multisets_merge_view<std::string> mvs( s, t );
c = x.count( max / 3 ) == 2 && 3 == s.size() &&
0 == s.count( "Pascal" ) && 1 == t.count( "Pascal" ) &&
0 == x.count( max - 1 ) && 1 == s.count( "C" ) &&
0 == a.count( 7 ) && 0 == b.count( 3 );
}
if ( !c || 1 != x.count( max / 3 ) || 1 != s.count( "Pascal" ) ||
0 != s.count( "C" ) || 2 != t.size() || 1 != x.count( max - 1 ) ||
1 != a.count( 7 ) || 1 != b.count( 3 ) )
{
return false;
}
if ( c )
{
const multisets_merge_view<int> mvi( a, b );
const multisets_merge_view<int> mvm( x, y );
const multisets_merge_view<std::string> mvs( s, t );
if ( 5 != mvi.size() || 2 != mvi.count( 4 ) || 0 != mvi.count( max ) ||
5 != mvs.size() || 1 != mvs.count( "C++" ) || 2 * max != mvm.size() ){
return false;
}
}
else
{
std::cout << "neither";
return false;
}
std::multiset<int, std::greater<int> > ga;
std::multiset<int, std::greater<int> > gb;
ga.insert( 0 );
ga.insert( max );
gb.insert( max );
std::multiset<std::string, string_size_less> sa;
std::multiset<std::string, string_size_less> sb;
sa.insert( "C++" );
sa.insert( "Haskell" );
sb.insert( "Ada" );
sb.insert( "SQL" );
sb.insert( "LISP" );
if ( c )
{
const multisets_merge_view<std::string, string_size_less> mvs( sa, sb );
const multisets_merge_view<int, std::greater<int> > mvi( ga, gb );
return 2 == sa.count( "C++" ) && 1 == sb.count( "C++" ) && 1 == gb.count( 0 ) &&
3U == sb.size() && ga.size() == ga.count( max ) && 3 == mvi.size();
}
return false;
}
int main()
{
std::cout
<< "Your solution is "
<< (check() ? "" : "not ")
<< "ready for submission."
<< std::endl;
}
And my code for the upper mentioned class:
#ifndef MSMVIEW_H
#define MSMVIEW_H
#include <set>
template<typename T1, typename T2 = std::greater<T1>>
class multisets_merge_view : public std::multiset<T1,T2>{
public:
multisets_merge_view(std::multiset<T1> &a, std::multiset<T1> &b);
multisets_merge_view(std::multiset<T1,T2> &a, std::multiset<T1,T2> &b);
~multisets_merge_view();
int size() const { return _size; }
int count(T1 t) const;
private:
std::multiset<T1> *_apo;
std::multiset<T1> *_bpo;
std::multiset<T1,T2> *_apt;
std::multiset<T1,T2> *_bpt;
std::multiset<T1> _ao;
std::multiset<T1> _bo;
std::multiset<T1,T2> _at;
std::multiset<T1,T2> _bt;
unsigned int _size;
};
template<typename T1, typename T2>
multisets_merge_view<T1,T2>::multisets_merge_view(std::multiset<T1> &a, std::multiset<T1> &b):_ao(a),_bo(b),_size(a.size()+b.size()){
_apo = &a;
_bpo = &b;
std::multiset<T1> tmp;
tmp.insert(a.begin(),a.end());
tmp.insert(b.begin(),b.end());
a.clear();
b.clear();
for(typename std::multiset<T1>::const_iterator i(tmp.begin()),end(tmp.end()); i!=end; ++i){
if(a.size() < _ao.size()){
a.insert(*i);
}else{
b.insert(*i);
}
}
};
template<typename T1, typename T2>
multisets_merge_view<T1,T2>::multisets_merge_view(std::multiset<T1,T2> &a, std::multiset<T1,T2> &b):_at(a),_bt(b),_size(a.size()+b.size()){
_apt = &a;
_bpt = &b;
std::multiset<T1,T2> tmp;
tmp.insert(a.begin(),a.end());
tmp.insert(b.begin(),b.end());
a.clear();
b.clear();
for(typename std::multiset<T1,T2>::const_iterator i(tmp.begin()),end(tmp.end()); i!=end; ++i){
if(a.size() < _at.size()){
a.insert(*i);
}else{
b.insert(*i);
}
}
};
template<typename T1, typename T2>
multisets_merge_view<T1,T2>::~multisets_merge_view(){
if(_apo != nullptr && _bpo != nullptr){
*_apo = _ao;
*_bpo = _bo;
}else if(_apt != nullptr && _bpt != nullptr){
*_apt = _bt;
*_bpt = _at;
}
};
template<typename T1, typename T2>
int multisets_merge_view<T1,T2>::count(T1 t) const{
int count = 0;
if(_apo != nullptr && _bpo != nullptr){
for(typename std::multiset<T1>::const_iterator i = _ao.begin(); i != _ao.end(); i++){
if(*i==t) count++;
}
for(typename std::multiset<T1>::const_iterator i = _bo.begin(); i != _bo.end(); i++){
if(*i==t) count++;
}
}else if(_apt != nullptr && _bpt != nullptr){
for(typename std::multiset<T1,T2>::const_iterator i = _at.begin(); i != _at.end(); i++){
if(*i==t) count++;
}
for(typename std::multiset<T1,T2>::const_iterator i = _bt.begin(); i != _bt.end(); i++){
if(*i==t) count++;
}
}
return count;
};
#endif
When I run the compiler, AddressSanitizer throws a memory reallocation error found in ~multisets_merge_view(), probably when *_apt=_at; *_bpt=_bt; happens (without providing a second template parameter in the main program, everything works fine, but as I said I can't modify that).
Is there a way to fix this while not touching the main program and still using the -fsanitize=address,leak,undefined?
Related
I have this cpp file and I have to write write a header for it, with an own template class. When I try to run the code it throws this 'std::logic_error' what(): basic_string::_M_construct null not valid error. It causes by the map_aligner<std::string, std::string> lsa; line but I don't really understand why and how to solve this issue.
The cpp:
#include <iostream>
#include "mapalign.h"
#include <string>
#include <algorithm>
#include <map>
#include "mapalign.h"
struct string_size_less
{
bool operator()( const std::string& a,
const std::string& b ) const
{
return a.size() < b.size();
}
};
const int max = 1000;
bool check()
{
std::map<std::string, int> sma;
std::map<std::string, int> smb;
std::map<std::string, int> smc;
map_aligner<std::string, int> sa;
sa.add( sma );
sa.add( smb );
sa.add( smc );
sma[ "C++" ] = 1;
smb[ "Ada" ] = 2;
smc[ "C" ] = 3;
smc[ "Python" ] = 4;
smc[ "Ada"] = 5;
sa.align();
std::map<int, double> ima;
std::map<int, double> imb;
for( int i = 0; i < max; ++i )
{
if ( 0 == i % 2 )
{
ima[ i ] = max - i;
}
else
{
imb[ i ] = max;
}
}
map_aligner<int, double> ia;
ia.add( ima );
ia.add( imb );
ia.align();
if ( ( 4 != sma.size() && 1 != imb.count( 0 )) || max * 1U != ima.size() ||
1 != smc.count( "C++" ) || "Ada" != sma.begin()->first ||
0 != sma.begin()->second || 4 != smc.size() ||
1 != smb.count( "Python" ) || 0 != imb.begin()->first ||
0.8 <= imb.begin()->second || 1 != imb.count( max / 2 ) )
{
return false;
}
sma[ "Pascal" ] = 5;
sa.set_filler( max );
sa.align();
std::map<std::string, std::string> langsa;
langsa[ "C++" ] = "<3";
langsa[ "Python" ] = ":|";
std::map<std::string, std::string> langsb;
langsb[ "Brainfuck" ] = ":S";
langsb[ "Python" ] = ":/";
langsb[ "C" ] = ":)";
map_aligner<std::string, std::string> lsa;
lsa.add( langsa );
lsa.add( langsb );
lsa.align();
lsa.erase( "Python" );
if ( 0 != langsa.count( "Python" ) || max != smc[ "Pascal" ] ||
!langsa.begin()->second.empty() || max != smb[ "Pascal" ] ||
2 * 1U != langsb.begin()->second.size() ||
0 != langsb.count( "Python" ) || 1 != langsb.count( "C++" ) )
{
return false;
}
std::map<std::string, std::string, string_size_less> lma;
std::map<std::string, std::string, string_size_less> lmb;
std::map<std::string, std::string, string_size_less> lmc;
lma[ "C++" ] = ":D";
lmb[ "Eiffel" ] = ":P";
lmc[ "C" ] = "8-)";
lmc[ "Ada" ] = "!";
map_aligner<std::string, std::string, string_size_less> ls;
ls.add( lma );
(ls += lmb) += lmc;
ls.align();
std::cout << (3 == ls.count()) << (1 == lmc.count( "Ada" )) <<
(3 * 1U == lmb.size()) << (1 == lma.count( "Python" )) <<
(2 == lsa.count()) << (2 == ia.count()) ;
return ( 3 == ls.count() && 1 == lmc.count( "Ada" ) &&
3 * 1U == lmb.size() && 1 == lma.count( "Python" ) &&
2 == lsa.count() && 2 == ia.count() );
}
int main()
{
std::cout
<< "Your solution is "
<< (check() ? "" : "not ")
<< "ready for submission."
<< std::endl;
}
The h:
#ifndef MAPALIGN_H
#define MAPALIGN_H
#include <vector>
#include <map>
#include <typeinfo>
template<typename KEY, typename VALUE, typename COMPARE = std::less<KEY>>
class map_aligner{
public:
typedef typename std::map<KEY, VALUE, COMPARE>::size_type size_type;
map_aligner() {}
void add(std::map<KEY, VALUE, COMPARE>& m) {
maps_.push_back(&m);
}
map_aligner<KEY, VALUE, COMPARE> operator+=(std::map<KEY, VALUE, COMPARE>& m){
return maps_.push_back(&m);
}
size_type count() const {
return maps_.size();
}
void align(){
for(int i = 0; i != (int)maps_.size(); i++ ){
std::map<KEY, VALUE>* first_map = maps_.at(i);
for(typename std::map<KEY, VALUE>::iterator j = first_map->begin(); j !=first_map->end(); j++ ){
for(int h = 0; h != (int)maps_.size(); h++ ){
std::map<KEY, VALUE>* second_map = maps_.at(h);
if(first_map != second_map && notContainsPair(second_map, j)){
second_map->insert(std::make_pair(j->first, filler_));
}
}
}
}
}
bool notContainsPair(std::map<KEY, VALUE>* map,typename std::map<KEY, VALUE>::iterator it){
for(typename std::map<KEY, VALUE>::iterator g = map->begin(); g != map->end(); g++ ){
if(it->first != g->first){
return true;
}
}
return false;
}
void set_filler(VALUE filler){
filler_ = filler;
}
void erase(KEY key){
for(int h = 0; h != (int)maps_.size(); h++ ){
std::map<KEY, VALUE>* map = maps_.at(h);
typename std::map<KEY, VALUE>::iterator it;
if(typeid(it->first) != typeid(it->first)){
map->erase(key);
}
}
}
private:
std::vector<std::map<KEY, VALUE, COMPARE>*> maps_;
VALUE filler_ = (VALUE) NULL;
};
#endif
That error is caused by you trying to construct a string with a null pointer.
Now look at the code that causes the error
map_aligner<std::string, std::string> lsa;
Both template parameters are strings.
Now look at this code in map_aligner
VALUE filler_ = (VALUE) NULL;
VALUE is a std::string so this code is constructing a string from a null pointer, exactly as the error indicates.
I don't know, but I guess you just want this
VALUE filler_ = VALUE();
It's a dangerous thing to try and construct an arbitrary type from NULL.
Looking at the following code
template <typename Itr>
constexpr auto foo(Itr first, Itr last)
{
for (; first != std::prev(last); std::advance(first, 1))
{
for (auto j{ first }; j != (std::prev(last) - first); std::advance(j, 1)) // Error here
{
// Do stuff
}
}
}
In the second for loop I get the error:
no operator found which takes a right-hand operand of type '__int64' (or there is no acceptable conversion)
I am not allowed to compare the iterator with a ptrdiff_t apperently. So how can I accomplish this task? I have tried using every cast available, to both j and the ptrdiff_t - but nothing is allowed.
The reason I need this, is because I only want the inner loop to iterate over a smaller subset of the container for each iteration of the outer loop.
An example where I need this is in the implementation of the bubble sort algorithm
template <typename Itr>
constexpr auto bubble_sort(Itr first, Itr last)
{
for (; first != std::prev(last); std::advance(first, 1))
{
auto swapped{ false };
for (auto j{ first }; j != (std::prev(last) - first); std::advance(j, 1))
{
if (*j > *std::next(j)) // Pred
{
std::iter_swap(j, std::next(j));
swapped = true;
}
}
if (!swapped) break;
}
}
If you want to write the method bubble_sort for forward iterators then it can look the following way as it is shown in the demonstrative program below. Neither ptrdiff_t is required.
Here you are.
#include <iostream>
#include <functional>
#include <iterator>
#include <algorithm>
#include <cstdlib>
#include <ctime>
template <typename ForwardIterator>
void bubble_sort( ForwardIterator first, ForwardIterator last )
{
for ( auto sorted = last; first != last && std::next( first ) != last; last = sorted )
{
for ( auto next = sorted = first, prev = next++; next != last; ++next, ++prev )
{
if ( *next < *prev )
{
std::iter_swap( prev, next );
sorted = next;
}
}
}
}
template <typename ForwardIterator, typename Comparison>
void bubble_sort( ForwardIterator first, ForwardIterator last, Comparison cmp )
{
for ( auto sorted = last; first != last && std::next( first ) != last; last = sorted )
{
for ( auto next = sorted = first, prev = next++; next != last; ++next, ++prev )
{
if ( cmp( *next, *prev ) )
{
std::iter_swap( prev, next );
sorted = next;
}
}
}
}
int main()
{
const size_t N = 10;
int a[N];
std::srand( ( unsigned int )std::time( nullptr ) );
for ( auto &item : a ) item = std::rand() % N;
for ( const auto &item : a ) std::cout << item << ' ';
std::cout << '\n';
bubble_sort( std::begin( a ), std::end( a ) );
for ( const auto &item : a ) std::cout << item << ' ';
std::cout << '\n';
bubble_sort( std::begin( a ), std::end( a ), std::greater<>() );
for ( const auto &item : a ) std::cout << item << ' ';
std::cout << '\n';
return 0;
}
The program output might look like
1 5 4 4 0 9 7 3 3 1
0 1 1 3 3 4 4 5 7 9
9 7 5 4 4 3 3 1 1 0
I want to build an unordered set for my Face structure, that is
class myFace
{
public:
//the three points
int u;
int v;
int k;
myFace() = default;
myFace(int u, int v, int k) : u(u), v(v), k(k) {}
bool operator< (const myFace& e) const
{
bool result = true;
min(u, v, k);
if ((u == e.u && v == e.v && k == e.k) ||
(u == e.u && v == e.k && k == e.v) ||
(u == e.v && v == e.u && k == e.k) ||
(u == e.v && v == e.k && k == e.u) ||
(u == e.k && v == e.u && k == e.v) ||
(u == e.k && v == e.v && k == e.u))
{
result = false;
}
return result;
}
};
I want to make sure that:
set<myFace> con;
myFace f1(1,2,3);
myFace f2(2,3,1);
myFace f3(3,1,2);
con.insert(f1);
con.insert(f2);
con.insert(f3);
cout << con.size() << endl;
the output should be 1.
Since f1,f2,f3 are same.
Or we can just say how to implement a set for 3 unordered elements, that is 123,132,213,231,312,321 are all same.
The secret is, to use the correct Comparator for your class and give it to the set. I used a similar approach for sets here.
I adapted this solution and created the below example code:
#include <iostream>
#include <set>
#include <vector>
#include <algorithm>
struct myFace
{
//the three points
int u;
int v;
int k;
myFace() = default;
myFace(int u, int v, int k) : u(u), v(v), k(k) {}
};
struct Comparator {
bool operator () (const myFace& lhs, const myFace& rhs) const {
// Convert the structs to vectors
std::vector<int> v1 = { lhs.u, lhs.v, lhs.k };
std::vector<int> v2 = { rhs.u, rhs.v, rhs.k };
// Sort them
std::sort(v1.begin(), v1.end());
std::sort(v2.begin(), v2.end());
// Compare them
return v1 < v2;
}
};
int main() {
std::set<myFace, Comparator> con;
myFace f1(1, 2, 3);
myFace f2(2, 3, 1);
myFace f3(3, 1, 2);
con.insert(f1);
con.insert(f2);
con.insert(f3);
std::cout << con.size() << std::endl;
return 0;
}
I found that use set can achieve the goal: implementing a set for 3 unordered elements, that is 123,132,213,231,312,321 are all same.
set<int> face;
face.insert(1);
face.insert(2);
face.insert(3);
set<int> face2;
face2.insert(2);
face2.insert(1);
face2.insert(3);
set<int> face3;
face3.insert(3);
face3.insert(1);
face3.insert(2);
set<set<int>> faces;
faces.insert(face);
faces.insert(face2);
faces.insert(face3);
cout << "----" << endl;
cout << faces.size() << endl;
I posted earlier today and was able to work out a lot of my errors. However, I still have one error that I cannot figure out for the life of me. I'm basically just trying to insert a Symbol object into a HashTable and I'm constantly getting this message back:
In file included from /opt/local/include/gcc47/c++/bits/basic_string.h:3032:0,
from /opt/local/include/gcc47/c++/string:54,
from /opt/local/include/gcc47/c++/bits/locale_classes.h:42,
from /opt/local/include/gcc47/c++/bits/ios_base.h:43,
from /opt/local/include/gcc47/c++/ios:43,
from /opt/local/include/gcc47/c++/ostream:40,
from /opt/local/include/gcc47/c++/iostream:40,
from Driver.cpp:1:
/opt/local/include/gcc47/c++/bits/functional_hash.h: In instantiation of 'struct std::hash<Symbol>':
SeparateChaining.h:143:33: required from 'size_t HashTable<HashedObj>::myhash(const HashedObj&) const [with HashedObj = Symbol; size_t = long unsigned int]'
SeparateChaining.h:56:51: required from 'bool HashTable<HashedObj>::insert(HashedObj&) [with HashedObj = Symbol]'
Driver.cpp:135:26: required from here
/opt/local/include/gcc47/c++/bits/functional_hash.h:60:7: error: static assertion failed: std::hash is not specialized for this type
More specifically though.... The error:
error: static assertion failed: std::hash is not specialized for this type
Here is my Driver.cpp file:
#include <iostream>
#include <iomanip>
#include <cassert>
#include <fstream>
#include <string>
#include <vector>
#include <time.h>
#include <unistd.h>
#include <map>
#include <cstdlib>
#include <cmath>
#include "SeparateChaining.h"
using namespace std;
int TABLE_SIZE; //I know it's a global, but it allows the Table Size to be taken in within main() and used in hash()
size_t hash(const string & key);
class Symbol
{
private:
int key;
int type;
string data;
public:
const string & getData() const
{
return data;
}
int getType()
{
return type;
}
int getKey()
{
return labs(key);
}
void setType(int Type)
{
type = Type;
}
void setData(string Data)
{
data = Data;
}
void setKey(int Key)
{
key = Key;
}
bool operator== (const Symbol & rhs) const
{
return getData() == rhs.getData();
}
bool operator!= (const Symbol & rhs) const
{
return !(*this == rhs);
}
};
int main()
{
HashTable<Symbol> hashtable(TABLE_SIZE);
Symbol temp;
vector<Symbol> symbols;
string s;
int t;
int hash_key_array[TABLE_SIZE]; //array to hold hash key values
ifstream file;
file.open("symbols.txt");
if(!file)
{
cout << "System failed to open file.";
}
else
{
cout << "File successfully opened" << endl;
}
//for loop to read in the string name and the integer that follows the string name from symbols.txt
while(file >> s)
{
temp.setData(s);
file >> t;
temp.setType(t);
symbols.push_back(temp);
}
for(int i = 0; i < symbols.size(); i++)
{
cout << symbols[i].getData() << "\n";
cout << symbols[i].getType() << "\n";
}
cout << "What would you like the table size to be?" << endl;
cout << "Note: If the table size is greater than the number of objects" <<
" in the symbols.txt file, it will inevitably throw a segmentation fault" << endl;
cin >> TABLE_SIZE;
for(int j = 0; j < TABLE_SIZE; j++)
{
temp.setData(symbols[j].getData());
cout << temp.getData() << endl;
temp.setType(symbols[j].getType());
cout << temp.getType() << endl;
temp.setKey(::hash(symbols[j].getData()));
cout << "The key is: " << temp.getKey() << endl;
cout << endl;
hash_key_array[j] = temp.getKey();
for (int i = 0; i < TABLE_SIZE; i++)
{
if (i != j)
{
if (hash_key_array[i] == hash_key_array[j])
{
cout << endl;
cout << "Collision occurred at " << hash_key_array[i] << endl;
//rehash();
//cout << "The new key is: " << temp.getKey() << endl;
break;
}
}
}
hashtable.insert(temp);
}
}
size_t hash(const string & key)
{
size_t hashVal = 0;
for(char ch : key)
{
hashVal = 37 * hashVal + ch;
}
return labs(hashVal);
}
And my Header File.... SeperateChaining.h:
#ifndef SEPARATE_CHAINING_H
#define SEPARATE_CHAINING_H
#include <vector>
#include <list>
#include <string>
#include <algorithm>
#include <functional>
//#include "Hash.h"
using namespace std;
// SeparateChaining Hash table class
//
// CONSTRUCTION: an approximate initial size or default of 101
//
// ******************PUBLIC OPERATIONS*********************
// bool insert( x ) --> Insert x
// bool remove( x ) --> Remove x
// bool contains( x ) --> Return true if x is present
// void makeEmpty( ) --> Remove all items
int nextPrime( int n );
bool isPrime( int n );
template <typename HashedObj>
class HashTable
{
public:
//Uses the whatever value table_size has
//Otherwise, it will make a hash table of size 101
explicit HashTable( int TABLE_SIZE )
{
currentSize = 0;
theLists.resize(TABLE_SIZE);
}
bool contains( const HashedObj & x ) const
{
//represents the correct list in the hash table vector to start looking through
auto & whichList = theLists[ myhash( x ) ];
//returns whatever you wanted to search for in the table provided it is there
return find( begin( whichList ), end( whichList ), x ) != end( whichList );
}
void makeEmpty( )
{
for( auto & thisList : theLists )
thisList.clear( );
}
bool insert(HashedObj & temp )
{
//represents the correct list in the hash table vector to start looking through
auto & whichList = theLists[myhash( temp )];
//goes through the beginning and end of the list, and if it
//doesn't get to the end, then it found the object you wanted to insert in the hash table already
//prevents duplicate insertions
if( find( begin( whichList ), end( whichList ), temp ) != end( whichList) )
return false;
//otherwise, it has gotten to the end of the list without finding a duplicate
//and puts what you want to insert in the list
whichList.push_back( temp );
// Rehash; see Section 5.5
if( ++currentSize > theLists.size( ) )
rehash( );
return true;
}
bool insert(const HashedObj && x )
{
auto & whichList = theLists[ myhash( x ) ];
if( find( begin( whichList ), end( whichList ), x ) != end( whichList ) )
return false;
whichList.push_back( std::move( x ) );
// Rehash; see Section 5.5
if( ++currentSize > theLists.size( ) )
rehash( );
return true;
}
bool remove( const HashedObj & x )
{
//represents the correct list in the hash table vector to start looking through
auto & whichList = theLists[ myhash( x ) ];
//trying to find x within the list
//the iterator points to the slot in the list that contains x
auto itr = find( begin( whichList ), end( whichList ), x );
//if it gets to the end of the list without finding what you want to remove, then it returns false
if( itr == end( whichList ) )
{
return false;
}
//if it finds x, it removes it from the list
whichList.erase( itr );
--currentSize;
return true;
}
/*
void printTable()
{
for(int i=0; i < symbols.size(); i++)
{
cout << "The hash table contains: " << symbols[i] << endl;
}
}
*/
private:
vector<list<HashedObj>> theLists; // The array of Lists
int currentSize;
void rehash( )
{
vector<list<HashedObj>> oldLists = theLists;
// Creates new double-sized, empty table
theLists.resize( nextPrime( 2 * theLists.size( ) ) );
for( auto & thisList : theLists )
thisList.clear( );
// Copies the old table into the new table
currentSize = 0;
for( auto & thisList : oldLists )
for( auto & x : thisList )
insert( std::move( x ) );
}
size_t myhash( const HashedObj & x ) const
{
static hash<HashedObj> hf;
return hf( x ) % theLists.size( );
}
};
int nextPrime( int n )
{
if( n % 2 == 0 )
{
++n;
}
for( ; !isPrime( n ); n += 2 )
{
}
return n;
}
bool isPrime( int n )
{
if( n == 2 || n == 3 )
return true;
if( n == 1 || n % 2 == 0 )
return false;
for( int i = 3; i * i <= n; i += 2 )
if( n % i == 0 )
return false;
return true;
}
#endif
I would really appreciate you guys helping me out!
You are doing this:
static hash<HashedObj> hf;
but you have not provided a hash template, or have not specialized std::hash for HashedObj.
You should avoid using namespace std;. Amongst other things, it is difficult to figure out which hash you want to get.
(SEE BELOW ALSO)
So I've got some functions and some operators for a set-manipulation program I'm coding, and I want to have power sets as a utility too (never mind the comments in the code). I don't want to use a binary approach, but I want to use recursion. I saw in Ralph Oberste-Vorth's book Bridge to Abstract Mathematics a definition of power sets (page 65), and on the next page I see all these equivalences like "if S = X, then P(S) = P(X)," and "if A and B are sets, then P(A) U P(B) = P(A U B)," and I'm reminded of recursion. I think recursion could work here but I'm not sure. I was playing around with Mathematica's Combinatorica package, and that one Haverford College paper on Hasse Diagrams, and I thought I could work out, in much the same way as is done here four minutes in, some kind of method based on the corresponding diagram for some set of size n, but I don't know that that will lead me the right way. I would like to build off of my already-built functions/operators.
#include <iostream>
#include <set>
#include <ostream>
#include <istream>
#include <vector>
using namespace std;
set<int> SetUnion( set<int> A , set<int> B ) // tus koj hlub
{
//A.insert( B.begin() , B.end() );
//return A;
set<int> pump;
for( set<int>::iterator cycle = A.begin() ; cycle != A.end() ; ++cycle )
{
pump.insert(*cycle);
}
for( set<int>::iterator cycle = B.begin() ; cycle != B.end() ; ++cycle )
{
pump.insert(*cycle);
}
return pump;
}
set<int> SetIntersection( set<int> A , set<int> B ) // tus koj hlub
{
set<int> pump;
for( set<int>::iterator cycle = A.begin ; cycle != A.end() ; ++cycle )
{
if( B.find(*cycle) != B.end() )
{
pump.insert(*cycle);
}
}
return pump;
}
set<int> SetDifference( set<int> A , set<int> B )
{
set<int> pump;
for( set<int>::iterator cycle = A.begin ; cycle != A.end() ; ++cycle )
{
if( B.find(*cycle) == B.end() )
{
pump.insert(*cycle);
}
}
return pump;
}
set<int> SymmetricDifference( set<int> A , set<int> B )
{
return SetUnion( SetDifference( A , B ) , SetDifference( B , A ) );
//return SetDifference( SetUnion( A , B ) , SetIntersection( A , B ) );
}
set<set<int>> PowerSet( set<int> A )
{
/*statements*/
}
set<int> Complement( set<int> A , int B )
{
set<int> pump;
for( int i = 1 ; i<=B ; i++ )
{
pump.insert(i);
}
set<int> collect = SetDifference( A , pump );
return collect;
}
set<int> operator+(set<int> A , set<int> B)
{
return SetUnion( A, B );
}
set<int> operator+(set<int> A , int B)
{
set<int> C;
C.insert(B);
return SetUnion( A , C );
}
set<int> operator+(int A , set<int> B)
{
set<int> C;
C.insert(A);
return SetUnion( B , C );
}
set<int> operator-(set<int> A , set<int> B)
{
set<int> pump;
for( set<int>::iterator cycle = A.begin ; cycle != A.end() ; ++cycle )
{
if( B.find(*cycle) == B.end() )
{
pump.insert(*cycle);
}
}
return pump;
}
set<int> operator-(set<int> A , int B)
{
set<int> C;
C.insert(B);
set<int> pump = SetDifference( A , C );
return C;
}
set<int> operator-(int A , set<int> B)
{
set<int> C;
C.insert(A);
set<int> pump = SetDifference( B , C );
return pump;
}
set<int> operator^(set<int> A , set<int> B)
{
return SetUnion( A , B );
}
set<int> operator^(set<int> A , int B)
{
set<int> C;
C.insert(B);
set<int> pump = SetUnion( A , C );
return pump;
}
set<int> operator^(int A , set<int> B)
{
set<int> C;
C.insert(A);
set<int> pump = SetUnion( B , C );
return pump;
}
set<int> operator%(set<int> A , set<int> B)
{
return SymmetricDifference( A , B );
}
set<int> operator%(set<int> A , int B)
{
set<int> C;
C.insert(B);
set<int> pump = SymmetricDifference( A , C );
return pump;
}
set<int> operator%(int A , set<int> B)
{
set<int> C;
C.insert(A);
set<int> pump = SymmetricDifference( B , C );
return pump;
}
set<int> operator~(set<int> A)
{
set<int> pump;
vector<int> hose;
for( set<int>::iterator cycle = A.begin() ; cycle != A.end() ; ++cycle )
{
hose.push_back(*cycle);
}
int last_value =
}
ostream& operator<<(ostream& out , set<int>& B) // tus koj hlub
{
int count=0;
if( B.size() == 0 )
{
out << "{}";
return out;
}
else
{
set<int>::iterator it;
out << "{";
for( it = B.begin() ; it != B.end() ; ++it )
{
++count;
if( count == B.size() )
{
out << *it;
}
else
{
out << *it << ", ";
}
}
out << "}";
return out;
}
}
istream& operator>>(istream& in , set<int>& B) // tus koj hlub
{
int user_input;
while(1)
{
in>>user_input;
if(user_input == -1)
break;
B.insert(user_input);
}
return in;
}
Also, why do I get an error on my "<<" operator symbol in the function here:
ostream& operator<<(ostream& out , set<set<int>>& B)
{
int count=0;
if( B.size() == 0 )
{
out << "{}";
return out;
}
else
{
set<set<int>>::iterator it;
out << "{";
for( it = B.begin() ; it != B.end() ; ++it )
{
count++;
if( count == B.size() )
{
out << *it;
}
else
{
out << *it << ", ";
}
}
out << "}";
return out;
}
}
The answer given by Mr. Shields produces the following error. I'm trying to figure out why it doesn't work:
Error: class "std::_Tree_const_iterator, std::allocator>>>> "has no member "insert"
ANSWER FROM AUTHOR:
set<set<int>> PowerSet( const set<int> A )
{
set<set<int>> ps;
if( A.size() == 0 )
{
ps.insert( set<int>() );
return ps;
}
set<int>::iterator it = A.begin();
int n = *it;
set<int> s1 = A;
s1.erase( n );
set<set<int>> ps1 = PowerSet( s1 );
set<set<int>> ps2;
for( set<set<int>>::iterator it = ps1.begin() ; it != ps1.end() ; ++it )
{
set<int> ss = *it;
ss.insert( n );
ps2.insert (ss );
}
for( set<set<int>>::iterator it = ps1.begin() ; it != ps1.end() ; ++it )
{
ps.insert(*it);
}
for( set<set<int>>::iterator it = ps2.begin() ; it != ps2.end() ; ++it )
{
ps.insert( *it );
}
return ps;
}
This C++ code below is horribly inefficient, but I think it should give you the idea for how to do this recursively. The recursion rule is basically this:
P({}) = {{}}
the power set of the empty set is the set containing the empty set
P({n} U S) = { {n} U T | T in P(S) } U P(S)
every set in the power set of {n} U S either contains n or does not contain n - exactly one of each for each set in the power set of S
Be aware that a set of cardinality K has a power set of cardinality 2^K. So you don't want to perform this operation on any large sets!
set<set<int>> PowerSet( set<int> A )
{
set<set<int>> PA;
if (A.empty())
{
//case: P({}) = {{}}
PA.insert(A);
}
else
{
//case: P({n} U S) = { {n} U T | T in P(S) } U P(S)
int n = *A.begin();
A.erase(A.begin());
//A is now "S" from the explanation above this code
auto PS = PowerSet(A);
for (auto T = PS.begin(); T != PS.end(); ++T)
{
//add each set T from P(S)
PA.insert(*T);
//add each set T from P(S) with n included as well
T->insert(n);
PA.insert(*T);
}
}
return PA;
}