链表(三)链表形式的荷兰国旗

 

问题:给定一个单向链表的头节点head,节点的值类型是整型,再给定一个整数point。实现一个调整链表的函数,将链表调整为左部分都是值小于pointt的节点,中间部分都是值等于pivot的节点,右部分都是值大于point的节点。除这个要求外,对调整后的节点顺序没有更多的要求。

第一种解法:类似于荷兰国旗,借助一个数组,把链表所有节点放入一个数组中,将此数组进行三个区域的划分。
//划分结束后再将数组依次next串起来,(在分到数组中时可以不用切断next,因为后面的赋值会覆盖掉,)返回数组中第一个元素即可(数组类型为Node)
//额外空间复杂度O(n)链表长度为n 达不到稳定性

链表结构:

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

		public Node(int a) {
			this.value = a;
		}
	}

 

借助数组方式实现:

public static Node listPartition1(Node head, int point) {
		if (head == null || head.next == null)
			return head;
		int i = 0;
		Node cur = head;
		while (cur != null) {
			cur = cur.next;
			i++;
		}
		Node nodelist[] = new Node[i];
		cur = head;
		for (i = 0; i < nodelist.length; i++) {
			nodelist[i] = cur;
			cur = cur.next;
			//指向空
			nodelist[i].next=null;	
		}
		arrpartition(nodelist, point);
		// 数组已经划分为三部分
		for (i = 0; i < nodelist.length - 1; i++) {
			nodelist[i].next = nodelist[i + 1];
		}
		nodelist[i].next = null;
		return nodelist[0];
	}
	private static void arrpartition(Node[] nodelist, int point) {
		int small = -1;
		int i = 0;
		int big = nodelist.length;
		while (i < big) {
			if (nodelist[i].value < point) {
				swap(nodelist, ++small, i++);
			} else if (nodelist[i].value > point) {
				swap(nodelist, --big, i);
			} else
				i++;
		}

	}
	private static void swap(Node[] nodelist, int i, int j) {
		Node t = nodelist[i];
		nodelist[i] = nodelist[j];
		nodelist[j] = t;
	}

第二种解法: 额外空间复杂度O(1)只用几个节点进行划分,可以完成稳定性。借助六个节点,分别为小于等于大于区域的头部和尾部,遍历链表,依次将相应的节点挂在相应区域的位置。

(注意节点next指针的处理,当把head挂上去时,为保证不出混乱,先记录下来head.next的节点,然后把head.next设置为空,最后再将节点连回去时,要注意可能某区域为空)

 

 

 

代码:

public static Node listPartition2(Node head, int point) {
		if (head == null || head.next == null)
			return head;
		Node Sst = null;
		Node Sed = null;
		Node Est = null;
		Node Eed = null;
		Node Lst = null;
		Node Led = null;
		Node next=null;
		while (head != null) {
			next=head.next;
			head.next=null;//保证挂在分组上的节点仅仅是这一个节点,而不是一大串节点,不然会乱掉
			if (head.value > point) {
				if (Lst == null) {
					Lst = head;
					Led = head;
				} else {
					Led.next = head;
					Led = head;
				}
			} else if (head.value < point) {
				if (Sst == null) {
					Sst = head;
					Sed = head;
				} else {
					Sed.next = head;
					Sed = head;
				}
			} else {
				if (Est == null) {
					Est = head;
					Eed = head;
				} else {
					Eed.next = head;
					Eed = head;
				}
			}
			head = next;
		}
		//空区处理,如果中间区域存在,与大区域相连(大区域存不存在并不重要,如果不存在即为null)
		//如果不存在,中间区域头就和大区域头合并。
		if (Est != null)
			Eed.next = Lst;
		else if (Est == null) {
			Est = Lst;
		}
		//如果小于区域不为空,与等于区域相连,返回值为小于区域头节点。如果为空,则返回值为等于区域头节点
		if (Sst != null)
			Sed.next = Est;
		if (Sst == null) {
			return Est;
		}
		return Sst;
		
	/*	if (Sed != null) {
			Sed.next = Est;
			Eed = Eed == null ? Sed : Eed;
		}
		all reconnect
		if (Eed != null) {
			Eed.next = Lst;
		}
		return Sst != null ? Sst : Est != null ? Est : Lst;
*/
	}

