玩转C语言随机数生成器(rand)的使用技巧
文章出自个人博客https://knightyun.github.io/2018/04/25/c-rand-number,转载请申明。
在程序设计中,难免会使用到随机值函数,其原理与语法大多类似,接下来以C语言为例介绍其随机值函数 rand()
用法。
原理
引用百度百科,首先,需要包含头文件:
#include <stdlib.h>
rand()函数是按指定的顺序来产生整数,因此每次执行上面的语句都打印相同的两个值,所以说C语言的随机并不是真正意义上的随机,有时候也叫伪随机数,使用 rand()
生成随机数之前需要用随机发生器的初始化函数 srand(unsigned seed)
(也位于 stdlib.h
中) 进行伪随机数序列初始化,seed
又叫随机种子,通俗讲就是,如果每次提供的 seed
是一样的话,最后每一轮生成的几个随机值也都是一样的,因此叫伪随机数,所以需要每次提供不同的 seed
达到完全的随机,我们通常用时间函数 time(NULL)
作为 seed
,因为时间值每秒都不同,这个函数需要包含以下头文件:
#include <time.h>
理论太泛,下面用例子分析理解。
举例分析
先来理解以下伪随机数,编译以下代码:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
srand(1);
int i;
for (i = 0; i < 10; i++)
printf("%d, ", rand()%11);
}
运行结果
8, 9, 9, 1, 7, 5, 5, 10, 1, 0,
然后无论运行多少次,结果都依然是以上随机数,不会改变,因为每次设置的种子 seed
都是 1
。
但是假如把 seed
换成 time(NULL)
,每次就不一样了,如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
srand(time(NULL));
int i;
for (i = 0; i < 10; i++)
printf("%d, ", rand()%11);
}
结果是就变了,并且每次都不一样:
6, 3, 4, 5, 5, 9, 8, 10, 10, 4,
6, 4, 2, 4, 3, 2, 5, 1, 2, 9,
这里的
time(NULL)
的结果是一个类似于1524655706
的数字,并且每秒都在递增 1,也就达成了 srand() 的 seed 不断变化的目的,不断生成新的随机数。
拓展
这里注意一下例子中函数 rand()
的用法,函数括号内不需要加参数,如果直接调用 rand()
的话会生成下面这样的数:
17163, 2663, 24810, 4875, 26975, 14119, 22193, 11233, 26009, 20105,
所以我们想要生成指定范围的随机数的话就需要使用到求余运算符 %
,这里有个规律:例如我们需要 0–10的随机数时,就写成 rand()%11
,0–100就写成 rand()%101
,就是运算符后的数字需要比需求范围极值大 1,当然这也是取余运算的原理。
上一篇: 深入理解C语言中的静态函数
下一篇: 多返回值C语言函数的编写指南
推荐阅读
-
总结一些在C语言中使用for循环的技巧
-
入门C语言的第一步:掌握Linux命令的使用技巧
-
玩转C语言随机数生成器(rand)的使用技巧
-
玩转C语言!带你了解rand函数的使用技巧
-
MAX_LEN) {
int pivot = partition(arr, left, right);
quicksort_optimized(arr, left, pivot - 1);
quicksort_optimized(arr, pivot + 1, right);
} else {
// 使用插入排序处理小数组
}
}
```
- 合并相同值进行分割:在每次划分后,我们将与枢轴相等的元素聚集在一起,以降低后续迭代中的重复处理。例如:
原序列: 1 4 6 7 6 6 7 6 8 6
- 选取枢轴(6)并划分:1 4 6 7 1 6 7 6 8 6
- 划分结果(未处理相等项):1 4 6 6 7 6 7 6 8 6
- 处理相等项后的划分结果:1 4 6 6 6 6 7 8 7
- 下次划分得到的子序列:1 4 和 7 8 7
通过这样的优化,我们可以明显减少迭代次数,从而提高排序效率。">
改进版快速排序:针对部分有序列的策略与优化技巧" - 随机选枢轴:当数据部分有序时,传统快速排序通过固定枢轴可能导致效率低下。为此,我们采用随机选取枢轴的方法,代码如下: ```c int SelectPivotRandom(int arr[], int low, int high) { srand(time(0)); int pivotPos = (rand() % (high - low)) + low; swap(arr[pivotPos], arr[low]); return arr[low]; } ``` - 优化小数组交换:针对小且部分有序的数组,快速排序不如插入排序高效。因此,当待排序序列长度小于等于10时,我们会切换至插入排序: ```c #define MAX_LEN 10 void quicksort_optimized(int *arr, int left, int right) { int length = right - left; if (length > MAX_LEN) { int pivot = partition(arr, left, right); quicksort_optimized(arr, left, pivot - 1); quicksort_optimized(arr, pivot + 1, right); } else { // 使用插入排序处理小数组 } } ``` - 合并相同值进行分割:在每次划分后,我们将与枢轴相等的元素聚集在一起,以降低后续迭代中的重复处理。例如: 原序列: 1 4 6 7 6 6 7 6 8 6 - 选取枢轴(6)并划分:1 4 6 7 1 6 7 6 8 6 - 划分结果(未处理相等项):1 4 6 6 7 6 7 6 8 6 - 处理相等项后的划分结果:1 4 6 6 6 6 7 8 7 - 下次划分得到的子序列:1 4 和 7 8 7 通过这样的优化,我们可以明显减少迭代次数,从而提高排序效率。
-
玩转排序技巧:C语言实现的堆排序详解
-
玩转C语言!探究sscanf函数的字符串格式化技巧