一.链表由N个结点组成。结点的结构如下
1.head.val表示结点head的值,用于比较,或者重设
2.head.next表示结点head的next指针存储(连接)下一个结点的内存地址
class ListNode { int val; ListNode next; ListNode(int x) { val = x; next = null; } }
二.改变链表结构的操作(插入、删除),需要注意空结点,防止出现越界异常。
1.在head结点后插入新结点,前提head结点不是空结点
new_node.next = head.next;(新结点的next指针记录了head结点下个结点的内存地址。)
head.next=new_node; (head结点的next指针记录了新结点的地址。)
2.删除head后一个结点,前提要head的下一个结点不是空结点。
head.next = head.next.next;(head.next.next表示head结点的next指针存储了head结点的下下一个结点的内存地址。)
三.虚拟结点
1.ListNode dummy = head;(表示将head结点的内存地址赋值给dummmy变量,引用的概念,head与dummy内存地址一样,作为虚拟结点,方便遍历结点,输出结果)
测试
class ListNode { int val; ListNode next; ListNode(int x) { val = x; next = null; } } public class Main { public static void main(String[] args) { // write your code here ListNode node1 = new ListNode(1); ListNode node2 = new ListNode(2); ListNode node3 = new ListNode(3); ListNode head = node1; node1.next = node2; node2.next = node3; for (ListNode node = head;node != null;node = node.next) { System.out.printf("%d",node.val); System.out.printf("->"); } System.out.printf(" "); node1 = node2; for (ListNode node = head;node != null;node = node.next) { System.out.printf("%d",node.val); System.out.printf("->"); } System.out.printf(" %d",node1.next.val); } }
2.删除链表中倒数第n个结点
//删除链表中倒数第n个结点 static ListNode removeNthFromEnd(ListNode head, int n) { if (n < 0) { return null; } ListNode dummy = new ListNode(0); dummy.next = head; for (int i = 0; i < n; i++) { if (head == null) { return null; } head = head.next; } ListNode preDelete = dummy; while (head != null) { head = head.next; preDelete = preDelete.next; } preDelete.next = preDelete.next.next; return dummy.next; }
3.将小于x的值放在x结点的左边,大于x的值放在x结点的右边。
public ListNode partition(ListNode head,int x) { if (head == null) { return null; } ListNode leftDummy = new ListNode(0); ListNode rightDummy = new ListNode(0); ListNode left = leftDummy; ListNode right = rightDummy; while (head != null) { if (head.val < x) { left.next = head; left = head; } else { right.next = head; right = head; } head = head.next; } right.next = null; left.next = rightDummy.next; return leftDummy.next; }
4.去除链表中重复的数
public static ListNode deleteDuplicates(ListNode head) { if (head == null || head.next == null) { return head; } ListNode dummy = new ListNode(0); dummy.next = head; // head = dummy; while (head.next != null && head.next.next != null)//要比较的2个数都存在 { if (head.next.val == head.next.next.val)//相邻2数是否相等 { int val = head.next.val; while (head.next != null && head.next.val == val)//是否存在连续相等的情况 { //删除操作 head.next = head.next.next; } } else { //移动手指 head = head.next; } } return dummy.next; }
5.重排链表,重排后的顺序(L1)->(Ln)->(L2)->(Ln-1)->(L3)->(Ln-2)
public static void reorderList(ListNode head) { // if (head == null || head.next == null) { return; } ListNode mid = findMiddle(head); ListNode tail = reverse(mid.next); mid.next = null;//防止回环 merge(mid,tail); } //找中间位置(经典) public static ListNode findMiddle(ListNode head) { ListNode fast = head.next; ListNode slow = head; while (fast != null && fast.next != null) { fast = fast.next.next; slow = slow.next; } return slow; } //1->2->3->null (null<-1<-2<-3)翻转链表(经典) public static ListNode reverse(ListNode head) { // ListNode newHead = null; while (head != null) { ListNode temp = head.next; head.next = newHead; newHead = head; head = temp; } return newHead; } //合并2链表(经典) public static void merge(ListNode head1,ListNode head2) { ListNode dummy = new ListNode(0); int index = 0; while (head1 != null && head2 != null) { if (index % 2 == 0) { dummy.next = head1; head1 = head1.next; } else { dummy.next = head2; head2 = head2.next; } index++; dummy = dummy.next; } //补刀,加入最后1个数 if (head1 != null) { dummy.next = head1; } else { dummy.next = head2; } }