Singly linked list - Java implementation

Table of contents

concept

What is a linked list?

Why can't the head node of the linked list move or operate?

What is the difference between linked list and array?

accomplish

node

Single list

add at the end

traverse

Add by number:

modify node

delete

interview questions

Find the length of a singly linked list

Find the Kth node from the bottom of the singly linked list

Find the common node of two linked lists, if there are more than one, return the first one.

Reversal of singly linked list

Print the nodes of a singly linked list from tail to head

Merge two ordered singly linked lists, still order after merging


concept

What is a linked list?

A linked list is a data structure that contains data fields and pointer fields, and is stored in the form of nodes. It is discontinuous in memory, and it is divided into leading nodes and non-leading nodes.

Why can't the head node of the linked list move or operate?

The operation of the linked list is based on the head node. If the head node is lost, the entire linked list will be lost.

What is the difference between linked list and array?

Linked lists are not contiguous in memory, while arrays are contiguous.

The insertion and deletion of linked lists are more efficient than arrays, and the traversal and modification of arrays are better than linked lists.

A linked list consumes twice the memory of an array in terms of space.

The linked list supports dynamic expansion, and the length of the array is fixed when it is initialized.


accomplish

node

Before implementing the singly linked list, first construct a linked list node HeroList. Here we take Marvel heroes as an example. The hero role has number no, name name, and sex sex. We define no, name and sex as data fields, and no is the primary key, unique It cannot be changed, which is convenient for us to modify and search. It is also necessary to define a next pointer field to point to the next node.

Below we implement the node through the Java language:

//链表节点类
class HeroList {
    int no;
    String name;
    boolean sex;
    HeroList next;

    public HeroList(int no, String name, boolean sex) {
        this.no = no;
        this.name = name;
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "HeroList{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", sex=" + sex +
                '}';
    }
}

Single list

With the nodes, we can use the next pointer to connect the nodes in series and assemble them into a singly linked list. This singly linked list should contain a head node, indicating the start, and various operation functions, which can search, modify, traverse, delete, add, etc. this singly linked list.

add at the end

Below we implement the addition of a singly linked list through the Java language:

class SingleLinkedList {
    //我们需要定义一个head节点,表示链表的开始,head节点不能动,数据域不存放数据,丢失head节点,链表则会丢失
    HeroList head = new HeroList(0, "", false);


    //在末尾添加节点
    public void addAtEnd(HeroList hero) {
    //因为头节点,不能动,我们需要一个临时节点来操作
        HeroList temp = head;
    //需要遍历,找到末尾节点
        while (true) {
            if (temp.next == null) //到末尾了
                break;
    //temp后移
            temp = temp.next;
        }

    //循环结束,temp就是末尾节点
        temp.next = hero;
    }
}

traverse

The Java language implements the traversal of a singly linked list :

    //链表的遍历
    public void listLinked() {
        //如果链表为null,无须遍历
        if (head.next == null) {
            System.out.println("链表为null");
            return;
        }
        //链表不为null,通过一个临时节点遍历链表
        HeroList temp = head.next;
        while (temp != null) {
            System.out.println(temp);
            temp = temp.next;
        }
    }

Add by number:

The Java language realizes the bitwise addition of a singly linked list :

    //按编号添加节点,如果编号已存在,添加失败
    public void addByNo(HeroList hero){
        //1:需要一个临时节点temp来操作
        HeroList temp = head;
        //待添加的节点是否存在,默认不存在
        boolean flag  = false;
        //2:遍历单链表
        while (true){
            if(temp.next==null) {//找到末尾,没找到,插入到末尾
                break;
            }
            if(temp.next.no>hero.no)//找到待添加的位置了,是temp的后面
            {
                break;
            }
            if(temp.next.no==hero.no){//已存在,添加失败
                flag = true;
                break;
            }
            //temp后移
            temp = temp.next;
        }

        if(flag){
            System.out.printf("待添加的节点%d已存在\n",hero.no);
        }else{
            //此时,将hero.next指向temp.next;
            hero.next = temp.next;
            //再将temp.next指向hero
            temp.next = hero;
        }
    }

modify node

The Java language implements the modification of the singly linked list :

The modification here refers to modifying the data field of the node according to the number.

 //修改节点
    public  void updateLinked(HeroList hero)
    {
         HeroList temp = head;
         //是否找到待修改的节点
         boolean flag = false;
         while (true){
             if(temp.next == null){//遍历到末尾了,还没找到
                 break;
             }
             if(temp.next.no == hero.no){//找到了,temp.next节点
                 flag = true;
                 break;
             }
             //temp后移
             temp = temp.next;
         }

         if(flag){
             temp.next.name = hero.name;
             temp.next.sex = hero.sex;
         }else
             System.out.println("待修改的节点不存在");

    }

delete

The Java language implements the deletion of a singly linked list :

Delete the singly linked list according to the node number. If the singly linked list is null, the deletion will fail.

//根据编号删除节点
    public  void delByNo(int no){
        HeroList temp = head;
        if(temp.next==null){
            System.out.println("链表为null,无法删除");
            return;
        }
        //是否找到待删除的节点,默认没找到
        boolean flag = false;
        while (true){
            if(temp.next == null){//找到末尾了,还没找到
                break;
            }
            if(temp.next.no==no){//找到了
                flag = true;
                break;
            }
            temp= temp.next;
        }

        if(flag)
            temp.next = temp.next.next;
        else
            System.out.printf("待删除的节点不存在%d",no);
    }

