将单向链表划分成左边小、中间等、右边大的形式
作者:互联网
文章目录
咋一看,似乎和快排的partition过程,也就是荷兰国旗问题很相似,只是此处换成了单链表结构,实际上也确实可以采用荷兰国旗问题来求解,只是此时的额外空间复杂度为O(N)。
1、采用荷兰国旗问题求解:
(1)将链表放到数组中
(2)使用荷兰国旗方法将数组分为小于区、等于区、大于区
(3)将数组重新连成链表,返回头节点
/**
* @author Java和算法学习:周一
*/
public static Node comparator(Node head, int pivot) {
if (head == null) {
return null;
}
// 获取链表节点数
Node current = head;
int i = 0;
while (current != null) {
i++;
current = current.next;
}
// 将链表放到数组中
Node[] arr = new Node[i];
current = head;
for (i = 0; i < arr.length; i++) {
arr[i] = current;
current = current.next;
}
// 将数组分为小于区、等于区、大于区(核心就是荷兰国旗问题)
partition(arr, pivot);
// 将数组连成链表
for (i = 1; i < arr.length; i++) {
arr[i - 1].next = arr[i];
}
arr[i - 1].next = null;
// 返回头节点
return arr[0];
}
private static void partition(Node[] arr, int pivot) {
int small = -1;
int big = arr.length;
int index = 0;
while (index < big) {
if (arr[index].value < pivot) {
swap(arr, ++small, index++);
} else if (arr[index].value == pivot) {
index++;
} else {
swap(arr, --big, index);
}
}
}
2、额外空间复杂度为O(1)的解法:
(1)使用6个变量,依次表示小于区头节点、尾结点,等于区头节点、尾结点,大于区头节点、尾结点
(2)遍历链表,把节点放到各个部分、同时调整尾结点
(3)将小于区 等于区 大于区 三块头尾连接起来
/**
* @author Java和算法学习:周一
*/
public static Node smallerEqualBigger(Node head, int pivot) {
// 小于区头节点
Node sH = null;
// 小于区尾节点
Node sT = null;
// 等于区头节点
Node eH = null;
// 等于区尾节点
Node eT = null;
// 大于区头节点
Node bH = null;
// 大于区尾节点
Node bT = null;
// 标记当前遍历的next节点
Node next = null;
// 将链表分成 小于区 等于区 大于区 三块
while (head != null) {
// 记录next节点
next = head.next;
// 当前节点next节点置空
head.next = null;
if (head.value < pivot) {
// 小于区
if (sH == null) {
// 如果是小于区的第一个节点,则小于区的头尾节点都指向当前节点
sH = head;
sT = head;
} else {
// 如果不是小于区的第一个节点,则小于区的尾结点指向当前节点,调整尾结点
// 即在当前区内将各节点再次连接起来
sT.next = head;
sT = head;
}
} else if (head.value == pivot) {
// 等于区
if (eH == null) {
// 如果是等于区的第一个节点,则等于区的头尾节点都指向当前节点
eH = head;
eT = head;
} else {
// 如果不是等于区的第一个节点,则等于区的尾结点指向当前节点,调整尾结点
eT.next = head;
eT = head;
}
} else {
// 大于区
if (bH == null) {
// 如果是大于区的第一个节点,则大于区的头尾节点都指向当前节点
bH = head;
bT = head;
} else {
// 如果不是大于区的第一个节点,则大于区的尾结点指向当前节点,调整尾结点
bT.next = head;
bT = head;
}
}
// 当前节点移动到next节点
head = next;
}
// 将小于区 等于区 大于区 三块头尾连接起来
// 小于区存在
if (sT != null) {
// 则小于区尾节点连接等于区头节点
sT.next = eH;
// 如果此时等于区尾结点为空(即整个等于区为空),那么等于区的尾结点则为小于区尾结点
// 如果此时等于区尾结点不为空,那么等于区的尾结点就是之前的尾结点
eT = eT == null ? sT : eT;
}
// 有等于区,eT 就是等于区的尾结点
// 无等于区,有小于区,eT 就是小于区的尾结点
// 无等于区,无小于区,eT 就是空
if (eT != null) {
// 则等于区的尾结点连接大于区头节点
eT.next = bH;
}
// 最后返回当前的头节点
// 有小于区,返回小于区头节点
// 无小于区,有等于区,返回等于区头节点
// 无小于区,无等于区,有大于区,返回大于区头节点
return sH != null ? sH : (eH != null ? eH : bH);
}
本文所有代码:https://github.com/monday-pro/algorithm-study/tree/master/src/basic/node
标签:右边,arr,结点,单向,head,next,链表,null,节点 来源: https://blog.csdn.net/weixin_50337833/article/details/121864940