Traverse through a linked list to find string - c++

I need to loop through a vector of linked list and check if a node with the string(s) exists. Obviously this only checks the beginning to see if it exists. I want to know how to go through the entire linked list.
vector <Dlist *> table; //Dlist is the linked list
int DL_Hash::Present(string &s) {
int index = djb_hash(s) % table.size();
for(int i = 0; i < table[index]->Size(); i++) {
if(table[index]->Begin()->s == s) {
return 1;
}
}
return 0;
}

You are not using variable i at all, and you indeed cant do something like table[index][i], as you cant index linked list. You only can get first element in list, and immediate next.
First you get pointer to the beginning (iterator would be more fitting). Then check every item for your condition, until you are at the end of list.
int DL_Hash::Present(string &s) {
int index = djb_hash(s) % table.size();
auto tmp = table[index]->Begin();
while (tmp != nullptr) { // check if you are at end of linked list
if (tmp->s == s)
return 1;
tmp = tmp.Next(); // asuming you have function to get next element in linked list.
}
return 0;
}
If Dlist would have iterators:
int DL_Hash::Present(string &s) {
int index = djb_hash(s) % table.size();
auto tmp = table[index]->begin();
while (tmp != table[index].end()) { // check if you are at end of linked list
if (tmp->s == s)
return 1;
tmp++;
}
return 0;
}
Or even better, using range for
int DL_Hash::Present(string &s) {
int index = djb_hash(s) % table.size();
for (auto &tmp : table[index]) {
if (tmp->s == s)
return 1;
}
return 0;
}

Related

a runtime error on my leetcode submission :heap use after free on address

#include <bits/stdc++.h>
using namespace std;
#include <unordered_set>
#include <queue>
struct word {
string s;
int level;
word(string a, int b)
: s(a)
, level(b)
{
}
};
bool isadj(string s1, string s2)
{
int len = s1.length(), count = 0;
for (int i = 0; i < len; i++) {
if (s1[i] != s2[i])
count++;
if (count > 1)
return false;
}
return count == 1 ? true : false;
}
int ladderLength(string beginWord, string endWord, vector<string>& wordList)
{
unordered_set<string> st;
for (string s : wordList)
st.insert(s); // adding elements into a set
if (st.find(endWord) == st.end())
return 0;
queue<word> q;
q.push(word(beginWord, 0)); // initialising the queue
while (!q.empty()) {
word temp = q.front(); // pop the current string
q.pop();
if (temp.s == endWord)
return temp.level;
for (auto it = st.begin(); it != st.end(); it++) { // loop over the set to find strings at a distance of 1 and add them to the queue
if (isadj(temp.s, *it)) // i have inserted code here to print the string *it
{
q.push(word(*it, temp.level + 1));
st.erase(*it); // delete the element to avoid looping
}
}
}
return 0;
}
int main()
{
// make dictionary
vector<string> D;
D.push_back("poon");
D.push_back("plee");
D.push_back("same");
D.push_back("poie");
D.push_back("plie");
D.push_back("poin");
D.push_back("plea");
string start = "toon";
string target = "plea";
cout << "Length of shortest chain is: "
<< ladderLength(start, target, D);
return 0;
}
The problem i am trying to solve is https://leetcode.com/problems/word-ladder/
I am unable to trace where I am using a memory that was deallocated again in my program?
The following are my attempts to debug :
I tried to run it on another online ide where the code compiles and runs successfully but gives a wrong answer . in order to debug it I have inserted some lines into my code in order to print all the strings which are at a distance of 1 for my current string. surprisingly an empty string is appearing to be in the set. Please help me in understanding where am I doing a mistake.
unordered_set::erase returns a value, and this returned value is important. You should not ignore it.
In your case, once you erase something from the set, it is invalid. Trying to increment it results in Undefined Behavior.
The correct approach is to replace the current iterator with the returned one, then not increment during the loop.
for (auto it = st.begin(); it != st.end(); )
if (...) {
// ...
it = st.erase(*it);
} else
++it;
After the line:
st.erase(*it); // delete the element to avoid looping
the it iterator is not valid and should not be used.
Your problem seems to be already addressed, but if you'd be interested, this'd also pass without using std::queue, only using std::unordered_set:
// The following block might slightly improve the execution time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(NULL);
std::cout.tie(NULL);
return 0;
}();
// Most of headers are already included;
// Can be removed;
#include <cstdint>
#include <string>
#include <vector>
#include <unordered_set>
#include <algorithm>
using ValueType = std::int_fast16_t;
static const struct Solution {
static const int ladderLength(
const std::string start,
const std::string end,
const std::vector<std::string>& words
) {
std::unordered_set<std::string> words_map(std::begin(words), std::end(words));
std::unordered_set<std::string> head;
std::unordered_set<std::string> tail;
std::unordered_set<std::string>* curr_head;
std::unordered_set<std::string>* curr_tail;
if (words_map.find(end) == std::end(words_map)) {
return 0;
}
head.insert(start);
tail.insert(end);
ValueType ladder = 2;
while (!head.empty() && !tail.empty()) {
if (head.size() < tail.size()) {
curr_head = &head;
curr_tail = &tail;
} else {
curr_head = &tail;
curr_tail = &head;
}
std::unordered_set<std::string> temp_word;
for (auto iter = curr_head->begin(); iter != curr_head->end(); iter++) {
std::string word = *iter;
for (ValueType index_i = 0; index_i < word.size(); index_i++) {
const char character = word[index_i];
for (ValueType index_j = 0; index_j < 26; index_j++) {
word[index_i] = 97 + index_j;
if (curr_tail->find(word) != curr_tail->end()) {
return ladder;
}
if (words_map.find(word) != std::end(words_map)) {
temp_word.insert(word);
words_map.erase(word);
}
}
word[index_i] = character;
}
}
ladder++;
curr_head->swap(temp_word);
}
return 0;
}
};
You might want to break it into more methods, a bit too long for a function.
References
For additional details, please see the Discussion Board where you can find plenty of well-explained accepted solutions with a variety of languages including low-complexity algorithms and asymptotic runtime/memory analysis1, 2.

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.

