Design and implementation of two-link list of JAVA data structure and algorithm __java

Source: Internet
Author: User
Tags prev

Reprint please indicate the source (extremely grateful.) ):
http://blog.csdn.net/javazejian/article/details/53047590
From "Zejian's blog."

Related articles:

Design and implementation analysis of sequence table and link list of Java Data structure and algorithm
Design and implementation of two-link list of Java Data structure and algorithm
Java data structure and algorithm of improved sequence table and double linked list similar to ArrayList and LinkedList (with iterator iterator and fast-fail mechanism)
Design and implementation of Java data structure and algorithm stack (stack)
Design and implementation of queues (queue) for Java data structure and algorithms
Recursive thinking of Java Data structure and algorithm (let's understand recursion more commonly)
Java data structure and algorithm tree basic concept and binary tree (BinaryTree) design and implementation
Design and implementation of a balanced binary lookup tree (AVL tree) for Java data structure and algorithm

The previous article analyzes the sequence table and the single linked list, this article will continue to talk about the linked list, in single-list analysis, we can know that each node has only one next field pointing to the successor node, and if the current node p is known and needs to find its precursor node, then the head pointer must be traversed to the precursor node of P. The efficiency of the operation is very low, so if P has a next field pointing to the predecessor node, then the efficiency is much higher, and for such a node, the list of the pre and subsequent node fields of the predecessor node is included, which is called the double linked list. In this article we will analyze the double linked list from the following nodes.

Design and implementation of double-linked list design and implementation of double-linked list scheduling double-linked list implementation efficiency analysis of double linked list design principle of double linked list

design and implementation of double linked list

The main advantage of a double linked list is that for any given node, can easily obtain its predecessor nodes or subsequent nodes, but the main disadvantage is that each node needs to add additional next domain, so need more space overhead, while the insertion and deletion of nodes will also be more time-consuming, because more pointers to the operation. The structure of the double linked list is as follows:

Create the Headdoubleilinkedlist class and implement the Ilinekedlist interface (same as the interface of the previous blog)

/**
 * Created by Zejian on 2016/10/23.
 * Double linked list, leading node (without data) Double linked list, for higher efficiency The class contains pointers to the tail tail/public
class Headdoubleilinkedlist<t> implements ilinkedlist<t> {

    protected dnode<t> Head;///With no data on the header node
    protected dnode<t> Tail;//pointer to tail point Public

    headdoubleilinkedlist () {
        //Initialization header node
        this.head =this.tail= new dnode<> ();          
    }
    Omit other code First ...
}

The node class structure is as follows:

Package com.zejian.structures.LinkedList.doubleLinked;

/**
 * Created by Zejian on 2016/10/23.
 * Double Link Table node *
/public class Dnode<t> {public

    T data;
    Public dnode<t> prev, next;//forward pointer and successor pointer public
    Dnode (T data, dnode<t> prev, dnode<t> next)
    { C9/>this.data = data;
        This.prev = prev;
        This.next = next;

    Public Dnode (T data)
    {This
        (data, NULL, NULL);
    }

    Public Dnode ()
    {This
        (null, NULL, NULL);
    }

    Public String toString ()
    {return
        this.data.toString ();
    }
}

Through the analysis of the last chapter, we have the insertion of the linked list, delete, find, replace and other operations are also familiar with, so for the realization of the double linked list, the main analysis of its insertion, deletion, search, replacement, and other methods, no analysis to see the implementation of the source code can (finally give the realization of the double linked list)

Insert operation analysis and implementation of double linked list
Let's take a look at the double linked list inserts, although there is no data in the head node, but because it is a two-way linked list, so when inserting a double linked list needs to be divided into two situations, one is inserted in the empty double linked list and tail insert, the other is a double linked list of the middle insert, The following figure inserts a value in an empty double list x:

You can see from the diagram that (a) and (b) belong to the same situation, that you need to pay attention to the case of Front.next!= null, or else you will throw a null pointer, and (c) the case is in the middle insert without NULL, because the insertion method has the following implementation code, because the middle insert will not be null at any point when its subsequent node is inserted:

/** * Insert node * @param index * @param data * @return * * @Override public boolean Add (int index, T data) {if (index<0| | Data==null) throw new NullPointerException ("Index < 0 | |

        data = null ");
        int j = 0;
        Dnode<t> front = This.head;
            Find the previous node where you want to insert the node while (Front.next!= null && J < index) {j + +;
        Front = Front.next; //Create the node that needs to be inserted, and let its front pointer point to front, and the successor pointer points to front.next dnode<t> q = new dnode<t> (data, front, front.ne

        XT);
        Empty double linked list inserts and tail inserts, without this action if (Front.next!= null) {//change Front.next's forward pointer front.next.prev = q;

        //Change front successor pointer front.next = q;
        Notice that the update tail points to the if (front==this.tail) {this.tail=q When the tail is inserted;
return true; }

Analysis and implementation of delete operation of double linked list
The deletion of the double linked list is similar to the principle of insert operation, we can see (a) (b) is the same case, need to prevent p.next.prev to throw the null pointer, and for (c) The situation is not related to the P.next.prev value, the deletion of the specific implementation is as follows:

/**
  * Delete the node * 1 according to the subscript *
  2. Remove the middle Delete *
  3. End deletion, update tail pointing
  * @param index subscript Starting value is 0
  * @return
 * * @Override Public
 T Remove (int index) {

     int size=length ();
     T Temp=null;

     if (index<0| | index>=size| | IsEmpty ()) {return
         temp;
     }

     Dnode<t> P=this.head;
     int j=0;
     Header Delete/end delete/middle Delete, find the node that needs to be deleted (the current node to be deleted is therefore i<=index) while
     (P!=null&&j<=index) {
         p=p.next;
         j + +;
     }
     This step
     if (p.next!=null) {
         P.next.prev=p.prev
     }
     is not required when the double linked list has only one node or the tail is deleted. P.prev.next=p.next;
     If it is the tail node if
     (p==this.tail) {
         this.tail = p.prev;//Update the point of the open point
     }
     temp=p.data;

     return temp;
 }

Analysis and implementation of double linked list's value-checking operation
The operation of the lookup value of a double linked list is no different from a single linked list, as long as you find the current node that you need to find to get its value, as follows:

The code implementation is as follows:

@Override public
T get (int index) {
    if (index>=0)
    {
        int j=0;
        Note that the starting node is This.head.next
        ///If the starting point is This.head, J's judgment is J<=index,
        //because the current node rather than the previous node is the one to look for.
        dnode<t> Pre=this.head.next;
        while (Pre!=null && j<index)
        {
            j + +;
            Pre=pre.next;
        }
        if (pre!=null) return
            pre.data
    }
    return null;
}

The Operation analysis and realization of the substitution value of double linked list
Double linked list of the replacement value process, you need to find the need to replace the node, this process is the same as the process of obtaining the value, find the node directly replace the value and return the old value can be. Simpler and more straightforward code:

@Override public
T Set (int index, T data) {
   T old=null;
   if (index>0&&data!=null) {
       int j=0;
       dnode<t> pre =this.head.next;
       Find where to replace while
       (Pre!=null&&j<index) {
           j + +;
           Pre=pre.next;
       }
       if (pre!=null) {
           old=pre.data;
           Replace data
           pre.data=data;
       }
   }
   return old;
}

Ok~, to this double linked list of the main operational implementation has been analyzed, the following gives the realization of the dual-linked list Source:

Package com.zejian.structures.LinkedList.doubleLinked;

Import com.zejian.structures.LinkedList.ILinkedList;
/** * Created by Zejian on 2016/10/23. * Double linked list, lead node (without data) Double linked list, for higher efficiency This class contains pointers to the tail tail/public class Headdoubleilinkedlist<t> implements Ilinkedlist <T> {protected dnode<t> head;///Without Data header node protected dnode<t> tail;//pointer to tail public headdoubleilink          Edlist () {this.head =this.tail= new dnode<> ();
     Initialize the header node}/** * Pass in an array and convert it to the list * @param array */public headdoubleilinkedlist (t[] array) {this ();
         if (array!=null && array.length>0) {this.head.next = new dnode<t> (array[0));
         Tail =this.head.next;
         Tail.prev=this.head;
         int i=1;
             while (i<array.length) {tail.next=new dnode<t> (array[i++]);
             Tail.next.prev=tail;
         tail = Tail.next; @Override public boolean IsEmpty ()}} Head.next==null;
     @Override public int Length () {int length=0;
     Dnode<t> Pre=head.next;
         while (pre!=null) {length++;
     Pre=pre.next;
 return length;
         @Override public T get (int index) {if (index>=0) {int j=0;
         Dnode<t> Pre=this.head.next;
             while (Pre!=null && J<index) {j + +;
         Pre=pre.next;
     } if (pre!=null) return pre.data;
 return null;
     @Override public T Set (int index, T data) {T old=null;
         if (index>0&&data!=null) {int j=0;
         dnode<t> pre =this.head.next;
             Find where to replace while (Pre!=null&&j<index) {j + +;
         Pre=pre.next;
             } if (pre!=null) {old=pre.data;
         Replace data pre.data=data;
 } return old; /** * Insert node * @param index
  * @param data * @return * * @Override public boolean Add (int index, T data) {if (index<0| | Data==null) throw new NullPointerException ("Index < 0 | |

         data = null ");
         int j = 0;
         Dnode<t> front = This.head;
             Find the previous node where you want to insert the node while (Front.next!= null && J < index) {j + +;
         Front = Front.next; //Create the node that needs to be inserted, and let its front pointer point to front, and the successor pointer points to front.next dnode<t> q = new dnode<t> (data, front, front.

         Next);  Empty double linked table inserts, you need to ensure that front.next is not empty if (Front.next!= null) {//change Front.next's forward pointer Front.next.prev
         = q;

         //Change front successor pointer front.next = q;
         Notice that the update tail points to the if (front==this.tail) {this.tail=q When the tail is inserted;
 return true; /** * Tail Add * @param data * @return * * @Override public boolean Add (T data) {if (data==null) r
     Eturn false; Create a new knotPoint, and point its forward pointer to tail dnode<t> q = new dnode<t> (data, tail, NULL);
     tail.next=q;
     Update tail node this.tail=q;
 return true;  /** * Delete the node * 1 according to the subscript * 2. Remove the center Delete * 3. Delete in the middle, update tail point * @param index subscript Starting value is 0 * @return * * * @Override public
     T Remove (int index) {int size=length ();

     T Temp=null; if (index<0| | index>=size| |
     IsEmpty ()) {return temp;
     } dnode<t> P=this.head;
     int j=0;
         Header Delete/end delete/middle Delete, find the node that needs to be deleted (the current node to be deleted is therefore i<=index) while (P!=null&&j<=index) {p=p.next;
     j + +;
     ///When a linked list is only a node, this step if (p.next!=null) {P.next.prev=p.prev is not required;
     } P.prev.next=p.next;

     If it is the tail node if (p==this.tail) {this.tail = p.prev;//Update the point of the open point} temp=p.data;
 return temp;
 /** * Deletes nodes based on data without having to store the previous node to delete the node like a one-way list * 1. Head Delete * 2. Middle Delete * 3. Tail Delete, update tail point * @param data * @return *

    @Override public boolean RemoveAll (T data) { Boolean isremove=false; if (data==null| |

     IsEmpty ()) return isremove;

     Note The starting point here, if the starting point for This.head, then the situation is different as the previous deletion based on the index to achieve dnode<t> p=this.head.next; Header Delete/end delete/middle Delete (size>1), find all nodes that need to be deleted while (P!=null) {if (Data.equals (P.data)) {if (p==this.ta
                 IL) {//If the end node is this.tail=p.prev;//to update the point p.prev=null of the node;
             This.tail.next=null;
                 }else {//If it is deleted in the middle, update the forward and subsequent pointers to the P.prev.next=p.next;
             P.next.prev=p.prev;
             } isremove=true;
         p=p.next;//continue to find}else {p=p.next;
 } return isremove;
     /** * Empty the list/@Override public void Clear () {this.head.next=null;
 This.tail=this.head;
     @Override public Boolean contains (T-data) {if (Data==null) {return false;
     } dnode<t> P=this.head.next; while (p!=null) {if (Data.equals (P.data)) {return true;
         }else {p=p.next;
 return false;
     @Override public String toString () {string str= "(";
     dnode<t> pre = This.head.next;
         while (pre!=null) {str = pre.data;
         Pre = Pre.next;
     if (pre!=null) str = ",";
 return str+ ")"; public static void Main (string[] args) {string[] letters={"A", "B", "C", "D", "Z", "E", "F"};//string[] Lette
     rs={"A"};

     headdoubleilinkedlist<string> list=new headdoubleilinkedlist<> (Letters);
     System.out.println ("List.get (3)->" +list.get (3));

     System.out.println ("list:" +list.tostring ());
     System.out.println ("List.add (4,y)->" +list.add (0, "Y"));
     System.out.println ("list:" +list.tostring ());
     System.out.println ("List.add (z)->" +list.add ("Z"));


     System.out.println ("list:" +list.tostring ()); System.out.println ("list.cOntains (z)-> "+list.contains (" Z "));
     System.out.println ("List.set (4,p)-->" +list.set (4, "P"));


     System.out.println ("list:" +list.tostring ());
System.out.println ("List.remove (6)-->" +list.remove (6));
     System.out.println ("List.remove (z)->" +list.removeall ("Z"));
 System.out.println ("list:" +list.tostring ()); }
}
design and implementation of cyclic double-linked list

If the next pointer field of the last node of the double linked list points to the head node, and the Prev pointer of the head node points to the last node of the head, the double linked list (circular doubly linkedlist) is formed, and the structure is illustrated as follows:

We no longer need the tail point node in the cyclic double linked list, because the whole list is already a loop, and the position of the tail node can be easily obtained at the head node heads. For the circular double linked list inserts, deletes the operation also does not need to distinguish the position operation situation, this is because the circular double linked list's own particularity, causes the p.next.pre never to be null, therefore we inserts and deletes when the code realization is relatively simple. Below we first analyze the circular double linked list insert operation, the following diagram:

We can see that (a) (b) (c) Three situations do not require a difference in position insertion, and the code is implemented as follows:

/**
 * According to index insert
 * Loop List no empty condition exists for either prev or next, so when added
 * Whether it's head or tail or medium, it is treated as a case
 * @param index
 * param data
 * @return * *
@Override public
boolean Add (int index, T data) {
    int size=length ();
    if (data==null| | index<0| | Index>=size) return
        false;

    int j=0;
    Dnode<t> P=this.head;
    Find the location of the insertion point while
    (P.next!=head&&j<index) {
        p=p.next;
        j + +;
    }

    Creates a new node, if index=3, then the insertion position is the 4th position
    dnode<t> q=new dnode<> (data,p,p.next);
    p.next=q;
    p.next.prev=q;

    return true;
}

The delete operation of the circular double linked list is illustrated as follows:

Similarly, from the graph we can also find that due to the characteristics of the cyclic double linked list, (a) (b) (c) Three cases do not need to distinguish between the operating position, the code implementation is as follows:

@Override public
T-Remove (int index) {
    T old = null;
    int size=length ();

    if (index<0| | Index>=size) return to old
        ;

    int j=0;
    Dnode<t> P=this.head.next;

    while (P!=head && j<index)
    {
        j + +;
        p = p.next;
    }

    if (P!=head)
    {old
        = P.data;
        P.prev.next = P.next;
        P.next.prev = P.prev;
    }
    return old;
}

As for the lookup value of the cyclic double linked list, the substitution value and so on are not much different from the double linked list, but what needs special attention is that when traversing the double linked list of loops, the ending flag is no longer the trailing node is empty, but the next pointer of the trailing node points to the head node heads. OK, here we give the implementation code of the cyclic double linked list:

package com.zejian.structures.LinkedList.doubleLinked;

Import com.zejian.structures.LinkedList.ILinkedList;
/** * Created by Zejian on 2016/10/24. * Cycle double linked list, with short node (excluding data), circular list can not need tail pointer/public class Loopheaddilinkedlist<t> implements ilinkedlist<t> {Prote CTED dnode<t> Head; Head node//protected dnode<t> tail with no data;
     The pointer to the tail is public loopheaddilinkedlist () {this.head = new dnode<> ();//initialization header node This.head.next=head;

 This.head.prev=head;
     /** * Pass in an array, convert to list * @param array/public loopheaddilinkedlist (t[] array) {this ();
         if (array!=null && array.length>0) {dnode<t> p= new dnode<> (array[0));
         head.next=p;
         Head.prev=p;
         P.prev=head;

         P.next=head;
         int i=1; while (i<array.length) {p.next=new dnode<> (ar 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.