将单向链表按某值划分成左边小,中间相等,右边大的形式

【题目】 给定一个单向链表的头节点head,节点的值类型是整型,再给定一个整数pivot。实现一个调整链表的函数,将链表调整为左部分都是值小于 pivot的节点,中间部分都是值等于pivot的节点,右部分都是值大于pivot的节点。除这个要求外,对调整后的节点顺序没有更多的要求。 例如:链表9->0->4->5->1,pivot=3。 调整后链表可以是1->0->4->9->5,也可以是0->1->9->5->4。总
之,满 足左部分都是小于3的节点,中间部分都是等于3的节点(本例中这个部分为空),右部分都是大于3的节点即可。对某部分内部的节点顺序不做要求。
进阶: 在原问题的要求之上再增加如下两个要求。
在左、中、右三个部分的内部也做顺序要求,要求每部分里的节点从左到右的顺序与原链表中节点的先后次序一致。

例如:链表9->0->4->5->1,pivot=3。
调整后的链表是0->1->9->4->5。 在满足原问题要求的同时,左部分节点从左到右为0、1。在原链表中也 是先出现0,后出现1;中间部分在本例中为空,不再讨论;右部分节点 从左到右为9、4、5。在原链表中也是先出现9,然后出现4,最后出现5。如果链表长度为N,时间复杂度请达到O(N),额外空间复杂度请达到O(1)。

分析:

一 普通解法:已知数组的partition过程,把链表的每一个node放到一个容器(生成一个node类型的数组),在这个数组中进行partition。partition的过程按照值来放,在数组中做到小于pivot的放它左边,等于pivot的值放中间,大于pivot的值放右边;在数组中调整好之后,然后从数组中开始重新连接这个链表,连完之后返回。但是这个方法需要时间复杂度O(n),额外空间复杂度O(n),而且partition不能达到稳定性(就是会改变原来的相对顺序);

具体步骤如下:

1.先遍历一遍链表,为了得到链表的长度,假设长度为N。

2.生成长度为N的Node类型数组,然后遍历一次链表,将节点一次放进数组中

3.在数组中做到小于pivot的放它左边,等于pivot的值放中间,大于pivot的值放右边,也就是改进了快排中partition过程。

4.然后从数组中开始重新连接这个链表的节点,连完之后返回。

二 进阶解法:按照原链表各个节点的对应顺序将链表分解成三部分,小于pivot的、等于pivot的,大于pivot的,之后再将三个连起来即可。这三个链表都有自己的两个指针HeadTail分别代表各自的头部和尾部,分成三个子链表之后,我们只需要遍历链表,然后和给定的值比较,按照条件,向三个链表中添加值就可以了,最后把三个链表连接起来就可以了。

public class SmallerEqualBigger {

	public static class Node {
		public int value;
		public Node next;

		public Node(int data) {
			this.value = data;
		}
	}
    //普通的需要额外空间O(n)且不能达到稳定性的方法
	public static Node listPartition1(Node head, int pivot) {
		if (head == null) {
			return head;
		}
		Node cur = head;
		int i = 0;
		while (cur != null) {
			i++;
			cur = cur.next;
		}
		Node[] nodeArr = new Node[i];
		i = 0;
		cur = head;
		for (i = 0; i != nodeArr.length; i++) {
			nodeArr[i] = cur;
			cur = cur.next;
		}
		arrPartition(nodeArr, pivot);
		for (i = 1; i != nodeArr.length; i++) {
			nodeArr[i - 1].next = nodeArr[i];
		}
		nodeArr[i - 1].next = null;
		return nodeArr[0];
	}

	public static void arrPartition(Node[] nodeArr, int pivot) {
		int small = -1;
		int big = nodeArr.length;
		int index = 0;
		while (index != big) {
			if (nodeArr[index].value < pivot) {
				swap(nodeArr, ++small, index++);
			} else if (nodeArr[index].value == pivot) {
				index++;
			} else {
				swap(nodeArr, --big, index);
			}
		}
	}

	public static void swap(Node[] nodeArr, int a, int b) {
		Node tmp = nodeArr[a];
		nodeArr[a] = nodeArr[b];
		nodeArr[b] = tmp;
	}
    //第二种 进阶的方法 不需要额外的空间复杂度,且能达到稳定性
	public static Node listPartition2(Node head, int pivot) {
		Node sH = null; // small head
		Node sT = null; // small tail
		Node eH = null; // equal head
		Node eT = null; // equal tail
		Node bH = null; // big head
		Node bT = null; // big tail
		Node next = null; // save next node
		// every node distributed to three lists
		while (head != null) {
			next = head.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;
				}
			}
			head = next;
		}
		// small and equal reconnect
		if (sT != null) {
			sT.next = eH;
			eT = eT == null ? sT : eT;
		}
		// all reconnect
		if (eT != null) {
			eT.next = bH;
		}
		return sH != null ? sH : eH != null ? eH : bH;
	}

	public static void printLinkedList(Node node) {
		System.out.print("Linked List: ");
		while (node != null) {
			System.out.print(node.value + " ");
			node = node.next;
		}
		System.out.println();
	}

	public static void main(String[] args) {
		Node head1 = new Node(7);
		head1.next = new Node(9);
		head1.next.next = new Node(1);
		head1.next.next.next = new Node(8);
		head1.next.next.next.next = new Node(5);
		head1.next.next.next.next.next = new Node(2);
		head1.next.next.next.next.next.next = new Node(5);
		printLinkedList(head1);
		// head1 = listPartition1(head1, 4);
		head1 = listPartition2(head1, 5);
		printLinkedList(head1);

	}

}

 

以下是建立单向链表并按整数从大到小排序的 C++ 代码示例: ```c++ #include <iostream> using namespace std; struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(NULL) {} }; ListNode* insertNode(ListNode* head, int val) { ListNode* newNode = new ListNode(val); if (head == NULL) { return newNode; } if (val > head->val) { newNode->next = head; return newNode; } ListNode* cur = head; while (cur->next != NULL && cur->next->val > val) { cur = cur->next; } newNode->next = cur->next; cur->next = newNode; return head; } ListNode* sortList(ListNode* head) { ListNode* newHead = NULL; ListNode* cur = head; while (cur != NULL) { ListNode* next = cur->next; newHead = insertNode(newHead, cur->val); cur = next; } return newHead; } void printList(ListNode* head) { while (head != NULL) { cout << head->val << " "; head = head->next; } cout << endl; } int main() { ListNode* head = NULL; head = insertNode(head, 3); head = insertNode(head, 1); head = insertNode(head, 5); head = insertNode(head, 2); printList(head); head = sortList(head); printList(head); return 0; } ``` 在此示例中,我们定义了一个 `ListNode` 结构体来表示链表节点,包含一个整数值 `val` 和一个指向下一个节点的指针 `next`。`insertNode` 函数用于将一个新节点插入到链表中,按整数从大到小排序。`sortList` 函数遍历原链表,将每个节点插入到新链表中,最终返回新链表的头节点。`printList` 函数用于打印链表中的所有节点值。 在 `main` 函数中,我们创建一个空链表,然后依次插入节点 3、1、5、2,打印原链表并排序后再次打印链表。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值