Java data structure - single linked list

Posted by chuddyuk on Thu, 27 Jan 2022 12:06:44 +0100

What is a linked list

The data structure of array is continuous storage space. Because the space is continuous, the efficiency of accessing is very high, but the efficiency of deleting and inserting data at the same time is very low. Therefore, the concept of linked list is proposed Unlike arrays, linked lists are not stored continuously. The following figure shows the storage space of linked lists It can be found that a1 is not at the highest address (110), but next points to the next data a2 This is the characteristic of the linked list. The data address of the data field is discontinuous and depends on the pointer field next to point to the next element

1) Linked list is stored in the form of nodes, which is chain storage
2) Each node contains data field and next field: point to the next node
3) The nodes of the linked list are not necessarily stored continuously
4) The linked list is divided into the linked list with the leading node and the linked list without the head node, which is determined according to the actual needs

1, Basic structure of single linked list

C/C + + version linked list
Implement the data field and next pointer field according to the above provisions. Unlike C/C + + language, Java does not have pointer symbol *, but passes the address by object reference, because an object itself can call the method of its class and access member data, which realizes the effect of similar structure and pointer

class LinkedList_ implements Cloneable{
    public int data;
    public String name;
    public LinkedList_ next;
    public LinkedList_(int data,String name) {
        this.data = data;
        this.name = name;
    }
    @Override
    public LinkedList_ clone()
    {
        LinkedList_ temp=null;
        try {
            //If the class does not implement the clonable interface, an exception will be thrown
            temp = (LinkedList_)super.clone();//Copy the basic message in the parent class first\
            temp.next=null;
            //Then, if there are some mutable objects (such as Date) in the subclass, you need to make a deep copy
            //temp.date = (Date)new Date().clone(); As follows
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return temp;
    }
    @Override
    public String toString() {
        return "LinkedList_{" +
                "data=" + data +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        LinkedList_ list = (LinkedList_) o;
        return data == list.data && Objects.equals(name, list.name) ;
    }

    @Override
    public int hashCode() {
        return Objects.hash(data, name, next);
    }
}

2, Function realization

  • 1: Add element 2: delete element 3: modify element 4: query element
  • 5: Merge two single linked lists 6: reverse single linked list
  • 7: Get the penultimate element 8: query in reverse order

Add element

public void add(LinkedList_ list)//Sort by element size
    {
        boolean flag=false;//Judge whether the element has flag bit
        LinkedList_ temp=head;//Head is the head pointer of the current linked list
        while(temp.next!=null){//Due to the existence of a header pointer, it is necessary to judge the temp Next instead of temp
            if(temp.next.data>list.data){//Determine the size of existing elements and inserted elements
                break;  //If the inserted element is smaller, exit the loop directly to prepare for insertion
            }
            else if(temp.next.data==list.data){//Determine whether the element already exists
                flag=true;
                break;
            }
            temp=temp.next;
        }
        if(flag){
            System.out.println("The current element already exists");
        }else{
            list.next=temp.next;//Element insertion
            temp.next=list;
        }
    }

Delete element

public void delete(LinkedList_ dellist)//Delete an element
    {
        if(head.next==null){ //First judge whether the linked list is empty
            System.out.println("The linked list is empty");
            return;
        }
        LinkedList_ temp=head;
        while(temp.next!=null){ //First determine whether the next element exists 
            if(temp.next.equals(dellist)){ //Determine whether it is an element to be deleted after it exists
                temp.next=temp.next.next;//If so, direct the pointer to the next element to be deleted
                break;  //After that, you just need to wait for Java's garbage collection mechanism to actively recycle
            }
            temp=temp.next; //If it is not an element to be deleted, the pointer is down
        }
    }

Modify element

    public void update(LinkedList_ newlist)//Modify according to the data of newlist
    {
        if(head.next==null){
            System.out.println("The linked list is empty");
            return;
        }
        LinkedList_ temp=head;
        while(temp.next!=null){ //If the data field of the element to be deleted is encountered
            if(newlist.data==temp.next.data){ //Then modify its name field
                temp.next.name= newlist.name;
            }
            temp=temp.next; //It doesn't just point to the next element
        }
    }

ergodic

