测试环境为 DEV-C++, 并且选择排序, 插入排序, 冒泡排序, 均为优化后的, 若想了解具体优化过程, 请参照: https://blog.csdn.net/qq_40164152
测试用例:
- #ifndef OPTIONAL_02_SHELL_SORT_SORTTESTHELPER_H
- #define OPTIONAL_02_SHELL_SORT_SORTTESTHELPER_H
- #include <iostream>
- #include <algorithm>
- #include <ctime>
- #include <string>
- #include <cassert>
- using namespace std;
- namespace SortTestHelper {
- // 生成有 n 个元素的随机数组, 每个元素的随机范围为[rangeL, rangeR]
- int *generateRandomArray(int n, int range_l, int range_r) {
- int *arr = new int[n];
- srand(time(NULL));
- for (int i = 0; i <n; i++)
- arr[i] = rand() % (range_r - range_l + 1) + range_l;
- return arr;
- }
- // 生成一个近乎有序的数组
- // 首先生成一个含有 [0...n-1] 的完全有序数组, 之后随机交换 swapTimes 对数据
- // swapTimes 定义了数组的无序程度
- 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;
- }
- // 拷贝整型数组 a 中的所有元素到一个新的数组, 并返回新的数组
- int *copyIntArray(int a[], int n){
- int *arr = new int[n];
- copy(a, a+n, arr);
- return arr;
- }
- // 打印 arr 数组的所有内容
- template<typename T>
- void printArray(T arr[], int n) {
- for (int i = 0; i <n; i++)
- cout << arr[i] << " ";
- cout << endl;
- return;
- }
- // 判断 arr 数组是否有序
- 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;
- }
- // 测试 sort 排序算法排序 arr 数组所得到结果的正确性和算法运行时间
- template<typename T>
- void testSort(const string &sortName, void (*sort)(T[], int), T arr[], int n) {
- clock_t startTime = clock();
- sort(arr, n);
- clock_t endTime = clock();
- cout <<sortName << ":" << double(endTime - startTime) / CLOCKS_PER_SEC << "s"<<endl;
- assert(isSorted(arr, n));
- return;
- }
- };
- #endif //OPTIONAL_02_SHELL_SORT_SORTTESTHELPER_H
选择排序:
基本思想: 每一趟在 n-i+1(i=1,2,...,n-1)个记录中选取关键字最小的记录作为有序序列中第 i 个记录. 直接选择排序和直接插入排序类似, 都将数据分为有序区和无序区, 所不同的是直接插入排序是将无序区的第一个元素直接插入到有序区以形成一个更大的有序区, 而直接选择排序是从无序区选一个最小的元素直接放到有序区的最后.
- #ifndef OPTIONAL_02_SHELL_SORT_SELECTIONSORT_H
- #define OPTIONAL_02_SHELL_SORT_SELECTIONSORT_H
- #include <iostream>
- #include <algorithm>
- using namespace std;
- template<typename T>
- void selectionSort(T arr[], int n){
- for(int i = 0 ; i <n ; i ++){
- int minIndex = i;
- for( int j = i + 1 ; j < n ; j ++ )
- if( arr[j] < arr[minIndex] )
- minIndex = j;
- swap( arr[i] , arr[minIndex] );
- }
- }
- #endif //OPTIONAL_02_SHELL_SORT_SELECTIONSORT_H
插入排序:
基本思想: 将一个记录插入到已排好序的有序表中, 从而得到一个新的, 记录数增 1 的有序表.
时间复杂度为 O(n^2), 若待排记录序列为正序, 时间复杂度可提高至 O(n); 空间上只需要一个记录的辅助空间.
- #ifndef OPTIONAL_02_SHELL_SORT_INSERTIONSORT_H
- #define OPTIONAL_02_SHELL_SORT_INSERTIONSORT_H
- #include <iostream>
- #include <algorithm>
- using namespace std;
- template<typename T>
- void insertionSort(T arr[], int n){
- for( int i = 1 ; i <n ; i ++ ) {
- T e = arr[i];
- int j;
- for (j = i; j> 0 && arr[j-1]> e; j--)
- arr[j] = arr[j-1];
- arr[j] = e;
- }
- return;
- }
- #endif //OPTIONAL_02_SHELL_SORT_INSERTIONSORT_H
冒泡排序:
基本思想: 首先将第一个记录的关键字和第二个记录的关键字进行比较, 若为逆序, 则将两个记录交换之, 然后比较第二个记录和第三个记录的关键字. 依次类推, 直至第 n-1 个记录和第 n 个记录的关键字进行过比较为止. 上述过程称做第一趟冒泡排序, 其结果使得关键字最大的记录被安置到最后一个记录的位置上. 然后进行第二趟冒泡排序, 对前 n-1 个记录进行同样操作, 其结果是使关键字次大的记录被安置到第 n-1 个记录的位置上. 一般地, 第 i 趟冒泡排序是从 1 到 n-i+1 依次比较相邻两个关键字, 并在 "逆序" 时交换相邻记录, 其结果是这 n-i+1 个记录中关键字最大的记录被交换到第 n-i+1 的位置上. 判别冒泡排序结束的条件应该是 "在一趟排序过程中没有进行过交换记录的操作".
- #ifndef OPTIONAL_02_SHELL_SORT_BUBBLESORT_H
- #define OPTIONAL_02_SHELL_SORT_BUBBLESORT_H#include <iostream>
- #include <algorithm>
- using namespace std;
- template<typename T>
- void bubbleSort( T arr[] , int n){
- int newn; // 使用 newn 进行优化
- do{
- newn = 0;
- for( int i = 1 ; i <n ; i ++ )
- if( arr[i-1]> arr[i] ){
- swap( arr[i-1] , arr[i] );
- // 记录最后一次的交换位置, 在此之后的元素在下一轮扫描中均不考虑
- newn = i;
- }
- n = newn;
- }while(newn> 0);
- }
- #endif //OPTIONAL_02_SHELL_SORT_BUBBLESORT_H
希尔排序与测试:
基本思想: 先将整个待排记录序列分割成为若干子序列分别进行直接插入排序, 待整个序列中的记录 "基本有序" 时, 再对全体记录进行一次直接插入排序. 可以看出希尔排序其实只是改进了的插入排序, 因此上面的插入排序也被称为直接插入排序.
特点: 子序列的构成不是简单地 "逐段分割", 而是将相隔某个 "增量" 的记录组成一个子序列. 它通过比较相距一定间隔的元素来工作; 各趟比较所用的距离随着算法的进行而减小, 直到只比较相邻元素的最后一趟排序为止.
- #include <iostream>
- #include "SortTestHelper.h"
- #include "SelectionSort.h"
- #include "InsertionSort.h"
- #include "BubbleSort.h"
- using namespace std;
- template<typename T>
- void shellSort(T arr[], int n){
- // 计算 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( int i = h ; i <n ; i ++ ){
- // 对 arr[i], arr[i-h], arr[i-2*h], arr[i-3*h]... 使用插入排序
- T e = arr[i];
- int j;
- for( j = i ; j>= h && e < arr[j-h] ; j -= h )
- arr[j] = arr[j-h];
- arr[j] = e;
- }
- h /= 3;
- }
- }
- // 比较 SelectionSort, InsertionSort 和 BubbleSort 和 ShellSort 四种排序算法的性能效率
- // ShellSort 是这四种排序算法中性能最优的排序算法
- int main() {
- int n = 20000;
- // 测试 1 一般测试
- cout<<"Test for random array, size ="<<n<<", random range [0,"<<n<<"]"<<endl;
- int *arr1 = SortTestHelper::generateRandomArray(n,0,n);
- int *arr2 = SortTestHelper::copyIntArray(arr1, n);
- int *arr3 = SortTestHelper::copyIntArray(arr1, n);
- int *arr4 = SortTestHelper::copyIntArray(arr1, n);
- SortTestHelper::testSort("Selection Sort", selectionSort, arr1, n);
- SortTestHelper::testSort("Insertion Sort", insertionSort, arr2, n);
- SortTestHelper::testSort("Bubble Sort", bubbleSort, arr3, n);
- SortTestHelper::testSort("Shell Sort", shellSort, arr4, n);
- delete[] arr1;
- delete[] arr2;
- delete[] arr3;
- delete[] arr4;
- cout<<endl;
- // 测试 2 测试近乎有序的数组, 只有 100 个数字无序
- int swapTimes = 100;
- cout<<"Test for nearly ordered array, size ="<<n<<", swap time ="<<swapTimes<<endl;
- arr1 = SortTestHelper::generateNearlyOrderedArray(n, swapTimes);
- arr2 = SortTestHelper::copyIntArray(arr1, n);
- arr3 = SortTestHelper::copyIntArray(arr1, n);
- arr4 = SortTestHelper::copyIntArray(arr1, n);
- SortTestHelper::testSort("Selection Sort", selectionSort, arr1, n);
- SortTestHelper::testSort("Insertion Sort", insertionSort, arr2, n);
- SortTestHelper::testSort("Bubble Sort", bubbleSort, arr3, n);
- SortTestHelper::testSort("Shell Sort", shellSort, arr4, n);
- delete[] arr1;
- delete[] arr2;
- delete[] arr3;
- delete[] arr4;
- return 0;
- }
测试结果:
来源: https://www.cnblogs.com/Tom-shushu/p/9977729.html