链表理论基础
- 链表几种类型:单链表(指针域只能指向节点的下一个节点),双链表(每个节点有两个指针域,一个指向下一个节点,一个指向上一个节点),循环链表(首尾相连)
- 链表的存储:链表的节点在内存中并不是连续分布,而是散乱分布在内存的某地址上。
- 链表的定义
struct ListNode{
int val;
ListNode next;
public void ListNode(int val,ListNode next){
this.val = val;
this.next = next;
}
}
- 链表的操作
删除节点:只需将想删除的节点的前一个结点的next指向想删除的下一个节点即可。
添加节点:先将新节点的next指向下一个节点,再将目标节点的next指向新节点。
插入/删除(时间复杂度) | 查询 | 适用场景 | |
数组 | O(n) | O(1) | 数据量固定,频繁查询 |
链表 | O(1) | O(n) | 数据量不固定,频繁删减 |
203.移除链表元素
解题思路
-
直接设置一个虚拟表头,然后在设置一个移动表头。当移动节点的下一个节点参数等于目标值时,移动节点的next为下下节点,否则移动移动节点到下一节点。当移动节点的next为空时,说明到了末尾,则跳出循环。
-
出现的问题:记住要先判断头节点是否为空。
解题代码:
public class Solution {
public ListNode RemoveElements(ListNode head, int val) {
if(head == null){
return null;
}
ListNode newNode = new ListNode();
newNode.next = head;
newNode.val = -1;
ListNode moveNode =newNode;
while(moveNode.next != null){
if(moveNode.next.val == val){
moveNode.next=moveNode.next.next;
}else{
moveNode = moveNode.next;
}
}
return newNode.next;
}
}
时间复杂度:O(n)
空间复杂度:O(1)
707.设计链表
public class MyLinkedList {
int size = 0;
ListNode dummyHead;
public MyLinkedList() {
size = 0;
dummyHead = new ListNode(-1);
}
public int Get(int index) {
if(index < 0 || index >= size){
return -1;
}
//ListNode dummyHead = new ListNode(-1);
ListNode temp = dummyHead;
//dummyHead.next = head;
while(index>0){
temp = temp.next;
index--;
}
return temp.next.val;
}
public void AddAtHead(int val) {
ListNode newNode = new ListNode(val);
//ListNode dummyHead = new ListNode(-1);
ListNode temp = dummyHead;
//dummyHead.next = head;
newNode.next = dummyHead.next;
dummyHead.next = newNode;
size++;
}
public void AddAtTail(int val) {
ListNode newNode = new ListNode(val);
// ListNode dummyHead = new ListNode(-1);
ListNode temp = dummyHead;
//dummyHead.next = head;
while(temp.next != null){
temp = temp.next;
}
temp.next = newNode;
size++;
}
public void AddAtIndex(int index, int val) {
ListNode newNode = new ListNode(val);
//ListNode dummyHead = new ListNode(-1);
ListNode temp = dummyHead;
//dummyHead.next = head;
if(index > size) return;
if(index <0) index = 0;
while(index-->0){
temp = temp.next;
}
newNode.next = temp.next;
temp.next = newNode;
size++;
}
public void DeleteAtIndex(int index) {
if(index < 0 || index >= size){
return;
}
//ListNode newNode = new ListNode(val);
//ListNode dummyHead = new ListNode(-1);
ListNode temp = dummyHead;
//dummyHead.next = head;
while(index-->0){
temp = temp.next;
}
temp.next = temp.next.next;
size--;
}
}
206.反转链表
public class Solution {
public ListNode ReverseList(ListNode head) {
ListNode newNode = null;
ListNode PrevNode = head;
while(PrevNode != null){
ListNode temp = PrevNode.next; //用临时节点来存储下一节点
PrevNode.next = newNode; //切断原来节点的联系,并指向反转后的新节点
newNode = PrevNode; // 改变newNode存储的节点为新节点
PrevNode = temp; //让旧节点向以前的顺序挪动一位,这样就拆开成两个相反的链
}
return newNode;
}
}