1、链表的表示
链表是一种跳跃结构,链表的跳跃结构是用指针来实现的。
相对数组来说,数组是一种连续结构,内存上连续。
链表有两种,一种是单向链表,每个节点都有一个next指针,指向下一个节点。
另一种是双向链表,有一个向前的指针和一个向后的指针。
2、链表的增删改查
- 增加:首先我们说一下单链表的头插法
创建一个节点p,让p指向头节点,然后头节点指向p - 查询:就是将单链表遍历一遍,时间复杂度为O(n),研究算法的时间复杂度就是研究他的最坏情况,如果最后一个节点是我们要找的元素,那么时间复杂度就是O(n)
- 删除:找到要删除的前一个元素
coding
public void remove(Node node){
if(head == null) return;
if(head == node){
head = head.next;
}
//快慢指针
Node low = head;
Node fast = head.next;
while(fast != node && fast!=null){
low = low.next;
fast = fast.next;
}
if(fast !=null){
low.next = fast.next;
}
}
3、反转一个链表问题
反转一个链表采用三指针方法
coding
public void reverse(ListNode head){
ListNode prev =head;
ListNode cur = null;
ListNode next = null;
while(cur != null){
next = cur.next;
cur = prev.next;
cur.next = prev;
prev = cur;
}
head = prev;
}
递归思路
//使用递归方法:将整条链表拆开,从单个节点出发考虑
public ListNode ReverseList(ListNode head) {
//递归结束条件
if(head == null || head.next ==null){
return head;
}
//继续遍历下一个节点
ListNode reverse = ReverseList(head.next);
//将后节点指向前节点
head.next.next = head;
//删除前节点指向后节点的指针
head.next =null;
//最终reverse为头节点
return reverse;
}
4、判断链表是否有环
首先我可以想到用set集合,然后把链表元素一个个扔进集合中,判断是否存在,如果存在那就说明有环。这个方法的空间复杂度为O(n),还有更优的方法。
我们可以采用快慢指针方法
coding
public boolean hasCycle(ListNode head) {
ListNode fast=head.next;
ListNode low=head;
while(fast!=null && fast.next !=null ){
if(fast == low){
return true;
}
low = low.next;
fast = fast.next.next;
}
return false;
}
5、总结
两个链表的合并时间复杂度为O(1)
链表的查询是O(n),插入是O(1),双向链表的删除是O(1)