day03链表基础_移除链表元素_设计链表_反转链表

链表理论基础

链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。

链表的入口节点称为链表的头结点也就是head。

单链表

上述即是单链表

双链表

每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。

双链表既可以向前查询也可以向后查询。

循环链表

链表首尾相连。

链表的存储方式

数组是在内存中是连续分布的,链表在内存中不是连续分布的。

链表是通过指针域的指针链接在内存中的各个节点。

链表定义

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;
	}
}

数组与链表

数组在定义的时候,长度就是固定的,如果想改动数组的长度,就需要重新定义一个新的数组。

链表的长度可以是不固定的,并且可以动态增删, 适合数据量不固定,频繁增删,较少查询的场景。

力扣203.移除链表元素

题目链接:https://leetcode.cn/problems/remove-linked-list-elements/

##虚拟头结点
可以让删除或者增加结点以一种统一的方式写出。

1.cur为什么不能指向dummyhead的下一个结点:因为假如需要删除的是dummyhead的下一个结点,需要提供上一个结点的指针和下一个结点的指针,由于是单链表,所以cur必须指向dummyhead。

2.为什么返回值是dummyhead.next而不是head:因为有可能head已经被删除了,需要返回dummyhead的下一节点。

完整代码

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode dummyhead = new ListNode();
        dummyhead.next=head;
        ListNode cur = dummyhead;
        while(cur.next!=null){
            if(cur.next.val==val){
                cur.next=cur.next.next;
            }else{
                cur=cur.next;
            }
        }
        return dummyhead.next;
    }
}

力扣707.设计链表

单链表代码

class ListNode{
    int val;
    ListNode next;
    ListNode(){}
    ListNode(int val){
        this.val=val;
    }
}
class MyLinkedList {
    int size;
    ListNode dummyhead;
    public MyLinkedList() {
        int size=0;
        dummyhead=new ListNode(0);
    }
    
    public int get(int index) {
        if(index<0 || index>=size) return -1;
        ListNode cur=dummyhead.next;
        while(index-->0){//比如获取第0个结点,即index=0,这里while循环就不会执行,直接返回第0个结点
            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 cur=dummyhead;
        while(index-->0) {
            cur = cur.next;
        }
        ListNode newnode=new ListNode(val);
        newnode.next=cur.next;
        cur.next=newnode;
    }
    
    public void deleteAtIndex(int index) {
        if(index<0 || index>size-1) return;
        ListNode cur=dummyhead;
        while(index-->0){
            cur=cur.next;
        }
        cur.next=cur.next.next;
        size--;
    }
}

力扣206.反转链表

题目链接:https://leetcode.cn/problems/reverse-linked-list/

双指针

必须先用temp保存下cur的下一节点,反转后再让cur和pre同时移动,当cur指向空结点时表示反转已完成,此时头结点是pre。

为什么pre指向null:pre是cur之前的一个结点,cur指向头结点,头结点之前是null。

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode cur=head;
        ListNode pre=null;
        ListNode temp=null;
        while(cur != null){
            temp=cur.next;
            cur.next=pre;
            pre=cur;
            cur=temp;
        }
        return pre;
    }
}

递归

与双指针同理

class Solution {
    public ListNode reverseList(ListNode head) {
        return reverse(null, head);
    }

    private ListNode reverse(ListNode prev, ListNode cur) {
        if (cur == null) {
            return prev;
        }
        ListNode temp = null;
        temp = cur.next;// 先保存下一个节点
        cur.next = prev;// 反转
        // 更新prev、cur位置
        // prev = cur;
        // cur = temp;
        return reverse(cur, temp);
    }
}

你可能感兴趣的:(链表,数据结构,leetcode)