Implement a simple Doubly Linked List

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
3
down vote

favorite












Purpose



I've never implemented a DoublyLinkedList and thought it would be a good data structure exercise. I tried using outside
resources as little as possible. I also tried to keep things as simple as possible



Discussion



The DoublyLinkedList is made up of a Node head, a Node tail, and an int length. I did not genericize the
API to keep things simple - the API only deals with int values.



The API is




  • getHead - gets the Node at the head of the linked list in O(1)


  • getTail - gets the Node at the tail of the linked list in O(1)


  • getLength - gets the length of the linked list in O(1)


  • isEmpty - convenience method; returns true if length is 0 and false otherwise in O(1)


  • insertAtHead - adds the input value at the head of the linked list in O(1)


  • insertAtTail - adds the input value at the tail of the linked list in O(1)


  • insertAt - adds the input value at some index in the linked list in O(n)


  • removeFirstOccurrence - removes the first occurrence of the input value (if it exists in list) in O(n)


  • removeAt - removes the node at the specified index in the linked list in O(n)


  • removeHead - removes the node at the head of the linked list in O(1)


  • removeTail - removes the node at the tail of the linked list in O(1)

Things I can improve:



  • When inserting at / removing at a particular index, I could speed up execution time by picking to start
    at the beginning or end of the list based on which the index is closest to

  • I tried adding a bunch of test cases, but I could have easily missed a case

  • Is my API sane / reasonable / did I miss implementing any obvious methods?

Implementation





public class DoublyLinkedList 
public static class Node
private Node previous;
private Node next;
private int value;

public Node(int value)
this.value = value;


public Node getPrevious()
return previous;


public Node getNext()
return next;


public int getValue()
return value;



private Node head;
private Node tail;
private int length;

public DoublyLinkedList()


public Node getHead()
return head;


public Node getTail()
return tail;


public int getLength()
return length;


public boolean isEmpty()
return length == 0;


public void insertAtHead(int value)
insertNode(null, new Node(value), head);


public void insertAtTail(int value)
insertNode(tail, new Node(value), null);


