随插随删的链表,Java模拟链表,操作链表,反转链表,合并两个链表并排序

1.认识链表

链表相较于数组,除了基本的数据域,还增加了指针域用于构建链式存储数据。

链表的每一个节点包含此节点的数据+指向下一节点地址的指针

对链表中的节点进行增加和删除时,只需要对上一节点指针地址进行修改,其他节点无需变动。所以链表增加、删除效率高,查找效率低。

对链表指针域进行反向连接,可形成双向链表或者循环链表

2.Java模拟链表

初始化链表时,定义一个头指针head(-1,head.next=null)用它来判断链表是否为NULL。

这个头指针不是节点,打印链表时也不能带它,他只是个辅助指针。

向链表中添加第一个节点的情况

向链表中两个节点间添加节点情况

删除链表中一个值为x的节点

通过ListNode类模拟链表

class ListNode{
    int data;
    ListNode next;
    static ListNode head = new ListNode(-1);    //head.next=null
    ListNode(int val){
        this.data=val;
    }
    //将y插入到x的前面
    void insert(int x,int y){
        ListNode node = head;
        ListNode newNode = new ListNode(y);
        int sign = 0;
        while(node.next!=null){
            if(node.next.data==x){
                newNode.next=node.next;
                node.next=newNode;
                sign=1;
                break;
            }
            node = node.next;
        }
        if(sign==0){
            node.next=newNode;
        }
    }
    //删除data=x的节点
    void delete(int x){
        ListNode node =head;
        while(node.next!=null){
            if(node.next.data==x){
                node.next = node.next.next;
                break;
            }
            node=node.next;
        }
    }
}

带输入输出条件来操作链表

输入: 3 操作次数i=3 
insert 0 1 行为:在节点值为0的前面插入值为1的节点 
insert 0 2 
insert 0 3 
输出: 1 2 3 打印链表 

代码:

import java.util.Scanner;
/**
 * 通过ListNode类模拟链表
 */
public class ListNode1 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入操作次数i");
        int i = sc.nextInt();
        ListNode ln = new ListNode();
        for(;i>=0;i--){
            String str = sc.nextLine();
            String[] strArr = str.split(" ");
            switch(strArr[0]){
                case "insert":
                ln.insert(Integer.parseInt(strArr[1]), Integer.parseInt(strArr[2]));
                break;
                case "delete":
                ln.delete(Integer.parseInt(strArr[1]));
                break;
            }
        }
        ListNode node = ln.head;
        if(node.next==null){
            System.out.println("NULL");
            return;
        }
        while(node.next!=null){
            System.out.print(node.next.data+" ");
            node=node.next;
        }

    }
}
class ListNode{
    int data;
    ListNode next;
    static ListNode head = new ListNode(-1);    //head.next=null
    ListNode(){}
    ListNode(int val){
        this.data=val;
    }
    //将y插入到x的前面
    void insert(int x,int y){
        ListNode node = head;
        ListNode newNode = new ListNode(y);
        int sign = 0;
        while(node.next!=null){
            if(node.next.data==x){
                newNode.next=node.next;
                node.next=newNode;
                sign=1;
                break;
            }
            node = node.next;
        }
        if(sign==0){
            node.next=newNode;
        }
    }
    //删除data=x的节点
    void delete(int x){
        ListNode node =head;
        while(node.next!=null){
            if(node.next.data==x){
                node.next = node.next.next;
                break;
            }
            node=node.next;
        }
    }
} 

3.Java反转链表

输入: {1,2,3} 
输出: {3,2,1} 

方法一

思路:

  • 先通过createListNode方法将输入数据用链表串起来

  • 然后通过ReverseList方法,传入链表真正的第一个节点head(ln.head.next)

  • 令新链表的头结点newNode=null,每访问原链表节点都让它成为新链表的头结点(head.next=newNode,newNode=head)

  • 需要注意,在摘下原链表的每一个节点时,保存该节点的下一个节点(temp=head.next),在head成为新链表的头节点后,将原链表的头节点设为temp(head=temp)

代码

import java.util.Scanner;

public class reListNode2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入初始链表,例如{1,2,3}");
        String str = sc.nextLine();
        str = str.substring(1, str.length()-1);
        String[] strArr = str.split(",");
        ListNode ln = new ListNode();
        createListNode(ln,strArr);
        ListNode head =ln.head.next;
        ReverseList(head);
    }

    //反转链表
     private static void ReverseList(ListNode head) {
            ListNode newNode = null;
            while(head!=null){
                ListNode temp = head.next;
                head.next=newNode;
                newNode=head;
                head=temp;
            }
            //反转后打印链表{3,2,1}
            System.out.print("{");
            while(newNode!=null){
                if(!(newNode.next==null)){
                    System.out.print(newNode.data+",");
                    newNode=newNode.next;
                }else{
                    System.out.print(newNode.data);
                    newNode=newNode.next;
                }
            }
            System.out.print("}");
        }

    //构造链表
    private static void createListNode(ListNode ln, String[] strArr) {
        if(strArr[0].equals("")){ 
        }else{
            ListNode node = ln.head;
            int i=0;
            while(i<strArr.length){
                ListNode newNode = new ListNode(Integer.parseInt(strArr[i]));
                node.next=newNode;
                node=newNode;
                i++;
            }
        }
    }

}

