常用排序算法的C++实现汇总
以下为常用排序算法的C++实现。其中快速排序,总结实现了双路快排和三路快排。最后还实现了一个SortHelper.h的文件,可以随机生成无序或者近似有序的数据,检验数组是否已经排好序,以及各排序算法程序运行时间对比。程序源文件可以在我的github地址下载得到。
插入排序
template<typename T>
void insertionSort(vector<T>& nums)
{
unsigned long n = nums.size();
for(unsigned int i = 1; i < n; i ++)
{
// 寻找元素arr[i]合适的插入位置
// method 1
#if 0
for(unsigned int j = i; j > 0; j--)
{
if(nums[j] < nums[j-1] )
{
swap(nums[j], nums[j-1]);
}
else
{
break;
}
}
#endif
// method 2
#if 0
for(unsigned int j = i; j > 0 && nums[j] < nums[j-1]; j --)
{
swap(nums[j], nums[j-1]);
}
#endif
// method 3
#if 1
T e = nums[i];
unsigned int j; // j保存元素e应该插入的位置
for(j = i; j > 0 && nums[j-1] > e; j--)
{
nums[j] = nums[j-1];
}
nums[j] = e;
#endif
}
return;
}
选择排序
template<typename T>
void selectionSort(vector<T>& nums)
{
unsigned long n = nums.size();
for(unsigned int i = 0 ; i < n ; i ++)
{
int minIndex = i;
for(unsigned int j = i + 1 ; j < n ; j ++ )
if(nums[j] < nums[minIndex])
minIndex = j;
swap(nums[i] , nums[minIndex]);
}
}
冒泡排序
Method 1
template<typename T>
void bubbleSort(vector<T>& nums)
{
unsigned long n = nums.size();
bool swapped;
do
{
swapped = false;
for(unsigned int i = 1; i < n; i ++)
{
if(nums[i-1] > nums[i])
{
swap(nums[i-1], nums[i]);
swapped = true;
}
}
// 优化, 每一趟Bubble Sort都将最大的元素放在了最后的位置
// 所以下一次排序, 最后的元素可以不再考虑
n--;
}while(swapped);
}
Method 2
template<typename T>
void bubble2Sort(vector<T>& nums)
{
unsigned long n = nums.size();
int newn; // 使用newn进行优化
do
{
newn = 0;
for(unsigned int i = 1; i < n; i ++)
{
if(nums[i-1] > nums[i])
{
swap(nums[i-1], nums[i]);
// 记录最后一次的交换位置,在此之后的元素在下一轮扫描中均不考虑
newn = i;
}
}
n = newn;
}while(newn > 0);
}
希尔排序
template<typename T>
void shellSort(vector<T>& nums)
{
unsigned long n = nums.size();
// 计算 increment sequence: 1, 4, 13, 40, 121, 364, 1093...
int h = 1;
while(h < n/3)
{
h = 3 * h + 1;
}
while( h >= 1 )
{
// h-sort the array
for(unsigned int i = h; i < n; i++)
{
// 对 nums[i], nums[i-h], nums[i-2*h], nums[i-3*h]... 使用插入排序
T e = nums[i];
int j;
for(j = i; j >= h && e < nums[j-h]; j -= h)
{
nums[j] = nums[j-h];
}
nums[j] = e;
}
h /= 3;
}
}
归并排序
// 将nums[l...mid]和nums[mid+1...r]两部分进行归并
template<typename T>
void merge(vector<T>& nums, unsigned long l, unsigned long mid, unsigned long r)
{
vector<T> aux(r-l+1);
for(unsigned long i = l; i <= r; i ++)
{
aux[i-l] = nums[i];
}
// 初始化,i指向左半部分的起始索引位置l;j指向右半部分起始索引位置mid+1
unsigned long i = l, j = mid+1;
for(unsigned long k = l; k <= r; k ++)
{
if(i > mid)
{
// 如果左半部分元素已经全部处理完毕
nums[k] = nums[j-l];
j++;
}
else if(j > r)
{
// 如果右半部分元素已经全部处理完毕
nums[k] = nums[i-l];
i++;
}
else if(aux[i-l] < aux[j-l])
{
// 左半部分所指元素 < 右半部分所指元素
nums[k] = nums[i-l];
i++;
}
else
{
// 左半部分所指元素 >= 右半部分所指元素
nums[k] = aux[j-l];
j++;
}
}
}
// 递归使用归并排序,对nums[l...r]的范围进行排序
template<typename T>
void mergeSort(vector<T>& nums, unsigned long l, unsigned long r)
{
if(l >= r)
{
return;
}
unsigned long mid = (l+r)/2;
mergeSort(nums, l, mid);
mergeSort(nums, mid+1, r);
merge(nums, l, mid, r);
}
template<typename T>
void mergeSort(vector<T>& nums)
{
unsigned long n = nums.size();
mergeSort(nums, 0, n-1);
}
快速排序
// 双路快速排序的partition2
// 返回p, 使得nums[l...p-1] < nums[p] ; nums[p+1...r] > nums[p]
template <typename T>
unsigned long partition2(vector<T>& nums, long long l, long long r)
{
// 随机在nums[l...r]的范围中, 选择一个数值作为标定点pivot
srand((unsigned)time(NULL));
long long pivot = rand() % (r-l+1) + l;
swap(nums[l], nums[pivot]);
T v = nums[l];
// nums[l+1...i) <= v; nums(j...r] >= v
long long i = l+1, j = r;
while(true)
{
while(i <= r && nums[i] < v)
i++;
while(j >= l+1 && nums[j] > v)
j--;
if(i > j)
break;
swap(nums[i], nums[j]);
i++;
j--;
}
swap(nums[l], nums[j]);
return j;
}
template <typename T>
unsigned long partition(vector<T>& nums, long long l, long long r)
{
T v = nums[l];
long long j = l; // nums[l+1...j] < v ; nums[j+1...i) > v
for(long long i = l + 1; i <= r; i ++)
{
if(nums[i] < v )
{
j ++;
swap(nums[j] , nums[i]);
}
}
swap(nums[l] , nums[j]);
return j;
}
// 对nums[l...r]部分进行快速排序
template <typename T>
void quickSort(vector<T>& nums, long long l, long long r)
{
if(l >= r)
return;
long long p = partition2(nums, l, r);
if(p == 0 || l+1 == p || p + 1 == r)
return;
quickSort(nums, l, p-1);
quickSort(nums, p+1, r);
}
#if 0
template <typename T>
void quickSort(vector<T>& nums)
{
srand((unsigned)time(NULL));
long long n = nums.size();
quickSort(nums, 0, n-1);
}
#endif
#if 1
// 递归的三路快速排序算法
template <typename T>
void quickSort3Ways(vector<T>& nums, long long l, long long r)
{
if(l >= r)
return;
// 随机在nums[l...r]的范围中, 选择一个数值作为标定点pivot
swap(nums[l], nums[rand()%(r-l+1)+l] );
T v = nums[l];
long long lt = l; // nums[l+1...lt] < v
long long gt = r + 1; // nums[gt...r] > v
long long i = l+1; // nums[lt+1...i) == v
while(i < gt)
{
if(nums[i] < v )
{
swap(nums[i], nums[lt+1]);
i ++;
lt ++;
}
else if(nums[i] > v )
{
swap(nums[i], nums[gt-1]);
gt --;
}
else
{ // nums[i] == v
i ++;
}
}
swap(nums[l], nums[lt] );
quickSort3Ways(nums, l, lt-1);
quickSort3Ways(nums, gt, r);
}
template <typename T>
void quickSort(vector<T>& nums)
{
srand((unsigned)time(NULL));
long long n = nums.size();
quickSort3Ways(nums, 0, n-1);
}
#endif
排序辅助测试函数
namespace sortHelper
{
/*
* 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR]
*/
template<typename T>
bool generateRandomArray(vector<T>& nums, unsigned int n, T range_l, T range_r)
{
nums.clear();
srand((unsigned)time(NULL));
for(unsigned int i = 0; i < n; i++)
{
T num =rand() % (range_r - range_l + 1) + range_l;
nums.push_back(num);
}
return true;
}
/*
* 生成一个近乎有序的数组
* 首先生成一个含有[0...n-1]的完全有序数组, 之后随机交换swapTimes对数据
* swapTimes定义了数组的无序程度:
* swapTimes == 0 时, 数组完全有序
* swapTimes 越大, 数组越趋向于无序
*/
template<typename T>
bool generateNearlyOrderedArray(vector<T>& nums, unsigned int n, int swapTimes)
{
nums.resize(n);
for(int i = 0 ; i < n ; i ++)
{
nums[i] = i;
}
srand((unsigned)time(NULL));
for(unsigned int i = 0 ; i < swapTimes ; i ++)
{
int posx = rand()%n;
int posy = rand()%n;
swap(nums[posx] , nums[posy]);
}
return true;
}
/*
* 打印arr数组的所有内容
*/
template<typename T>
void printArray(vector<T>& nums)
{
unsigned int n = nums.size();
for(unsigned int i = 0; i < n; i++)
{
cout<<nums[i]<<" ";
}
cout<<endl;
return;
}
/*
* 判断arr数组是否有序
*/
template<typename T>
bool isSorted(vector<T>& nums)
{
unsigned long n = nums.size();
for(unsigned int i = 0; i < n - 1; i++)
{
if(nums[i] > nums[i + 1])
{
return false;
}
}
return true;
}
};
main函数
int main(int argc, const char * argv[])
{
vector<int> nums;
unsigned int n = 10000;
int range_l = 0;
int range_r = 1000000;
clock_t startTime, endTime;
nums.clear();
generateRandomArray(nums, n, range_l, range_r);
startTime = clock();
selectionSort(nums);
endTime = clock();
cout<<"SelectionSort : "<< double(endTime - startTime) / CLOCKS_PER_SEC << " s"<<endl;
isSorted(nums);
nums.clear();
generateRandomArray(nums, n, range_l, range_r);
startTime = clock();
insertionSort(nums);
endTime = clock();
cout<<"InsertionSort : "<< double(endTime - startTime) / CLOCKS_PER_SEC << " s"<<endl;
isSorted(nums);
nums.clear();
generateRandomArray(nums, n, range_l, range_r);
startTime = clock();
bubbleSort(nums);
endTime = clock();
cout<<"BubbleSort : "<< double(endTime - startTime) / CLOCKS_PER_SEC << " s"<<endl;
isSorted(nums);
nums.clear();
generateRandomArray(nums, n, range_l, range_r);
startTime = clock();
bubble2Sort(nums);
endTime = clock();
cout<<"Bubble2Sort : "<< double(endTime - startTime) / CLOCKS_PER_SEC << " s"<<endl;
isSorted(nums);
nums.clear();
generateRandomArray(nums, n, range_l, range_r);
startTime = clock();
shellSort(nums);
endTime = clock();
cout<<"ShellSort : "<< double(endTime - startTime) / CLOCKS_PER_SEC << " s"<<endl;
isSorted(nums);
nums.clear();
generateRandomArray(nums, n, range_l, range_r);
startTime = clock();
mergeSort(nums);
endTime = clock();
cout<<"MergeSort : "<< double(endTime - startTime) / CLOCKS_PER_SEC << " s"<<endl;
isSorted(nums);
return 0;
}
程序运行结果如下图所示:
以上程序源文件都可以在我的github地址中下载得到。