 public void traverse()//Traversal single linked list
    {
        if(head.next==null){
            System.out.println("The linked list is empty");
            return;
        }
        LinkedList_ temp=head;
        while(temp.next!=null){
            System.out.println(temp.next);
            temp=temp.next;
        }
    }

Fusion linked list

    public void addTwoOrderedList(SingleLinkedList otherList)//Connect two single linked lists
    {
//        boolean flag=false;
        LinkedList_ list=otherList.head.next;

        while(list!=null) {//In fact, it is to traverse the linked list to be added first 
            LinkedList_ temp=this.head; //Then add the linked list to the original single linked list according to the add method
            boolean flag=false;
            while (temp.next != null) {
                if (temp.next.data > list.data) {
                    break;
                } else if (temp.next.data == list.data) {
                    flag = true;
                    break;
                }
                temp = temp.next;
            }
            if (flag) {
                System.out.println("The current element already exists");
            } else {
                //This shows that list is better than temp Next small
                //The clone method is used to prevent the pointer field of the original list from being connected
                LinkedList_ newlist = (LinkedList_) list.clone();
//                LinkedList_ newlist=new LinkedList_(list.data,list.name);
                LinkedList_ next = temp.next;
                temp.next=newlist;
                newlist.next=next;
            }
            list=list.next;
        }
    }

Invert element

  public SingleLinkedList reverse()//reversal
    {
        SingleLinkedList newlist=new SingleLinkedList();
        LinkedList_ cur = this.head.next; //First valid data
        LinkedList_ temphead = newlist.head;
        LinkedList_ tempnext = null;
        //The first method is inefficient inversion, but the original single linked list will not be destroyed
        //Method 1 idea: two for loops, and the outer for loop is used to indicate that several elements have been traversed
        //The inner for loop is used to point the element to the last element to be inserted
        //For example, if the outer layer is for i=0 for the first time, the inner layer needs to perform the maximum number of times of temp = temp next;  //
        //Then you can get the last element, the second time you can get the penultimate element, and so on
//        int length = this.getLength();
//        for(int i=0;i<length;i++) { //length=6
//        LinkedList_ temp= this.head; //0 0 1 2 3 4 5
//            for(int j=length;j>i;j--) {
//                temp=temp.next;  //
//            }
//            temphead.next=temp.clone();
//            temphead=temphead.next;
//        }
//        temphead.next=null;
        //Method 2 is more efficient inversion, but the single linked list calling this function will be destroyed
        while(cur!=null){
            tempnext=cur.next;
            cur.next=temphead.next;
            temphead.next=cur;
            cur=tempnext;
        }
        //Method 3 stores the traversed elements in the array according to the method
        //Then insert the elements of the array into the new linked list in reverse order 
        return newlist;
    }

Get the x-th element in reverse order

public LinkedList_ getLastIndexNode(int lastIndex)//Get the last x data element
    {
        if(head.next==null||(this.getLength()<lastIndex)||lastIndex<0){
            System.out.println("The linked list is empty/Unreasonable query data index");
            return null;
        }
        LinkedList_ temp=head.next; //First valid data to U-turn pointer
        int time=this.getLength()-lastIndex;//Gets the number of times this element needs to be traversed
        for(int i=0;i<time;i++){
            temp=temp.next;
        }
        return temp;
    }

Reverse traversal

public void reverseTraverse()//Reverse traversal
    {
        //Method go through the linked list and add the data to the linked list, and then output the linked list in reverse order
//        int i=this.getLength();
//        LinkedList_ temp=head;
//        LinkedList_[]listArr=new LinkedList_[i];
//        while(temp.next!=null){
//            listArr[--i]=temp.next;
//            temp=temp.next;
//        }
//        System.out.println(Arrays.toString(listArr));
        //Method 2: direct traversal
//        for(int j=0;j<this.getLength();j++){
//            LinkedList_ temp=head;
//           for(int k=this.getLength();k>j;k--){
//               temp=temp.next;
//           }
//            System.out.println(temp);
//        }
        //Method 3: use stack
        Stack<LinkedList_> stack = new Stack<>();
        LinkedList_ temp=this.head.next;
        while(temp!=null){
            stack.add(temp);
            temp=temp.next;
        }
        while(stack.size()>0){
            System.out.println(stack.pop());
        }
    }

Complete code

package algorithm.DataStruct.LinkList;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Objects;
import java.util.Stack;

/**
 * @author: Serendipity
 * Date: 2022/1/25 21:11
 * Description:
 * 1:Add element 2: delete element 3: modify element 4: query element
 * 5:Merge two single linked lists 6: reverse single linked list 7: get the penultimate element 8: reverse order query
 */
public class SingleLinkedList{

