Inline function always returns the same value - c++

I am trying to implement my own priority queue that does the same thing as the standard priority queue from STL. The elements from queue have to respect an order, and for this I used a compare function. For this case the elements from queue are sorted ascending by their frequency and the compare function returns the difference between 2 elements' frequency. If the difference is less than 0, we found the place where the element should be inserted, otherwise the iteration continues.
My struggle is that the compare function always returns the value 0 regardless of difference between frequences (eg if one element has frequency equals to 2 and other has it equals to 3, their difference if -1, but relation function will return 0).
Here is the source code:
#pragma once
#include"BinaryTree.h"
typedef int(*TRelation)(const BinaryTree& bt1, const BinaryTree& bt2);
inline int getPriority(const BinaryTree& bt1, const BinaryTree& bt2) {
return bt1.getFrequence() - bt2.getFrequence();
}
class PriorityQueue {
TRelation relation;
BinaryTree* first;
public:
PriorityQueue() {
relation = getPriority;
first = nullptr;
}
void add(BinaryTree* e) {
if (first == nullptr) {
first = e;
return;
}
//add at start
if (relation(*e, *first)<0)
{
BinaryTree *aux= first;
first = e;
e->next = aux;
return;
}
BinaryTree *pre=first ;
BinaryTree *current = first;
while (current!=nullptr && relation(*e, *current)>=0) {
pre = current;
current = current->next;
}
pre->next = e;
e->next = current;
}
I also tried different implementation of getPriority() function like changing its returning type, elements' type, etc.

Related

Iterator stops pointing to a value when it is added to a struct which is added to a vector of lists?

The premise of the project I am doing is to make skip lists with iterators and not pointers. I have created a vector of lists of nodes. And in the node struct, it contains an iterator which is supposed to be the iterator of the list below it while preserving position. The problem is when I create a new node, set its below iterator to the list below's iterator, and later try to access it by de referencing it, it seg faults. I think this is because the iterator is not initialized and it cant be dereferenced as it does not appear to be a bounds issue.
struct Node // in header file
{
int value;
list<Node>::iterator below;
Node(int v, list<Node>::iterator b){
value = v;
below = b;
}
Node(){}
Node(int v){
value = v;
}
};
vector<list<Node>> skipList; //this is the skipList initialized in the header
//insert called to add numbers to skiplist
void SkipLists::insert(int num){
list<Node>::iterator loc;
if(skipList.empty()){
list<Node> nodes;
nodes.push_back(Node(num));
skipList.push_back(nodes);
}else{
loc = insertPlace(num, skipList[skipList.size()-1].begin(), skipList.size() -1);
skipList[0].insert(loc, Node(num));
}
cout << "1. " << *this << "\n\n\n";
stack(num, loc);
//this if statement also segfaults
if(skipList.size() > 1){
cout << (*(skipList[1].front().below)).value;
}
}
//in insertPlace function it segfaults on the while loop's only if a recursive call is made. Meaning the previous value added to the skiplist had height to it. It segfaults when dereferencing it. I tested this by moving it out of the while loop.
list<Node>::iterator SkipLists::insertPlace(int num, list<Node>::iterator it, int height){
if(height == 0){
while(it != skipList[0].end() && skipList[0].size() > 0 && num > (*it).value){ // problem: likely not returning a good (*it).below or never setting it properly.
it++;
}
return it;
}
while(it != skipList[height].end() && skipList[height].size() > 0 && num > (*it).value){
cout << "he\n";
it++;
cout << "lo\n";
}
return insertPlace(num, (*it).below, --height);
}
stack is used to add vertical elements in the skip list based on probability. This is where the nodes are given a "below" iterator.
void SkipLists::stack(int num, list<Node>::iterator loc){
int flip = rand() % 2;
int count = 1;
list<Node>::iterator prev = loc;
list<Node>::iterator it;
while(flip == 1){
count++;
flip = rand() % 2;
if(skipList.size() < count){
list<Node> nodes;
nodes.push_back(Node(num, prev));
skipList.push_back(nodes);
prev = skipList[skipList.size()-1].begin();
}else{
it = skipList[count-1].begin();
while(it != skipList[count -1].end() && num > (*it).value){
it++;
}
prev = skipList[count -1].insert(it,Node(num, prev));
}
}
}
vector<list<Node>> skipList; is dangerous. If a new list is added then the vector might relocate all other lists and that invalidates all stored iterators. Even though the lists can be move constructed in a new place, they are still new objects and comparing .end() with a iterator obtained from another object is undefined behaviour.
I think that is what eventually happens in your code.
[Probably not a proper answer, but its too long for a comment and I won't debug author's code to make sure.]
One obvious error is your Node class implementation.
If you look at your Node constructor that takes a single int, you failed to initialize the below iterator. Thus any access in attempting to dereference below will result in undefined behavior occurring, as you're doing in this line:
cout << (*(skipList[1].front().below)).value;
If the skip list is empty, you will see that your code will produce Node objects where below is not initialized.
Here is a stripped down, simple example using more or less the code you posted:
#include <list>
#include <vector>
#include <iostream>
struct Node // in header file
{
int value;
std::list<Node>::iterator below;
Node(int v, std::list<Node>::iterator b) {
value = v;
below = b;
}
Node() {}
Node(int v) {
value = v;
}
};
class SkipLists
{
private:
std::vector<std::list<Node>> skipList;
public:
void insert(int num);
std::list<Node>::iterator insertPlace(int num, std::list<Node>::iterator it, int height);
void stack(int num, std::list<Node>::iterator loc);
};
using namespace std;
void SkipLists::insert(int num)
{
list<Node>::iterator loc;
if (skipList.empty())
{
list<Node> nodes;
nodes.push_back(Node(num));
skipList.push_back(nodes);
}
else
{
loc = insertPlace(num, skipList[skipList.size() - 1].begin(), skipList.size() - 1);
skipList[0].insert(loc, Node(num));
}
stack(num, loc);
//this if statement also segfaults
if (skipList.size() > 1) {
cout << (*(skipList[1].front().below)).value;
}
}
list<Node>::iterator SkipLists::insertPlace(int num, list<Node>::iterator it, int height)
{
if (height == 0) {
while (it != skipList[0].end() && skipList[0].size() > 0 && num > (*it).value)
{
it++;
}
return it;
}
while (it != skipList[height].end() && skipList[height].size() > 0 && num > (*it).value)
{
cout << "he\n";
it++;
cout << "lo\n";
}
return insertPlace(num, (*it).below, --height);
}
void SkipLists::stack(int num, list<Node>::iterator loc) {
int flip = rand() % 2;
int count = 1;
list<Node>::iterator prev = loc;
list<Node>::iterator it;
while (flip == 1) {
count++;
flip = rand() % 2;
if (skipList.size() < count) {
list<Node> nodes;
nodes.push_back(Node(num, prev));
skipList.push_back(nodes);
prev = skipList[skipList.size() - 1].begin();
}
else {
it = skipList[count - 1].begin();
while (it != skipList[count - 1].end() && num > (*it).value) {
it++;
}
prev = skipList[count - 1].insert(it, Node(num, prev));
}
}
}
// Test
int main()
{
SkipLists s;
s.insert(4);
}
You will see that below is not initialized on the line you are saying your application crashes on when running this very small sample.
You also have the same issue with the Node default constructor where both the value and below members are not initialized. When you create an object, all the members should be in some sort of valid state, or "null" in some way. For iterators, it is harder to do this since there isn't a "null" iterator, unless you can set the iterator to an existing list's end() iterator.
Basically you need to design your class so that you are sure that the iterator is pointing somewhere valid, or some other means of indicating that the iterator should not be dereferenced.

Comparing stack data structure c++

I have the following program.What is the best , and most efficient way to check if the two stacks are equal by the values they contain?
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
struct StackNode
{
int data;
StackNode* next;
};
StackNode* newNode(int data)
{
StackNode* stackNode = new StackNode[sizeof(StackNode)];
stackNode->data = data;
stackNode->next = NULL;
return stackNode;
}
int isEmpty( StackNode *root)
{
return !root;
}
void push( StackNode** root, int data)
{
StackNode* stackNode = newNode(data);
stackNode->next = *root;
*root = stackNode;
}
int pop( StackNode** root)
{
if (isEmpty(*root))
return INT_MIN;
StackNode* temp = *root;
*root = (*root)->next;
int popped = temp->data;
free(temp);
return popped;
}
int peek(StackNode* root)
{
if (isEmpty(root))
return INT_MIN;
return root->data;
}
bool AreEqual(StackNode** lhs, StackNode** rhs)
{
////// ?
}
int main()
{
StackNode* root = NULL;
StackNode * r2 = NULL;
push(&root, 10);
push(&root, 20);
push(&root, 30);
push(&r2, 123);
push(&r2, 1231213);
AreEqual(&root, &r2);
}
if the stacks contains equivalent numbers but in different order , then the method should return true .. I would be very thankful if you could give me some directions for that task.Thanks in advice.
Considering
if the stacks contains equivalent numbers but in different order , then the method should return true
I think the optimal solution would be via sort and compare.
Extract the data from each stack
k1 = {data of lhs} -> O(n)
k2 = {data of rhs} -> O(n)
Sort the two arrays
k1_sorted = sort(k1) -> O(n log(n))
k2_sorted = sort(k2) -> O(n log(n))
Now you can compare the two sorted arrays in O(n). Keep in mind the possible repeated numbers in k1_sorted and k2_sorted.
As well as the sort method, you could take a counting approach:
#include <string>
#include <iostream>
#include <vector>
#include <map>
/**
* Returns true iff the two vectors contain the same elements
* (including number of duplicates) in any order.
*
* Alternatively std::sort both vectors and just compare them
* for equality, which may or may not be faster.
*/
bool sortOfEquivalent(const std::vector<int>& lhs, const std::vector<int>& rhs)
{
std::map<int, std::pair<int,int>> accumulator;
for (const auto x : lhs) {
accumulator[x].first++;
}
for (const auto x : rhs) {
accumulator[x].second++;
if (accumulator[x].second > accumulator[x].first) {
// Can bail early here; the RHS already has
// more x's than the LHS does
return false;
}
}
for (const auto& y : accumulator) {
if (y.second.first != y.second.second)
return false;
}
return true;
}
int main()
{
std::vector<int> lhs{3,5,5,7,1};
std::vector<int> rhs{1,2,3,4,5,6,7};
std::cout << sortOfEquivalent(lhs, rhs);
}
Depending on your data, this may or may not be faster than the sorting method. It also may or may not take less storage than the sorting method.
Also in reality you'd probably take a reference to accumulator[x] in that second loop rather than looking up the element three times.
However, you can only apply this solution to your situation if you treat your stack as not-a-stack, i.e. using its underlying data store (forward iteration is required). This may or may not be permitted.
On the outside your functions handle a stack, but the actual structure you implement the stack in is a simple linked list.
And comparing two linked lists is done by comparing each element one by one, stopping when either list runs out or you find a difference in the elements.

the sequence of insert and erase using stl::list

When I am doing practice on leetcode, I met a problem like this:
I used a stl::list container as cache for LRU algorithm. But the sequence of erasing an item and inserting an item made the result different.
I know that it is actually a double list as stl::list. And the sequence of inserting and erasing should not matter when I use iterator.
The code is here
class LRUCache{
public:
map<int, list<pair<int,int>>::iterator> mKey;
list<pair<int,int>> lCache;
int cap;
LRUCache(int capacity) {
cap = capacity;
}
int get(int key) {
auto iter = mKey.find(key);
if(iter != mKey.end()) {
int value = (iter->second)->second;
//**the sequence of next two lines can not be changed!***
lCache.erase(iter->second);
mKey[key] = lCache.insert(lCache.begin(), make_pair(key,value));
return value;
}
return -1;
}
void set(int key, int value) {
auto iter = mKey.find(key);
if(iter == mKey.end()) {
if(lCache.size() < cap) {
mKey[key] = lCache.insert(lCache.begin(), make_pair(key,value));
}
else{
mKey[key] = lCache.insert(lCache.begin(), make_pair(key,value));
mKey.erase(lCache.back().first);
lCache.pop_back();
}
}
else {
lCache.erase(iter->second);
mKey[key] = lCache.insert(lCache.begin(), make_pair(key,value));
}
}
};
It's not quite clear what you are asking. If your question is why these two lines can't be reordered:
//**the sequence of next two lines can not be changed!***
lCache.erase(iter->second);
mKey[key] = lCache.insert(lCache.begin(), make_pair(key,value));
then that's simple. iter points to the same node as mKey[key], so the assignment actually changes the value of iter->second. If the assignment would happen first, then iter->second would point to the freshly inserted list node, not the previously existing one.

vector sort - c++

I have a vector that that stores Node*. A Node has the member properties:row,col,value. In my vector, I have gotten it to where all the Nodes* within the same row but not necessarily in correct column order. So basically I want to sort it so it's truly in row-major form. Right now, the columns are out of order within each "row". I appreciate any help you could give!
Edit:
Here is the method I have that is sorting my vector by row. Is there a way to additionally sort the columns as well?
vector<Node*> vect;
int i,j,minIndex;
Node* temp = new Node(NULL,NULL,0,0,0);
for(i=0;i<vect.size()-1;i++)
{
minIndex = i;
for(j=i+1;j<vect.size();j++)
{
if(vect.at(j)->row<vect.at(minIndex)->row)
{
minIndex = j;
}
}
if(minIndex!=i)
{
temp = vect.at(i);
vect.at(i) = vect.at(minIndex);
vect.at(minIndex) = temp;
}
}
You don't really need to implement your own sorting algorithm here. You can just use the standard template library's sort() method and then override default the behavior for sorting your Node* vector.
// This returns true if Node* a should be considered "less than" Node* b.
struct less_node : binary_function <Node*,Node*,bool>
{
bool operator() (const Node*& a, const Node*& b) const
{
// sort by row first
if (a->row < b->row)
return true;
// then sort by col within each row
if (a->row == b->row && a->col < b->col)
return true;
return false;
}
};
Once you have this less_node structure defined, you would just call:
sort(vect.begin(), vect.end(), less_node());

list stays empty even after inserting an element C++

I am trying to insert pointers into a list but every time I try to print the list, or check whats in the list it says its empty. This means that my insertion is incorrect, but I don't understand why, my following classes are:
namespace {
template <typename T>
pair < node<T>*, bool> addElement (const T& elem, btree<T>* bt) {
class list < node<T>* >::iterator itr = bt->level().begin();
if (bt->level().empty()) {
node <T>*n = new node<T>(elem, bt->max());
cout << n->getItem() << endl;
bt->addElem(itr, n);
return make_pair(n, true);
}
for (; itr != bt->level().end(); ++itr) {
if (elem < (*itr)->getItem()) {
node <T>* n = new node<T> (elem, bt->max());
(*itr)->previous()->addNext(n);
n->addPrev((*itr)->previous());
n->addNext(*itr);
(*itr)->addPrev(n);
bt->addElem(itr, n);
return make_pair(n, true);
} else if (elem == (*itr)->getItem()) return make_pair(*itr, false);
}
// other stuff + return statement
}
addElem does the following:
void addElem (std::_List_iterator<node<T>*>& itr, node <T>* n) {
neighbours.insert(itr, n);
if (neighbours.empty()) cout << "wa?";
}
where btree class consists of:
size_t maxNodeElems;
list < node<T>*> neighbours;
the other things like addPrev() and previous() are just getters and setters. Anyways, I ran a test file on it that pretty much constructs a btree, and calls an insert function which directly calls this addElement function. But whenever I try to print the list inside the btree, it says its empty and seg faults. I don't understand why it's not storing.
Any help would be appreciated!
NOTE: the "Wa?" keeps printing
It seems you are trying to keep a sorted list, that's why you have:
// find the place to insert elem
for (; itr != bt->level().end(); ++itr) {
if (elem < (*itr)->getItem()) {
// insert...
}
}
But if the list is empty (initial state), itr will be probably equal bt->level().end() in the first place, so you will never insert anything...
You also should consider the case when you are trying to insert element for which (elem < (*itr)->getItem()) is always false (the new greatest element in the list). You need to handle that case as well.