单向链表(基础)

Posted by 令德湖周杰伦 on 12-20,2023

1.单向链表数据结构

public class ListNode {
    int val; //节点
    ListNode next; //指向下一个节点
    ListNode() {}
    ListNode(int val) { this.val = val; }
    ListNode(int val, ListNode next) { 
	this.val = val; 
	this.next = next; 
    }

    @Override
    public String toString() {
        String s = "";
        ListNode node = this;
        while (node!=null){
            s = s.concat(node.val + "->");
            node = node.next;
        }
        return s;
    }
}

2.链表的基础操作

2.1 建立链表

时间复杂度O(n)

public ListNode buildListNode(int[] arr){
        ListNode head = null;
        ListNode cur= null;
        for (int i = 0; i < arr.length; i++) {
            ListNode node = new ListNode(arr[i]);
            node.next = null;
            if(head == null){
                //1.头节点赋值
                head = node;
            }else{
                //2.遍历指针连接到新节点
                cur.next = node;
            }
            //3.遍历指针指向最新的节点
            cur = node;
        }
        return head;
    }

2.2 求链表的长度

时间复杂度O(n)

 public int length(ListNode head){
        int length = 0;
        if(head == null){
            return length;
        }
        //遍历链表即可
        ListNode cur = head;
        while(cur!=null){
            length++;
            cur = cur.next;
        }
        return length;
    }

2.3 在链表头部插入节点

时间复杂度O(1)

public ListNode insertHeadNode(ListNode head, int item){
        ListNode node;
        if(head == null){
            node = new ListNode(item);
        }else {
            node = new ListNode(item);
            node.next = head;
        }
        return node;
    }

2.4 在链表尾部插入节点

时间复杂度O(n)

 public ListNode insertTailNode(ListNode head, int item){
        ListNode node;
        if(head == null){
            node = new ListNode(item);
            head = node;
        }else {
            //找到链表的尾部
            ListNode cur = head;
            while(cur.next!=null){
                cur = cur.next;
            }
            //插入节点
            node = new ListNode(item);
            cur.next = node;
        }
        return head;
    }

2.5 在有序链表中插入节点并保持有序

思路:在查找过程中要记录前驱节点,以便插入新节点时使用
时间复杂度O(n)

public ListNode insertSortListNode(ListNode head, int item){
        ListNode node;
        if(head == null){
            node = new ListNode(item);
            return node;
        }
        node = new ListNode(item);
        //寻找插入位置,如果比头节点小,往前插
        if(item < head.val){
            node.next = head;
            head = node;
        }else{
            //往后找插入位置,同时记录pre为前驱节点
            ListNode cur = head;
            ListNode pre = head;
            while(cur!=null && item >= cur.val){
                pre = cur;
                cur = cur.next;
            }
            //插入节点
            node.next = cur;
            pre.next = node;
        }
        return head;
    }

2.6 删除链接中指定节点

思路:在查找过程中要记录前驱节点,以便删除节点时使用
时间复杂度O(n)

public ListNode deleteNode(ListNode head, int item){
        if(head == null){
            return head;
        }
        ListNode cur;
        if(head.val == item){
            //先设置在赋值为null
            cur = head.next;
            head.next = null;
            return cur;
        }else{
            //往后找节点,同时记录pre为前驱节点
            cur = head;
            ListNode pre = head;
            while (cur!=null && item != cur.val){
                pre = cur;
                cur = cur.next;
            }
            //如果不为null,证明找到了该节点,删除节点
            if(cur != null){
                pre.next = cur.next;
                cur.next = null;
            }
        }
        return head;
    }

2.7 逆转链表

public ListNode invert(ListNode head){
        //pre指针, 上一个节点,刚开始为空
        ListNode pre = null;
        //遍历指针
        ListNode cur = head;
        //copy指针, 用来反向连接上一个节点pre
        ListNode copyCur = null;
        while (cur!=null){
            pre = copyCur;
            copyCur = cur;
            cur = cur.next;
            copyCur.next = pre;
        }
        head = copyCur;
        return head;
    }