連結串列(三)連結串列形式的荷蘭國旗
阿新 • • 發佈:2018-12-21
問題:給定一個單向連結串列的頭節點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();
}
}