数组快排
快速排序很多人都懂,大体思路是首先选中一个标志位(通常选定数组的第一个元素),然后用首尾两个标识分别找出大于标志位的和小于标志位的两个数,然后交换,接着继续找下去,直到首尾两个标识相等,此时再将标志位于标识交换,就得到了标志位索面的元素小于标志位,右面的大于标志位,接着递归下去就行了。
网上写代码的很多,但是感觉都很乱,思路不清晰,这里我将数组快排的两种形式(递归与非递归)写出来,方便大家快速理解。
//递归方法
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;
}
}
看到这里想必你对快排有了更清晰的认识了,多写多练!