链表理论基础
链表的定义:
链表是⼀种通过指针串联在⼀起的线性结构,每⼀个节点由两部分组成,⼀个是数据域⼀个是指针域 (存放指向下⼀个节点的指针),最后⼀个节点的指针域指向null
(空指针的意思)。
链表的⼊⼝节点称为链表的头结点也就是
head
。
链表的常见类型:
单链表
单链表中的指针域只能指向节点的下⼀个节点。
![](https://img-blog.csdnimg.cn/direct/265eeeb088194ddd927e360e68622c4d.png)
双链表
每⼀个节点有两个指针域,⼀个指向下⼀个节点,⼀个指向上⼀个节点。
双链表 既可以向前查询也可以向后查询。
![](https://img-blog.csdnimg.cn/direct/94339c53fb6947e9802d3e752ff437a3.png)
循环链表
链表⾸尾相连
![](https://img-blog.csdnimg.cn/direct/705a16c1eaff490e8361026dc2a122b4.png)
链表的存储方式
数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。
链表是通过指针域的指针链接在内存中各个节点。所以来链表在内存中是散乱分布的
链表的定义
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;
}
}
链表的操作
删除节点
因为链表中的节点不能直接删除,所以需要找到待删除节点的前一个节点,让其指向待删除节点的后一个节点,这样即可完成删除,该操作结束后,待删除节点被自动回收装置回收即完成删除
如果要删除头节点让头节点后移即可(head=head.next)
增加节点
找到需要添加位置,让其前一个节点的next指向新节点,然后新节点的next指向 前一个节点的next
203.移除链表元素
题目链接
视频链接
手把手带你学会操作链表 | LeetCode:203.移除链表元素
思路:
简单的数组删除操作
代码
/**
* Definition for singly-linked list.
* 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; }
* }
*/
class Solution {
public ListNode removeElements(ListNode head, int val) {
while (head!=null&&head.val==val){//如果头节点的val==val那么删除头节点
head=head.next;//头节点直接后移
}
ListNode temp=head;//设置一个temp 指针指向头节点用来遍历链表
while (temp!=null&&temp.next!=null){
if(temp.next.val==val) {//如果找到需要删除的节点,直接删除
temp.next = temp.next.next;
}else {
temp=temp.next;//如果找到需要删除的节点,temp后移继续找
}
}
return head;
}
}
使用虚拟头节点对删除操作进行统一
/**
* Definition for singly-linked list.
* 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; }
* }
*/
class Solution {
public ListNode removeElements(ListNode head, int val) {
listNode dummyhead=new listNode();//使用虚拟头节点对节点的增加和删除操作进行统一
dummyhead.next=head;
listNode temp=dummyhead;//这里遍历指针需要指向虚拟头节点(删除节点你需要找到前一个节点)所以这里需要指向虚拟头节点
while (temp.next!=null){
if(temp.next.val==val){
temp.next=temp.next.next;
}else {
temp=temp.next;
}
}
return dummyhead.next;
}
}
}
707.设计链表
题目链接
视屏链接
手把手带你学会操作链表 | LeetCode:203.移除链表元素、、
代码:
class Node{//编写节点类
int val;
Node next;
public Node(int val) {//节点构造函数
this.val = val;
}
}
class LinkedList{//创建链表类
Node dummyhead;//虚拟头节点
int size;//链表当前大小
public void MyLinkedList() {//链表类的初始化
dummyhead=new Node(0);
size=0;
}
public int get(int index) {//获取指定节点的val
if(index<0||index>size){
return -1;
}
Node curnt=dummyhead;
for (int i = 0; i <=index ; i++) {
curnt=curnt.next;
}
return curnt.val;
}
public void addAtHead(int val) {//将一个值为 val 的节点插入到链表中第一个元素之前
Node newnode = new Node(val);
newnode.next=dummyhead.next;
dummyhead.next=newnode;
size++;
}
public void addAtTail(int val) {//将一个值为 val 的节点插入到链表中末端
Node curnt=dummyhead;
while (curnt.next!=null){
curnt=curnt.next;
}
curnt.next=new Node(val);
size++;
}
public void addAtIndex(int index, int val) {//在第n个元素前添加一个节点
Node curnt=dummyhead;
while (index-->0) {
curnt = curnt.next;
}
Node newnode = new Node(val);
newnode.next=curnt.next;
curnt.next=newnode;
size++;
}
public void deleteAtIndex(int index) {//如果下标有效,则删除链表中下标为 index 的节点
Node curnt=dummyhead;
while (index-->0) {
curnt = curnt.next;
}
curnt.next=curnt.next.next;
size--;
}
}
206.反转链表
题目链接
视频链接
手把手带你学会操作链表 | LeetCode:203.移除链表元素
思路:
使用双指针,⾸先定义⼀个cur指针,指向头结点,再定义⼀个pre指针,初始化为null。 然后就要开始反转了,⾸先要把 cur->next 节点⽤tmp指针保存⼀下,也就是保存⼀下这个节点。 为什么要保存⼀下这个节点呢,因为接下来要改变 cur->next 的指向了,将cur->next 指向pre ,此时已经反转了 第⼀个节点了。 接下来,就是循环⾛如下代码逻辑了,继续移动pre和cur指针。
代码:
/**
* Definition for singly-linked list.
* 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; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre=null;//pre指针指向头节点前一个
ListNode cur=head;//cur指针指向头节点
ListNode temp;//临时变量保存cur.next
while (cur!=null){
temp=cur.next;
cur.next=pre;
pre=cur;
cur=temp;
}
return pre;
}
}