Back to Basic: Doubly Linked List with JavaScript
March 5, 2013 7:38 am Leave your thoughtsThis is a first post of our series “back to basic”. We understand that there are always people starting out to be developers such as first year university students or just experienced developers wanting to revisit the basic. The aim of this series is exactly that, revisiting programming concepts using simple workable examples. Over the next few months we will cover the basics in addition to our normal posts.
In a nutshell a linked list is a collection of nodes with connections to each others. The varieties includes: singly linked list, doubly linked list, circular linked list and many more. A well known real world analogy of circular linked list would be flight queue where aeroplanes circle the airport until their turn to land.
Today we are going to build a simple doubly linked list implementation using javascript. The full working code example can be found in this jsFiddle. Let’s go through the code portions step by step.
The HTML and CSS
Let’s create a simple HTML depicting 3 blocks with forward and backward button. The correct html and header tags are assumed.
Basically we setup 5 blocks displayed with forward and backward action buttons.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<div class="block" id="b5"> b5 <span class="arr">→</span> </div> <div class="block" id="b4"> <span class="arr">←</span> b4 <span class="arr">→</span> </div> <div class="block" id="b3"> <span class="arr">←</span> b3 <span class="arr">→</span> </div> <div class="block" id="b2"> <span class="arr">←</span> b2 <span class="arr">→</span> </div> <div class="block" id="b1"> <span class="arr">←</span> b1 </div> <hr /> <span id="actionMsg">Press one of the buttons</span> <hr /> <input type="button" id="backward" value="backward" class="actionButton" /> <input type="button" id="forward" value="forward" class="actionButton" /> |
Then the CSS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
div.block { position: relative; top: 5px; height: 80px; width: 100px; display: inline-block; line-height: 80px; font-weight: bold; background-color: #bf0000; text-align: center; color: white; font-family: arial; border: 2px solid white; border-radius: 5px; } #actionMsg { font-family: arial; text-align: center; width: 100%; display: block; } span.arr { font-size: 30px; font-weight: 600; font-family: sans-serif; } |
By now you should be able to see something like this screenshot below (no you can’t interact with this image, if you want to try it you can go to the fiddle :)):
The JavaScript
First of we build our class declaration. This is the most important part since the ability to trigger movements between each blocks is done here.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
function Block () { this.id = null; this.elementRef = null; this.defaultMovingDistance = 100; /* hardcoded for our quick purposes matching our HTML example */ this.backLink = null; this.nextLink = null; this.setBackLink = function (bLink) { this.backLink = bLink; } //sets next link this.setNextLink = function (nLink) { this.nextLink = nLink; } //sets back link this.setElementRef = function (id) { this.elementRef = $('#' + id); this.id = id; } //move forward based on the position of the last link this.moveForward = function () { this.elementRef.animate( { left: "+=" + this.defaultMovingDistance + "px" }, 1000, "linear" ); //there's something behind tell it to go forward! if (this.backLink !== null) { //just to show what we are about to do updateMessage(this.id + " will now pull " + this.backLink.id + " using our link"); var that = this; setTimeout(function() { that.backLink.moveForward(); }, 3000); } else { updateMessage("No more links to pull"); $(".actionButton").removeAttr('disabled'); } } //move backward based on the position of the last link this.moveBackward = function () { this.elementRef.animate( { left: "-=" + this.defaultMovingDistance + "px" }, 1000, "linear" ); //there's something behind tell it to go forward! if (this.nextLink !== null) { //just to show what we are about to do updateMessage(this.id + " will now pull " + this.nextLink.id + " using our link"); var that = this; setTimeout(function() { that.nextLink.moveBackward(); }, 3000); } else { updateMessage("No more links to pull"); $(".actionButton").removeAttr('disabled'); } } } |
As you can see from the code above, our class name is Block . Within the class, we also prepare a link that will hold reference to the previous object (backlink) and another link to hold reference to the next object (nextLink). In addition we have also added setter functions; in JavaScript we don’t really need this, but it’s good for readability. We’ll talk about the moveForward and moveBackward function later.
Next we add a simple update message function. This is just a helper function to set the text in the message area in the html.
1 2 3 4 5 6 |
function updateMessage(txt) { $('#actionMsg').hide(function() { $('#actionMsg').text(txt); $('#actionMsg').show(); }) } |
Next we instantiate five objects and we give IDs that are identical to the DIVs in the HTML. We do this later when we need to move the blocks around.
1 2 3 4 5 6 7 8 9 10 |
var block1 = new Block(); block1.setElementRef("b1") var block2 = new Block(); block2.setElementRef("b2") var block3 = new Block(); block3.setElementRef("b3") var block4 = new Block(); block4.setElementRef("b4") var block5 = new Block(); block5.setElementRef("b5") |
After instantiating the objects, we then have to link them together.
1 2 3 4 5 6 7 8 9 10 11 12 |
//setup the links //set the back link block1.setBackLink(block2); block2.setBackLink(block3); block3.setBackLink(block4); block4.setBackLink(block5) //set the forward link block5.setNextLink(block4); block4.setNextLink(block3); block3.setNextLink(block2); block2.setNextLink(block1); |
Notice that in the code above we set the link for forward and backward link. This is why it’s called doubly linked list. Also note that we are just passing the blocks directly to the setNextLink and setBackLink because in JavaScript variables are passed by reference by default unless you do some deep object cloning.
Moving Forward and Backward
1 2 3 4 5 6 7 |
//the forward click //we go through the link list forward wise and move the blocks $('#forward').on("click", function() { var currentBlock = block1; $(".actionButton").attr('disabled', 'disabled'); currentBlock.moveForward(); }); |
In the code above we basically call the moveForward function of block1, which is our right-most block. The idea is block1 will move to the right and then pulled the block directly behind it. The next block will do the same. Let’s go through the code on the moveForward function a bit more.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
//move forward based on the position of the last link this.moveForward = function () { this.elementRef.animate( { left: "+=" + this.defaultMovingDistance + "px" }, 1000, "linear" ); //there's something behind tell it to go forward! if (this.backLink !== null) { //just to show what we are about to do updateMessage(this.id + " will now pull " + this.backLink.id + " using our link"); var that = this; setTimeout(function() { that.backLink.moveForward(); }, 3000); } else { updateMessage("No more links to pull"); |
When this function is called, basically we move the html object tied in via reference (this.elementRef) with this object to the right. This object will then check if it has anything linked behind it. If there is, then call the moveForward function of that object. This will continue until the last object. That is until the backLink is null and there is nothing more to do but to turn the buttons back on.
This is the great thing about using linked list, no need to iterate over the 5 objects using each manually, instead we just call the first object’s moveForward function and the objects takes are itself.
The backward logic is quite similar to the forward iteration. Only this time we start at the last block, which is block5 and calling the moveBackward function until there are no blocks left.
Closing
If you think about it, linked lists are quite simple but they are indispensable. Almost all of things that we iterate will depend on this concept one way or another. We hope this short post is beneficial to all of you.
Lastly here’s a very detailed explanation of linked list on wikipedia.
Categorised in: Back to Basic, Coding, Javascript, jQuery