排序基础——准备

开始之前的话

边学习边记录,算法的基础是从排序开始,这一部分内容是我从慕课网上的liuyubobobo老师的视频中学习到的,基本上也就是学习他的视频内容,转化为自己的文字。代码使用C++。

排序学习的工具准备

在开始学习排序之前需要先准备一些辅助用的工具,新建一个sorthelper.h的头文件,将我们需要的工具都写在这里面。

需要用到的头文件

头文件与下面用到的方法的对应关系大家可以自己去查。。

#include <iostream>
#include <ctime>
#include <cassert>
#include <cstring>

随机数组生成器

排序学习的后期可能会测试一些非常长的数组,因此编写一个随机生成数组的方法很有必要。

先贴代码

//随机数组生成,n为数组长度,L与R分别代表随机数的最小值和最大值,返回数组的指针
int* generateRandomArray(int n, int L, int R){
        //断言,左边界必须小于等于右边界
        assert( L <= R );
        int *arr = new int[n];
        srand(time(NULL));

        for (int i = 0; i < n; ++i) {
        //用求模的方式确保随机数的范围
            arr[i] = rand() % (R - L + 1) + L;
        }

        return arr;
    }

经过查阅,说明一下以上代码中的细节。

  • 首先是time()函数,调用它会返回 自1970年1月1日00:00:00至系统现在这一刻所经过的秒数 ,返回值类型是time_t,是一个正整数,time()有两种调用方式,第一种是将一个变量地址填入括号,这样这个变量就会获得返回值,另一种方法是填入NULL,那么可以用a = time(NULL)的方式获得返回值。
  • srand()与rand()函数,这两个函数需要配合使用,调用前者需要传入一个参数,称为“种子”,这个函数会根据“种子”生成伪随机数序列,调用rand()则会从srand()生成的伪随机数序列中取出一个伪随机数,换言之,如果srand填入的种子不变,那么随机数每次都会按照固定的序列生成,因此要达到真正的随机,必须要使srand的种子是随机的,那么刚好time(NULL)返回的是一个无时无刻不在变化的数字,使得srand的种子不断变化。

近乎有序数组生成器

近乎有序的数组是随机数组中的一种特殊情况,也是必须要考虑的。

编写思路很简单,首先初始化一个0到n的数组,然后随机挑几对元素进行交换就得到了一个近乎有序的数组。

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 x = rand() % n;
            int y = rand() % n;
            swap(arr[x], arr[y]);
        }

        return arr;
    }

数组有序判断

在排过序之后还需检查数组是否有序以证明排序是否成功,比较简单,就不做说明了。

bool isSorted(int arr[], int n){

        for (int i = 0; i < n - 1; i ++) {
            if (arr[i] > arr[i + 1])
                return false;
        }

        return true;
    }

排序时间测试

记录排序所用的时间是对排序算法性能衡量的重要指标。

先贴代码

//排序用时测试 sortname为排序方法的名称,sort是排序方法,arr为待排数组,n为数组长度
    void sortTimeCounter(string sortname, void(*sort)(int[], int), int arr[], int n) {
        //开始时间
        clock_t startTime = clock();
        sort(arr, n);
        //结束时间
        clock_t endTime = clock();
        //有序判断
        assert(isSorted(arr, n));
        //将时间单位转化为秒并打印
        cout << std::fixed << sortname << " : " << double(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
    }

也并没有太多需要说明的地方,通过传入要使用的排序方法的函数指针,以及待排数组,得到排序所用时间。

  • 唯一的小细节是clock()函数返回的是clock_t类型,这是当前的时间,单位是计算机的时钟计时单元,并不是秒,需要除以CLOCKS_PER_SEC这个常量将单位转换为秒。

  • 另外,发现直接输出double类型控制台会自动使用科学计数法表示输出,很不直观,加入std::fixed可以转化为十进制输出。

数组打印

这个是我自己写的方法,liuyubobobo老师并没有写,因为我担心在自己写的时候出了什么问题,方便通过打印排除问题。

    //数组打印
    void printArray(int arr[], int n){
        for (int i = 0; i < n; i ++) {
            cout << arr[i] << " " ;
        }
    }

数组拷贝

当我们需要比较多个排序算法的性能时,就需要多个相同的随机数组,因此需要数组拷贝方法

    //数组拷贝
    int* copyIntArray(int a[], int n){
        int* arr = new int[n];
        copy(a, a+n, arr);
        return arr;
    }

本篇到此为止,希望这对你有帮助,如果有错误或是有需要补充的地方,望告知。


种一棵树最好的时间是在十年前,而后是现在。

Loading Disqus comments...
Table of Contents