前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >自己搞排序算法测试用例!

自己搞排序算法测试用例!

作者头像
用户6557940
发布2022-07-24 16:28:46
1.1K0
发布2022-07-24 16:28:46
举报
文章被收录于专栏:Jungle笔记

每次写完一个排序算法,比如冒泡排序、选择排序,总是要验证一下算法是否正确。如何验证呢?代码里创建一个数组arr[10],如下:

代码语言:javascript
复制
  int arr[10] = { 10, 220, 3, 45, 0, 11, -1, 99, 84, 101 };
  // 测试选择排序算法
  SelectionSort(arr, 10);
  for (int i = 0; i < 10; i++){
    cout << arr[i] << "  ";
  }
  cout << endl;

如果打印出来的序列是有序的,这说明自己编码的排序算法对这个测试用例是正确的。但更多情况下,可能需要更多的测试用例,或者序列元素个数更大(50,100,甚至成千上万),这个时候还手写数组arr吗?显然很耗费时间。那不妨,搞一个生成排序算法测试用例的东西?

生成随机数

要保证序列中元素的无序,即随机,需要用到C中的 rand() 函数来生成随机数。但不能直接使用rand(),否则每次该函数生成的数字是一样的。这是因为rand()函数产生的随机数是伪随机数,是根据一个数值(种子)按照某个公式推算出来的。而这个种子在电脑启动后是不变的。所以要用srand函数修改这个种子。

代码语言:javascript
复制
    srand(time(NULL)); 
    for (int i = 0; i < n; i++){
      // 生成随机数
      arr[i] = rand() ;
    }

限定随机数范围

也许还希望生成的随机数能够限定在某个范围[Left, Right]里,那就再用一个求余运算,再加上一个偏移Left:

代码语言:javascript
复制
    // 设置随机种子
    srand(time(NULL));
    for (int i = 0; i < n; i++){
      // 生成随机数
      arr[i] = rand() % (Right - Left + 1) + Left;
    }
    return arr;

这样就ok了,不过我们默认Left <= Right。万一写错了呢?为避免这种情况,最好是在进行上述for循环之前做个判断:

代码语言:javascript
复制
if (Right < Left){
    cout << "error: wrong parameters!" << endl;
    abort();
  }

不过总觉得上述代码有点累赘,那直接用个assert:

代码语言:javascript
复制
assert(rangeL <= rangeR);

assert会计算括号里的表达式是否为真,表达式值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。

排序算法测试用例生成函数

综上所述,排序算法测试用例的生成函数的代码如下:

代码语言:javascript
复制
  // 生成有n个元素的随机数组,每个元素的随机范围为[rangeL, rangeR]
int* generateRandomArray(int n, int Left, int Right){
    assert(Left <= Right);
    int *arr = new int[n];

    // 设置随机种子
    srand(time(NULL));
    for (int i = 0; i < n; i++){
      // 生成随机数
      arr[i] = rand() % (Right - Left + 1) + Left;
    }
    return arr;
  }

生成比较有序的序列

有时候,我们需要测试一些算法对已经比较有序的序列的排序性能,这时候需要生成一个比较有序的序列。怎么办呢?这么办:

代码语言:javascript
复制
// 生成近乎有序的数据
  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(posx, posy);
    }
    return arr;
  }

入口参数swapTimes表示对一个完全有序的序列中的元素进行交换的次数。交换次数越少,这个序列有序度越高。

复制序列

有时候需要比较多个排序算法对同一个未排序序列的运算性能,那不妨再new一个空间,使用memcpy复制一下第一次生成的原始序列:

代码语言:javascript
复制
  int* copyArr(int inputArr[], int n){
    int* outputArr = new int[n];
    memcpy(outputArr, inputArr, sizeof(int)*n);
    return outputArr;
  }

缺憾之处在于,上面3个函数中都使用了new,那么在每次调用该函数后,务必要delete,而且是delete数组

代码语言:javascript
复制
int *arr1 = SortTestHelper::generateRandomArray(n, 0, n);
// do something on arr1
delete[] arr1;

判断排序后的序列是否有序

如何来判断经过排序后的序列是否真的是有序了呢?不妨设计个函数isSorted:

代码语言:javascript
复制
  bool isSorted(int arr[], int n){
    for (int i = 0; i < n-1; i++){
      if (arr[i] > arr[i + 1]){
        return false;
      }
    }
    return true;
  }

测试排序算法性能

总得测试下排序算法的性能吧,这里的性能指的是时间。那就在排序前后记个时间,相减得到的时间差就ok:

代码语言:javascript
复制
  void testSort(string sortName, void(*sort)(T[], int), T arr[], int n){
    clock_t startTime = clock();
    sort(arr, n);
    clock_t endTime = clock();

    assert(isSorted(arr, n));
    cout << sortName << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
  }

测试结果

这样一来,就可以直接测试下已经写好的排序算法性能了:

代码语言:javascript
复制
  int n = 10000;
  int *arr1 = generateRandomArray(n, 0, n);
  int *arr2 = copyArr(arr1, n);
  int *arr3 = copyArr(arr1, n);
  int *arr4 = copyArr(arr1, n);
  testSort("SelectionSort", SelectionSort, arr1, n);
  testSort("InsertSort", InsertSort2, arr2, n);
  testSort("BubbleSort", BubbleSort, arr3, n);
  testSort("ShellSort1", ShellSort1, arr4, n);

  delete[] arr1;
  delete[] arr2;
  delete[] arr3;
  delete[] arr4;

随着测试样本数量n的增大,各类排序算法耗费的时间差异会逐渐明显。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-03-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Jungle笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档