I am trying to implement a selection sort algorithm that will work with linked lists and will use iterators to scrool through them. The selection sort algorithm is the following: for each element of the list except the last one(let's call it K), it will seek out the smallest on from the position we are currently on(so it will start from K until the last element). After that it will swap K and the smallest element.
I think that my mistake is in the first for loop; I am very unsure that --a.end() is the pre-last element. I get some output, though it is wrong.
#include <iostream>
#include <list>
using namespace std;
void sort_list(list<int>& a)
{
//from the first until the pre-last element
for(list<int> :: iterator itr = a.begin(); itr != (--a.end()); ++itr)
{
int smallest = *itr;
//get smallest element after current index
list<int> :: iterator itr2 =itr;
++itr2;
for(; itr2 != a.end(); ++itr2)
{
if (smallest > *itr2)
{
smallest = *itr2;
}
}
//swap smallest and current index
int tmp = *itr;
*itr = smallest;
smallest = tmp;
}
}
int main()
{
//create a list and some elements
list<int> listi;
listi.push_back(5);
listi.push_back(4);
listi.push_back(3);
listi.push_back(2);
listi.push_back(1);
// sort the list
sort_list(listi);
//print all of the elements
for(list<int> :: iterator itr = listi.begin(); itr != listi.end(); ++itr)
{
cout << *itr << endl;
}
return 0;
}
When you do itr2 = ++itr you also change the value of itr, so instead you should do something like
list<int> :: iterator itr2 = itr;
for(++itr2; itr2 != a.end(); ++itr2) {
...
}
Furthermore, you have to keep a pointer to the smallest element, if you want to swap it later, like this:
int* smallest = &(*itr);
This also requires some other changes, you can find a working example of your code here.
The problem is you spoil itr while initializing itr2.
Related
int removeDuplicates(vector<int>& nums) {
vector<int>::iterator iter = nums.begin();
vector<int>::iterator test = nums.begin(); //used to test
while (nums.begin() != nums.end())
{
vector<int>::iterator temp = iter;
vector<int>::iterator temp2 = ++iter;
if (temp2 == nums.end()) break;
if (*temp == *temp2)
{
iter = nums.erase(temp);
cout << *test << " "; //test here, error happen
}
}
return nums.size();
}
int main()
{
vector<int> test = { 1,1,2,2,4,5,6,6 };
int result = removeDuplicates(test);
}
error message: "vector iterator not dereferencable!"
I have seen some articles say "iterators before erase position keep valid, only iterators after erase position become invalid."
But as I try with above code, I found iterators before erase position also become invalid, I don't know why. Please help!
vector<int>::iterator iter = nums.begin();
vector<int>::iterator test = nums.begin();
vector<int>::iterator temp = iter;
temp, iter and test point to same element.
iter = nums.erase(temp);
That element is erased. This invalidates temp and test. iter however is reassigned to the next element.
cout << *test << " ";
The invalidated test is inderected. Behaviour is undefined.
This situation is reproduced whenever *temp == *temp2 is true in the first iteration. In later iterations iter and temp no longer point to the first element.
This should help you.
int removeDuplicates(std::vector<int>& nums)
{
for (auto iter = nums.begin(); iter != nums.end(); /* DO NOT INCREMENT */)
{
if (std::find(iter + 1, nums.end(), *iter) != nums.end())
{
iter = nums.erase(iter);
}
else
{
++iter;
}
}
return static_cast<int>(nums.size());
}
cppreference.com says the following about vector::erase:
Invalidates iterators and references at or after the point of the erase, including the end() iterator.
So in your example both test and temp are initialized with nums.begin(). When you erase temp, this invalidates temp. Consequently you need to make sure that temp gets re-initialized or you keep a copy of the erased element for later usage.
So how about changing you code like this:
int removeDuplicates(vector<int>& nums) {
vector<int>::iterator iter = nums.begin();
vector<int>::iterator test = nums.begin(); //used to test
while (nums.begin() != nums.end())
{
vector<int>::iterator temp = iter;
vector<int>::iterator temp2 = ++iter;
size_t dist = std::distance(nums.begin(), temp);
if (temp2 == nums.end()) break;
if (*temp == *temp2)
{
iter = nums.erase(temp);
test = nums.begin();
test += dist;
cout << *test << " "; //test here, error happen
}
}
return nums.size();
}
I am learning c++ and I am working my way double linked lists, but I noticed something very peculiar when I was trying to delete elements from my list.
Problem: I am inserting an element before the value of 2 in my list , numbers, and then I am trying to delete any element that has the value 1.
Expected: After I call erase() in my conditional statement in my first loop my list, numbers, should get adjusted. The only values that numbers should should contain 0,1234,2,3.
Observed: My list numbers contains the values 0,1,1234,2,3. It is as if nothing was erased.
Code Example:
#include "stdafx.h"
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<int> numbers;
numbers.push_back(1);
numbers.push_back(2);
numbers.push_back(3);
numbers.push_front(0);
list<int>::iterator it = numbers.begin();
it++;
numbers.insert(it, 100);
cout << "Element: " << *it << endl;
list<int>::iterator eraseIt = numbers.begin();
eraseIt++;
eraseIt = numbers.erase(eraseIt);
cout << "Element: " << *eraseIt << endl;
for (list<int>::iterator it = numbers.begin(); it != numbers.end(); it++)
{
if (*it == 2)
{
numbers.insert(it, 1234);
}
if (*it == 1)
{
it = numbers.erase(it);
}
else
{
it++;
}
}
for (list<int>::iterator it = numbers.begin(); it != numbers.end(); it++)
{
cout << *it << endl;
}
return 0;
}
I would greatly appreciate any assistance with this problem. Thank you for your time.
You should remove the it++ at the end of the for loop declaration, because it might be increased inside the for loop too; when it gets inscreased twice some elements will be skipped. i.e.
for (list<int>::iterator it = numbers.begin(); it != numbers.end(); )
LIVE
It's quite enough to remember the next iterator value before doing any deletion/insertion at the current position. This will help you to keep yourself careless about what and when are your modifications concretely doing.
list<int>::iterator it = numbers.begin();
while (it != numbers.end()) {
{
list<int>::iterator next_it = it;
++next_it;
// Do your insertion or deletion here
it = next_it;
}
Take this code:
std::list<int> intList;
for (int i = 0; i < 10; ++i) {
intList.push_back( 1 << i );
}
std::list<int>::const_iterator iterator;
for (iterator = intList.begin(); iterator != intList.end(); ++iterator) {
std::cout << *iterator;
}
I see how to iterate through a list. Looking at the iteration I think you skip the last item. Is this the case and if so what is the best way to solve it.
Actually, the last item is not skipped. The iterator pointing to intList.end()-1 points to the last item instead of intList.end() as you may be thinking.
I'm currently trying to delete 2 elements from a vector if some condition is met. I can successfully remove a single element without the "vector iterator not dereferencable" error occuring, I know the problem is been caused by removing two elements at once which messes up with the Iterators but am unsure as to the correct way of removing more than one element at once.
vector<SomeObj*> objs;
vector<SomeObj*>::iterator it = objs.begin();
while (it != objs.end())
{
vector<SomeObj*>::iterator it2 = objs.begin();
bool deleted = 0;
while (it2 != objs.end())
{
if ((*it)->somecondition(**it2))
{
delete *it2;
*it2 = NULL;
it = objs.erase(it2);
delete *it;
*it = NULL;
it = objs.erase(it); //Will error here due to invalidating the iterator
deleted = 1;
break;
}
++it2;
}
if (!deleted)
++it;
}
The problem is that the first call to erase() might very well invalidate the other iterator. See this post for a quick summary of what gets invalidated when in various containers. I'd say the simplest solution is to first traverse the container and mark the entries to be erased but do not erase them, and then in a second scan just erase everything that was marked. For performance reasons in this second scan you should either use std::remove_if or use reverse iterator.
Working with nested iterators is tricky if you are mutating the container.
I've put together some sample code that does what you are wanting. What I'm doing is delaying the removal by setting the elements to be removed to nullptr and then removing those as we encounter them in the loops.
#include <iostream>
#include <vector>
class Example
{
public:
Example(int size) : size(size) {}
bool somecondition(const Example& other) const
{
return size == other.size;
}
int size;
};
int main()
{
std::vector<Example*> vec;
vec.push_back(new Example(1));
vec.push_back(new Example(2));
vec.push_back(new Example(3));
vec.push_back(new Example(2));
for (auto it1 = vec.begin(); it1 != vec.end();)
{
if (!*it1)
{
it1 = vec.erase(it1);
continue;
}
for (auto it2 = vec.begin(); it2 != vec.end(); ++it2)
{
if (!*it2)
{
vec.erase(it2);
// we need to start the outer loop again since we've invalidated its iterator
it1 = vec.begin();
break;
}
if (it1 != it2 && (*it1)->somecondition(**it2))
{
delete *it1;
*it1 = nullptr;
delete *it2;
*it2 = nullptr;
break;
}
}
++it1;
}
for (auto example : vec)
{
std::cout << example->size << std::endl;
}
return 0;
}
I'm trying to create a list of prime numbers using a linked list.
My plan was to use two iterators to basically do the Sieve of Eratosthenes. I start one iterator and make that the current prime, which will start at 2. It goes into another iteration removing every multiple of that number, leaving no multiples of 2 and a prime number for the next increment, which in this case would be 3. It exits the 2nd loop and starts over with this new list with an increment by one. Once it finishes, the list should be only filled with prime numbers.
Here is my code:
#include <iostream>
#include <list>
using namespace std;
int main(){
int maxnum = 1001;
int prime;
list<int> mylist;
list<int>::iterator it1, it2;
for(int i=2; i<maxnum; ++i)
mylist.push_back(i);
it2 = mylist.begin();
for(it2; it2!=mylist.end(); ++it2){
prime = *it2;
it1 = it2;
for(it1; it1!=mylist.end(); ++it1){
if(*it1%prime == 0)
mylist.erase(it1);
}
}
for (it1 = mylist.begin(); it1!=mylist.end(); ++it1)
cout << " " << *it1;
}
I can't find any examples of a nested list being used like this, so I don't know if something is innately wrong with doing this with lists. I've been stuck on segmentation faults.
Thanks for any help.
EDIT: Ok, I figured out my problems. From now on I will always iterate with a while when using lists. Here is the working code.
#include <iostream>
#include <list>
using namespace std;
int main(){
int maxnum = 1001;
int prime;
list<int> mylist;
list<int>::iterator it1, it2;
for(int i=2; i<maxnum; ++i)
mylist.push_back(i);
it2 = mylist.begin();
while (it2!=mylist.end()){
prime = *it2;
it1 = it2;
++it1;
while (it1!=mylist.end()){
if(*it1%prime == 0)
it1 = mylist.erase(it1);
else
++it1;
}
++it2;
}
it1 = mylist.begin();
for (it1; it1!=mylist.end(); ++it1)
cout << " " << *it1;
}
for(it1; it1!=mylist.end(); ++it1){
if(*it1%prime == 0)
mylist.erase(it1);
replace it with
++it1; //otherwise you actually delete the number you are checking!!!
while (it1!=mylist.end())
if((*it1%prime)) // imho the better way of checking ;)
++it1;
else
it1 = mylist.erase(it1); //erase returns the next iterator
std::list<T>::erase() returns an iterator to the next item following the item being erased:
it1 = it2;
while (it1!=mylist.end()){
if(*it1%prime == 0)
it1 = mylist.erase(it1);
else
++it1;
}
The problem lies in this code:
for(it1; it1!=mylist.end(); ++it1){
if(*it1%prime == 0)
mylist.erase(it1);
}
When you're calling mylist.erase(it1) it1 is no longer usable. The element where it points have been erased from the list and thus you cannot iterate any more on this it1.
You can use the return value of erase that gives the next valid iterator, but in that case you cannot use the for loop anymore as it would iterate even after deletion.
Here is an example of correct usage of erase (it should be adapted to suit your algorithm):
it1 = mylist.begin();
while (mylist.end() != it1)
{
if(*it1%prime == 0)
{
it1 = mylist.erase(it1);
}
else
{
++it1;
}
}
Another option would be to iterate before erasing. It would work for list aserase does not invalid the other list iterators.
it1 = mylist.begin();
while (mylist.end() != it1)
{
iterator it3 = it1;
++it1;
if(*it3%prime == 0)
{
mylist.erase(it3);
}
}
But this would work for a vectoras erase would potentially invalidate all the following iterators.
Source