代码随想录刷题Day4

68 阅读3分钟

From代码随想录 链表

  1. 理论基础
  • 链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。链表的入口节点称为链表的头结点也就是head。

image.png

  • ###链表的类型
  • 1.单链表如上图
  • 2.双链表
  • 单链表中的指针域只能指向节点的下一个节点。
  • 双链表:每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。双链表 既可以向前查询也可以向后查询。
  • 双链表 既可以向前查询也可以向后查询。

image.png

  • 3.循环链表
  • 循环链表就是链表首尾相连。可以用来解决约瑟夫环问题。

image.png

  • ###链表的存储方式
  • 链表在内存中可不是连续分布的。链表是通过指针域的指针链接在内存中各个节点。所以链表中的节点在内存中不是连续分布的 ,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。
  • ###链表的定义
public class ListNode {
    // 结点的值
    int val;

    // 下一个结点
    ListNode next;

    // 节点的构造函数(无参)
    public ListNode() {
    }

    // 节点的构造函数(有一个参数)
    public ListNode(int val) {
        this.val = val;
    }

    // 节点的构造函数(有两个参数)
    public ListNode(int val, ListNode next) {
        this.val = val;
        this.next = next;
    }
}
  • ###链表的操作
  • 1.删除节点 image.png
  • 删除D节点,只要将C节点的next指针 指向E节点就可以了。
  • Java有自己的内存回收机制,就不用自己手动释放D节点的内存
  • 2.添加节点

image.png

  • 删除D节点,只要将C节点的next指针 指向E节点就可以了。
  • Java有自己的内存回收机制,就不用自己手动释放D节点的内存
  • ###性能分析

image.png

链表

  1. 203. 移除链表元素
  • 不定义虚拟头结点
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        // 先判断链表头是不是要删除的对象,直至链表头不是要删除的对象,如[1,1,1,1] val=1
        while(head!=null&&head.val==val){//头指针不能是空,否则会报空指针异常。
            head=head.next;
        }
        // 再判断非头结点的节点怎么删除
        ListNode cur=head;// 定义一个临时结点,此结点的val不等于val
        while (cur != null && cur.next!= null) {
            if(cur.next.val==val){
                cur.next = cur.next.next;
            }else{
                cur = cur.next;
            }
        }
        return head;
        }
}
  • 定义虚拟头结点
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode dummy = new ListNode();//创建虚拟头结点
        dummy.next=head;//定义头指针
        ListNode cur=dummy;// 定义一个临时结点
        while (cur.next!= null) {
            if(cur.next.val==val){
                cur.next = cur.next.next;
            }else{
                cur = cur.next;
            }
        }
        return dummy.next;//不返回head是因为head可能被删除了
        }
}

  • 为啥方法1返回head,方法2返回dummy.next,还不是很懂o(╥﹏╥)o
  1. 707. 设计链表
class ListNode{
    int val;
    ListNode next;
    public ListNode() {
    }
    public ListNode(int val){
        this.val=val;
    }
}

class MyLinkedList {
    int size;//size存储链表元素的个数
    ListNode head ;//虚拟头结点
    public MyLinkedList() {
        size=0;
        head = new ListNode(0);
    }
    
    public int get(int index) {
        //如果index非法,返回-1
        if (index < 0 || index >= size) {
            return -1;
        }
        ListNode cur=head;// 定义一个临时结点
        for(int i=0;i<=index;i++){
            cur=cur.next;
        }
        return cur.val;
    }
    
    public void addAtHead(int val) {
        addAtIndex(0,val);
    }
    
    public void addAtTail(int val) {
        addAtIndex(size,val);
    }
    
    public void addAtIndex(int index, int val) {
        if (index > size) {
            return;
        }
        if (index < 0) {
            index = 0;
        }
        size++;
        ListNode pre=head;
        for(int i=0;i<index;i++){
            pre=pre.next;
        }
        ListNode toAdd = new ListNode(val);
        toAdd.next=pre.next;
        pre.next=toAdd;
    }
    
    public void deleteAtIndex(int index) {
        //如果index非法,返回-1
        if (index < 0 || index >= size) {
            return ;
        }
        size--;
        ListNode pre = head;
        for(int i=0;i<index;i++){
            pre=pre.next;
        }
        pre.next=pre.next.next;
    }
}