快速排序是一种比归并排序还要快的排序算法,具体原理如下图所示
对上图所示的数组,首先随机选取一个参照元素,一般选取最左边的元素4为参照元素,然后将数组排序成以4为分界点,左边都是小于4的元素,右边都是大于4的元素,按照这种方式进行不断递归,就可实现整个数组的排序。
上图显示的是程序的实现过程,首先指定最左边的元素
为参照元素,索引为
,小于元素
的 最后一个元素的索引为
,正在处理的元素在大于元素
的元素的后面,索引为
,如果
,此时就将元素
合并到左边的元素中,
,如果此时
,那么就将
位置的元素与
位置的元素交换,交换后
,此时
位置的元素就是小于
的,原来
位置的大于
元素交换到
位置了,
,以此类推,
遍历到数组的最后一个元素后for循环停止。此时还需要最后将
位置的元素与
位置的元素交换,完成partition操作。
首先对整个数组进行partition操作,然后通过递归过程,最终将只处理一个只有一个元素的数组,一个元素的数组是有序的,然后就可对整个数组进行排序。
关于快速排序的原理,也可参考这两篇博客,博客一,博客二。
下面是程序实现
#include <iostream>
#ifndef _SORTINGHELP_H_
#define _SORTINGHELP_H_
#include "SortingHelp.h"
#endif // _SORTINGHELP_H_
#include "MergeSorting.h"
using namespace std;
//对arr[l...r]进行partition操作
//返回p,使得arr[l...p-1] < arr[p]; arr[p+1...r] > arr[p]
template<typename T>
int __partition(T arr[], int l, int r){
T v = arr[l];
int j = l;
//arr[l+1...j] < v; arr[j+1...i) > v
for(int i = l + 1; i <= r; i++){
if (arr[i] < v){
swap(arr[i], arr[j + 1]);
j++;
}
}
swap(arr[l], arr[j]);
return j;
}
//对arr[l...r]部分进行排序
template<typename T>
void __quickSorting(T arr[], int l, int r){
if (l >= r)
return;
int p = __partition(arr, l, r);
__quickSorting(arr, l, p - 1);
__quickSorting(arr, p + 1, r);
}
template<typename T>
void quickSorting(T arr[], int n){
__quickSorting(arr, 0, n-1);
}
int main(){
int a[] = {8,7,6,5,4,3,2,1};
int n = 8;
quickSorting(a, n);
for(int i = 0; i < n; i++){
cout<<a[i]<<" ";
}
cout<<endl;
return 0;
}
//int main()
//{
// int n = 100000;
// int *arr = generateRandomArray(n, 0, n);
// int *arr2 = copyIntArray(arr, n);
// testSorting("MergeSorting", MergeSorting, arr, n);
// testSorting("quickSorting", quickSorting, arr2, n);
// delete[] arr;//最后删除数组开辟的空间
// delete[] arr2;
// return 0;
//}
输出结果为
与归并排序比较
int main()
{
int n = 100000;
int *arr = generateRandomArray(n, 0, n);
int *arr2 = copyIntArray(arr, n);
testSorting("MergeSorting", MergeSorting, arr, n);
testSorting("quickSorting", quickSorting, arr2, n);
delete[] arr;//最后删除数组开辟的空间
delete[] arr2;
return 0;
}
输出为
排序10万个元素的数组,快速排序要快于归并排序
上面程序中引用的 SortingHelp.h 和 MergeSorting.h 如下,
关于归并排序请参见以前博客数据结构与算法C++之归并排序
//MergeSorting.h
#include <iostream>
#ifndef _SORTINGHELP_H_
#define _SORTINGHELP_H_
#include "SortingHelp.h"
#endif // _SORTINGHELP_H_
using namespace std;
//将arr[l...mid]和arr[mid+1...r]两部分进行归并
template<typename T>
void __merge(T arr[], int l, int mid, int r){
T aux[r-l+1];
for (int i = l; i <= r; i++){
aux[i-l] = arr[i];
}
int i = l, j = mid + 1;
for (int k = l; k <= r; k++){
if (i > mid){
arr[k] = aux[j-l];
j++;
}
else if (j > r){
arr[k] = aux[i-l];
i++;
}
else if (aux[i-l] < aux[j-l]){
arr[k] = aux[i-l];
i++;
}
else{
arr[k] = aux[j-l];
j++;
}
}
}
//递归使用归并排序,对arr[l...r]的范围进行排序
template<typename T>
void __mergeSorting(T arr[], int l, int r){
if (l >= r)
return;
int mid = (l + r)/2;
__mergeSorting(arr, l, mid);
__mergeSorting(arr, mid+1, r);
if (arr[mid] > arr[mid+1])//如果左边的序列已经小于右边的序列,就不用合并了
__merge(arr, l, mid, r);
}
template<typename T>
void MergeSorting(T arr[], int n){
__mergeSorting(arr, 0, n-1);
}
//SortingHelp.h
#include <iostream>
#include <ctime> //time()函数
#include <cstdlib> //rand()函数
#include <cassert> //assert()函数
using namespace std;
int* generateRandomArray(int n, int rangeL, int rangeR){//生成随机数组
assert(rangeL < rangeR);
int *arr = new int[n];
srand(time(NULL));
for (int i = 0; i < n; i++){
arr[i] = rand() % (rangeR - rangeL + 1) + rangeL;
}
return arr;
}
int* generateNearlyOrderedArray(int n, int swapTimes){//生成近乎有序的数组
int *arr = new int[n];
for (int i = 0; i < n; i++){
arr[i] = i;
}
srand(time(NULL));
for (int i = 0; i < swapTimes; i++){
int posx = rand() % n;
int posy = rand() % n;
swap(arr[posx], arr[posy]);
}
return arr;
}
template<typename T>
void printArray(T arr[], int n){//打印数组元素
for (int i = 0; i < n; i ++){
cout<<arr[i]<<" ";
}
cout<<endl; //换行
return;
}
template<typename T>
bool isSorted(T arr[], int n){//测试排序算法是否正确
for (int i = 0; i < n - 1; i++){
if (arr[i] > arr[i + 1])
return false;
}
return true;
}
template<typename T>
void testSorting(string sortName, void(*sorting)(T[], int), T arr[], int n){
//第二个参数是传入排序函数的指针
clock_t startClock = clock();
sorting(arr, n);
clock_t endClock = clock();
assert(isSorted(arr, n));
cout<<sortName<<" : "<<double(endClock-startClock)/CLOCKS_PER_SEC<<" s"<<endl;
return;
}
int* copyIntArray(int arr[], int n){
int* arr2 = new int[n];
copy(arr, arr+n, arr2);
return arr2;
}
template<typename T> //定义模板类型,使对各种数据类型都适用,如double,float,string
void SelectionSorting(T a[], int n){//选择排序算法
for (int i = 0; i < n; i++){
int minIndex = i;
for (int j = i + 1; j < n; j++){
if (a[j] < a[minIndex])
minIndex = j;
}
swap(a[i], a[minIndex]);
}
}
template<typename T>
void InsertionSortingImproved(T arr[], int n){
for (int i = 0; i < n - 1; i++){
T temp = arr[i+1];
int j;
for (j = i + 1; j > 0; j--){
if (arr[j-1] > temp){
arr[j] = arr[j-1];
}
else{
break;
}
}
arr[j] = temp;
}
return;
}