I asked a question last night on how to sort() a double linked list in C++.
I managed to get it to work, but now I'd like to merge two lists, but I can't
get it to work. I don't have much code, I'm sorry. Everything I tried
absolutely made no sense. I'd just like if someone could give me some hints on
where to start, or on how to do this, with the information I'm going to
provide.
This is what I had in the beginning:
void next() { if (curr != tail) curr = curr->next; }
I believe I only need these.
I looked at some exemples online, but it doesn't make any sense to me. It
seems so different than what I have right now. Apparently it should be A LOT
easier than doing a sort function, which I had barely any trouble doing.
Any explanation/hints would be greatly appreciated! And I'm sorry once again
for the lack of code, I just don't know where to start.
You can actually do this in multiple ways
Take the two sorted lists, and literally merge them so that you end up with a sorted list
Take the two sorted lists, and create a third new list that contains elements from both the lists in sorted order
Merge the two sorted/unsorted lists, and then sort the resulting list
It looks like you're trying to do no. 3 here.
In which case, you can just
Start from head of the current list, and go to next until you reach the last element
Set curr->next = other_list.head
Call sort on the current list
This would however destruct the original list. I think it's better to copy them to a third list.
for_each(auto x in list2name)
{
list1name.push_back(x);
}
or if you're using C++ 11
for(auto x : list2name)
{
list1name.push_back(x);
}
If you have used the std::list as a linked list you can always use the existing merge() function http://www.cplusplus.com/reference/stl/list/
If this is something you have implemented yourself just get the tail of one of the lists and use something like this:
tail = list_1.get_tail();
tail.set_next(list_2.get_head())
Basically getting the last entry in list 1 and then setting the next elemt to be the first element of list 2.
I'm still a bit confused what you're after, but this is the most basic way I can think of.
Then again, I might be completely off.
Good luck
Related
I was reading on this Haskell page about adding an element to the end of a List.
Using the example, I tried it out for my self. Given the following List I wanted to add the number 56 at the end of it.
Example:
let numbers = [4,8,15,16,23,42]
numbers ++ [56]
I was thrown off by this comment:
Adding an item to the end of a list is a fine exercise, but usually
you shouldn't do it in real Haskell programs. It's expensive, and
indicates you are building your list in the wrong order. There is
usually a better approach.
Researching, I realize that what I'm actually doing is creating a List with 56 as the only element and I'm combining it with the numbers list. Is that correct?
Is using ++ the correct way to add an element to the end of a List?
++ [x] is the correct way to add an element to the end of a list, but what the comment is saying is that you shouldn't add elements to the end of a list.
Due to the way lists are defined, adding an element at the end always requires making a copy of the list. That is,
xs ++ ys
needs to copy all of xs but can reuse ys unchanged.
If xs is just one element (i.e. we're adding to the beginning of a list), that's no problem: Copying one element takes practically no time at all.
But if xs is longer, we need to spend more time in ++.
And if we're doing this repeatedly (i.e. we're building up a big list by continually adding elements to the end), then we need to spend a lot of time making redundant copies. (Building an n-element list in this way is an O(n2) operation.)
If you need to do this, there is usually a better way to structure your algorithm. For example, you can build your list in reverse order (adding elements at the beginning) and only call reverse at the end.
It's the correct way in that all ways of doing it must reduce to at least that much work. The problem is wanting to append to the end of a list at all. That's not an operation that's possible to do efficiently with immutable linked lists.
The better approach is figuring out how to solve your specific problem without doing that. There are a lot of potential approaches. Picking the right one depends on the details of what you're doing. Maybe you can get away with just using laziness correctly. Maybe you are best off generating the list backwards and then reversing it once at the end. Maybe you're best off using a different data structure. It all depends on your specific use case.
I have been learning C++ for a while, and just started looking at linked lists recently. I can construct a template class List with the usual functions insert/remove from back/front. Now I came up with an exercise that asks me to write a function to handle insertions/deletions anywhere in the list.
Please bear in mind that my questions are very basic.
The problem I have is that I see the question as ambiguous. What kind of information does the function require? For instance, for deletion, I can come up with several candidates:
1) delete the first node that has a particular value (argument: value)
2) delete all nodes with a particular value (argument: value)
3) delete a particular node (argument: pointer to that node)
1) and 2) I can easily code. 3) is harder but I can also do it. I just don't see the point in 3). Is it usual to manipulate nodes (outside the list definition) when using lists? As in, is it usual for a program using lists to actually manipulate pointers to the nodes?
What is the usual meaning of "delete anywhere" in this setting?
Similarly, for "insert anywhere", the wording is strange. What does "anywhere" mean? Is the place in the linked list supposed to be given by a particular node?
In linked list you have constant time access to first element. So delete/insert anywhere means the place that exists between first and last element. Basically you need to have 2 iterators. When you find the place you want remove/insert a element, you should refer to the object just before it. because you have not access to the prev element, only to the next one:
Let's say our linked list looks like this:
E0->E1->E2->E3->E4
If you want remove E3, you need to have iterator set on E2 so that you could correct pointers for E2->next.
Good reference is the book Standard Library wrote by Nicolai M. Josuttis. The problem you have encountered is widely described there.
node*insert(node*head,int d){
node*temp=new node;
temp->data=d;
if(head==NULL){
temp->next=NULL;
head=temp;}
else
{node*curr=head,*pre=NULL;
while (curr!=NULL && curr->data<temp->data)
{
pre=curr;
curr=curr->next;
}
temp->next=curr;
if(pre==NULL)
head=temp;
pre->next=temp;
}
return head;
}
I'm trying to make my program run more efficiently, and I believe fixing this linear search would do a great deal of help in terms of speed, but am curious as to how I'd go about changing this to something like binary search, as I believe the list isn't necessarily ordered. Is there some way of ordering the list based on it's first argument key?
What I'm working with currently:
int* key_sequences::data(int key){
for(it=myList.begin(); it!=myList.end(); ++it){
if(it->first==key){
return &(it->second[0]);
}
}
return nullptr;
};
Searching in a simply linked list is O(n), where n is the size of the list.
However, in some implementations, people use three list pointers, one at the start, one at the middle and one at the end, so that when searching comes up - they can speedup the process, so you can search online for this.
BUT, if I were you and was so interesting in speeding up the search, I would try another data structure (hash? like std::unordered_map) or sort the list.
I was thinking about ways of sorting a linked list and I came up with two different ways (using BubbleSort, because I'm relatively new at programming and it is the simplest algorithm for me). Example struct:
struct node {
int value;
node *next;
};
The two different methods:
Rearranging the list elements
Doing something like swap(root->value, root->next->value)
I did some Google searches on the subject, and from the looks of it, the first method seems to be more popular. From my experience, such that it is, rearranging the list is more complicated than simply swapping the actual node values. Is there any benefit in rearranging the whole list, and if yes, what is it?
I can think of two advantages:
1) Other pointers might exist, pointing to nodes in this list. If you rearrange the list, these pointers will still point to the same values they pointed to before the sorting; if you swap values, they won't. (Which one of these two is better depends on the details of your design, but there are designs in which it is better if they remain pointing to the same values.)
2) It doesn't matter much for a list of mere ints, but eventually you might be sorting a list of more complex things, so that swapping values is very expensive or even impossible.
As answered by Beta, it's better to rearrange the nodes (via the next pointers) than it is to swap node data.
If actually using a bubble sort or any sort that "swaps" nodes via the pointers, swap the next (or head) pointers to the two nodes to be swapped first, then swap those two nodes next pointers. This handles both the adjacent node case where 3 pointers are rotated, and the normal case where 2 pairs of pointers are swapped.
Another simple option is to create an new empty list (node * pNew = NULL;) for the sorted list. Remove a node from the original list one at a time and insert that node into the sorted list in order, or scan the original list for the largest node, remove that node and prepend the sorted list with that node.
If the list is large and speed is important, than bottom up merge sorts are much faster.
Hello I dont know if there is a command in C++ which I can use to jump directly to 5th node in a linked list? I know with : p->next i can try to go to the next node but what if I want to go to the 56th right awat is there a way ? like p->next(56) or something ? Thanks
If the linked list does not have a command like p->get(56) built in then you have to write your own function that uses a for loop. It takes the list and the number of the element you want and then calls next that number of times.
There is no such "command". A characteristic of a linked list is that it is slower to locate a particular node by position. Unless of course, you've already stored a pointer to that node.
If this is a problem, then a linked list is not the correct data structure for your purposes.
At least if you have an iterator of the category InputIterator (those of std::list are of this category) you can use std::advance. For example, if you want to get the iterator pointing to the fifth element from the beginning of the list:
std::list<int> l;
// ...
std::list<int>::iterator it = l.begin();
std::advance(it, 4);
// Now it points to the fifth element
But as the others already mentioned: A linked list isn't supposed to have random access. You always have to travel through it in order to get a certain entry. And thus std::advance will perform very poor for large lists.
C++ doesn't provide a linked list type that you can access at that level. It does have std::list<>, which provides encapsulation. You can not directly index into a linked list... though you can advance 56 steps from the first (or some other already-found) element, but each node must be traversed and this is relatively inefficient. If you need better performance, you should reconsider your choice of container: perhaps a vector or map would be more appropriate.
This is the nature of linked lists. You'll have to traverse all the way to the nth element.