快速排序实现(C++实现)

理解:

  1. 对某一数组A,每次选择一个值作为pivot支点,将所有小于pivot的值放在pivot左边,将所有大于pivot的值放在pivot右边,如此将数组分成了左右两部分SubAL,SubAR。
  2. 对每一部分数组Sub,重复进行以上过程,最终实现完整排序。
#include<iostream>
using namespace std;

template <class T>
void Swap(T&a, T&b){
	T tmp = a;
	a = b;
	b = tmp;
}

template <class T>
T indexOfMax(T a[], int n){
	int i,index;
	int max = 0;
	for (i = 0; i < n; i++){
		if (max < a[i]){
			max = a[i];
			index = i;
		}		
	}
	return index;
}

template <class T>
void quicksort(T a[], int n){
	//驱动函数

	if (n <= 1)return;	
	int max = indexOfMax(a, n);
	Swap(a[n - 1], a[max]);
	//将最大的函数移到最右侧,以免leftCursor连续自增,导致数组越界
	quickSort(a, 0, n - 2);
}

template <class T>
void quickSort(T a[], int leftEnd, int rightEnd){

	if (leftEnd >= rightEnd) return;

	int leftCursor = leftEnd;
	int rightCursor = rightEnd + 1;
	//为了后面的do-while语句作出的协调

	T pivot = a[leftEnd];
	//将最左端的元素当作支点pivot

	while (true){
		do{	// 直接do-while,跳过最左端的pivot
			leftCursor++;
		} while (a[leftCursor] < pivot);
		//找到大于等于支点的元素下标

		do{
			rightCursor--;
		} while (a[rightCursor] > pivot);
		//找到小于等于支点的元素下标

		if (leftCursor >= rightCursor) break;
		//如果左游标大于等于右游标,说明遍历已经重合或擦肩而过,放弃交换,该轮结束。
		//ps:注意,这里只有两种情况:rightCursor == leftCursor 或 rightCursor == leftCursor-1.
		//因为只要经历了前面的第一个do-while循环,我们可以肯定:在leftCursor前面的值都已经小于pivot,
		//因此,这些值必然符合第二个do-while的终止条件
		
		Swap(a[leftCursor], a[rightCursor]);
		//否则就说明可以交换
	}

	a[leftEnd] = a[rightCursor];
	//将右游标此时停留的位置的值赋给最左端(支点pivot)的值
	a[rightCursor] = pivot;
	//将支点值赋给右游标停下的位置。

	//相当于交换操作。————为什么?如何理解与rightCursor交换的操作而不是与leftCursor交换?
	//假设从上述while中break跳出,分析此时leftCursor和rightCursor的位置关系 与 元素大小关系。
	//如果leftCursor位置上的元素大于pivot,则rightCursor必然为leftCursor-1;pivot应为中值,故与必然比pivot小的a[rightCursor]交换,如此使得左端的值比pivot小。如果交换了a[leftCursor]就会出现pivot左边出现比pivot大的值。这是错误的。
	//如果leftCursor位置上的元素等于pivot,则rightCursor必然等于leftCursor。同理,既然相等则直接交换即可。
	//只有以上两种情况的可能性。

	quickSort(a, leftEnd, rightCursor - 1);
	quickSort(a, rightCursor + 1, rightEnd);
	//递归调用该函数,这里可以看出以rightCursor位置的值作为分界点,就是之前的pivot
}


int main(){
	const int n = 1000;
	int A[n];
	int i;
	for (i = 0; i < n; i++){
		A[i] = ceil(rand());
	}

	quicksort(A,n);
	for (i = 0; i < n; i++){
		cout << A[i] << " ";
	}
	system("pause");
	return 0;
}

更为简洁的写法——挖坑理解:

void qSort(vector<int> &a, int left, int rightEnd){
	int l = left;	// 左游标
	int r = rightEnd;	//右游标
	if(l >= r)	return;
	int p = a[left];	//取基准数,此时a[left]位置挖出了一个坑待填。
	while(l < r){
		while(l < r && a[r] >= p) r--;
		if(l < r) a[l] = a[r];	// 如果l<r,那么只可能是出现了小于p的数,填入坑。
		// 填坑后,a[r]又空出来了,又挖了一个坑。
		while(l < r && a[l] < p) l++;
		if(l < r) a[r] = a[l];	// 此时出现了大于等于p的数,填入坑
	}
	// 此时一定有l == r,因为while中无时无刻不在判定l和r的大小
	a[l] = p;
	qSort(a, left, l - 1);
	qSort(a, l + 1, rightEnd);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值