包括数组的荷兰国旗实现,也可以借助链表达到稳定性


(以下可忽略)

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

		public Node(int a) {
			this.value = a;
		}
	}
	public static Node listPartition1(Node head, int point) {
		if (head == null || head.next == null)
			return head;
		int i = 0;
		Node cur = head;
		while (cur != null) {
			cur = cur.next;
			i++;
		}
		Node nodelist[] = new Node[i];
		cur = head;
		for (i = 0; i < nodelist.length; i++) {
			nodelist[i] = cur;
			cur = cur.next;
			//指向空
			nodelist[i].next=null;	
		}
		arrpartition(nodelist, point);
		// 数组已经划分为三部分
		for (i = 0; i < nodelist.length - 1; i++) {
			nodelist[i].next = nodelist[i + 1];
		}
		nodelist[i].next = null;
		return nodelist[0];
	}

	private static void arrpartition(Node[] nodelist, int point) {
		int small = -1;
		int i = 0;
		int big = nodelist.length;
		while (i < big) {
			if (nodelist[i].value < point) {
				swap(nodelist, ++small, i++);
			} else if (nodelist[i].value > point) {
				swap(nodelist, --big, i);
			} else
				i++;
		}

	}

	private static void swap(Node[] nodelist, int i, int j) {
		Node t = nodelist[i];
		nodelist[i] = nodelist[j];
		nodelist[j] = t;
	}

	// 额外空间复杂度O(1)只用几个节点进行划分,可以完成稳定性。注意节点next指针的处理。最后分组为空时的处理
	public static Node listPartition2(Node head, int point) {
		if (head == null || head.next == null)
			return head;
		Node Sst = null;
		Node Sed = null;
		Node Est = null;
		Node Eed = null;
		Node Lst = null;
		Node Led = null;
		Node next=null;
		while (head != null) {
			next=head.next;
			head.next=null;//保证挂在分组上的节点仅仅是这一个节点,而不是一大串节点,不然会乱掉
			if (head.value > point) {
				if (Lst == null) {
					Lst = head;
					Led = head;
				} else {
					Led.next = head;
					Led = head;
				}
			} else if (head.value < point) {
				if (Sst == null) {
					Sst = head;
					Sed = head;
				} else {
					Sed.next = head;
					Sed = head;
				}
			} else {
				if (Est == null) {
					Est = head;
					Eed = head;
				} else {
					Eed.next = head;
					Eed = head;
				}
			}
			head = next;
		}
		//空区处理,如果中间区域存在,与大区域相连(大区域存不存在并不重要,如果不存在即为null)
		//如果不存在,中间区域头就和大区域头合并。
		if (Est != null)
			Eed.next = Lst;
		else if (Est == null) {
			Est = Lst;
		}
		//如果小于区域不为空,与等于区域相连,返回值为小于区域头节点。如果为空,则返回值为等于区域头节点
		if (Sst != null)
			Sed.next = Est;
		if (Sst == null) {
			return Est;
		}
		return Sst;
		
	/*	if (Sed != null) {
			Sed.next = Est;
			Eed = Eed == null ? Sed : Eed;
		}
		all reconnect
		if (Eed != null) {
			Eed.next = Lst;
		}
		return Sst != null ? Sst : Est != null ? Est : Lst;
*/
	}
	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);

		//Node head1 = null;
		printLinkedList(head1);
		head1 = listPartition2(head1, 2);// 更改新的头节点
		printLinkedList(head1);
	}
	private static void printLinkedList(Node head) {
		System.out.println("Node List:");
		while (head != null) {
			System.out.print(head.value + " ");
			head = head.next;
		}
		System.out.println();
	}
}

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值