Synchronizing MapB to MapA in C++ - c++

I have a std::map that I generate from a json and a map that I generate from sqlite.
I want to compare the two maps and make changes to the sqlite so that it matches the json. I originally used the map.find(key) method through both maps to figure out what to add and what to delete but my friend told me that map was sorted from least to greatest key and so I could just run through it once.
I came up with two methods. Do you have any advice on which algorithm would be preferred and why? I am thinking the one I have uncommented is faster as (and please correct me if I'm wrong) I believe the uncommented one is O(n) worst case while the latter is O(n^2) worst case.
Also, my friend had mentioned that I didn't need the second 'clean up' while loop to reconcile the remaining sqlMap items, but I really think I need it. Is he right?
Here's my code:
void SqlSync::syncEvents() {
int added = 0;
int replaced = 0;
int deleted = 0;
int skipped = 0;
// get categories from Apsiva
std::map<int, Event> jsonMap = _apsivaRest->getEvents();
// get categories from sqlite
std::map<int, Event> sqlMap = _sqliteConnection->getEventMap(true);
// COMPARE
map<int, Event>::iterator jsonIter = jsonMap.begin();
map<int, Event>::iterator sqlIter = sqlMap.begin();
while (jsonIter != jsonMap.end() && sqlIter != sqlMap.end()) {
int jsonId = jsonIter->first;
Event jsonObj = jsonIter->second;
int sqlId = sqlIter->first;
if (jsonId < sqlId) {
// add
_sqliteConnection->addEvent(jsonObj);
++added;
++jsonIter;
} else if (jsonId > sqlId) {
// remove
_sqliteConnection->deleteEvent(sqlId);
++deleted;
++sqlIter;
} else {
if (jsonObj.isNewerThan(sqlIter->second)) {
_sqliteConnection->updateEvent(jsonObj);
++replaced;
} else {
// ignore
cout << "Skipped event b/c not newer" << endl; // delete when verified
++skipped;
}
++jsonIter;
++sqlIter;
}
}
// int jRemaining = std::distance(jsonIter, jsonMap.end());
// int sRemaining = std::distance(sqlIter, sqlMap.end());
// add remaining jsonMap Objects
while (jsonIter != jsonMap.end()) {
Event jsonObj = jsonIter->second;
_sqliteConnection->addEvent(jsonIter->second);
++added;
++jsonIter;
}
// delete remaining sqlMap Objects
while (sqlIter != sqlMap.end()) {
_sqliteConnection->deleteEvent(sqlIter->first);
++deleted;
++sqlIter;
}
// OLD WAY TO COMPARE.
// // add/replace keys found in json
// for (map<int, Event>::const_iterator jsonIter = jsonMap.begin(); jsonIter != jsonMap.end(); ++jsonIter) {
// map<int,Event>::const_iterator it = sqlMap.find(jsonIter->first);
// Event jsonObj = jsonIter->second;
// if (it != sqlMap.end()) {
// Event sqlObj = it->second;
// if (jsonObj.isNewerThan(sqlObj)) {
//// _sqliteConnection->updateEvent(jsonObj);
// ++replaced;
// } else {
// // ignore
// cout << "Skipped category b/c not newer" << endl; // delete when verified
// ++skipped;
// }
// } else {
//// _sqliteConnection->addEvent(jsonObj);
// ++added;
// }
// }
//
// // delete sqlmap CategoryRows not in jsonMap
// for (map<int, Event>::const_iterator sqlObj = sqlMap.begin(); sqlObj != sqlMap.end(); ++sqlObj) {
// if (jsonMap.find(sqlObj->first) == jsonMap.end()) {
//// _sqliteConnection->deleteEvent(sqlObj->first);
// ++deleted;
// }
// }
#ifdef DEBUG
cout << "CATEGORIES SYNC:" << endl;
cout << "---------------" << endl;
cout << "Added: " << added << " | Replaced: " << replaced
<< " | Deleted: " << deleted << " | Skipped: " << skipped << endl;
#endif //DEBUG
}

The uncommented way is more efficient. The complexity will be O(n+m) when n and m are sizes of json and SQLite maps.
You will need the last loop, since when you exit the first loop you don't know which map end you reached first. Consider next case - json map has ids 1,2,4,5 and SQLite has ids 1,2,6,7.
You will need the last loop in order to delete items 6 and 7.

Related

if user enter 5 then display the last 5 elements of linked list vise versa

i am stuck in my uni assignment....
i have an linked list of 20 elements, i have to take the value from user and if user enter 5 then print the last 5 elements of linked list
void traverse(List list) {
Node *savedCurrentNode = list.currentNode;
list.currentNode = list.headNode;
for(int i = 1; list.next() == true; i++)
{
std::cout << "Element " << i << " " << list.get() << endl;
}
list.currentNode = savedCurrentNode;
}
im trying this but this method prints all the elements of my linked list
For what little code you have, a review:
// Why are you passing the list by value? That is wasteful.
void traverse(List list) {
// I don't see you taking a value anywhere; surely you know how to do that
// What is happening here? Can't you just assign the head to something
// directly?
Node *savedCurrentNode = list.currentNode;
list.currentNode = list.headNode;
// Like you said, this traverses the entire list, it's also poorly
// formed. You literally don't need i.
// for (; list.next(); /* However your list increments here */)
for(int i = 1; list.next() == true; i++)
{
std::cout << "Element " << i << " " << list.get() << endl;
}
// What is the purpose of this?
list.currentNode = savedCurrentNode;
}
For someone who is writing a linked list, this code seems to be fundamentally flawed. My expectation of someone tackling a linked list is that they are about to stop being a beginner, but I'm not seeing that here in the code and what structure of the list class is implied. The list class is weird to say the least.
And just to be clear, my expectation stems from where I place the linked list assignment in my curriculum. It's also more idiomatic than this list.
With that out of the way, this task is trivial if you took the time to think the project through. Most students skip the planning step and create unnecessary headaches for themselves.
Knowing that you would need the total size of the list, why not just make it member data? Any function that adds to the list will increment the value accordingly. And any function that subtracts from the list will decrement accordingly. That way you always know the size of the list at all times.
Knowing the size of the list is most of the battle. You then need to do the arithmetic necessary to advance in the list to satisfy your requirement. And now you can print.
#include <iostream>
class SList {
public:
SList() = default;
//
// Rule of 5 intentionally left out
//
void push_front(int val) {
m_head = new Node{val, m_head};
++m_size; // The magic happens here
}
std::size_t size() const { return m_size; }
void traverse_last(int numElements, std::ostream& sout = std::cout) const {
int placement = m_size;
Node* walker = m_head;
// Move our walker node the appropriate amount of steps
while (walker && placement > numElements) {
walker = walker->next;
--placement;
}
// Now that we're in position, we can print
while (walker) {
sout << walker->data << ' ';
walker = walker->next;
}
sout << '\n';
}
private:
struct Node {
int data;
Node* next = nullptr;
};
Node* m_head = nullptr;
std::size_t m_size = 0ULL;
};
int main() {
SList test;
for (int i = 5; i > 0; --i) {
test.push_front(i);
}
std::cout << "Size: " << test.size() << '\n';
for (int i = 1; i <= 5; ++i) {
test.traverse_last(i);
}
test.traverse_last(10);
}
Output:
❯ ./a.out
Size: 5
5
4 5
3 4 5
2 3 4 5
1 2 3 4 5
1 2 3 4 5
void traverse(List list, int printFrom)
{
Node *savedCurrentNode = list.currentNode;
list.currentNode = list.headNode;
for(int i=1; list.next(); i++)
{
if(i > printFrom)
{
cout << "Element " << (i - printFrom) << " " << list.get() << endl;
}
}
list.currentNode = savedCurrentNode;
}
solved my prblem by this there printFrom is a variable whose value is number of elemenets that skipped like if my linked list have size of 20 and user want to see last 5 then printFrom stores 15 and skipped 15 values and print last 5

I want to combine the list and find(), but I don't know how to merge them

Please see the part where the find() function is called. (I ran it in Visual Studio.)
Code:
using namespace std;
int main(void) {
//Implementing the find()
/*
bool Find(const Stu & a); {
return (*it).name;
}
*/
list<Astu>::iterator that;
//that = astu.begin();
//that = find(astu.begin(), astu.end(), (*it).name);
for (it = stu.begin(); it != stu.end(); it++) {
that = find_if(astu.begin(), astu.end(), (*it).name);
if (that != astu.end()) {
all = astu.erase(all);
all++;
}
else
all++;
}
/*
//Filter absenteeism from the total student roster
for (it = stu.begin(); it != stu.end(); it++) {
for (all = astu.begin(); all != astu.end();) {
if (!strcmp((*all).name, (*it).name)) {
//Delete attendees and latecomers from the list
all = astu.erase(all);
}
else
all++;
}
}
*/
cout << "---------------------\n결석자: " << endl;
//이름순으로 정렬
astu.sort(SizeComp2);
//결석자들 출력
for (all = astu.begin(); all != astu.end(); all++) {
cout << "이름: " << (*all).name << endl;
}
return 0;
}
Output:
C2064 error occurred: Term does not evaluate to a function that takes
1 argument.
Even with find_if() in this code, there is a problem. The bool() part in the comment was used for the find_if object, but it doesn't seem to be used well here.
I deleted the part where there was no problem as a result of debugging. You must use an unconditional list, not a vector.
Where should I fix it?
The third argument to std::find_if is a function.
You could use a lambda as the function:
auto that = find_if(astu.begin(), astu.end(), [it](Astu const& astu)
{
return astu.name == it->name;
});
[This assumes that Astu::name is a std::string]

QT scene->removeItem (* QgraphicsItem) removes the object from the scene but it is still observed

I am creating a simple game using QT c ++, I have an asteroid class and a Qvector of said class. Every 15 seconds an asteroid is created and added to the Qvector.
void MainWindow::generarAsteroides(){
srand(time(NULL));
int aleatorio=1+rand()%1000;
int a_w = 30+rand()%200;
v_asteroides.push_back(new asteroides(aleatorio,-1000,a_w,a_w,500));
mundo->addItem(v_asteroides.last());
std::cout << "Asteroide generado en X : "<< aleatorio << std::endl;
sonido->stop();
sonido->setMedia(QUrl("qrc:/multimedia/suspenso1.mp3"));
sonido->play();
}
when it exceeds a certain Y coordinate, I call a function through a Timer to traverse the vector and eliminate from the scene with
void MainWindow::actualizar(){
for(auto &ast : v_asteroides){
if(ast->destruir()){
mundo->removeItem(ast);
v_asteroides.erase(std::remove(v_asteroides.begin(),v_asteroides.end(),ast),v_asteroides.end());
sonido->stop();
sonido->setMedia(QUrl("qrc:/multimedia/explosion1.mp3"));
sonido->play();
//std::cout << "eliminado" <<std::endl;
}
}
//std::cout << "tamaño : " <<v_asteroides.size() << std::endl;
mundo->advance();
mundo->update();}
however the object that is supposed to be removed from the screen remains there (still) without disappearing.
The error is that : for (xx : vs_) and vs_.erase can not be used together.
You should use the iter returned by v_asteroides.erase(xxx) for the next loop.
use next code as suggested:
auto iter = vs_.begin();
for (; iter != vs_.end(); )
{
//if need erase
{
//other logic code
// mundo->removeItem(*iter);
iter = vs_.erase(iter); // at last row
}
// else
{
//++iter;
}
}

Incorrect count output / Having difficulty trying to create a HashTable/Set using open addressing

I'm trying to create a program that opens a .txt file containing a speech and assigns each word to a space in the array/set based on the hash value. Collisions are accounted for using open addressing method. The program should be able to perform the following functions: add(), remove(), find(), count() which keeps count of the elements IN the array/set, and loadfactor(). A template header.h file was provided that required some filling in, but my unfamiliarity with that style of coding was making it difficult for me to understand it. Below I have provided the code I have so far, and everything seems to be working except the mCount. The speech contains about 300 words but when I run the code, the count output shows 17. I'm assuming the error is in my resizing function but I am unsure.
//hashset.h file
#pragma once
#include <cmath>
#include <functional>
#include <vector>
template <typename TValue, typename TFunc>
class HashSet
{
private:
// Unlike Java, the C++ hashtable array won't be full of null references.
// It will be full of "Entry" objects, each of which tracks its current state
// as EMPTY, FULL (with a value), or NIL (value was once here, but was removed).
class Entry
{
public:
enum EntryState { EMPTY, FULL, NIL };
TValue value;
EntryState state;
Entry() : value(), state(EMPTY) {}
Entry(const TValue& v) : value(v), state(EMPTY) {}
};
TFunc mHash;
std::vector<Entry> mTable;
std::size_t mCount;
public:
// Constructs a hashtable with the given size, using the given function for
// computing h(k).
// hash must be a callable object (function, functor, etc.) that takes a parameter
// of type TValue and returns std::size_t (an integer).
HashSet(int size, TFunc hash) : mHash(hash)
{
// initialize count
mCount = 0;
// hashtable array cannot be same data type as that of what is being stored (cannot be string)
// requirement #4 - if user inputs array size that is not a power of 2, constructor must round to nearest power of 2 value
size = pow(2, (int(log(size - 1) / log(2)) | 1));
mTable.resize(size); // resizes the vector to have given size.
// Each element will be default-constructed to have state EMPTY.
}
void resize(int new_size) {
HashSet aux{ new_size, mHash }; //double the size, same hash function
for (const auto& entry : mTable)
if (entry.state == Entry::FULL && entry.state == Entry::EMPTY && entry.state == Entry::NIL) //there is an element
aux.add(entry.value); //insert it on the new set
*this = aux;
}
// Inserts the given value into the set.
void add(const TValue& value)
{
// Use the type std::size_t for working with hash table indices.
// Invoke the mHash function, passing the key to calculate h(k), as in
// size_t hashCode = mHash(value);
// Mod down to size.
// Go to the table at that index and do the insertion routine.
// Note, if table is full when trying to add an element, it should double in size
// to keep table size a power of 2
if (double(mCount) / mTable.size() > 0.8) // load factor comparison
this->resize(2 * mTable.size()); // call resize function if array is too small to accommodate addition
size_t hashCode = mHash(value) % mTable.size(); // mod value by table size to get starting index
if (mTable[hashCode].state == Entry::EMPTY || mTable[hashCode].state == Entry::NIL) { // NIL space CAN be replaced with value
mTable[hashCode].value = value; // store value in vector index specified by hashCode
mCount++; // increment counter when word is added
}
else {
for (std::size_t i = 1; i < mTable.size(); i++) {
// use open addressing to find next open space
if (mTable[hashCode].state != Entry::EMPTY) {
hashCode = ((mHash(value) % mTable.size()) + ((int)(pow(i, 2) + i) >> 1)) % mTable.size(); // h(k) + f(i) or h(k) + ((i^2 + i)) / 2
}
else if (mTable[hashCode].value == value) { // account for duplicates
break; // exit for-loop
}
else if (mTable[hashCode].state == Entry::EMPTY || mTable[hashCode].state == Entry::NIL) { // NIL space CAN be replaced with value
mTable[hashCode].value = value; // store value in vector index specified by new hashCode
mCount++; // increment counter when word is added
break; // exit for-loop
}
else
break; // exit for-loop
}
}
}
// Returns true if the given value is present in the set.
bool find(const TValue& key)
{
size_t hashCode = mHash(key) % mTable.size(); // mod value by table size to get starting index to do retrace
if (mTable[hashCode].value == key)
return true;
else if (mTable[hashCode].state != Entry::EMPTY || mTable[hashCode].state == Entry::NIL) { // check that set is not empty or has a NIL state
for (std::size_t i = 1; i < mTable.size(); i++) {
// use open addressing again to find key
if (mTable[hashCode].value != key)
hashCode = ((mHash(key) % mTable.size()) + ((int)(pow(i, 2) + i) >> 1)) % mTable.size();
else if (mTable[hashCode].value == key) {
return true; // value found at speecified location
break; // exit for-loop as first instance of value has been found
}
//else if (i == mTable.size()) // end of table reached, element not in set
//return false;
}
}
else // end of table reached, element was not in set
return false;
}
// Removes the given value from the set.
void remove(const TValue& key)
{
size_t hashCode = mHash(key) % mTable.size(); // mod value by table size to get starting index to do retrace
if (mTable[hashCode].value == key) {
mTable[hashCode].value = Entry::NIL; // replace value with NIL so find() op does not return a false when searching for element
mCount--; // decrement element counter
}
else if (mTable[hashCode].state != Entry::EMPTY || mTable[hashCode].state != Entry::NIL) { // check that there is a value to be removed
for (std::size_t i = 1; i < mTable.size(); i++) {
// use open addressing again to find key
if (mTable[hashCode].value != key) {
hashCode = ((mHash(key) % mTable.size()) + ((int)(pow(i, 2) + i) >> 1)) % mTable.size();
}
else {
mTable[hashCode].value = Entry::NIL; // if found after open addressing, replace with NIL
mCount--; // decrement element counter
}
}
}
}
int count() {
return mCount;
}
double loadFactor() {
double a = double(mCount) / mTable.size();
return a;
}
};
// main function
#include "hashset.h"
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
string testline;
vector<string> word;
HashSet<std::string, std::hash<std::string> > obj1{ 50, std::hash<std::string>{} };
ifstream Test("speech.txt");
if (!Test)
{
cout << "There was an error opening the file.\n";
return 0;
}
//store words in vector
while (Test >> testline) {
word.push_back(testline);
//obj1.add(testline);
}
//output whole vector with position numbers for each entry
cout << "Array contents:\n";
for (int i = 0; i < word.size(); i++) {
obj1.add(word[i]);
cout << word[i] << "(" << i << ")" << endl;
}
cout << "current count: " << obj1.count() << endl;
obj1.add("abcd"); // should hash to 4
if (obj1.find("abcd"))
cout << "abcd is in the set " << endl;
else
cout << "abcd is not in set " << endl;
obj1.add("adcb"); // should hash to 4 then 5 after probing
if (obj1.find("adcb"))
cout << "adcb is in the set " << endl;
else
cout << "adcb is not in set " << endl;
obj1.add("acde"); // should hash to 4 then 7 after probing
if (obj1.find("acde"))
cout << "acde is in the set " << endl;
else
cout << "acde is not in set " << endl;
obj1.remove("adcb"); // 5 should have NIL
if (obj1.find("adcb"))
cout << "adcb is in the set " << endl;
else
cout << "adcb is not in set " << endl;
if (obj1.find("acde"))
cout << "acde is still in the set " << endl;
else
cout << "acde is not in set " << endl;
cout << "final count: " << obj1.count() << endl;
system("pause");
exit(0);
}
}
The errors around NIL are because the enum defining NIL is part of the Entry class. You need to prefix NIL with the class name so the compile knows where the keyword comes from.
else if (mTable[hashCode] != NULL || mTable == Entry::NIL) { // getting error NIL identifier not found
The HashSet variable declaration is complaining because you are passing the wrong types. HashSet constructor takes a size and and a hash function. You are passing it a size and a string. Note the comment above the HashSet constructor
// hash must be a callable object (function, functor, etc.) that takes a parameter
// of type TValue and returns std::size_t (an integer).
This is your clue how to construct a HashSet object.

Solving 8-Puzzle in C++ with A* results in endless loop

I'm currently trying to solve the 8-Puzzle with the A* search algorithm, but my program gets stuck in an endless loop.
My main searching loop is:
std::vector<Field> Search::AStar(Field &start, Field &goal){
std::cout << "Calculating..." << std::endl;
std::unordered_map<Field, Field> explored;
std::vector<Field> searched;
if (Puzzle::finished(start))
return MakePath(start, start);
std::priority_queue<Field, std::vector<Field>, std::greater<Field>> frontier;
frontier.push(start);
Field current;
Field child;
size_t i = 0;
while (!frontier.empty())
{
current = frontier.top();
frontier.pop();
if (++i > 500)
{
std::cout << "Iteration Error" << std::endl;
return searched;
}
searched.push_back(current);
for (Direction d : Puzzle::Actions(current))
{
child = Puzzle::Action(d, current);
if (Puzzle::finished(child))
{
std::cout << "Found goal!" << std::endl;
return MakePath(explored[child], start);
}
child.CostG = current.CostG + 1; // Make a step
if (!isIn(child, explored) || child.CostG < explored[child].CostG)
{
child.CostH = Puzzle::Heuristic(child, goal); // Calculate Heuristic
child.CostF = child.CostG + child.CostH; // Calculate final costs
frontier.push(child);
explored[child] = child;
explored[child].setParent(&explored[current]);
}
}
}
std::cout << "Error: frontier Empty" << std::endl;
return searched;
}
The vector "searched" is just so that I can see what A* does, and I will delete it as soon as the algorithm works.
The CostG stands for the number of steps done until this point, the CostH are the estimated minimum (heuristic) costs to the "goal" and the CostF are those two combined.
The index of the Field::Boxes vector is the number of the field, and every element contains the position.
My Heuristic function looks like this:
inline int Heuristic(Field &goal)
{
size_t d = 0;
for (size_t i = 0; i < Boxes.size(); i++)
{
d += (std::abs(static_cast<int>(Boxes[i].x) - static_cast<int>(goal.Boxes[i].x))
+ std::abs(static_cast<int>(Boxes[i].y) - static_cast<int>(goal.Boxes[i].y)));
}
return d;
}
For better readability and stuff, the code also is on Github. However, to execute it, you need SFML in your Visual Studio include direction.
Every help is appreciated!
Edit 1:
You now no longer need SFML to executed & debug the program! I commited the changes to github, the link is the same.
The problem is that although you remove the current node from your frontier, you never added it to the explored set, i.e. you never close it. The following code should work. My revisions closely follow Wikipedia's A* Pseudocode.
I also recommend you test your algorithm with the trivial heuristic (the one that returns zero for all values) on a simple puzzle to verify that your algorithm is implemented correctly. (See this answer for a brief explanation of this technique.)
while (!frontier.empty())
{
current = frontier.top();
frontier.pop();
if (++i > 500)
{
std::cout << "Iteration Error" << std::endl;
return searched;
}
// Check for goal here
if (Puzzle::finished(current)
{
std::cout << "Found goal!" << std::endl;
return MakePath(explored[current], start);
}
explored[current] = current; //close the current node
searched.push_back(current);
for (Direction d : Puzzle::Actions(current))
{
child = Puzzle::Action(d, current);
if (isIn(child,explored))
{
continue; //ignore the neighbor which is already evaluated
}
child.CostG = current.CostG + 1; // Make a step
if (!isIn(child, frontier)) //discovered a new node
{
frontier.push(child);
}
else if (child.CostG >= explored[child].CostG)
{
continue; //this is not a better path
{
//the path is best until now. Record it!
child.CostH = Puzzle::Heuristic(child, goal); // Calculate Heuristic
child.CostF = child.CostG + child.CostH; // Calculate final costs
//frontier.push(child); moved up to earlier point in code
explored[child] = child;
explored[child].setParent(&explored[current]);
}
}