链表
链表的定义(代码)
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; } }
链表操作
删除节点
添加节点
除了查找,其他的增删改操作,都应该先找到目标位置的前驱元素,这样才能进行操作。这种执行流程也是基于链表的设计特点考虑的(next/pre节点)。
LeetCode.203 移除链表元素
遇到的问题:
结果不能返回head,因为后续的删除操作并没有影响到Head的指向
class Solution { public ListNode removeElements(ListNode head, int val) { if (head == null){ return head; } ListNode dummy = new ListNode(-1 , head); ListNode pre = dummy; ListNode node = dummy.next; while(pre.next != null){ if(node.val == val){ ListNode temp = node.next; pre.next = node.next; node = temp; } else{ pre = pre.next; node = node.next; } } return dummy.next;//此处不能返回head,因为后续的删除操作并没有影响到Head的指向 } }
LeetCode.707 设计链表
遇到的问题:
实现的逻辑还是很好理解的,但是要多动手去画链表的各种操作过程,脑测很容易搞不清楚应该使用前驱还是当前节点。
单链表实现:
//单链表 class ListNode{ int val; ListNode next; public ListNode(){} public ListNode(int val){ this.val = val; } } class MyLinkedList { ListNode head; int size; public MyLinkedList() { size = 0; head = new ListNode(0); } public int get(int index) { if(index >= size || index < 0){ return -1; } ListNode cur = head; for(int i = 0 ; i <= index ; i++){ cur = cur.next; } return cur.val; } public void addAtHead(int val) { ListNode newNode = new ListNode(val); ListNode temp = head.next; head.next = newNode; newNode.next = temp; size++; } public void addAtTail(int val) { ListNode pre; pre = head;//一开始是head.next想着直接找到末尾对应的节点 for(int i = 0 ; i < size ; i++){ pre = pre.next; } ListNode newNode = new ListNode(val); pre.next = new ListNode(); pre.next = newNode; size++; } public void addAtIndex(int index, int val) { if(index > size || index < 0){ return; } size++; ListNode pre = head; for(int i = 0 ; i < index ; i++){ pre = pre.next; } ListNode newNode = new ListNode(val); newNode.next = pre.next; pre.next = newNode; } public void deleteAtIndex(int index) { if(index >= size || index <0){ return; } size--; if(index == 0){ head = head.next; return; } ListNode cur = head; for(int i = 0 ; i < index ; i++){ cur = cur.next; } cur.next = cur.next.next; } }
双向链表实现:
//双向链表 class ListNode{ int val; ListNode next; ListNode pred; public ListNode(){} public ListNode(int val){ this.val = val; } } class MyLinkedList { ListNode head; int size; public MyLinkedList() { size = 0; head = new ListNode(0); } public int get(int index) { if(index >= size || index < 0){ return -1; } ListNode cur = head; for(int i = 0 ; i <= index ; i++){ cur = cur.next; } return cur.val; } public void addAtHead(int val) { size++; ListNode newNode = new ListNode(val); ListNode pre = head; ListNode temp = pre.next; if(pre.next != null){ pre.next.pred = newNode; } newNode.pred = pre; pre.next = newNode; newNode.next = temp; } public void addAtTail(int val) { ListNode pre; pre = head;//一开始是head.next想着直接找到末尾对应的节点 for(int i = 0 ; i < size ; i++){ pre = pre.next; } ListNode newNode = new ListNode(val); pre.next = new ListNode(); pre.next = newNode; newNode.pred = pre; size++; } public void addAtIndex(int index, int val) { if(index > size || index < 0){ return; } size++; ListNode pre = head; for(int i = 0 ; i < index ; i++){ pre = pre.next; } ListNode newNode = new ListNode(val); newNode.pred = pre; if(pre.next != null){ pre.next.pred = newNode; } newNode.next = pre.next; pre.next = newNode; } public void deleteAtIndex(int index) { if(index >= size || index <0){ return; } size--; if(index == 0){ head = head.next; return; } ListNode cur = head; for(int i = 0 ; i < index ; i++){ cur = cur.next; } if(cur.next.next != null){ cur.next.next.pred = cur; } cur.next = cur.next.next; } }
LeetCode.206 翻转链表
看了视频好理解多了,但是可能还是不够熟练,后续要多多回看
易混淆:
要注意循环的终止条件,是基于翻转链表的基本操作的,每进行一次翻转,前驱和当前节点都会向后移动一位
也别忘了在此之前要保存cur.next节点以供cur的在翻转之后向后移动
class Solution { public ListNode reverseList(ListNode head) { ListNode pre = null; ListNode cur = head; ListNode temp = null; while(cur != null){ temp = cur.next; cur.next = pre; pre = cur; cur = temp; } return pre; } }