    public static void main(String[] args) {
        functionChoose();
    }

    private final LinkedList_ head=new LinkedList_(0,"");
    public LinkedList_ getHead(){
        return head.next;
    }
    public static void functionChoose()
    {
        SingleLinkedList list1 = new SingleLinkedList();
        SingleLinkedList list2 = new SingleLinkedList();
        try(BufferedReader br=new BufferedReader(new InputStreamReader
                (System.in))){
            while (true){
                System.out.println("Function selection");
                System.out.println("1:Sequential insertion");
                System.out.println("2:Delete element");
                System.out.println("3:Modify element");
                System.out.println("4:Display element");
                System.out.println("5:Reverse linked list");
                System.out.println("6:Get reciprocal x Element of");
                System.out.println("7:Reverse traversal");
                System.out.println("8:Merge two linked lists");
                System.out.println("9:sign out");
                int choose = Integer.parseInt(br.readLine());
                switch (choose){
                    case 1->{
                        System.out.println("Select the linked list number 1 to insert/2");
                        choose = Integer.parseInt(br.readLine());
                        switch (choose){
                            case 1->{
                                System.out.println("Enter the data to insert data And name");
                                list1.add(new LinkedList_(Integer.parseInt(br.readLine()),
                                        br.readLine()));
                                break;
                            }default -> {
                                System.out.println("Enter the data to insert data And name");
                                list2.add(new LinkedList_(Integer.parseInt(br.readLine()),
                                        br.readLine()));
                            }
                        }
                        break;
                    }
                    case 2->{
                        System.out.println("Select the linked list number 1 to delete the data/2");
                        choose = Integer.parseInt(br.readLine());
                        switch (choose){
                            case 1->{
                                System.out.println("Enter data to delete data And name");
                                list1.delete(new LinkedList_(Integer.parseInt(br.readLine()),
                                        br.readLine()));
                                break;
                            }default -> {
                                System.out.println("Enter data to delete data And name");
                                list2.delete(new LinkedList_(Integer.parseInt(br.readLine()),
                                        br.readLine()));
                            }
                        }
                        break;
                    }
                    case 3->{
                        System.out.println("Select the linked list number 1 to modify the data/2");
                        choose = Integer.parseInt(br.readLine());
                        switch (choose){
                            case 1->{
                                System.out.println("Enter the data to modify data,And enter a new name");
                                list1.update(new LinkedList_(Integer.parseInt(br.readLine()),
                                        br.readLine()));
                                break;
                            }default -> {
                                System.out.println("Enter the data to modify data,And enter a new name");
                                list2.update(new LinkedList_(Integer.parseInt(br.readLine()),
                                        br.readLine()));
                            }
                        }
                        break;
                    }
                    case 4->{
                        System.out.println("Select the linked list number 1 of the data to query/2");
                        choose = Integer.parseInt(br.readLine());
                        switch (choose){
                            case 1->{
                                list1.traverse();
                                break;
                            }default -> {
                                list2.traverse();
                            }
                        }
                        break;
                    }
                    case 5->{
                        System.out.println("Select the linked list number 1 to reverse the data/2");
                        choose = Integer.parseInt(br.readLine());
                        switch (choose){
                            case 1->{
                                list1.reverse();
                                break;
                            }default -> {
                                list2.reverse();
                            }
                        }
                        break;
                    }
                    case 6->{
                        System.out.println("Select the linked list number 1 of the reciprocal data to query/2");
                        choose = Integer.parseInt(br.readLine());
                        switch (choose){
                            case 1->{
                                System.out.println("Enter reciprocal data");
                                choose = Integer.parseInt(br.readLine());
                                System.out.println(list1.getLastIndexNode(choose));
                                break;
                            }default -> {
                                System.out.println("Enter reciprocal data");
                                choose = Integer.parseInt(br.readLine());
                                System.out.println(list2.getLastIndexNode(choose));
                            }
                        }
                        break;
                    }
                    case 7->{
                        System.out.println("Select the linked list number 1 to traverse the data in reverse order/2");
                        choose = Integer.parseInt(br.readLine());
                        switch (choose){
                            case 1->{
                                list1.reverseTraverse();
                                break;
                            }default -> {
                                list2.reverseTraverse();
                            }
                        }
                        break;
                    }
                    case 8->{
                        list1.addTwoOrderedList(list2);
                        break;
                    }
                    case 9->System.exit(0);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public void add(LinkedList_ list)//Sort by element size
    {
        boolean flag=false;//Judge whether the element has flag bit
        LinkedList_ temp=head;//Head is the head pointer of the current linked list
        while(temp.next!=null){//Due to the existence of a header pointer, it is necessary to judge the temp Next instead of temp
            if(temp.next.data>list.data){//Determine the size of existing elements and inserted elements
                break;  //If the inserted element is smaller, exit the loop directly to prepare for insertion
            }
            else if(temp.next.data==list.data){//Determine whether the element already exists
                flag=true;
                break;
            }
            temp=temp.next;
        }
        if(flag){
            System.out.println("The current element already exists");
        }else{
            list.next=temp.next;//Element insertion
            temp.next=list;
        }
    }
    public void addTwoOrderedList(SingleLinkedList otherList)//Connect two single linked lists
    {
//        boolean flag=false;
        LinkedList_ list=otherList.head.next;

        while(list!=null) {//In fact, it is to traverse the linked list to be added first
            LinkedList_ temp=this.head; //Then add the linked list to the original single linked list according to the add method
            boolean flag=false;
            while (temp.next != null) {
                if (temp.next.data > list.data) {
                    break;
                } else if (temp.next.data == list.data) {
                    flag = true;
                    break;
                }
                temp = temp.next;
            }
            if (flag) {
                System.out.println("The current element already exists");
            } else {
                //This shows that list is better than temp Next small
                //The clone method is used to prevent the pointer field of the original list from being connected
                LinkedList_ newlist = (LinkedList_) list.clone();
//                LinkedList_ newlist=new LinkedList_(list.data,list.name);
                LinkedList_ next = temp.next;
                temp.next=newlist;
                newlist.next=next;
            }
            list=list.next;
        }
    }
    public void traverse()//Traversal single linked list
    {
        if(head.next==null){
            System.out.println("The linked list is empty");
            return;
        }
        LinkedList_ temp=head;
        while(temp.next!=null){
            System.out.println(temp.next);
            temp=temp.next;
        }
    }
    public void update(LinkedList_ newlist)//Modify according to the data of newlist
    {
        if(head.next==null){
            System.out.println("The linked list is empty");
            return;
        }
        LinkedList_ temp=head;
        while(temp.next!=null){ //If the data field of the element to be deleted is encountered
            if(newlist.data==temp.next.data){ //Then modify its name field
                temp.next.name= newlist.name;
            }
            temp=temp.next; //It doesn't just point to the next element
        }
    }
    public void delete(LinkedList_ dellist)//Delete an element
    {
        if(head.next==null){ //First judge whether the linked list is empty
            System.out.println("The linked list is empty");
            return;
        }
        LinkedList_ temp=head;
        while(temp.next!=null){ //First determine whether the next element exists
            if(temp.next.equals(dellist)){ //Determine whether it is an element to be deleted after it exists
                temp.next=temp.next.next;//If so, direct the pointer to the next element to be deleted
                break;  //After that, you just need to wait for Java's garbage collection mechanism to actively recycle
            }
            temp=temp.next; //If it is not an element to be deleted, the pointer is down
        }
    }
    public int getLength() //Get the length of single linked list
    {
        int size=0;
        LinkedList_ temp=head.next;
        while(temp!=null){
            size++;
            temp=temp.next;
        }
        return size;
    }
    public LinkedList_ getLastIndexNode(int lastIndex)//Get the last x data element
    {
        if(head.next==null||(this.getLength()<lastIndex)||lastIndex<0){
            System.out.println("The linked list is empty/Unreasonable query data index");
            return null;
        }
        LinkedList_ temp=head.next; //First valid data to U-turn pointer
        int time=this.getLength()-lastIndex;//Gets the number of times this element needs to be traversed
        for(int i=0;i<time;i++){
            temp=temp.next;
        }
        return temp;
    }
    public void reverseTraverse()//Reverse traversal
    {
        //Method go through the linked list and add the data to the linked list, and then output the linked list in reverse order
//        int i=this.getLength();
//        LinkedList_ temp=head;
//        LinkedList_[]listArr=new LinkedList_[i];
//        while(temp.next!=null){
//            listArr[--i]=temp.next;
//            temp=temp.next;
//        }
//        System.out.println(Arrays.toString(listArr));
        //Method 2: direct traversal
//        for(int j=0;j<this.getLength();j++){
//            LinkedList_ temp=head;
//           for(int k=this.getLength();k>j;k--){
//               temp=temp.next;
//           }
//            System.out.println(temp);
//        }
        //Method 3: use stack
        Stack<LinkedList_> stack = new Stack<>();
        LinkedList_ temp=this.head.next;
        while(temp!=null){
            stack.add(temp);
            temp=temp.next;
        }
        while(stack.size()>0){
            System.out.println(stack.pop());
        }
    }
    public SingleLinkedList reverse()//reversal
    {
        SingleLinkedList newlist=new SingleLinkedList();
        LinkedList_ cur = this.head.next; //First valid data
        LinkedList_ temphead = newlist.head;
        LinkedList_ tempnext = null;
        //The first method is inefficient inversion, but the original single linked list will not be destroyed
        //Method 1 idea: two for loops, and the outer for loop is used to indicate that several elements have been traversed
        //The inner for loop is used to point the element to the last element to be inserted
        //For example, if the outer layer is for i=0 for the first time, the inner layer needs to perform the maximum number of times of temp = temp next;  //
        //Then you can get the last element, the second time you can get the penultimate element, and so on
//        int length = this.getLength();
//        for(int i=0;i<length;i++) { //length=6
//        LinkedList_ temp= this.head; //0 0 1 2 3 4 5
//            for(int j=length;j>i;j--) {
//                temp=temp.next;  //
//            }
//            temphead.next=temp.clone();
//            temphead=temphead.next;
//        }
//        temphead.next=null;
        //Method 2 is more efficient inversion, but the single linked list calling this function will be destroyed
        while(cur!=null){
            tempnext=cur.next;
            cur.next=temphead.next;
            temphead.next=cur;
            cur=tempnext;
        }
        //Method 3 stores the traversed elements in the array according to the method
        //Then insert the elements of the array into the new linked list in reverse order
        return newlist;
    }
}
class LinkedList_ implements Cloneable{
    public int data;
    public String name;
    public LinkedList_ next;
    public LinkedList_(int data,String name) {
        this.data = data;
        this.name = name;
    }
    @Override
    public LinkedList_ clone()
    {
        LinkedList_ temp=null;
        try {
            //If the class does not implement the clonable interface, an exception will be thrown
            temp = (LinkedList_)super.clone();//Copy the basic message in the parent class first\
            temp.next=null;
            //Then, if there are some mutable objects (such as Date) in the subclass, you need to make a deep copy
            //temp.date = (Date)new Date().clone(); As follows
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return temp;
    }
    @Override
    public String toString() {
        return "LinkedList_{" +
                "data=" + data +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        LinkedList_ list = (LinkedList_) o;
        return data == list.data && Objects.equals(name, list.name) ;
    }

    @Override
    public int hashCode() {
        return Objects.hash(data, name, next);
    }
}

summary

Because the data of the single linked list is discontinuous, and if you need to insert and delete elements, you only need to change the pointer. Therefore, the efficiency of re insertion and deletion is higher than that of the array. However, because the array can directly use the index to access the elements, the element access efficiency of the array is higher Therefore, the use of these two data structures should select the best requirements

Topics: Java data structure linked list