interview questions

Find the length of a singly linked list

    //1:求单链表的长度,或者单链表的有效长度
    //给定一个单链表的头节点,返回单链表的长度
    public static int getLength(HeroList head){
        int length = 0;
        if(head.next==null){
            return length;
        }
        //开始遍历
        HeroList temp = head;
        while (temp.next!=null){
            length++;
            temp = temp.next;
        }
        return length;
    }

Find the Kth node from the bottom of the singly linked list

    //2:求单链表单数第k个结点
    //如果节点存在,返回节点,不存在返回null
    public static HeroList getKNode(HeroList head,int k){
        //求单链表倒数第K个节点,就是遍历到length-K位置的节点,用一个for循环
        //k的范围应该大于0,小于length
        int size = getLength(head);
        if(k>size||k<0){
            return null;
        }
        HeroList temp = head.next;
        for(int i = 0;i<size-k;i++){
            temp = temp.next;
        }
        return temp;
    }

}

Find the common node of two linked lists, if there are more than one, return the first one.

    //给定2个单链表的头节点,求这两个单链表的公共部分,并且返回,如果没有公共部分,返回null
    public HeroList getPublicPart(HeroList head1,HeroList head2){
        //要找两个单链表的公共部分,首先要遍历,如何一次遍历,就找到公共节点呢?
        //这里的思路是链表A遍历到末尾后,指向链表B的头节点,链表B遍历到末尾后,指向链表A的头节点,这样子,2个链表的
        //速度一样,路程一样,当两个指针相遇的时候,就是公共部分的起始节点。如果循环,结束,没有相遇的指针,p1和p2都在末尾,
        //为null,直接返回即可。
        //代码如下:
        HeroList p1 = head1;
        HeroList p2 = head2;
        
        while (p1!=p2){
            p1 = (p1==null)?p2:p1.next;
            p2 = (p2==null)?p1:p2.next;
        }
        return p1;
    }

Reversal of singly linked list

    //3:单链表的反转
    public static void reverseLinked(HeroList head){
        //思路,
        //如果单链表为null或者节点数目为1,无需反转
        if(head==null||head.next==null)
            return;

        // 需要三个指针,第一个辅助节点cur,用来遍历头节点,指向head.next
        HeroList cur = head.next;
        //第二个指针,next,用来保存/备份cur节点的下一个节点,在操作过程中,不丢失原链表
        HeroList next;
        //第三个指针,reverse,新链表的头节点
        HeroList reverse = new HeroList(0,"",false);

        //开始遍历原链表
        while (cur!=null){
            //备份cur.next
            next = cur.next;
            //断开cur,并放到reverse.next的前面
            cur.next = reverse.next;
            //将cur链接到reverse的后面
            reverse.next = cur;
            //cur后移
            cur = next;
        }

        //原链表的头,指向reverse的下一个节点
        head.next = reverse.next;
    }

Print the nodes of a singly linked list from tail to head

Method 1: Reverse the singly linked list, and then traverse the output, not recommended, it will change the structure of the original linked list

Method 2: Traverse the original linked list, push it into the stack, and pop it out.

    //4:从尾到头,打印单链表
    public static void printEtoFLinked(HeroList head){
        if(head.next==null)
            return;

        Stack<HeroList> stack  = new Stack<>();
        HeroList temp = head.next;
        while (temp!=null){
            stack.push(temp);
            temp = temp.next;
        }

        while (stack.size()>0){
            System.out.println(stack.pop());
        }
    }

Merge two ordered singly linked lists, still order after merging

 //合并2个有序的单链表,合并后依然有序
    public static HeroList mergeLinked(HeroList hero1,HeroList hero2){
        HeroList temp1 = hero1.next;
        HeroList temp2 = hero2.next;
        //1第一步先判断
        if (temp1 == null && temp2 == null)
            return null;
        if (temp1 == null)
            return temp2;
        if (temp2 == null)
            return temp1;

        //2定义新链表的firstNode,LastNode;
        HeroList firstNode;
        HeroList lastNode;

        //3比较待合并链表的值,设置新链表的首节点和尾节点,并且temp后移
        if(temp1.no<temp2.no){
            firstNode = temp1;
            lastNode  = temp1;
            temp1 = temp1.next;
        }else {
            firstNode = temp2;
            lastNode  = temp2;
            temp2 = temp2.next;
        }

        //4开始循环,循环终止条件是temp1并且temp2不为null
        while (temp1!=null && temp2!=null){
            //循环的目的依次比较,将较小的节点添加到新链表的lastNode
            if(temp1.no<temp2.no){
                lastNode.next = temp1;
                lastNode = temp1;
                temp1 = temp1.next;
            }else{
                lastNode.next = temp2;
                lastNode = temp2;
                temp2 = temp2.next;
            }
        }
        //5循环结束,判断temp1或者temp2是否为null,将一方不为null的节点保存到新链表的lastNode
        if(temp1==null){
            lastNode.next = temp2;
        }else{
            lastNode.next = temp1;
        }

        return firstNode;
    }

Guess you like

Origin blog.csdn.net/qq_34123324/article/details/132306725