From代码随想录 链表
- 理论基础
- 链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。链表的入口节点称为链表的头结点也就是head。
- ###链表的类型
- 1.单链表如上图
- 2.双链表
- 单链表中的指针域只能指向节点的下一个节点。
- 双链表:每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。双链表 既可以向前查询也可以向后查询。
- 双链表 既可以向前查询也可以向后查询。
- 3.循环链表
- 循环链表就是链表首尾相连。可以用来解决约瑟夫环问题。
- ###链表的存储方式
- 链表在内存中可不是连续分布的。链表是通过指针域的指针链接在内存中各个节点。所以链表中的节点在内存中不是连续分布的 ,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。
- ###链表的定义
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.删除节点
- 删除D节点,只要将C节点的next指针 指向E节点就可以了。
- Java有自己的内存回收机制,就不用自己手动释放D节点的内存
- 2.添加节点
- 删除D节点,只要将C节点的next指针 指向E节点就可以了。
- Java有自己的内存回收机制,就不用自己手动释放D节点的内存
- ###性能分析
链表
- 不定义虚拟头结点
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
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;
}
}