简体   繁体   中英

Dynamically exclude some numbers from randomly generated sequence

I want to produce a random sequence of numbers between a range, for example 100 to 200 .

After a while, depending on some events, I want to produce a new sequence between the same range (100 to 200), but this time I want to exclude some numbers. For example I don't want [150,165,170] .

And the next time, these excluded numbers may or may not be included in the sequence.

One possible approach could be an array of numbers like this:

int rndm[] {100,101,102,103,...};

and use the index of the array to generate a random number at a time:

random(rndm[0-99]); 

But I need to use as few instruction/data structures as possible in order to achieve performance.

I am using C for this code and I use random() or randomSeed(seed) and I want to know what the most efficient approach to handle this issue is, in terms of data structures should be used for the speed and memory.

This solution is efficient in the case that there are not many exclusions during the lifetime, once the exclusion function is quadratic.

There is a struct called RandomArray that holds a pointer to and array with size N. N is the desired size of the sequence. The time and space complexity is linear O(N) for the create function.

When an event happens it shall call the function excludeValue , with a time complexity of O(N) and space complexity of 1.

If it is desired to exclude a bunch of values, the function excludeValues (pay attention to s at the end) shall be called. In this case the complexity is O(N x K) and the space complexity is 1. K is the amount of values that shall be excluded.

#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);
}

This was asked here on the Arduino forum but I saw it here too. My answer is in Arduino's flavor of C++ since it was posted there...

Of course, performance varies as the set of excluded numbers grows relative to the set of numbers to be used to create your "new sequence."

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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM