I have two lists, for which I am currently using std::list < size_t >.
Let's call them list A and list B.
Let list A have elements [1, 2, 3, 4] and list B have elements [5, 6, 7, 8].
I want to concatenate the two list. However, in my application, there are eight ways to concatenate. I will describe two ways to keep it minimal:
- Concatenate A and B directly. So list C = [1, 2, 3, 4, 5, 6, 7, 8].
- Reverse lists A and B and then concatenate. So list C = [4, 3, 2, 1, 8, 7, 6, 5].
For the first case, I could use the following code (source: cppreference):
std::list <size_t> C;
C.splice(C.begin(), A);
C.splice(C.end(), B);
This gives a nice constant time implementation.
For the second case, where I have to reverse the lists, I could use reverse() for the purpose (source: cppreference):
A.reverse();
B.reverse();
C_reversed.splice(C_reversed.begin(), A);
C_reversed.splice(C_reversed.end(), B);
std::cout << "C_reversed: " << C_reversed << std::endl;
This works nicely, however, it has a linear time complexity. Is there a better way to do this? I read through Stack Overflow: Why does std::list::reverse have O(n) complexity?, and understood that it cannot be done using reverse(). Is there some other way to accomplish this in constant time?
My fallback option is to maintain four lists, two for each of A and B, so that I can concatenate in constant time. However, this results in additional space complexity. Example given below:
std::list <size_t> A1 = {1, 2, 3, 4};
std::list <size_t> A1_reversed = {4, 3, 2, 1};
std::list <size_t> B1 = {5, 6, 7, 8};
std::list <size_t> B1_reversed = {8, 7, 6, 5};
std::list <size_t> C1;
C1.splice(C1.begin(), A1);
C1.splice(C1.end(), B1);
std::list <size_t> C1_reversed;
std::cout << "C1: "<< C1 <<std::endl;
C1_reversed.splice(C1_reversed.begin(), A1_reversed);
C1_reversed.splice(C1_reversed.end(), B1_reversed);
std::cout << "C1_reversed: "<< C1_reversed <<std::endl;
Code for experimentation is given below:
/** Concatenation of two lists **/
#include <iostream>
#include <list>
std::ostream& operator<<(std::ostream& ostr, const std::list< size_t >& list) {
for (auto &i : list) {
ostr << " " << i;
}
return ostr;
}
int main(int argc, char **argv) {
/** Initialize **/
std::list < size_t > A = {1, 2, 3, 4};
std::list < size_t > B = {5, 6, 7, 8};
/** A + B **/
std::list < size_t > C;
C.splice(C.begin(), A);
C.splice(C.end(), B);
std::cout << C << std::endl;
/** Reverse A + reverse B **/
A = {1, 2, 3, 4};
B = {5, 6, 7, 8};
std::list < size_t > C_reversed;
A.reverse();
B.reverse();
C_reversed.splice(C_reversed.begin(), A);
C_reversed.splice(C_reversed.end(), B);
std::cout << C_reversed << std::endl;
/** Maintaining four lists **/
std::list <size_t> A1 = {1, 2, 3, 4};
std::list <size_t> A1_reversed = {4, 3, 2, 1};
std::list <size_t> B1 = {5, 6, 7, 8};
std::list <size_t> B1_reversed = {8, 7, 6, 5};
std::list <size_t> C1;
C1.splice(C1.begin(), A1);
C1.splice(C1.end(), B1);
std::list <size_t> C1_reversed;
std::cout << "C1: "<< C1 <<std::endl;
C1_reversed.splice(C1_reversed.begin(), A1_reversed);
C1_reversed.splice(C1_reversed.end(), B1_reversed);
std::cout << "C1_reversed: "<< C1_reversed <<std::endl;
return 0;
}
rbeginandrendto iterate a list backward and as such avoid actual reversing.splice()does not takereverse_iterators, i.e.,rbeginandrend.