class ListNode{
    int data;
    ListNode next;
    static ListNode head = new ListNode(-1);    //head.next=null
    ListNode(){}
    ListNode(int val){
        this.data=val;
    }
}

方法二:递归

public ListNode ReverseList(ListNode head) {
    if(head==null||head.next==null){
        return head;
    }
    //保存当前节点的下一个节点
    ListNode next = head.next;
    //从当前节点的下一个节点开始递归调用
    ListNode reverse = ReverseList(next);
    //reverse是反转之后的链表,因为函数reverseList
    // 表示的是对链表的反转,所以反转完之后next肯定
    // 是链表reverse的尾结点,然后我们再把当前节点
    //head挂到next节点的后面就完成了链表的反转。
    next.next = head;
    //head相当于变成了尾结点,尾结点都是为空的,
    head.next = null;
    return reverse;
}

方法三:使用栈

原理就是把链表节点一个个入栈,当全部入栈完之后再一个个出栈,出栈的时候在把出栈的结点串成一个新的链表。

import java.util.Stack;
public class Solution {
public ListNode ReverseList(ListNode head) {
    while(head!=null){
        stack.push(head);
        head=head.next;
    }
    if(stack.isEmpty())
        return null;	//证明链表中根本没元素
    ListNode node = stack.pop();
    ListNode dummy = node;
    //栈中的结点全部出栈,然后重新连成一个新的链表
    while (!stack.isEmpty()) {
        ListNode tempNode = stack.pop();
        node.next=tempNode;
        node = node.next;
    }
    //最后一个结点就是反转前的头结点,一定要让他的next
    //等于空,否则会构成环
    node.next=null;
    return dummy;
    }
}

上面的情况适用于牛客网刷题,链表事先是给你构造好了的。

如果没给你构造链表的情况下,根据输入的数据也可以获取到翻转后的链表。

//例如输入的的是{1,2,3}

import java.util.Scanner;
import java.util.Stack;
/**
 * 通过栈反转链表
 */

public class reListNode3 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入初始链表,例如{1,2,3}");
        String str = sc.nextLine();
        str = str.substring(1, str.length()-1);
        String[] strArr = str.split(",");
        ListNode head = new ListNode(Integer.parseInt(strArr[0]));  //这里只是新建了个值为1的链表节点,该节点next=null
        System.out.print("{");
        ListNode reList=ReverseList(head,strArr);
        while(reList!=null){
            if(reList.next!=null){
                System.out.print(reList.data+",");
            }else{
                System.out.print(reList.data);
            }
            reList = reList.next;
        }
        System.out.print("}");
    }

    //反转链表
    private static ListNode ReverseList(ListNode head,String[] strArr) {
        Stack stack = new Stack<ListNode>();
        stack.push(head);
        int i=1;
        while(head!=null&&i<strArr.length){
            head = new ListNode(Integer.parseInt(strArr[i]));
            stack.push(head);
            i++;
        }
        if(stack.isEmpty()) return null;

        ListNode node = (ListNode)stack.pop();
        ListNode dummy = node;
        while(!stack.isEmpty()){
            ListNode temp = (ListNode)stack.pop();
            node.next=temp;
            node=node.next;
        }
        node.next=null;
        return dummy;
    }
}

class ListNode{
    int data;
    ListNode next;
    ListNode(){}
    ListNode(int val){
        this.data=val;
    }
}

在没有构造链表的情况下直接输出翻转后的链表,相当于根据输入的数据倒着构造一个链表

4.合并两个链表并排序

输入:

{1,3,5},{2,4,6}

输出:

{1,2,3,4,5,6}

输入:

{},{}

输出:

{}

思路一:

  • 创建最终得到的链表node的哑节点node(-1),和一个存放node的dummy节点
  • list1list2都不为null时循环
  • 哪个的val小哪个赋给哑节点的next称为最终链表的头节点,node虚拟结点后移,该val所在的节点后移。
  • 退出循环后,哪个list不为空,哪个结点(包括剩下的)给node的next
  • 最终返回dummy.next,因为dummy是最开始的node(-1)是个哑节点,不应该被输出
import java.util.*;
/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
        ListNode node = new ListNode(-1);
        ListNode dummy = node;
        while(list1!=null&&list2!=null){
            if(list1.val>=list2.val){
                node.next=list2;
                list2=list2.next;
                node=node.next;
            }else{
                node.next=list1;
                list1=list1.next;
                node=node.next;
            }
        }
        if(list1==null){
            node.next=list2;
        }else{
            node.next=list1;
        }
        return dummy.next;
    }
}

思路二:递归

  • 先说终止条件:如果list1和list2其中有一个为空,返回另一个链表

  • 比较list1.val和list2.val,将较小的listX.next与merge后的表头连接即:

    例如:list1.next = Merge(list1.next,list2);

    每次返回排序好的链表头

import java.util.*;
/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
        if(list1==null){
            return list2;
        }
        else if(list2==null){
            return list1;
        }
        if(list2.val>list1.val){
            list1.next=Merge(list1.next,list2);
            return list1;
        }else{
            list2.next=Merge(list1,list2.next);
            return list2;
        }
    }
}
posted @ 2022-07-15 15:56  BAISHUN66  阅读(36)  评论(0编辑  收藏  举报