Reputation: 3
Let's say I have something like this below:
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<int> mylist{ 1, 5, 3, 2, 4 };
// sort
mylist.sort();
// printing the list after sort
for (auto it = mylist.begin(); it != mylist.end(); ++it)
cout << ' ' << *it;
return 0;
}
However, if I do that, the original list is permanently changed. I know there are a lot of ways to do it. But specifically I want to know how I can sort it without making a copy of the original list explicitly. I want to do it with a function that is passed by value so that changes will be temporary.
Upvotes: 0
Views: 779
Reputation: 20141
Re-arrange elements of a list without changing the list itself reminds me to something what I would call a proxy.
In this case, a std::vector
of list iterators could be used as proxy. I would consider a std::vector
as cache friendly (contiguous storage of contents) which may be an additional advantage concerning the performance of sorting.
The proxy vector is sorted with a custom predicate which considers the contents at iterators.
A sample:
#include <algorithm>
#include <iostream>
#include <list>
#include <vector>
int main()
{
using listInt = std::list<int>;
listInt myList{ 1, 5, 3, 2, 4 };
// proxy for sorted access
{ std::vector<listInt::iterator> proxy;
proxy.reserve(myList.size());
for (listInt::iterator iter = myList.begin();
iter != myList.end(); ++iter) {
proxy.push_back(iter);
}
// sort proxy:
std::sort(proxy.begin(), proxy.end(),
[](listInt::iterator iter1, listInt::iterator iter2)
{
return *iter1 < *iter2;
});
// show proxy result
for (listInt::iterator iter : proxy) {
std::cout << ' ' << *iter;
}
std::cout << '\n';
}
std::cout << "The list (still in original order):\n";
for (int value : myList) {
std::cout << ' ' << value;
}
std::cout << '\n';
}
Output:
1 2 3 4 5
The list (still in original order):
1 5 3 2 4
Please note, as long as none of the list elements is deleted the list iterators are stable. (Get pointer to node in std::list or std::forward_list)
It might be questionable whether to store iterators instead of the values (which are plain int
) is an advantage in any way. However, the size of iterator probably won't change if the list would contain elements of a "heavier" type where a deep copy would have a significant impact or even prohibited.
Googling a bit afterwards, I found this:
SO: Sort by proxy (or: sort one container by the contents of another) in C++
which might be related (IMHO).
Upvotes: 0
Reputation: 122460
I want to do it with a function that is passed by value so that changes will be temporary.
Sure you can do that:
#include <iostream>
#include <list>
using namespace std;
void foo(list<int> l) { // pass by copy !
l.sort();
// printing the list after sort
for (auto it = l.begin(); it != l.end(); ++it)
cout << ' ' << *it;
}
int main()
{
list<int> mylist{ 1, 5, 3, 2, 4 };
// sort
foo(mylist);
return 0;
}
Upvotes: 2