我想在一个范围之间产生一个随机的数字序列,例如100 to 200
。
过了一段时间,根据一些事件,我想在相同的范围(100到200)之间产生一个新序列,但这次我想排除一些数字。例如,我不想要[150,165,170]
。
下一次,这些排除的数字可能会也可能不会包含在序列中。
一种可能的方法可能是这样的数字数组:
int rndm[] {100,101,102,103,...};
并使用数组的索引一次生成一个随机数:
random(rndm[0-99]);
但我需要使用尽可能少的指令/数据结构才能实现性能。
我正在使用C代码,我使用random()
或randomSeed(seed)
我想知道处理这个问题最有效的方法是什么,在数据结构方面应该用于速度和记忆。
答案 0 :(得分:1)
一旦排除函数是二次函数,这个解决方案在生命周期中排除的次数很多的情况下是有效的。
有一个名为 RandomArray 的结构,它包含一个指向大小为N的数组.N是所需的序列大小。时间和空间复杂度是创建函数的线性O(N)。
当事件发生时,它应调用函数 excludeValue ,时间复杂度为O(N),空间复杂度为1.
如果希望排除一堆值,则应调用函数 excludeValues (最后注意s)。在这种情况下,复杂度为O(N x K),空间复杂度为1. K是应排除的值的数量。
#include <stdio.h>
#include <stdlib.h>
struct RandomArray {
int *pData;
size_t dataLen;
int excludedIdx;
};
struct RandomArray *excludeValue(struct RandomArray *pAr, int val) {
size_t i;
for (i = 0; i < pAr->excludedIdx; ++i) {
if (pAr->pData[i] == val) {
pAr->excludedIdx--;
int tmp = pAr->pData[i];
pAr->pData[i] = pAr->pData[pAr->excludedIdx];
pAr->pData[pAr->excludedIdx] = tmp;
// Do test again the position
--i;
}
} return pAr;
}
struct RandomArray *excludeValues(struct RandomArray *pAr, int *pVals, size_t len) {
size_t i;
for (i = 0; i < len; ++i)
excludeValue(pAr, pVals[i]);
}
struct RandomArray *destroyRandomArray(struct RandomArray *pAr) {
if (pAr) {
if (pAr->pData)
free(pAr->pData);
pAr->dataLen = 0;
}
return pAr;
}
struct RandomArray *createRandomArray(
struct RandomArray *pAr,
size_t dataLen,
int lowLimit, int highLimit) {
int i;
int range = (highLimit - lowLimit);
pAr->pData = (int*)malloc(sizeof(int) * dataLen);
pAr->dataLen = dataLen;
srand(time(NULL));
for (i = 0; i < dataLen; ++i) {
pAr->pData[i] = rand() % (range + 1) + lowLimit;
}
// Clear excluded indexs
pAr->excludedIdx = pAr->dataLen; return pAr;
}
void printRandomArray(struct RandomArray *pAr) {
size_t i;
printf("Random Array (len = %d): ", pAr->dataLen);
for (i =0; i < pAr->dataLen; ++i) {
printf(" %d", pAr->pData[i]);
}
printf("\n");
}
void printValidRandomArray(struct RandomArray *pAr) {
size_t i;
printf("Valid Random Array (len = %d): ", pAr->excludedIdx);
for (i =0; i < pAr->excludedIdx; ++i) {
printf(" %d", pAr->pData[i]);
}
printf("\n");
}
void printExcludedRandomArray(struct RandomArray *pAr) {
size_t i;
printf("Excluded Random Array (len = %d): ", pAr->dataLen - pAr->excludedIdx);
for (i = pAr->excludedIdx; i < pAr->dataLen; ++i) {
printf(" %d", pAr->pData[i]);
}
printf("\n");
}
void printAllRandomArray(struct RandomArray *pAr) {
printRandomArray(pAr);
printValidRandomArray(pAr);
printExcludedRandomArray(pAr);
}
int main() {
int lowLimit = 100;
int highLimit = 105;
int arrayLen = 10;
struct RandomArray myAr;
createRandomArray(&myAr, arrayLen, lowLimit, highLimit);
printAllRandomArray(&myAr);
printf("\n");
excludeValue(&myAr, 100);
printAllRandomArray(&myAr);
printf("\n");
excludeValue(&myAr, 101);
printAllRandomArray(&myAr);
printf("\n");
excludeValue(&myAr, 102);
printAllRandomArray(&myAr);
printf("\n");
excludeValue(&myAr, 103);
printAllRandomArray(&myAr);
printf("\n");
excludeValue(&myAr, 104);
printAllRandomArray(&myAr);
printf("\n");
excludeValue(&myAr, 105);
printAllRandomArray(&myAr);
destroyRandomArray(&myAr);
createRandomArray(&myAr, arrayLen, lowLimit, highLimit);
printf("\n\n\n");
printAllRandomArray(&myAr);
printf("\n");
int vals[] = { 102, 105, 104 };
excludeValues(&myAr, vals, sizeof(vals) / sizeof(vals[0]));
printAllRandomArray(&myAr);
destroyRandomArray(&myAr);
}
答案 1 :(得分:-1)
这被问到here on the Arduino forum,但我也在这里看到了。我的答案是Arduino的C ++风格,因为它发布在那里......
当然,性能会随着排除数字的集合相对于用于创建“新序列”的数字集的增长而变化。
void setup() {
Serial.begin(115200);
randomSeed(analogRead(A0));
}
void loop() {
// create an arbitray sized array to be filled with unique values to exclude from desired array
const int arraySize = 5;
int exclusions[arraySize];
for (int i = 0; i < arraySize; i++) {
// fill the array with unique values...
int val;
do {
val = random(100, 200);
} while([&]() {
for (auto j : exclusions) {
if (val == j) {
return true;
}
}
return false;
}());
exclusions[i] = val;
}
Serial.print(F("Exclusion Array: "));
for (int i = 0; i < arraySize; i++) {
Serial.print(exclusions[i]);
if (i < arraySize - 1)
Serial.print(F(", "));
}
Serial.println();
// create a new array of arbitrary length of unique random numbers in >>>the same<<< range as above (but not necessary)
Serial.print(F("Starting...\n"));
uint32_t start = millis();
const int listSize = 32;
int list[listSize];
for (int i = 0; i < listSize; i++) {
// fill the array with unique values that will exclude exclusions[]
int val;
do {
val = random(100, 200);
} while([&]() {
for (auto j : list) {
if (val == j) {
return true;
}
for (auto k : exclusions) {
if (val == k) {
return true;
}
}
}
return false;
}());
list[i] = val;
}
uint32_t end = millis();
Serial.println(end - start);
// OPTIONAL -> lets sort the final arry to make spotting the duplicates easier:
for (int i = 0; i < listSize; i++) {
for (int j = i + 1; j < listSize; j++) {
if (list[j] < list[i]) {
int temp = list[i];
list[i] = list[j];
list[j] = temp;
}
}
}
// output the final array
Serial.print(F("Final Array: "));
for (int i = 0; i < listSize; i++) {
Serial.print(list[i]);
if (i < listSize - 1)
Serial.print(F(", "));
}
Serial.print(F("\n\n\n"));
delay(1000);
}