I want to use structure Item as key in unordered_map
I implemented structures for hash and equal operations.
But I have an error
hashtable_policy.h:1384:16: error: no match for call to '(const ItemHash) (const Item&)'
solution.cpp:28:12: note: candidate: 'size_t ItemHash::operator()(Item)'
32 | size_t operator()(Item item) {
solution.cpp:28:12: note: passing 'const ItemHash*' as 'this' argument discards qualifiers
How can I fix the error?
My code
vector<int> get_key(const string& s) {
vector<int> res(26, 0);
for (int i = 0; i < s.size(); ++i) {
int pos = s[i] - 'a';
res[pos]++;
}
return res;
}
struct Item {
vector<int> v;
Item(const vector<int>& vec) : v(vec) {}
bool operator==(Item other) {
if (v.size() != other.v.size()) {
return false;
}
for (int i = 0; i < v.size(); ++i) {
if (v[i] != other.v[i]) {
return false;
}
}
return true;
}
};
struct ItemHash {
size_t operator()(Item item) {
auto vec = item.v;
size_t seed = vec.size();
for(auto& i : vec) {
seed ^= i + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
return seed;
}
};
struct ItemEqual {
bool operator()(Item item1, Item item2) {
return item1 == item2;
}
};
vector<vector<int> > Solution::anagrams(const vector<string> &A) {
vector<vector<int>> res;
unordered_map<Item, vector<int>, ItemHash, ItemEqual> hash; // hash_key, vector of indexes
for (int i = 0; i < A.size(); ++i) {
Item item = Item(get_key(A[i]));
hash[item].push_back(i);
}
for (const auto& i : hash) {
res.push_back(i.second);
}
return res;
}
You need to const-qualify ItemHash::operator()(Item), i.e.,
struct ItemHash {
size_t operator()(Item item) const
// ^^^^ here
{
// as before...
}
Note that as #JeJo pointed out in the comments, you need the same fix for ItemEqual.
Related
I tried to create a template for a generic 2D array, which would allow me to create arrays of different data types and fill them with random values. My current code seemingly creates three objects, but fills them with the same random values, and the double type massive does not even have double values. I think the problem is somewhere in the constructor and with the pointers, but I am not sure how to fix this.
My class:
template <typename T>
class MATRIX
{
private:
T** M;
int m = 8;
int n = 12;
public:
MATRIX(T matr[8][12]);
void fill();
};
Constructor:
template <typename T>
MATRIX<T>::MATRIX(T matr[8][12]){
M = (T**) new T*[m];
for (int i = 0; i < m; i++)
M[i] = (T*)new T[n];
}
Method:
template <typename T>
void MATRIX<T>::fill(){
T randomNumber;
srand((unsigned) time(0));
for (int i = 0; i < m; i++){
for (int j = 0; j < n; j++){
randomNumber = (rand() % (122 + 1 - 65)) + 65;
M[i][j] = randomNumber;} } }
Main:
int main() {
int intMatr[8][12];
MATRIX<int>a(intMatr);
a.fill();
double doubleMatr[8][12];
MATRIX<double>b(doubleMatr);
b.fill();
char charMatr[8][12];
MATRIX<char>c(charMatr);
c.fill();
return 0; }
Not really a direct answer to your question, howeverr try not to use new/delete if you don't have to as is shown in this example (note the array2d_t class is something I wrote earlier and reused for this example so it can do a bit more then needed)
I also show how to use c++'s random generators to create characters for your matrix.
#pragma once
#include <vector>
#include <iostream>
#include <random>
#include <utility>
#include <string>
#include <stdexcept>
//---------------------------------------------------------------------------------------------------------------------
template<typename type_t, std::size_t rows_v, std::size_t cols_v>
struct array2d_t
{
constexpr array2d_t() :
m_values{}
{
}
constexpr explicit array2d_t(const type_t(&values)[rows_v][cols_v])
{
// constexpr compatible initialization
for (auto row = 0; row < rows_v; ++row)
{
for (auto col = 0; col < cols_v; ++col)
{
m_values[row][col] = values[row][col];
}
}
}
~array2d_t() = default;
// return a row
constexpr auto operator[](const std::size_t row)
{
//assert(row < rows_v);
if (row >= rows_v) throw std::invalid_argument("row out of bounds");
return row_t(&m_values[row][0]);
}
// return a const row
constexpr auto operator[](const std::size_t row) const
{
//assert(row < rows_v);
if (row >= rows_v) throw std::invalid_argument("row out of bounds");
return const_row_t(&m_values[row][0]);
}
// return iterator to the first row (so array can be used in range based for loop)
constexpr auto begin()
{
return std::begin(m_values);
}
// return iterator to the last row (so array can be used in range based for loop)
constexpr auto end()
{
return std::end(m_values);
}
constexpr std::size_t rows() const
{
return rows_v;
}
constexpr std::size_t columns() const
{
return cols_v;
}
private:
//-----------------------------------------------------------------------------------------------------------------
/// row helper
struct row_t
{
constexpr row_t(type_t* row) :
m_row{ row }
{
}
constexpr type_t& operator[](const std::size_t column) const
{
//assert(column < cols_v);
if (column >= cols_v) throw std::invalid_argument("column out of bounds");
return m_row[column];
}
constexpr auto begin() const
{
return std::begin(m_row);
}
constexpr auto end() const
{
return begin() + rows_v;
}
private:
type_t* m_row;
};
//-----------------------------------------------------------------------------------------------------------------
// row helper for const
struct const_row_t
{
constexpr const_row_t(const type_t* row) :
m_row{ row }
{
}
constexpr const type_t& operator[](const std::size_t column) const
{
//assert(column < cols_v);
if (column >= cols_v) throw std::invalid_argument("column out of bounds");
return m_row[column];
}
constexpr auto begin() const
{
return std::begin(m_row);
}
constexpr auto end() const
{
return begin() + rows_v;
}
private:
const type_t* m_row;
};
type_t m_values[rows_v][cols_v];
};
template<typename type_t, std::size_t rows_v, std::size_t cols_v>
std::ostream& operator<<(std::ostream& os, array2d_t<type_t,rows_v,cols_v>& arr)
{
for (const auto& row : arr)
{
bool comma = false;
for (const auto& value : row)
{
if (comma) std::cout << ", ";
std::cout << value;
comma = true;
}
std::cout << "\n";
}
std::cout << "\n";
return os;
}
//---------------------------------------------------------------------------------------------------------------------
class MATRIX :
public array2d_t<char, 8, 12>
{
public:
void fill()
{
// initialize a vector of valid character for random to pick from
// static ensures this is only done on first call to function
static std::vector<char> valid_chars = []
{
std::vector<char> chars;
chars.reserve(52);
for (char c = 'A'; c < 'Z'; ++c) chars.push_back(c);
for (char c = 'a'; c < 'z'; ++c) chars.push_back(c);
return chars;
}();
// this is how to setup random number generation in C++
static std::random_device rd{};
static std::default_random_engine random{ rd() };
static std::uniform_int_distribution<std::size_t> distribution(0, valid_chars.size() - 1);
for (auto& row : *this)
{
for (auto& value : row)
{
value = valid_chars[distribution(random)];
}
}
}
};
//---------------------------------------------------------------------------------------------------------------------
int main()
{
MATRIX m;
m.fill();
std::cout << m;
return 0;
}
I am trying to write sorting template function to make it work with custom classes.
My code is:
#include <iostream>
#include <vector>
struct test
{
int value;
test(int a) : value(a){};
void print() { printf("the value is : %d", value); };
};
template <class T>
void bubblesort(T *m_data, size_t size, bool (*cmp)(const T &l, const T &r))
{
for (uint32_t i = 0; i < size; i++)
for (uint32_t j = 1; j < size - i; j++)
if (cmp(m_data[j - 1], m_data[j]))
{
T temp = m_data[j];
m_data[j] = m_data[j - 1];
m_data[j - 1] = temp;
}
}
int main()
{
std::vector<test> arr;
for (size_t i = 0; i < 10; i++)
arr.emplace_back(i);
std::vector<test *> arr1;
for (auto &i : arr)
arr1.emplace_back(&i);
bubblesort<test>(&arr[0], arr.size(), [](const test &l, const test &r) { return l.value < r.value; });
// bubblesort<test*>(&arr1[0], arr1.size(), [](const test *&l, const test *&r) { return l->value < r->value; });
for (auto i : arr)
printf("%d\n", i.value);
}
My question is how do you sort arr1 using the bubblesort function above? What kind of modification do I have to make in my code to be able to do so?
uncommenting the bubblesort line gives error
error: invalid user-defined conversion from 'main()::<lambda(const test*&, const test*&)>' to 'bool (*)(test* const&, test* const&)' [-fpermissive]
[build] 48 | bubblesort<test *>(&arr1[0], arr1.size(), [](const test *&l, const test *&r) { return l->value < r->value; });
Your function has the wrong type; T is test*, so you need test* const& - "reference to const pointer to test" - as the error message says.
(const test*& is "reference to pointer to const test.)
Your solution cannot work with templates...it cannot deduce the parameters type.
Consider modifying your code as follow:
struct test
{
int value;
explicit test(int a) : value(a) {};
void print() { printf("the value is : %d", value); };
};
template <class T, class _cmp>
void bubblesort(T *m_data, size_t size, _cmp cmp)
{
for (uint32_t i = 0; i < size; i++)
for (uint32_t j = 1; j < size - i; j++)
if (cmp(m_data[j - 1], m_data[j]))
{
T temp = m_data[j];
m_data[j] = m_data[j - 1];
m_data[j - 1] = temp;
}
}
int main()
{
std::vector<test> arr;
for (int i = 0; i < 10; i++)
arr.emplace_back(i);
std::vector<test *> arr1;
for (auto i : arr)
arr1.emplace_back(&i);
bubblesort<test>(&arr[0], arr.size(), [](const test &l, const test &r) -> bool { return l.value < r.value; });
bubblesort<test*>(&arr1[0], arr1.size(), [](const test* l, const test* r) -> bool { return l->value < r->value; });
for (auto i : arr)
printf("%d\n", i.value);
}
I was trying to fix a bug, and I am extremely confused, it seems that whenever I use std::cout the program will freeze. I have absolutely no idea why this is happening, and if any of you I know why I would love to know.
here is my source code for reference (the std::cout is at the bottom in the main function):
#include <iostream>
#include <vector>
#include <unordered_map>
#include <exception>
#include <string>
#include <fstream>
/*
template<
typename T
>
std::ostream& operator<< (std::ostream& stream, std::vector<T> vec)
{
for (int i = 0; i < vec.size() - 1; ++i)
{
stream << vec[i] << " ";
}
stream << vec.back();
return stream;
}
*/
class gate
{
public:
std::unordered_map<std::string, int> m_inputs;
std::unordered_map<std::string, int> m_outputs;
virtual std::vector<bool> calculate(const std::vector<bool>& inputs) = 0;
gate(const std::unordered_map<std::string, int>& inputs, const std::unordered_map<std::string, int>& outputs) :
m_inputs(inputs),
m_outputs(outputs)
{}
};
class elementary_gate : public gate
{
private:
std::unordered_map<std::vector<bool>, std::vector<bool>> m_truth_table;
public:
elementary_gate(const std::unordered_map<std::vector<bool>, std::vector<bool>>& truth_table,
const std::unordered_map<std::string, int>& inputs,
const std::unordered_map<std::string, int>& outputs
) :
gate(inputs, outputs),
m_truth_table(truth_table)
{}
std::vector<bool> calculate(const std::vector<bool>& inputs) override
{
return m_truth_table[inputs];
}
};
class gate_reference
{
private:
gate* m_gate;
std::vector<int> m_input_connection_ids;
std::vector<int> m_output_connection_ids;
public:
gate_reference(gate* gate_ref, const std::vector<int>& input_connection_ids, const std::vector<int>& output_connection_ids) :
m_gate(gate_ref),
m_input_connection_ids(input_connection_ids),
m_output_connection_ids(output_connection_ids)
{}
std::vector<bool> calculate(const std::vector<bool>& inputs)
{
return m_gate->calculate(inputs);
}
std::vector<int> get_input_connection_ids()
{
return m_input_connection_ids;
}
void set_output_connection_ids(const std::vector<bool>& output_vector, std::vector<bool>& connection_values)
{
for (int i = 0; i < output_vector.size(); ++i)
{
connection_values[m_output_connection_ids[i]] = output_vector[i];
}
}
};
class compound_gate : public gate
{
private:
std::vector<gate_reference> m_gates;
std::vector<int> m_output_connection_ids;
int connection_count;
int input_count;
public:
std::vector<bool> calculate(const std::vector<bool>& inputs) override
{
if (inputs.size() != input_count)
{
throw std::length_error("incorrect input size for logic gate");
}
std::vector<bool> connection_values(connection_count);
for (int i = 0; i < input_count; ++i)
{
connection_values[i] = inputs[i];
}
for (gate_reference gate_ref : m_gates)
{
std::vector<int> input_ids = gate_ref.get_input_connection_ids();
std::vector<bool> input_vector = construct_io_vector(input_ids, connection_values);
std::vector<bool> output_vector = gate_ref.calculate(input_vector);
gate_ref.set_output_connection_ids(output_vector, connection_values);
}
return construct_io_vector(m_output_connection_ids, connection_values);
}
private:
std::vector<bool> construct_io_vector(const std::vector<int>& connection_ids, const std::vector<bool>& connection_values)
{
std::vector<bool> input_vector;
for (int connection_id : connection_ids)
{
input_vector.push_back(connection_values[connection_id]);
}
return input_vector;
}
};
std::vector<bool> get_vector_from_int(int num, int pad_length)
{
std::vector<bool> bool_vec;
while (num)
{
if (num % 2)
{
bool_vec.push_back(true);
}
else
{
bool_vec.push_back(false);
}
num >>= 1;
}
while (bool_vec.size() < pad_length)
{
bool_vec.push_back(false);
}
std::reverse(bool_vec.begin(), bool_vec.end());
return bool_vec;
}
class gates
{
public:
static std::unordered_map<std::string, elementary_gate*> gate_list;
};
std::unordered_map<std::string, elementary_gate*> gates::gate_list;
gate* load_elementary_gate(const std::string& filename)
{
std::ifstream file(filename);
std::string gate_name = filename.substr(0, filename.find('.'));
int input_count;
file >> input_count;
std::unordered_map<std::string, int> inputs;
for (int i = 0; i < input_count; ++i)
{
std::string input_name;
file >> input_name;
inputs.insert(std::make_pair(input_name, i));
}
int output_count;
file >> output_count;
std::unordered_map<std::string, int> outputs;
for (int i = 0; i < output_count; ++i)
{
std::string output_name;
file >> output_name;
outputs.insert(std::make_pair(output_name, i));
}
int table_rows = 1 << input_count;
std::unordered_map<std::vector<bool>, std::vector<bool>> truth_table;
for (int i = 0; i < table_rows; ++i)
{
std::vector<bool> input_vector = get_vector_from_int(i, input_count);
std::vector<bool> output_vector(output_count);
for (int i = 0; i < output_count; ++i)
{
int val;
file >> val;
output_vector[i] = val;
}
truth_table.insert(std::make_pair(input_vector, output_vector));
}
elementary_gate* gate = new elementary_gate(truth_table, inputs, outputs);
gates::gate_list.insert(std::make_pair(gate_name, gate));
return gate;
}
gate* extract_gate_type(std::string& raw_gate)
{
std::string gate_name = raw_gate.substr(0, raw_gate.find('('));
raw_gate = raw_gate.substr(raw_gate.find('(') + 1, raw_gate.size() - raw_gate.find('(')- 2);
return gates::gate_list[gate_name];
}
std::vector<std::string> split_string(std::string str, char delim)
{
std::vector<std::string> split;
bool new_str = true;
for (char c : str)
{
if (new_str)
{
split.emplace_back("");
}
if (c == delim)
{
new_str = true;
}
else
{
if (c != ' ')
{
new_str = false;
split.back() += c;
}
}
}
return split;
}
gate* load_circuit(const std::string& filename)
{
std::ifstream file(filename);
std::string gate_name = filename.substr(0, filename.find('.'));
int input_count;
file >> input_count;
std::unordered_map<std::string, int> inputs;
for (int i = 0; i < input_count; ++i)
{
std::string input_name;
file >> input_name;
inputs.insert(std::make_pair(input_name, i));
}
int output_count;
file >> output_count;
std::unordered_map<std::string, int> outputs;
for (int i = 0; i < output_count; ++i)
{
std::string output_name;
file >> output_name;
outputs.insert(std::make_pair(output_name, i));
}
std::vector<gate*> gates;
std::vector<std::string> sub_gates_raw;
while (!file.eof())
{
std::string gate_str;
char c = ' ';
while (c != ')')
{
file >> c;
gate_str += c;
}
std::cout << gate_str.size() << std::endl;
if (gate_str.size() < 1)
{
continue;
}
gates.push_back(extract_gate_type(gate_str));
sub_gates_raw.push_back(gate_str);
}
std::vector<std::vector<std::string>> io_split;
for (std::string str : sub_gates_raw)
{
io_split.push_back(split_string(str, ','));
}
std::vector<std::vector<std::pair<std::string, std::string>>> gate_io_split;
for (std::vector<std::string> gate_strs : io_split)
{
std::vector<std::pair<std::string, std::string>> gate_strs_lr_split;
for (std::string io_str : gate_strs)
{
std::vector<std::string> gate_str_lr_split = split_string(io_str, '=');
gate_strs_lr_split.push_back(std::make_pair(gate_str_lr_split[0], gate_str_lr_split[1]));
}
gate_io_split.push_back(gate_strs_lr_split);
}
std::unordered_map<std::string, int> connection_list;
for (std::vector<std::pair<std::string, std::string>> gate_strs : gate_io_split)
{
for (std::pair<std::string, std::string> connection : gate_strs)
{
connection_list.insert(std::make_pair(connection.first, connection_list.size() - 1));
}
}
for (std::pair<std::string, int> input : inputs)
{
inputs.insert_or_assign(input.first, connection_list[input.first]);
}
for (std::pair<std::string, int> output : outputs)
{
outputs.insert_or_assign(output.first, connection_list[output.first]);
}
std::vector<std::vector<std::pair<int, int>>> gates_connection_indexes;
std::vector<std::vector<bool>> is_input;
for (int i = 0; i < gate_io_split.size(); ++i)
{
std::vector<std::pair<std::string, std::string>> gate_connection_indexes_str = gate_io_split[i];
std::vector<std::pair<int, int>> gate_connection_indexes;
std::vector<bool> gate_connections;
for (std::pair<std::string, std::string> gate_connection_index_str : gate_connection_indexes_str)
{
gate_connections.push_back(gates[i]->m_inputs.count(gate_connection_index_str.first));
std::pair<int, int> connnection_indexes = std::make_pair(connection_list[gate_connection_index_str.first], connection_list[gate_connection_index_str.second]);
gate_connection_indexes.push_back(connnection_indexes);
}
is_input.push_back(gate_connections);
gates_connection_indexes.push_back(gate_connection_indexes);
}
std::vector<gate_reference> gate_references;
for (int i = 0; i < gates_connection_indexes.size(); ++i)
{
}
return nullptr;
}
int main(void)
{
std::cout << "hello";
//load_elementary_gate("nand.gate");
//load_circuit("not.circuit");
//load_circuit("or.circuit");
return 0;
}
I'm new to C++. I was trying a leetcode question (436. Find Right Interval). Thought of complicating it by writing my own lower_bound just for my knowledge. But the below code is showing me runtime error: reference binding to null pointer of type 'value_type' (stl_vector.h). I'm unable to understand what's the issue, would someone please clarify what I'm doing wrong.
class Solution {
public:
vector<int> findRightInterval(vector<Interval>& intervals) {
int n = intervals.size();
vector<int> res;
vector<pair<Interval, int>> s_i;
for(int i = 0; i<n; i++) {
s_i.push_back(make_pair(intervals[i], i));
}
sort(s_i.begin(), s_i.end(), [](const pair<Interval, int>& a, const pair<Interval, int> &b) -> bool {
return a.first.start < b.first.start;
});
for(auto x : s_i) {
cout<<"["<<x.first.start<<","<<x.first.end<<"],"<<x.second<<endl;
}
for(int i = 0; i<n; i++) {
int val = intervals[i].end;
cout<<val<<endl;
//pair<Interval, int> temp = make_pair(Interval(val, val), 0);
auto it = lower_bound(s_i.begin(), s_i.end(), val,
[](const pair<Interval, int> &a, int val) -> bool {
return a.first.start < val;
});
if (it != s_i.end()) {
res[i] = it->second;
} else {
res[i] = -1;
}
}
return res;
}
};
I would like to dump the content inside the object tmp_np which is a UllmanSet which if you know a key then you know the position and if you know the position , you know the key. Is there a standard C++ container that's similar to the Ullmanset. Ullmanset 's index starts at 0 and Ullmanset1's index start at 1.
and also dump the content of frontierq which is a PriorityQ class.
UllmanSet tmp_np;
template<unsigned B>
class BasedUllmanSet
{
size_t n;
std::vector<int> key;
BasedVector<unsigned, B> pos;
public:
BasedUllmanSet()
: n(0)
{}
BasedUllmanSet(size_t cap)
: n(0), key(cap), pos(cap)
{}
size_t capacity() const { return key.size(); }
size_t size() const { return n; }
bool empty() const { return n == 0; }
void clear() { n = 0; }
void resize(size_t cap)
{
key.resize(cap);
pos.resize(cap);
n = 0;
}
bool contains(int k) const
{
unsigned p = pos[k];
return (p < n
&& key[p] == k);
}
void insert(int k)
{
if (contains(k))
return;
unsigned p = n++;
key[p] = k;
pos[k] = p;
}
void extend(int k)
{
assert(!contains(k));
unsigned p = n++;
key[p] = k;
pos[k] = p;
}
void erase(int k)
{
if (!contains(k))
return;
unsigned p = pos[k];
--n;
if (p != n)
{
int ell = key[n];
pos[ell] = p;
key[p] = ell;
}
}
int ith(int i)
{
assert(i >= 0 && i < (int)n);
return key[i];
}
};
using UllmanSet = BasedUllmanSet<0>;
using UllmanSet1 = BasedUllmanSet<1>;
The priority queue is implemented as followed. I like to print out the values inside the queue using std::cout.
PriorityQ<std::pair<int, int>, Comp> frontierq;
class Comp
{
public:
Comp() {}
bool operator()(const std::pair<int, int> &lhs,
const std::pair<int, int> &rhs) const
{
return (lhs.second > rhs.second
|| (lhs.second == rhs.second
&& lhs.first > rhs.first));
}
};
class PriorityQ
{
public:
Comp comp;
std::vector<T> v;
unsigned n;
public:
PriorityQ() : n(0) {}
PriorityQ(Comp comp_) : comp(comp_), n(0) {}
size_t size() const { return n; }
void clear() { n = 0; }
bool empty() { return n == 0; }
void push(const T &x)
{
assert(v.size() >= n);
if (v.size() == n)
v.push_back(x);
else
v[n] = x;
++n;
std::push_heap(&v[0], &v[n], comp);
}
const T &pop()
{
assert(n > 0);
std::pop_heap(&v[0], &v[n], comp);
--n;
return v[n];
}
const T &top()
{
assert(n > 0);
return v[0];
}
};
C++ standard containers do get this esoteric. If you have another question about the priority queue you should make another post.