算法通关村第一关——链表青铜挑战笔记

129 阅读3分钟

1.理解Java是如何构造出链表的

单链表:每个节点通过 一个next指针指向下一个节点形成的链

/**
  简易版本的链表
*/
public class Course{
    int val;
    // 即指向下一个course的地址
    Course next;
}

/**
  自定义链表的实现
*/
public class ListNode{
    private int data;
    private ListNode next;
    public ListNode(int data) {
        this.data = data;
    }
    public int getData(){
        return data;
    }
    public void setData(int data){
        this.data = data;
    }
    public ListNodegetNext() {
        return next;
    }
    public void setNext(ListNode next) {
        this .next = next;
    }
}

/**
  leetcode版本
*/
public class ListNode{
    public int val;
    public ListNode next;

    public ListNode(int val){
        this.val = val;
        //这个作用不大 写了会更规范
        next = null;
    }
}

2.链表增加元素,首部、中间和尾部分别会有什么问题,该如何处理?

头部添加:新增节点的next指向head节点,把head改为新增节点

尾部添加:尾部元素的next指向新增节点即可

中间添加:需要注意的是我们遍历到要插入位置的时候,需要获取前一个指针,但是单链表没有pre指针,所以通常都需要遍历到添加位置的前一个位置,也就是用cur.next来判断

public Node insert(Node head,Node insertNode,int position){
    if(head == null) return null;
    //节点个数 伪代码、未实现
    int count = getLength(head);
    if(position > count + 1 || position < 1){
        System.out.println("越界");
        return head;
    }

    // 头部添加
    if(position == 1){
        insertNode.next = head;
        head = insertNode;
        return head;
    }

    Node cur = head;
    int curInt = 1;
    // count - 1的目的是为了获取插入位置的前一个位置
    while(curInt < count - 1){
        cur = cur.next;
        curInt++;
    }
    insertNode.next = cur.next;
    cur.next = insertNode;

    return head;
    
}

3.链表删除元素,首部、中间和尾部分别会有什么问题,该如何处理?

头部删除:直接把head改为head.next即可

尾部删除:跟中间插入一样 要在删除位置的前一位停下,将next指向null,删除位置的元素没有地方引用 会被JVM回收

中间删除:跟中间插入一样 要在删除位置的前一位停下,将next指向删除位置元素的next,删除元素没有引用 会被JVM回收

public Node delete(Node head,int position){
    if(head == null) return null;
    //节点个数 伪代码、未实现
    int count = getLength(head);
    // 这里与插入不一样 大于count就不行 因为插入可以在count + 1那个位置插入元素,
    // 但是删除 不能删除 count+1位置的元素 因为count+1位置是null
    if(position > count || position < 1){
        System.out.println("越界");
        return head;
    }

    // 头部删除
    if(position == 1){
        head = head.next;
        return head;
    }

    Node cur = head;
    int curInt = 1;
    // count - 1的目的是为了获取插入位置的前一个位置
    while(curInt < count - 1){
        cur = cur.next;
        curInt++;
    }

    Node next = cur.next;
    cur.next = next.next;
    return head;
    
}

4.双向链表是如何构造的,如何实现元素的插入和删除

双链表:每个节点都有pre、next两个指针分别指向前一个和下一个节点

增删 都要考虑三种情况:头、尾、中

public class DoubleListNode{
    public int data;
    public DoubleListNode pre;
    public DoubleListNode next;

    public DoubleListNode(int val){
        data = val;
    }


	// 与单链表不同的是,双链表有pre和next双指针
    public void insertFirst(int data){
        DoubleListNode node = new DoubleListNode(data);
        if(head == null){
            // head和last分别是头尾指针 此处未定义
            last = node;
        }else{
            head.pre = node;
            node.next = head;
        }
        head = node;
    }

    public void insertLast(int data){
        DoubleListNode node = new DoubleListNode(data);
        if(head == null){
            // head和last分别是头尾指针 此处未定义
            head = node;
            last = node;
        }else{
            last.next = node;
            node.pre = last;
            last = node;
        }
    }

    // key表示的是要插入在哪个元素后面的 那个元素的值
    public void insertAfter(int key,int data){
        DoubleListNode node = new DoubleListNode(data);
        DoubleListNode cur = head;
        while(cur != null && cur.data != key){
            cur = cur.next;
        }

        if(cur == null){
            // 链表为空
            if(head == null){
                head = node;
                last = node;
            }else{
                // 链表不为空 但是链表没有key这个节点 所以添加在链表最后
                last.next = node;
                node.pre = last;
                last = node;
            }
        }else{
            // 在链表中找到了key这个节点
            // 这个节点是最后一个节点
            if(cur == last){
                node.pre = last;
                node.next = null;
                last.next = node;
                last = node;
            }else{
                // 此处要注意顺序
                node.next = cur.next;
                node.pre = cur;
                cur.next.pre = node;
                cur.next = node;
            }
        }
    }


    // 头部删除
    public DoubleListNode deleteFirst(){
        DoubleListNode cur = head;
        if(head == null) return null;
        if(head.next == null){
            last = null;
        }else{
            cur.next.pre = null;
            cur = cur.next;
        }
        return cur;
    }

    // 尾部删除
    public DoubleListNode deleteFirst(){
        // 获取尾元素
        DoubleListNode cur = last;
        if(head == null) return null;
        if(head.next == null){
            head = null;
            last = last.pre;
        }else{
            last.pre.next = null;
            last = last.pre;
        }

        return cur;
    }


    // 删除中间节点
    public DoubleListNode deleteKey(int key){
        DoubleListNode cur = head;
        while((cur.next != null) && (cur.data != key)){
            cur = cur.next;
        }

        if(head == null){
            return null;
        }

        // 三种情况
        if(cur == head){
            head = cur.next;
            cur.next.pre = null;
        }else if(cur == last){
            last.pre.next = null;
            last = cur.pre;
        }else{
            cur.pre.next = cur.next;
            cur.next.pre = cur.pre;
            cur.next = null;
            cur.pre = null;
        }
        
        return head;
    }
}