快排之三指针扫描分区

快排之三指针扫描分区

适用于选取主元时,所选主元在数组中有多个相同值。若数组中没有主元的相同值,没有必要用三指针扫描分区法。

下面主要分析的是partition部分的方法:
图片来源蓝桥学苑
三个指针:less(指向第一个等于主元的位置);sc(向右移动的扫描指针,指针左侧皆小于等于主元);bigger(指针右侧皆大于主元)
在分区时有三个阶段:

  • 阶段1:
    sp指针一直向右移,当扫描到小于主元的值时sc++,当扫描到大于主元的值时,其做法同单向扫描分区法一直(即swap(arr,sp,bigger)并且bigger- -),当扫描到等于主元的值时将less指针放置于sc指针的位置上,此时less指针指向了第一个等于主元的位置。 随后进入阶段2。
  • 阶段2:
    sp指针依旧向右移动,当扫描到小于主元的值时swap(arr,sp,e)并且e++这样做是为了确保小于主元的值始终在e指针的左侧。当扫描到等于主元的值时,sp++。当扫描到大于主元的值时swap(arr,sp,bigger)并且bigger- -。
  • 阶段3
    经过上述两个阶段后,数组被划分成下图。
    在这里插入图片描述
    主元依旧在begin位,此时e指向第一个等于主元位,bigger指向最后一个等于主元位。
    我们所要做的就是将swap(arr,begin,e - 1)而后e- -,如此e左侧的全小于主元,[e,bigger]都等于主元,bigger右侧全大于主元,分区完成。用数组保存e和bigger的位置,并将数组返回给quickSort方法中,最后在quickSort中递归调用quickSort[begin,e - 1]与[bigger + 1,end]排序即可。
public class 快排之三指针扫描分区 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] arr = { 8, 8, 7, 6, 5, 0, 4, 8, 3, 2, 8, 7, 10 };
		quickSort(arr, 0, arr.length - 1);
		for (int num : arr) {
			System.out.print(num + " ");
		}
	}

	private static void quickSort(int[] arr, int begin, int end) {
		if (begin >= end) {
			return;
		}
		int[] position = partition(arr, begin, end);
		quickSort(arr, begin, position[0] - 1);
		quickSort(arr, position[1] + 1, end);
	}

	// 要考虑到数组中没有与主元相等的特殊情况
	private static int[] partition(int[] arr, int begin, int end) {
		int pivot = arr[begin];
		int sp = begin + 1;
		int e = begin + 1;// 相等指针
		int bigger = end;
		while (sp <= bigger) {
			if (arr[sp] < pivot) {
				sp++;
			} else if (arr[sp] > pivot) {
				swap(arr, sp, bigger);
				bigger--;
			} else {
				e = sp;
				sp++;
				break;
			}
		}
		while (sp <= bigger) {
			if (arr[sp] < pivot) {// 小于主元时,交换位置,e++
				swap(arr, sp, e);
				e++;
				sp++;
			} else if (arr[sp] > pivot) {
				swap(arr, sp, bigger);
				bigger--;
			} else {// 等于主元时,sp++
				sp++;
			}
		}
		// 假如不存在等于主元的元素
		if (arr[e] != pivot) {
			swap(arr, begin, bigger);
			int[] position = { bigger, bigger };
			return position;
		}
		// 若存在与主元相等的元素,主元依旧在begin位,此时e指向第一个等于主元位,bigger指向最后一个等于主元位
		else {
			swap(arr, begin, e - 1);
			e--;
			int[] position = { e, bigger };// 记录两个端点位置
			return position;
		}
	}

	private static void swap(int[] arr, int i, int j) {
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
}

猜你喜欢

转载自blog.csdn.net/a739260008/article/details/86537795