快速排序的实现

最简单的快排

void QSort(int arr[],int low,int high)
{
	int first = low;
	int last = high;

	if (low>=high)
		return;
	//选择分割
	int key = SelectPivot(arr,low,high);//选择选取序列的第一个元素作为基准
	//一次分割
	while (low < high)
	{
		while (high > low && arr[high]>=key)
		{
			high--;
		}
		arr[low]=arr[high];
		while (high > low && arr[low]<=key)
		{
			low++;
		}
		arr[high]=arr[low];
	}
	arr[low]=key;//此时low=high,则把key放入low 或 high 均可

	//本次分割结束把序列分成了两个序列,分别在两个序列上进行快排
	QSort(arr,first,low-1);
	QSort(arr,low+1,last);
}

int SelectPivot(int arr[],int low,int high)
{
	return arr[low];//选择选取序列的第一个元素作为基准
}

随机化快排

/*快速排序,随机选择枢轴*/
void QSort(int arr[],int low,int high)
{
	int first = low;
	int last = high;

	if (low >= high)
		return;
	
	//一次分割
	int key = SelectPivotRandom(arr,low,high);//随机选择枢轴的位置
	while(low < high)
	{
		while(high > low && arr[high] >= key)
		{
			high--;
		}
		arr[low] = arr[high];
		while(high > low && arr[low] <= key)
		{
			low++;
		}
		arr[high] = arr[low];
	}
	arr[low] = key;
	//一次分割结束
	QSort(arr,first,low-1);
	QSort(arr,low+1,last);
}

void swap(int& n,int& m)
{
	int tmp = n;
	n = m;
	m = tmp;
}

/*随机选择枢轴的位置,区间在low和high之间*/
int SelectPivotRandom(int arr[],int low,int high)
{
	//产生枢轴的位置
	srand((unsigned)time(NULL));
	int pivotPos = rand()%(high - low) + low;

	//把枢轴位置的元素和low位置元素互换,此时可以和普通的快排一样调用划分函数
	swap(arr[pivotPos],arr[low]);
	return arr[low];
}

三数取中

void QSort(int arr[],int low,int high)
{
	int first = low;
	int last = high;

	if (low >= high)
		return;
	//一次分割
	int key = SelectPivotMedianOfThree(arr,low,high);//使用三数取中法选择枢轴
	while(low < high)
	{
		while(high > low && arr[high] >= key)
		{
			high--;
		}
		arr[low] = arr[high];
		while(high > low && arr[low] <= key)
		{
			low++;
		}
		arr[high] = arr[low];
	}
	arr[low] = key;
	//分割结束

	QSort(arr,first,low-1);
	QSort(arr,low+1,last);
}

/*函数作用:取待排序序列中low、mid、high三个位置上数据,选取他们中间的那个数据作为枢轴*/
int SelectPivotMedianOfThree(int arr[],int low,int high)
{
	int mid = low + ((high - low) >> 1);//计算数组中间的元素的下标

	//使用三数取中法选择枢轴
	if (arr[mid] > arr[high])//目标: arr[mid] <= arr[high]
	{
		swap(arr[mid],arr[high]);
	}
	if (arr[low] > arr[high])//目标: arr[low] <= arr[high]
	{
		swap(arr[low],arr[high]);
	}
	if (arr[mid] > arr[low]) //目标: arr[low] >= arr[mid]
	{
		swap(arr[mid],arr[low]);
	}
	//此时,arr[mid] <= arr[low] <= arr[high]
	return arr[low];
	//low的位置上保存这三个位置中间的值
	//分割时可以直接使用low位置的元素作为枢轴,而不用改变分割函数了
}

void swap(int& n,int& m)
{
	int tmp = n;
	n = m;
	m = tmp;
}

三数取中 + 结合插排 + 处理相等元素

void QSort(int arr[],int low,int high)
{
	int first = low;
	int last = high;

	int left = low;
	int right = high;

	int leftLen = 0;
	int rightLen = 0;

	if (high - low + 1 < 10)
	{
		InsertSort(arr,low,high);
		return;
	}

	//一次分割
	int key = SelectPivotMedianOfThree(arr,low,high);//使用三数取中法选择枢轴

	while(low < high)
	{
		while(high > low && arr[high] >= key)
		{
			if (arr[high] == key)//处理相等元素
			{
				swap(arr[right],arr[high]);
				right--;
				rightLen++;
			}
			high--;
		}
		arr[low] = arr[high];
		while(high > low && arr[low] <= key)
		{
			if (arr[low] == key)
			{
				swap(arr[left],arr[low]);
				left++;
				leftLen++;
			}
			low++;
		}
		arr[high] = arr[low];
	}
	arr[low] = key;

	//一次快排结束
	//把与枢轴key相同的元素移到枢轴最终位置周围
	int i = low - 1;
	int j = first;
	while(j < left && arr[i] != key)
	{
		swap(arr[i],arr[j]);
		i--;
		j++;
	}
	i = low + 1;
	j = last;
	while(j > right && arr[i] != key)
	{
		swap(arr[i],arr[j]);
		i++;
		j--;
	}
	QSort(arr,first,low - 1 - leftLen);
	QSort(arr,low + 1 + rightLen,last);
}

/*函数作用:取待排序序列中low、mid、high三个位置上数据,选取他们中间的那个数据作为枢轴*/
int SelectPivotMedianOfThree(int arr[],int low,int high)
{
	int mid = low + ((high - low) >> 1);//计算数组中间的元素的下标

	//使用三数取中法选择枢轴
	if (arr[mid] > arr[high])//目标: arr[mid] <= arr[high]
	{
		swap(arr[mid],arr[high]);
	}
	if (arr[low] > arr[high])//目标: arr[low] <= arr[high]
	{
		swap(arr[low],arr[high]);
	}
	if (arr[mid] > arr[low]) //目标: arr[low] >= arr[mid]
	{
		swap(arr[mid],arr[low]);
	}
	//此时,arr[mid] <= arr[low] <= arr[high]
	return arr[low];
	//low的位置上保存这三个位置中间的值
	//分割时可以直接使用low位置的元素作为枢轴,而不用改变分割函数了
}

void swap(int& n,int& m)
{
	int tmp = n;
	n = m;
	m = tmp;
}

//直接插入排序--小 到 大  
void InsertSort(int arr[],int low,int high)  
{  
	int i = 0;
	int j = 0;  
	int key;//存放乱序的元素  
	for ( i = low + 1;i < high + 1;i++)  
	{  
		if (arr[i-1] > arr[i])  
		{  
			key = arr[i];  
			for ( j = i-1;j >= 0 && arr[j] > key;j--)  
			{  
				arr[j+1] = arr[j];                  
			}  
			arr[j+1] = key;  
		}  
	}  
}

注意:

1、检查数据是否已经排好序

//降序
for (int i = 0;i < len-1;i++)
{
	assert(arr[i] >= arr[i+1]);//括号里面是正常情况下的状态
} 
//升序
for (int i = 0;i < len-1;i++)
{
	assert(arr[i] <= arr[i+1]);//括号里面是正常情况下的状态
} 

2、上述代码是实现从小到大排序,如果是从大到小排序,则需要改变以下代码,其他不变

//从小到大
while(high > low && arr[high] >= key)
{
	...
}
while(high > low && arr[low] <= key)
{
	...
}
//从大到小
while(high > low && arr[high] <= key)
{
	...
}
while(high > low && arr[low] >= key)
{
	...
}



 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值