list-->[-1-]<-->[-2-]<-->[-3-]<-->[-4-]<-->[-5-]
The above diagram is a circular doubly linked list of 5 nodes, and "list" is a reference/pointer to the first node.The last node, 5, and the fist node, 1, reference one another, as this list is circular, but I couldn't depict that diagrammatically.
Does the assignment
list.next.next.next =list.prev
on the above list modify it into the list
list-->[-1-]<-->[-2-]<-->[-3-]<-->[-5-]?
EDIT:
This isn't homework. I'm going over exercises in a textbook for self study. The book doesn't provide answers, so I decided to ask here.
as it is double linked, to create an other, valid, doubly-linked list, you have to update at least one next and one prev link (in the general case). as you update only one next link, it can not create what you show, as this is a valid example.
3.next would be 5, but 5.prev would still be 4.
No. It will "mess" things up quite a bit though.
Since your only changing one end of the connection between 2 -> 3, and the value you set it to us undefined (list.prev), it will create a broken list where 2 no longer points to anything meaningful. You could fix it though, since having a circular doubly linked list will allow you to "go backwards" from 1 -> 5 -> 4 -> 3 -> 2 and fix the pointers
Related
Sry for the bad headline could find the right words.
At the moment I'm trying to make some basic data structures that F# can use in any situation the first one is a Double linked list.
My question is not as much how to get it implemented, but rather if there is a why to hide the ugliness of the data structure. short form, i have something that as node at could look like
type Node<'N> =
| (node<'N> ref, 'N, node<'N>)
| Empty
and to analyse this when we have more then three items of the list is rather error prone. So is there a way that i can make the "look" the user of the library sees so it could look more like a List from the .NET. I'm asking for a way that doesn't rely on an already established data type, and one that not return a string look ( " ... " )
You can wrap your F# type in a class and keep the actual F# representation hidden. For example, if you wanted a super simple mutable list, you could do something like this:
type private MyListNode<'T> =
| Empty
| Cons of 'T * MyListNode<'T>
type MyList<'T>() =
let mutable nodes = Empty
member x.Prepend(el) = nodes <- Cons(el, nodes)
member x.ToArray() =
let rec loop el = seq {
match el with
| Empty -> ()
| Cons(x, xs) ->
yield x
yield! loop xs }
loop nodes |> Array.ofSeq
The C# user can work with MyList, which is ordinary class with Prepend and ToArray methods. The MyListNode type is private (hidden inside your F# library) and C# users will never see it.
This is not an answer to the question, but to the comments, because what I'm going to say requires diagrams and so it won't work in comments.
kam wrote:
But my Double Linked List are running in O(1) and if we assume that it is only the data and not the "pointers" that are immutable then you could still copy the whole list in O(1) time since the only thing you do when adding or deleting are changing or make a pointer (ref cell) to the old list then we still have that we have a copy of the old list without copying every single element again.
If you try to do that, you will find that with a doubly-linked list, you can't, in fact, preserve the old list pointers. Here's why.
With a singly-linked list, you can prepend to a list in O(1) time while maintaining any pointers to the old list intact. Here's an example:
Old list containing three items:
New list after prepending a new head:
Note how the reference from the other code has stayed intact. The old list, referenced by the other code, is ["Item 1"; "Item 2"; "Item 3"]. The new list is ["New head item"; "Item 1"; "Item 2"; "Item 3"]. But the reference held by a different part of the code still points to a well-formed list. The "well-formed" part is important, as you're about to see.
With a doubly-linked list, things get more complicated — and it turns out that it is not possible to maintain immutability and have O(1) time. First let's look at the old list containing three items:
This is a well-formed doubly-linked list. It obeys the following properties that all well-formed doubly-linked lists should obey:
All nodes have a Fwd and Back pointer.
All nodes but the head node have a valid (non-null) Back pointer. Only the head node's Back pointer is null.
All nodes but the tail node have a valid (non-null) Fwd pointer. Only the tail node's Fwd pointer is null.
From any node that isn't the tail, going forward and then back should bring you back to the same node you started at.
From any node that isn't the head, going back and then forward should bring you back to the same node you started at.
Now, how do we add a new head item while still making sure that the reference from the other code continues to point to a well-formed doubly-linked list?
Here's a first attempt. We add the new head item, adjust its Fwd pointer to point to the "old" head node, and rewrite that node's Back pointer to point to the new head node:
This is still a well-formed list, as you can easily verify. All five properties still hold true for every node. But wait! The reference from some other part of the code has had its list changed out from under it! Where before it was pointing to a list of three items, now it's pointing to the second item of a list of four items! If that other code is only iterating forwards, it won't notice a change. But the minute it tries to iterate backward, it will notice that there's a new head item that wasn't there before! We have broken the immutability promise. Immutability is a guarantee to other code that consumes our data structure that "If you have a reference to this data structure, the data you see will never change out from under you." And we just broke that promise: the old code used to see the list ["Item 1"; "Item 2"; "Item 3"], and now it sees the list ["New head item"; "Item 1"; "Item 2"; "Item 3"].
Okay, then. Are there ways to keep that promise, and not change what the other code sees? Well, we could try not rewriting that old head node; that way the old code still sees a doubly-linked list of three items, and everyone's happy, right? Well, let's see what it would look like if we did it that way:
Great: the other code still sees the exact same doubly-linked list that it used to see, and there's no way to get from the old list to the new head node. So any part of that other code that tries to go backwards from the head of the list will find that the head still goes to null, like it should. But wait: what about the five properties of a well-formed list? Well, it turns out we've violated property #4: from the head node, going forward and then going back ends up at a null pointer, not the node we started at. So we no longer have a well-formed list: bummer.
Okay, so that approach won't work. What else could we try. Well... hey! I have an idea! Let's just make a copy of the old head node, and adjust the copy while we leave the old head node alone! That's still O(1) since we know we're only copying one node. Then the other code sees exactly what it used to see, a list of three items, but the new list has four items. Brilliant! Just what we want, right? Well, let's look at it:
Okay, does this work? Well, the other code has a reference to the old, unchanged head node, so that's fine: it can't ever accidentally see the new data, so it still continues to see exactly what it used to have, a list of three items. Good. And from the new head node, we can go forward and back and end up where we started, so that's good... but wait... no, there's still a problem. From the copy of item 1 node, going forward and then back takes us to the old "item 1" node, not to the "copy of item 1" node. So we have still violated the properties of well-formed lists, and this list isn't well-formed either.
There's an answer to that one, too: copy the node with item 2 in it. I'm getting tired of drawing diagrams and this answer is getting long, so I'll let you work that one out for yourself — but you'll quickly see that then, the node with the copy of item 2 has the same problem as before: going forward and back takes you to the "old" item 2. (Or else you've adjusted the "old" item 2 node, and thereby broken the immutability promise since the other code can now see the "new" data via some series of Fwd and/or Back operations).
But there's a solution to that one, too: just copy item 3 as well. I won't draw that diagram either, but you can work it out for yourself. And you'll find that once you've copied items 1, 2, and 3 into the new list, you've managed to satisfy both the immutability promise, and all the properties of well-formed lists. The other code still sees the untouched old list, and the new list has four items in it. The only problem is, you had to copy every item in the list — an O(N) operation, by definition — in order to achieve this result.
Summary: Singly-linked lists have three properties:
You can prepend items in O(1) time.
Other code that had a reference to the old list still sees the same data after your prepend operation.
The old list and the new list are both well-formed.
With doubly-linked lists, however, you only get to have two of those three properties. You can have an O(1) prepend operation and maintain well-formed lists, but then any other code will see the list data change. Or you could have O(1) prepend and still have the other code see the same data it used to, but then your lists will no longer be well-formed. Or, by copying every node in the list, you can let the other code still see the same data it used to, AND your new list will be well-formed — but you had to do an O(N) operation in order to achieve this result.
This is why I said that it's not possible to have an immutable doubly-linked list with O(1) operations.
I am looking for a template of sorts for merging two linked chains that have already been sorted. I'm still fairly new to Java, and this seems to be a pretty challenging task to accomplish with the limited knowledge I have. I have an understanding of how to merge sort an array, but when it comes to linked lists I seem to be drawing blanks. Any help you all could give me, be it actual code or simply advise on where to start, would be greatly appreciated.
Thank you for your time!
If the two linked list are already sorted, then it is so easy to merge those two together. I am gonna tell you the algorithm but you need to write the code yourself since it seems like a school project. First you make a new linked list, and then assign the head of the new list to be the min of list1Head and list2Head, then you just walk the two list, each time picking the min of the current node of the two list and append to the new created list, make the current to be .Next if it got picked. If one of the list doesn't have more nodes, then append the rest of another list directly to the new list. Done
Can't you look at the first element in each list and take the smallest. This is the start of the new list. Remove this from the front ofwhichever list it came from. Now look at the first element again and take the smallest and make it the second element in the new list. Then just repeat this process zipping the two lists together.
If you want to avoid creating a new list the just find the smallest then look at the thing is pointing at and the beginning of the other list and see which is smaller. If you are not already pointing at the smaller one the update the pointer so it is. Then rinse and repeat.
This is less of a how to in a technical sense, but a more of what approach to use in an algorithmic way, I guess..
I have a Photo model, which has an id, created_at and the image itself.
I want to allow the user to order their photos in whatever order they feel like. So I guess I can add an attribute which will note the order somehow, and then reorder it by that column. But how would I build that column in a way that is efficient?
My options as I see it are:
a simple integer to denote the order. so 1,2,3,4,5. If the user chooses to put photo#5 before photo#2, I need to reassign all photos with a new sequential numbering to match the new order. With many photos, and drag and drop, this could have a lot of writes to the DB, and could be slow and inefficient
Make it so that any photo that is first, will get a higher number, so when the user puts photo#5 before photo#2, #5 will get a higher number than #2 but smaller than #1, but this can also get messy pretty quick..
Allow only "bump to first place or bump to last place" and in the last place make it a larger number than the previous last, and in the first place make it a smaller number than the previous first place. seeing that users won't have millions of photos, using an integer could work.
linked-list - this could technically work, but only in very limited situation where I have/ want to use all the photos. If I need a subset of the photos and want it custom ordered this won't work. I prefer a way that I can use <=> in o(1) and know immediately how to sort and not to go through all of it (which would be o(n^2))
Is there a better way to do this?
I have done the exactly same stuff in RoR. I think the approach you choose depends on what kind of operation you will do on the model most frequently.
I tried to use database to implement a double linked list. Which means, your Photo model have two more attributes, prev and next. prev is the id of the previous Photo item, and next is the id of the next Photo item. If you are still not clear, check out any data structure book about double linked list.
For this data structure, complexity for inserting is O(1), and querying is O(n).
Another approach is the one you mentioned in item 1: a simple integer to denote the order. so 1,2,3,4,5. .... Complexity inserting is O(n), and querying is O(1).
Thus, if you do inserting more than querying, choose my approach. Otherwise choose your first approach.
There are two ways that I can think to do this. Two basic data structures are Arrays and LinkedLists. The main difference between the two is that an item in an Array is referenced by it's index location, where as an item in a LinkedList is referenced by what's in front of it and what's behind it.
Therefor you could have a location (or number as you mentioned) that is correlated to is position on the page or screen, and you can store this number in the model and change it whenever the user moves the image. To do this effectively you would not want to push every image back one or forward one, but instead only allow swapping. So two photos could swap places easily.
Another way to do this would be to have each photo have a pointer that points to the next photo, in essence creating a linked list. Then you would print out all the photos until you reach a null pointer. This would be very easy to move one photo around.
To insert a new photo, you set the pointer index of the photo being inserted to the next photo in the list, and then you change the photo that was pointing to the next photo, to the photo being inserted.
1 -> 2 -> 3 #insert 4 after 1, before 2
1 -> 2 -> 3 4 -> 2 # point 4's pointer to 2
1 -> 4 -> 2 -> 3 # change 1's pointer to 4
I know that in order to find a loop in a linked list I can define two references to the list and move them at different speeds. Move one forward by 1 node and the other by 2 nodes.
So if the linked list has a loop they will definitely meet,
else either of the two references(or their next) will become null.
My question is : why the other reference should be moved in 2 nodes
why it cant be moved by any other even/odd number, is the correctness of the solution
relies on this ?
Thanks in advnance.
The larger the step, the more times around the loop before they are guaranteed to meet.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Linked list interview question
This is an interview question for which I don't have an answer.
Given Two lists, You cannot change list and you dont know the length.
Give best possible algorithm to:
Check if two lists are merging at any point?
If merging, at what point they are merging?
If I allow you to change the list how would you modify your algorithm?
I'm assuming that we are talking about simple linked lists and we can safely create a hash table of the list element pointers.
Q1: Iterate to end of both lists, If the respective last elements are the same, the lists merge at some point.
Complexity - O(N), space complexity - O(1)
Q2:
Put all elements of one list into a hash table
Iterate over 2nd list, probing the hash table for each element of the list. The first hit (if any) is the merge point, and we have the position in the 2nd list.
To get the position in the 1st list, iterate over the first list again looking for the element found in the previous step.
Time complexity - O(N). Space complexity - O(N)
Q3:
As Q1, but also reverse the direction of the list pointers.
Then iterate the reversed lists looking for the last common element - that is the merge point - and restoring the list to the original order.
Time complexity - O(N). Space complexity - O(1)
Number 1: Just iterate both and then check if they end with the same element. Thats O(n) and it cant be beaten (as it might possibly be the last element that is common, and getting there always takes O(n)).
Walk those two lists parallel by one element, add each element to Set of visited nodes (can be hash map, or simple set, you only need to check if you visited that node before). At each step check if you visited that node (if yes, then it's merging point), and add it to set of nodes if you visit it first time. Another version (as pointed by #reinier) is to walk only first list, store its nodes in Set and then only check second list against that Set. First approach is faster when your lists merge early, as you don't need to store all nodes from first list. Second is better at worst case, where both list don't merge at all, since it didn't store nodes from second list in Set
see 1.
Instead of Set, you can try to mark each node, but if you cannot modify structure, then it's not so helpful. You could also try unlink each visited node and link it to some guard node (which you check at each step if you encountered it while traversing). It saves memory for Set if list is long enough.
Traverse both the list and have a global variable for finding the number of NULL encountered . If they merge at some point there will be only 1 NULL else there will be two NULL.