链表的划分——按值划分为三个区域
题目:
根据值val将链表划分为小于val的左半区,等于val的中间半区,大于val的右半区
方法1:
将其转为node数组,用数组的思想将其实现(需额外空间,且实现还更复杂)
代码解析:
1 public static void PartitionList1(MyLink list,int val) { 2 Node p = list.head; 3 //要先知道长度才知道给数组开多少空间 4 int len = 0, cnt = 0; 5 while (p != null) { 6 len++; 7 p = p.next; 8 } 9 Node[] arr = new Node[len]; 10 //将链表节点内容复制到数组中 11 p = list.head; 12 while (p != null) { 13 arr[cnt++] = p; 14 p = p.next; 15 } 16 //对数组进行调整 17 int less = -1, more = arr.length; 18 int now = 0; 19 while (now < more) { 20 if (arr[now].num < val) { 21 swap(arr,++less,now++); 22 } 23 else if (arr[now].num == val) { 24 now++; 25 } 26 else { 27 swap(arr,--more,now); 28 } 29 } 30 //将得到的数组内容返还给链表 31 list.head = arr[0]; 32 p = list.head; 33 for (int i = 1; i < arr.length; i++) { 34 p.next = arr[i]; 35 p = p.next; 36 } 37 p.next = null; 38 }
方法2:
将其分为小于等于大于三块链表型区域,用链表分别进行区域内部和区域之间连接
1 public static void PartitionList2(MyLink list,int val) { 2 Node sh = null, st = null;//小于部分的头尾指针 3 Node eh = null, et = null;//等于部分的头尾指针 4 Node bh = null, bt = null;//大于部分的头尾指针 5 Node p = list.head; 6 Node next = null;//用来存储下一个节点 7 //先把三块分区域的链表组织好 8 while (p != null) { 9 next = p.next;//即在一次循环中同时获得了相邻的两个节点内容 10 p.next = null;//这个节点可以直接指向null(因为后面不再用它了) 11 if (p.num < val) { 12 if (sh == null) { 13 sh = p; 14 st = p;//sh==null已经说明st==null 15 } 16 else {//要更新st 17 st.next = p; 18 st = st.next; 19 } 20 } 21 else if (p.num == val) { 22 if (eh == null) { 23 eh = p; 24 et = p; 25 } 26 else { 27 et.next = p; 28 et = et.next; 29 } 30 } 31 else { 32 if (bh == null) { 33 bh = p; 34 bt = p; 35 } 36 else { 37 bt.next = p; 38 bt = bt.next; 39 } 40 } 41 p = next; 42 } 43 if (st != null) {//如果有小于区域(没有小于区域就不用考虑小于到等于的连接 ) 44 st.next = eh;//先不管eh是不是null,在下一步处理 45 et = et == null ? st : et;//找谁做连接到大于区域的头(如果et为空就用st) 46 } 47 if (et != null) {//如果有小于或者等于的区域(此时等于同时考虑了两个区域是否至少存在一个) 48 //则需要将其连到大于区域(不关心大于区域是否为空) 49 et.next = bh; 50 } 51 //找到最前面那个不为空的头即可 52 list.head = sh != null ? sh : (eh != null) ? eh : bh; 53 }