public void insertAt(int value, int index)
if (index > length

public void removeFirstOccurrence(int value)
Node currentNode = head;
while (currentNode != null)
if (currentNode.value == value)
removeNode(currentNode);
return;

currentNode = currentNode.next;



public void removeAt(int index)

public void removeHead()
removeNode(head);


public void removeTail()
removeNode(tail);


private void removeNode(Node node)
if (node.previous == null)
head = node.next;


if (node.next == null)
tail = node.previous;


if (node.previous != null)
node.previous.next = node.next;


if (node.next != null)
node.next.previous = node.previous;


length--;


private void insertNode(Node nodeBefore, Node node, Node nodeAfter)
node.next = nodeAfter;
node.previous = nodeBefore;

if (nodeBefore == null)
head = node;


if (nodeAfter == null)
tail = node;


if (nodeBefore != null)
nodeBefore.next = node;


if (nodeAfter != null)
nodeAfter.previous = node;


length++;








share|improve this question

























    up vote
    3
    down vote

    favorite












    Purpose



    I've never implemented a DoublyLinkedList and thought it would be a good data structure exercise. I tried using outside
    resources as little as possible. I also tried to keep things as simple as possible



    Discussion



    The DoublyLinkedList is made up of a Node head, a Node tail, and an int length. I did not genericize the
    API to keep things simple - the API only deals with int values.



    The API is




    • getHead - gets the Node at the head of the linked list in O(1)


    • getTail - gets the Node at the tail of the linked list in O(1)


    • getLength - gets the length of the linked list in O(1)


    • isEmpty - convenience method; returns true if length is 0 and false otherwise in O(1)


    • insertAtHead - adds the input value at the head of the linked list in O(1)


    • insertAtTail - adds the input value at the tail of the linked list in O(1)


    • insertAt - adds the input value at some index in the linked list in O(n)


    • removeFirstOccurrence - removes the first occurrence of the input value (if it exists in list) in O(n)


    • removeAt - removes the node at the specified index in the linked list in O(n)


    • removeHead - removes the node at the head of the linked list in O(1)


    • removeTail - removes the node at the tail of the linked list in O(1)

    Things I can improve:



    • When inserting at / removing at a particular index, I could speed up execution time by picking to start
      at the beginning or end of the list based on which the index is closest to

    • I tried adding a bunch of test cases, but I could have easily missed a case

    • Is my API sane / reasonable / did I miss implementing any obvious methods?

    Implementation





    public class DoublyLinkedList 
    public static class Node
    private Node previous;
    private Node next;
    private int value;

    public Node(int value)
    this.value = value;


    public Node getPrevious()
    return previous;


    public Node getNext()
    return next;


    public int getValue()
    return value;



    private Node head;
    private Node tail;
    private int length;

    public DoublyLinkedList()


    public Node getHead()
    return head;


    public Node getTail()
    return tail;


    public int getLength()
    return length;


    public boolean isEmpty()
    return length == 0;


    public void insertAtHead(int value)
    insertNode(null, new Node(value), head);


    public void insertAtTail(int value)
    insertNode(tail, new Node(value), null);


    public void insertAt(int value, int index)
    if (index > length

    public void removeFirstOccurrence(int value)
    Node currentNode = head;
    while (currentNode != null)
    if (currentNode.value == value)
    removeNode(currentNode);
    return;

    currentNode = currentNode.next;



    public void removeAt(int index)

    public void removeHead()
    removeNode(head);


    public void removeTail()
    removeNode(tail);


    private void removeNode(Node node)
    if (node.previous == null)
    head = node.next;


    if (node.next == null)
    tail = node.previous;


    if (node.previous != null)
    node.previous.next = node.next;


    if (node.next != null)
    node.next.previous = node.previous;


    length--;


    private void insertNode(Node nodeBefore, Node node, Node nodeAfter)
    node.next = nodeAfter;
    node.previous = nodeBefore;

    if (nodeBefore == null)
    head = node;


    if (nodeAfter == null)
    tail = node;


    if (nodeBefore != null)
    nodeBefore.next = node;


    if (nodeAfter != null)
    nodeAfter.previous = node;


    length++;








    share|improve this question





















      up vote
      3
      down vote

      favorite









      up vote
      3
      down vote

      favorite











      Purpose



      I've never implemented a DoublyLinkedList and thought it would be a good data structure exercise. I tried using outside
      resources as little as possible. I also tried to keep things as simple as possible



      Discussion



      The DoublyLinkedList is made up of a Node head, a Node tail, and an int length. I did not genericize the
      API to keep things simple - the API only deals with int values.



      The API is




      • getHead - gets the Node at the head of the linked list in O(1)


      • getTail - gets the Node at the tail of the linked list in O(1)


      • getLength - gets the length of the linked list in O(1)


      • isEmpty - convenience method; returns true if length is 0 and false otherwise in O(1)


      • insertAtHead - adds the input value at the head of the linked list in O(1)


      • insertAtTail - adds the input value at the tail of the linked list in O(1)


      • insertAt - adds the input value at some index in the linked list in O(n)


      • removeFirstOccurrence - removes the first occurrence of the input value (if it exists in list) in O(n)


      • removeAt - removes the node at the specified index in the linked list in O(n)


      • removeHead - removes the node at the head of the linked list in O(1)


      • removeTail - removes the node at the tail of the linked list in O(1)

      Things I can improve:



      • When inserting at / removing at a particular index, I could speed up execution time by picking to start
        at the beginning or end of the list based on which the index is closest to

      • I tried adding a bunch of test cases, but I could have easily missed a case

      • Is my API sane / reasonable / did I miss implementing any obvious methods?

      Implementation





      public class DoublyLinkedList 
      public static class Node
      private Node previous;
      private Node next;
      private int value;

      public Node(int value)
      this.value = value;


      public Node getPrevious()
      return previous;


      public Node getNext()
      return next;


      public int getValue()
      return value;



      private Node head;
      private Node tail;
      private int length;

      public DoublyLinkedList()


      public Node getHead()
      return head;


      public Node getTail()
      return tail;


      public int getLength()
      return length;


      public boolean isEmpty()
      return length == 0;


      public void insertAtHead(int value)
      insertNode(null, new Node(value), head);


      public void insertAtTail(int value)
      insertNode(tail, new Node(value), null);


      public void insertAt(int value, int index)
      if (index > length

      public void removeFirstOccurrence(int value)
      Node currentNode = head;
      while (currentNode != null)
      if (currentNode.value == value)
      removeNode(currentNode);
      return;

      currentNode = currentNode.next;



      public void removeAt(int index)

      public void removeHead()
      removeNode(head);


      public void removeTail()
      removeNode(tail);


      private void removeNode(Node node)
      if (node.previous == null)
      head = node.next;


      if (node.next == null)
      tail = node.previous;


      if (node.previous != null)
      node.previous.next = node.next;


      if (node.next != null)
      node.next.previous = node.previous;


      length--;


      private void insertNode(Node nodeBefore, Node node, Node nodeAfter)
      node.next = nodeAfter;
      node.previous = nodeBefore;

      if (nodeBefore == null)
      head = node;


      if (nodeAfter == null)
      tail = node;


      if (nodeBefore != null)
      nodeBefore.next = node;


      if (nodeAfter != null)
      nodeAfter.previous = node;


      length++;








      share|improve this question











      Purpose



      I've never implemented a DoublyLinkedList and thought it would be a good data structure exercise. I tried using outside
      resources as little as possible. I also tried to keep things as simple as possible



      Discussion



      The DoublyLinkedList is made up of a Node head, a Node tail, and an int length. I did not genericize the
      API to keep things simple - the API only deals with int values.



      The API is




      • getHead - gets the Node at the head of the linked list in O(1)


      • getTail - gets the Node at the tail of the linked list in O(1)


      • getLength - gets the length of the linked list in O(1)


      • isEmpty - convenience method; returns true if length is 0 and false otherwise in O(1)


      • insertAtHead - adds the input value at the head of the linked list in O(1)


      • insertAtTail - adds the input value at the tail of the linked list in O(1)


      • insertAt - adds the input value at some index in the linked list in O(n)


      • removeFirstOccurrence - removes the first occurrence of the input value (if it exists in list) in O(n)


      • removeAt - removes the node at the specified index in the linked list in O(n)


      • removeHead - removes the node at the head of the linked list in O(1)


      • removeTail - removes the node at the tail of the linked list in O(1)

      Things I can improve:



      • When inserting at / removing at a particular index, I could speed up execution time by picking to start
        at the beginning or end of the list based on which the index is closest to

      • I tried adding a bunch of test cases, but I could have easily missed a case

      • Is my API sane / reasonable / did I miss implementing any obvious methods?

      Implementation





      public class DoublyLinkedList 
      public static class Node
      private Node previous;
      private Node next;
      private int value;

      public Node(int value)
      this.value = value;


      public Node getPrevious()
      return previous;


      public Node getNext()
      return next;


      public int getValue()
      return value;



      private Node head;
      private Node tail;
      private int length;

      public DoublyLinkedList()


      public Node getHead()
      return head;


      public Node getTail()
      return tail;


      public int getLength()
      return length;


      public boolean isEmpty()
      return length == 0;


      public void insertAtHead(int value)
      insertNode(null, new Node(value), head);


      public void insertAtTail(int value)
      insertNode(tail, new Node(value), null);


      public void insertAt(int value, int index)
      if (index > length

      public void removeFirstOccurrence(int value)
      Node currentNode = head;
      while (currentNode != null)
      if (currentNode.value == value)
      removeNode(currentNode);
      return;

      currentNode = currentNode.next;



      public void removeAt(int index)

      public void removeHead()
      removeNode(head);


      public void removeTail()
      removeNode(tail);


      private void removeNode(Node node)
      if (node.previous == null)
      head = node.next;


      if (node.next == null)
      tail = node.previous;


      if (node.previous != null)
      node.previous.next = node.next;


      if (node.next != null)
      node.next.previous = node.previous;


      length--;


      private void insertNode(Node nodeBefore, Node node, Node nodeAfter)
      node.next = nodeAfter;
      node.previous = nodeBefore;

      if (nodeBefore == null)
      head = node;


      if (nodeAfter == null)
      tail = node;


      if (nodeBefore != null)
      nodeBefore.next = node;


      if (nodeAfter != null)
      nodeAfter.previous = node;


      length++;










      share|improve this question










      share|improve this question




      share|improve this question









      asked May 1 at 2:47









      Jae Bradley

      822514




      822514




















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          2
          down vote



          accepted










          Your code is reasonable enough. A few details:



          • All the methods of Node including constructor should be private. Your class should encapsulate and hide from the world the details of implementation. Besides, allowing the user to create instances of Node makes no sense because the user can't do anything with them.


          • Methods getHead and getTail should return the value of the node rather than the Node itself. From the user's perspective your class deals with numbers, and the user expects the first and the last elements to be numbers as well.


          • I would use a method, that accepts two parameters, to insert the node, not the method with 3 parameters as in your code. It would look like private void insertAfter(Node node, Node newNode). You can easily get nodeAfter from the first parameter. If the first parameter is null, the method would add the newNode to the very beginning of the list.


          • I'd follow the convention of Deque interface when naming methods. getFirst(), getLast(), addFirst(value), addLast(value), removeFirst(), removeLast(). Methods pushFirst(value), pushLast(value), popFirst(), popLast() would be also useful.


          • Document your public api. Javadocs would be fine.






          share|improve this answer





















          • It might be worth recommending implementing the Deque interface to ensure that the contract is followed. There are a few more methods, but they should each only be a few lines of code.
            – Gerrit0
            May 1 at 20:15










          Your Answer




          StackExchange.ifUsing("editor", function ()
          return StackExchange.using("mathjaxEditing", function ()
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          );
          );
          , "mathjax-editing");

          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "196"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );








           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f193318%2fimplement-a-simple-doubly-linked-list%23new-answer', 'question_page');

          );

          Post as a guest






























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          2
          down vote



          accepted










          Your code is reasonable enough. A few details:



          • All the methods of Node including constructor should be private. Your class should encapsulate and hide from the world the details of implementation. Besides, allowing the user to create instances of Node makes no sense because the user can't do anything with them.


          • Methods getHead and getTail should return the value of the node rather than the Node itself. From the user's perspective your class deals with numbers, and the user expects the first and the last elements to be numbers as well.


          • I would use a method, that accepts two parameters, to insert the node, not the method with 3 parameters as in your code. It would look like private void insertAfter(Node node, Node newNode). You can easily get nodeAfter from the first parameter. If the first parameter is null, the method would add the newNode to the very beginning of the list.


          • I'd follow the convention of Deque interface when naming methods. getFirst(), getLast(), addFirst(value), addLast(value), removeFirst(), removeLast(). Methods pushFirst(value), pushLast(value), popFirst(), popLast() would be also useful.


          • Document your public api. Javadocs would be fine.






          share|improve this answer





















          • It might be worth recommending implementing the Deque interface to ensure that the contract is followed. There are a few more methods, but they should each only be a few lines of code.
            – Gerrit0
            May 1 at 20:15














          up vote
          2
          down vote



          accepted










          Your code is reasonable enough. A few details:



          • All the methods of Node including constructor should be private. Your class should encapsulate and hide from the world the details of implementation. Besides, allowing the user to create instances of Node makes no sense because the user can't do anything with them.


          • Methods getHead and getTail should return the value of the node rather than the Node itself. From the user's perspective your class deals with numbers, and the user expects the first and the last elements to be numbers as well.


          • I would use a method, that accepts two parameters, to insert the node, not the method with 3 parameters as in your code. It would look like private void insertAfter(Node node, Node newNode). You can easily get nodeAfter from the first parameter. If the first parameter is null, the method would add the newNode to the very beginning of the list.


          • I'd follow the convention of Deque interface when naming methods. getFirst(), getLast(), addFirst(value), addLast(value), removeFirst(), removeLast(). Methods pushFirst(value), pushLast(value), popFirst(), popLast() would be also useful.


          • Document your public api. Javadocs would be fine.






          share|improve this answer





















          • It might be worth recommending implementing the Deque interface to ensure that the contract is followed. There are a few more methods, but they should each only be a few lines of code.
            – Gerrit0
            May 1 at 20:15












          up vote
          2
          down vote



          accepted







          up vote
          2
          down vote



          accepted






          Your code is reasonable enough. A few details:



          • All the methods of Node including constructor should be private. Your class should encapsulate and hide from the world the details of implementation. Besides, allowing the user to create instances of Node makes no sense because the user can't do anything with them.


          • Methods getHead and getTail should return the value of the node rather than the Node itself. From the user's perspective your class deals with numbers, and the user expects the first and the last elements to be numbers as well.


          • I would use a method, that accepts two parameters, to insert the node, not the method with 3 parameters as in your code. It would look like private void insertAfter(Node node, Node newNode). You can easily get nodeAfter from the first parameter. If the first parameter is null, the method would add the newNode to the very beginning of the list.


          • I'd follow the convention of Deque interface when naming methods. getFirst(), getLast(), addFirst(value), addLast(value), removeFirst(), removeLast(). Methods pushFirst(value), pushLast(value), popFirst(), popLast() would be also useful.


          • Document your public api. Javadocs would be fine.






          share|improve this answer













          Your code is reasonable enough. A few details:



          • All the methods of Node including constructor should be private. Your class should encapsulate and hide from the world the details of implementation. Besides, allowing the user to create instances of Node makes no sense because the user can't do anything with them.


          • Methods getHead and getTail should return the value of the node rather than the Node itself. From the user's perspective your class deals with numbers, and the user expects the first and the last elements to be numbers as well.


          • I would use a method, that accepts two parameters, to insert the node, not the method with 3 parameters as in your code. It would look like private void insertAfter(Node node, Node newNode). You can easily get nodeAfter from the first parameter. If the first parameter is null, the method would add the newNode to the very beginning of the list.


          • I'd follow the convention of Deque interface when naming methods. getFirst(), getLast(), addFirst(value), addLast(value), removeFirst(), removeLast(). Methods pushFirst(value), pushLast(value), popFirst(), popLast() would be also useful.


          • Document your public api. Javadocs would be fine.







          share|improve this answer













          share|improve this answer



          share|improve this answer











          answered May 1 at 19:52









          ekaerovets

          25613




          25613











          • It might be worth recommending implementing the Deque interface to ensure that the contract is followed. There are a few more methods, but they should each only be a few lines of code.
            – Gerrit0
            May 1 at 20:15
















          • It might be worth recommending implementing the Deque interface to ensure that the contract is followed. There are a few more methods, but they should each only be a few lines of code.
            – Gerrit0
            May 1 at 20:15















          It might be worth recommending implementing the Deque interface to ensure that the contract is followed. There are a few more methods, but they should each only be a few lines of code.
          – Gerrit0
          May 1 at 20:15




          It might be worth recommending implementing the Deque interface to ensure that the contract is followed. There are a few more methods, but they should each only be a few lines of code.
          – Gerrit0
          May 1 at 20:15












           

          draft saved


          draft discarded


























           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f193318%2fimplement-a-simple-doubly-linked-list%23new-answer', 'question_page');

          );

          Post as a guest













































































          Popular posts from this blog

          Greedy Best First Search implementation in Rust

          Function to Return a JSON Like Objects Using VBA Collections and Arrays

          C++11 CLH Lock Implementation