1. 程式人生 > >連結串列(三)連結串列形式的荷蘭國旗

連結串列(三)連結串列形式的荷蘭國旗

問題:給定一個單向連結串列的頭節點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();
	}
}