C++实现快速排序改进版

算法思想

一趟快排:找一个数据,以它的作为“枢轴(pivot)”,凡其小于枢轴的数据均移动至该数据之前,反之,凡大于枢轴的数据均移动至该数据之后。
 一趟快排之后,记录的无序序列 arr[s…t] 将分割成两部分:arr[s…i-1]arr[i+1…t] ,且
a r r [ m ] ≤ a r r [ i ] ≤ a r r [ n ] s ≤ m ≤ i − 1 ,   i + 1 ≤ n ≤ t ,   a r r [ i ]   i s   t h e   p i v o t arr[m] \leq arr[i] \leq arr[n] \qquad s \leq m \leq i-1 ,\ i+1 \leq n \leq t ,\ arr[i]\ is \ the \ pivot arr[m]arr[i]arr[n]smi1, i+1nt, arr[i] is the pivot

快速排序:通过一趟快排将待排数据分隔成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

算法时间复杂度分析

  • 最好的情况:每次划分所取的基准都是当前无序区的"中值"数据,划分的结果是基准的左、右两个无序子区间的长度大致相等。时间复杂度:O(nlogn)
  • 最坏的情况: 每次划分选取的基准都是当前无序区中最小(或最大)的数据,划分的结果是基准左边的子区间为空(或右边的子区间为空),而划分所得的另一个非空的子区间中数据数目,仅仅比划分前的无序区中记录个数减少一个。时间复杂度为O(n*n)

算法实现与改进

基础版

int partition1(vector<int>& arr, int low, int high) {
	int pivot = arr[low];//定义基准
	while (low < high) {
		//必须先从右往左扫描,防止最右侧的数据丢失
		while (low < high && arr[high] >= pivot) //寻找小于基准的数据的下标
			high--;
		arr[low] = arr[high];
		while (low < high && arr[low] <= pivot)//寻找大于基准的数据的下标
			low++;
		arr[high] = arr[low];
	}
	arr[low] = pivot;//写回
	return low;
}
void Qsort1(vector<int>& arr, int low, int high) {
	if (low < high ) {//递归出口: low>=high
	    //对arr[1ow...high]进行一趟快排,并返回枢轴下标
		int pivotloc = partition1(arr, low, high);
		Qsort1(arr, low, pivotloc - 1);
		Qsort1(arr, pivotloc + 1, high);
	}
}

随机数改进版

随机生成基准(pivot),但是由于生成随机数的成本也较高,不一定能够优化时间。

int partition2(vector<int>& arr, int low, int high) {
	srand(time(nullptr));
	int random = rand() % (high - low + 1) + low;
	int pivot = arr[random];
	swap(arr[random], arr[low]);
	while (low < high) {
		//必须先从右往左扫描,防止最右侧的数据丢失
		while (low < high && arr[high] >= pivot) 
			high--;
		arr[low] = arr[high];
		while (low < high && arr[low] <= pivot) 
			low++;
		arr[high] = arr[low];
	}
	arr[low] = pivot;
	return low;
}
void Qsort2(vector<int>& arr, int low, int high) {
	if (low < high) {//递归出口: low>=high
		 //对arr[1ow...high]进行一趟快排,并返回枢轴下标
		int pivotloc = partition2(arr, low, high);
		Qsort2(arr, low, pivotloc - 1);
		Qsort2(arr, pivotloc + 1, high);
	}
}

近似取中值改进版

基准取arr[low]、arr[high]、arr[mid]的中间值,其中mid=(low+high)/2;

int partition3(vector<int>& arr, int low, int high) {
	int pivot, mid = (low + high) / 2;

	if ((low -mid) * (mid - high) > 0) {
		pivot = arr[mid];
		swap(arr[low], arr[mid]);
	}
	else if ((mid - low) * (low - high) > 0) {
		pivot = arr[low];
	}
	else {
		pivot = arr[high];
		swap(arr[low], arr[high]);
	}

	swap(arr[low], arr[mid]);
	while (low < high) {
		//必须先从右往左扫描,防止最右侧的数据丢失
		while (low < high && arr[high] >= pivot)
			high--;
		arr[low] = arr[high];
		while (low < high && arr[low] <= pivot)
			low++;
		arr[high] = arr[low];
	}
	arr[low] = pivot;
	return low;
}
void Qsort3(vector<int>& arr, int low, int high) {
	if (low < high) {//递归出口: low>=high
		//对arr[1ow...high]进行一趟快排,并返回枢轴下标
		int pivotloc = partition3(arr, low, high);
		Qsort3(arr, low, pivotloc - 1);
		Qsort3(arr, pivotloc + 1, high);
	}
}

小区间优化

小区间的排序,选择用 二分查找的插入排序进行优化

void BiInsertionSort(vector<int>& arr,int begin,int end) {//arr[begin...end]
	// 作折半插入排序
	int low, high, mid,temp;
	for (int i = begin + 1; i <= end; i++) {
		temp = arr[i];//暂存arr[i]
		//在 arr[begin...i-1]中折半查找插入位置(high+1)
		low = begin;
		high = i - 1;
		while (low <= high) {
			mid = (low + high) / 2;
			if (temp < arr[mid])       //升序"<",降序“>”
				high = mid - 1;        // 插入点在低半区
			else  low = mid + 1;        // 插入点在高半区
		}
		for (int j = i - 1; j >= high + 1; j--) {
			arr[j + 1] = arr[j];//数据后移
		}
		arr[high + 1] = temp;

	}

} 
int partition2(vector<int>& arr, int low, int high) {
	srand(time(nullptr));
	int random = rand() % (high - low + 1) + low;
	int pivot = arr[random];
	swap(arr[random], arr[low]);
	while (low < high) {
		//必须先从右往左扫描,防止最右侧的数据丢失
		while (low < high && arr[high] >= pivot)  
			high--;
		arr[low] = arr[high];
		while (low < high && arr[low] <= pivot) 
			low++;
		arr[high] = arr[low];
	}
	arr[low] = pivot;
	return low;
}
void Qsort2(vector<int>& arr, int low, int high) {//arr[low..high]
	if (high - low < 10) {
		BiInsertionSort(arr, low, high);
	}
	if (low < high) {//递归出口: low>=high
		//对arr[1ow...high]进行一趟快排,并返回枢轴下标
		int pivotloc = partition2(arr, low, high);
		Qsort2(arr, low, pivotloc - 1);
		Qsort2(arr, pivotloc + 1, high);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值