數組快排
快速排序很多人都懂,大體思路是首先選中一個標誌位(通常選定數組的第一個元素),然後用首尾兩個標識分別找出大於標誌位的和小於標誌位的兩個數,然後交換,接着繼續找下去,直到首尾兩個標識相等,此時再將標誌位於標識交換,就得到了標誌位索麪的元素小於標誌位,右面的大於標誌位,接着遞歸下去就行了。
網上寫代碼的很多,但是感覺都很亂,思路不清晰,這裏我將數組快排的兩種形式(遞歸與非遞歸)寫出來,方便大家快速理解。
//遞歸方法
public static void quickSort(int[] array, int low, int high) {
//遞歸的終止條件就是,如果你的結束標識大於了開始標識就結束
if (low > high) return;
int i = low;
int j = high;
//選中第一個元素當標誌位
int key = array[low];
int t;
while (i < j) {
//找到第一個小於key的位置
while (key <= array[j] && i < j)
j--;
//找到第一個大於key的位置
while (key >= array[i] && i < j)
i++;
//交換兩個數
if (i < j) {
t = array[i];
array[i] = array[j];
array[j] = t;
}
}
//將標誌位和ij的重合位置進行交換
array[low] = array[i];
array[i] = key;
//對標誌位的左面進行快排
quickSort(array, low, i - 1);
//對標誌位的右面進行快排
quickSort(array, i + 1, high);
}
//非遞歸
public static void quickSort(int[] a) {
Stack<int[]> stack = new Stack<>();
//棧中存的是每次需要快排的數組的區間的首位標識
stack.add(new int[]{0, a.length - 1});
//只要棧不爲空就說明還有若干段沒排好序
while (!stack.isEmpty()) {
//彈出第一組排序的首尾標識
int[] tuple = stack.pop();
int start = tuple[0], end = tuple[1], i = tuple[0], j = tuple[1];
//循環和遞歸是一樣的
while (i < j) {
while (i < j && a[start] < a[j])
j--;
while (i < j && a[start] >= a[i])
i++;
if (i < j) {
int temp = a[j];
a[j] = a[i];
a[i] = temp;
}
}
if (start != i) {
int temp = a[start];
a[start] = a[i];
a[i] = temp;
}
//此時i = j,a[i] = a[j] = key,這個key就是第一個標誌位
//如果此時,i的左面只有一個start元素,此時就不需要排序了
if (i - 1 > start)
stack.add(new int[]{0, i - 1});
//同理,j的右面只有一個元素end,就不需要排序了
if (j + 1 < end)
stack.add(new int[]{j + 1, end});
}
}
鏈表快排
整體思想是兩個指針p1和p2,保持p1前面的比key小,p1和p2之間的比key大。key就是我們選取的標誌位,我這裏選的是鏈表的頭結點。
/*class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class l148QuickSortList {
public static ListNode sortList(ListNode head) {
quickSort(head, null);
return head;
}
public static void quickSort(ListNode head, ListNode end) {
if (head != end) {
//先分再排
ListNode node = sort(head, end);
//排序
quickSort(head, node);
quickSort(node.next, end);
}
}
public static ListNode sort(ListNode head, ListNode end) {
//指定兩個指針p1在前,p2在後
ListNode p1 = head;
ListNode p2 = head.next;
while (p2 != null) {
//如果p2比head的值小的話,p1前進一位,和p2的val進行交換,然後p2再前進一步
//始終保持p1前面的比key小,p2和p1中間的比key大於等於,p2後面的是沒有比過的
if (p2.val < head.val) {
p1 = p1.next;
int temp = p1.val;
p1.val = p2.val;
p2.val = temp;
}
p2 = p2.next;
}
//如果p1移動了就和key交換值,否則說明都比key大
if (p1 != head) {
int tmp = p1.val;
p1.val = head.val;
head.val = tmp;
}
return p1;
}
}
看到這裏想必你對快排有了更清晰的認識了,多寫多練!