链表理论基础
- 链表的类型
- 每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针)
- 双链表:每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点
- 循环链表:首尾相连,可以解决约瑟夫环的问题
- 每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针)
- 链表的存储方式:链表在内存的空间地址是不连续的,分配机制取决于操作系统的内存管理
- 链表的定义
public class ListNode<T> { // 节点存储的数据 public T Data { get; set; } // 指向下一个节点的引用 public ListNode<T> Next { get; set; } public ListNode(T data) { Data = data; Next = null; // 初始时没有下一个节点,因此设为 null } }
-
链表操作:插入和删除都是O(1),查询O(n)。适合数据量不固定,频繁增删,较少查询的场景
203.移除链表元素
看解题思路前:先循环判断移除非首节点,再判断移除首节点
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int val=0, ListNode next=null) {
* this.val = val;
* this.next = next;
* }
* }
*/
public class Solution
{
public ListNode RemoveElements(ListNode head, int val)
{
ListNode result = head;
while (head != null)
{
if (head.next != null && head.next.val == val)
{
head.next = head.next.next;
continue;
}
head = head.next;
}
if (result != null && result.val == val)
{
result = result.next;
}
return result;
}
}
看解题思路后:
- 原链表删除元素:直接使用原来的链表来进行删除操作(移除头结点和移除其他节点的操作是不一样的,因为链表的其他节点都是通过前一个节点来移除当前节点,而头结点没有前一个节点。) 优化自己原先的代码:先处理头节点,再处理非头结点,感觉比较好理解,不容易乱
PS:感觉我原先的写法也还可以,最后如果头节点与val相等,只要处理一次就行了(其它的都合并到非头节点的处理里了)/** * Definition for singly-linked list. * public class ListNode { * public int val; * public ListNode next; * public ListNode(int val=0, ListNode next=null) { * this.val = val; * this.next = next; * } * } */ public class Solution { public ListNode RemoveElements(ListNode head, int val) { while (head != null && head.val == val) { head = head.next; } ListNode cur = head; while (cur != null && cur.next != null) { if (cur.next.val == val) { cur.next = cur.next.next; }else { cur = cur.next; } } return head; } }
- 使用虚拟头节点:设置一个虚拟头结点在进行删除操作(这样原链表的所有节点就都可以按照统一的方式进行移除了,不容易乱)
/** * Definition for singly-linked list. * public class ListNode { * public int val; * public ListNode next; * public ListNode(int val=0, ListNode next=null) { * this.val = val; * this.next = next; * } * } */ public class Solution { public ListNode RemoveElements(ListNode head, int val) { ListNode dummyHead = new ListNode(); dummyHead.next = head; ListNode cur = dummyHead; while (cur != null && cur.next != null) { if (cur.next.val == val) { cur.next = cur.next.next; } else { cur = cur.next; } } return dummyHead.next; } }
707.设计链表
看解题思路前:我把MyLinkedList作为一个链表的头节点去写了。。。并且有部分问题,看了解题思路被自己蠢到,写了挺长时间的全部重写
看解题思路后:设置一个虚拟头结点再进行操作
class ListNode
{
public int val;
public ListNode next;
public ListNode(int val)
{
this.val = val;
}
}
public class MyLinkedList
{
ListNode dummyHead;
int count;
public MyLinkedList()
{
dummyHead = new ListNode(0);
count = 0;
}
public int Get(int index)
{
if (index < 0 || index > count - 1)
{
return -1;
}
ListNode cur = dummyHead;
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(count, val);
}
public void AddAtIndex(int index, int val)
{
if (index > count) return;
ListNode cur = dummyHead;
for (int i = 0; i < index; i++)
{
cur = cur.next;
}
ListNode newNode = new ListNode(val);
newNode.next = cur.next;
cur.next = newNode;
count++;
}
public void DeleteAtIndex(int index)
{
if (index < 0 || index > count - 1) return;
ListNode cur = dummyHead;
for (int i = 0; i < index; i++)
{
cur = cur.next;
}
cur.next = cur.next.next;
count--;
}
}
/**
* Your MyLinkedList object will be instantiated and called as such:
* MyLinkedList obj = new MyLinkedList();
* int param_1 = obj.Get(index);
* obj.AddAtHead(val);
* obj.AddAtTail(val);
* obj.AddAtIndex(index,val);
* obj.DeleteAtIndex(index);
*/
206.反转链表
--没时间了晚点写