my function to sort a shared pointer list in c++ is not completing the sort

I have an STL std::list of 5 shared pointers that point to node objects needing to be sorted by their respective id numbers.
do
{
check = 0, i = 0;
auto it = newList.begin();
while (i < newList.size() - 1)
{
first = *it;
second = *++it;
if (comp_id(first, second))
{
temp = second;
second = first;
first = temp;
check = 1;
}
i++;
}
} while (check == 1);
In this code, the comp_id() returns true, and runs through the organization, but nothing is changing in the list while it happens. I was hoping to get some perspective as to why this is happening, and how to fix it.
P.S. I am not allowed to use the list_name.sort() method :(
The reason it doesn't work is because you are making modifications only to local variables (first and second) which are copies of values from the list. You are not modifying the actual content of the list at all.
To make the code work, simply change your first and second variables into list iterators, and then dereference them whenever you want to access their values, eg:
auto size = newList.size();
if (size > 1)
{
--size;
do
{
check = 0, i = 0;
auto it = newList.begin();
while (i < size)
{
auto first = it;
auto second = ++it;
if (comp_id(*first, *second))
{
auto temp = *second;
*second = *first;
*first = temp;
check = 1;
}
++i;
}
}
while (check == 1);
}
For that matter, i can be replaced with an iterator, as well:
if (newList.size() > 1)
{
auto begin = newList.begin();
auto end = newList.end()-1;
do
{
check = 0;
auto it = begin;
while (it != end)
{
auto first = it;
auto second = ++it;
if (comp_id(*first, *second))
{
auto temp = *second;
*second = *first;
*first = temp;
check = 1;
}
}
}
while (check == 1);
}

How to replace std::vector by linked list?

I have used std::vector for making my algorithm. I would like to replace the vectors by linked lists.
In order to do so, I was thinking of using the std::list, but I have no idea how to do this, for example I have tried following example for finding a value within a vector/list:
void find_values_in_vector(const std::vector<int>& input_vector, int value, int &rv1, int &rv2)
{
if (input_vector[0] >= value) { // too small
rv1 = 0; rv2 = 0; return;
}
int index = (int)input_vector.size() - 1;
if (input_vector[index] <= value) { // too big
rv1 = index; rv2 = index; return;
}
// somewhere inside
index = 0;
while (input_vector[index] <= value) {
index++;
}
rv1 = index - 1; rv2 = index; return;
}
void find_values_in_list(const std::list<int>& input_list, int value, int &rv1, int &rv2)
{
if (*input_list.begin() >= value) { // too small
rv1 = 0; rv2 = 0; return;
}
if (*input_list.end() <= value) { // too big
rv1 = (int)input_list.size() - 1; rv2 = (int)input_list.size() - 1; return;
}
// somewhere inside
int index = 0; int temp = *input_list.begin();
while (temp <= value) {
temp = *input_list.next(); index++;
}
rv1 = index - 1; rv2 = index; return;
}
This seems not to work, as the member function next() is not existing. However I remember that browsing through a linked list is done by going to the beginning, and moving further to the next element until the a certain point is reached. I have seen that there is a way to get this done by using an interator in a for-loop, but I wonder what's wrong with my approach? I was under the impression that a std::list was a standard implementation of a double-directional linked list, or am I wrong and in that case, what std class is the implementation of a linked list (it does not need to be a double-directional linked list)?
The standard way to iterate through containers is like this:
for(std::list<int>::iterator it = input_list.begin();
it != input_list.end();
it++)
{
....
}
This also works for vectors,maps,deque,etc. The Iterator concept is consistently implemented throughout the STL so it's best to get used to this concepts.
There are also iterator operations like std::distance and std::advance etc. for the different types of iterators (I suggest you read up on them and their advantages/limitations)
If you have C++ 11 available you can also use this syntax (may not be useful for your problem though.)
for(const auto& value : input_list)
{
...
}
This also works throughout the STL container.
This should work for vector, list, deque, and set (assuming the contents are sorted).
template <class T>
void find_values_in_container(const T& container, int value, int &rv1, int &rv2)
{
rv1 = rv2 = 0; // Initialize
if (container.empty() || container.front() >= value)
{
return;
}
for (const auto& v : container)
{
rv2++;
if (v > value)
{
break;
}
rv1++;
}
return;
}

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.