I am trying to create random integer array generator with no duplicate by using this:
int pt_rand(int nbits) {
int mask;
if (0 < nbits && nbits < sizeof(int)*8) {
mask = ~(~((unsigned int) 0) << nbits);
}
else {
mask = ~((unsigned int) 0);
}
return rand() & mask;
}
int *gen_rand_int_array_nodups(int length, int nbits) {
int * a = malloc(sizeof(int)*length);
for (int i = 0; i < length; i++) {
a[i] = pt_rand(nbits);
for (int j = 0; j < i; j++) {
do {
a[i] = pt_rand(nbits);
} while (a[i] == a[j]);
}
}
shuffle_int_array(a, length);
return a;
}
This code is trying to generate unique random integers within given nbits by checking elements one by one. However, I'm still getting duplicates in the result and I've not figured it out why. I know this is a bad practice of using this method to generate unique random numbers but the requirement of my assignment requires me to somehow make use of nbits param. I've looked up for the easiest way to the same thing by filling an array with increment number and swap them around but that's just an alternative solution and I still have to confirm if I'm allowed to use that instead.
for (int j = 0; j < i; j++) {
do {
a[i] = pt_rand(nbits);
} while (a[i] == a[j]);
}
Say i=3, j=1, a={5,2,3,2}. Now you detect you already have the 2 ... so say pt_rand() gives you 5 now. How do you detect you already have 5?
Corrected version:
int *gen_rand_int_array_nodups(int length, int nbits) {
int * a = malloc(sizeof(int)*length);
for (int i = 0; i < length; i++) {
int duplicate;
do
{
duplicate = 0;
a[i] = pt_rand(nbits);
for (int j = 0; j < i; j++) {
if (a[j] == a[i])
{
duplicate = 1;
break;
}
}
} while (duplicate);
}
shuffle_int_array(a, length);
return a;
}
Related
I want to randomize a to p without repetition.
int main(){
int array2[4][4];
bool arr[100]={0};
int i;
int j;
srand(time(NULL));
for(i=0; i<=3; i++){
for(j=0; j<=3; j++){
int randomNumber1;
randomNumber1 = (rand() % (82-65+1))+65;
if (!arr[randomNumber1])
{
printf("%c ",randomNumber1);
array2[i][j]=randomNumber1;
}
else
{
i--;
j--;
arr[randomNumber1]=1;
}
}
printf("\n");
}
return;
the output still has repeat alphabet. I want to have the output in 4x4 with with all a to p without it repeating.
There are some errors in your code. IMHO the most serious is that arr[randomNumber1]=1; is is the wrong branch of the test. That means that your current code does not invalidate once a number was used but only if it has already been invalidated => if you control the arr array at the end of the program all value are still 0.
That is not all. When you get a duplicate, you should only reset the inner loop, and you are currently off by 2 in your maximum ascii code: you go up to R when you want to stop at P.
Your code should be:
for (i = 0; i <= 3; i++) {
for (j = 0; j <= 3; j++) {
int randomNumber1;
randomNumber1 = (rand() % (81 - 65)) + 65;
if (!arr[randomNumber1])
{
printf("%c ", randomNumber1);
array2[i][j] = randomNumber1;
arr[randomNumber1] = 1;
}
else
{
//i--;
j--;
}
}
printf("\n");
}
But this kind of code is terribly inefficient. In my tests it took 30 to 60 steps to fill 16 values, because random can return duplicates. This is the reason why you were advised in comments to use instead the modern algorithm for Fisher-Yates shuffle:
int main() {
int array2[16];
unsigned i, j, k=0;
// initialize array with alphabets from A to P
for (i = 0; i < sizeof(array2); i++) {
array2[i] = 'A' + i;
}
// Use Fisher-Yates shuffle on the array
srand(time(NULL));
for (i = 15; i > 0; i--) {
j = rand() % (i + 1);
if (j != i) {
int c = array2[i];
array2[i] = array2[j];
array2[j] = c;
}
}
// Display a 4x4 pattern
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
printf("%c ", array2[k++]);
}
printf("\n");
}
return 0;
}
Which shuffles the array in only 16 steps.
Here is the outline
// Need some #includes here - exercise for the reader
char items[] = "abcdefghijklmnopqrstuvwxyz";
int len = sizeof(items);
srand(time(NULL));
while (len > 0) {
int r = rand() % len;
printf("%c", items[r]);
len--;
items[r] = items[len];
}
This should do the trick to print the whole alphabet in random order without repeats. Modify to do what you need it to do
I am having trouble achieving the wanted results. The program should ask for 20 inputs and then go over each to see if they appear more than once. Then only print out those that appeared once.
However currently my program prints out random numbers that are not inputted.
For example:
array = {10,10,11,12,10,10,10.....,10} should return 11 and 12
#include <stdio.h>
void main() {
int count, size=20, array[size], newArr[size];
int number=0;
for(count = 0; count < size; count++) {
// Ask user for input until 20 correct inputs.
printf("\nAnna %d. luku > ", count+1);
scanf("%d", &number);
if( (number > 100) || (number < 10) ) {
while(1) {
number = 0;
printf("Ei kelpaa.\n");//"Is not valid"
printf("Yrita uudelleen > ");//"Try again >"
scanf("%d", &number);
if ( (number <= 100) && (number >= 10) ) {
break;
}
}
}
array[count] = number;
}
for(int i=0; i < size; i++) {
for(int j=0; j<size; j++){
if(array[i] == array[j]){
size--;
break;
} else {
// if not duplicate add to the new array
newArr[i] == array[j];
}
}
}
// print out all the elements of the new array
for(int k=0; k<size; k++) {
printf("%d\n", newArr[k]);
}
}
You don't need the newArr here, or the separate output loop. Only keep a count that you reset to zero at the beginning of the outer loop, and increase in the inner loop if you find a duplicate.
Once the inner loop is finished, and the counter is 1 then you don't have any duplicates and you print the value.
In code perhaps something like:
for (unsigned i = 0; i < size; ++i)
{
unsigned counter = 0;
for (unsigned j = 0; j < size; ++j)
{
if (array[i] == array[j])
{
++counter;
}
}
if (counter == 1)
{
printf("%d\n", array[i]);
}
}
Note that the above is a pretty naive and brute-force way to deal with it, and that it will not perform very well for larger array sizes.
Then one could implement a hash-table, where the value is the key, and the count is the data.
Each time you read a value you increase the data for that value.
Once done iterate over the map and print all values whose data (counter) is 1.
Use functions!!
Use proper types for indexes (size_t).
void printdistinct(const int *arr, size_t size)
{
int dist;
for(size_t s = 0; s < size; s++)
{
int val = arr[s];
dist = 1;
for(size_t n = 0; n < size; n++)
{
if(s != n)
if(val == arr[n]) {dist = 0; break;}
}
if(dist) printf("%d ", val);
}
printf("\n");
}
int main(void)
{
int test[] = {10,10,11,12,10,10,10,10};
printdistinct(test, sizeof(test)/sizeof(test[0]));
fflush(stdout);
}
https://godbolt.org/z/5bKfdn9Wv
This is how I did it and it should work for your:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <stdarg.h>
void printdistinct(const int *muis, size_t size);
int main()
{
int loop=20,i,muis[20],monesko=0;
for(i=0; i<loop; i++){
monesko++;
printf ("Anna %d. luku: \n",monesko);
scanf("%d", &muis[i]);
if (muis[i]<10 || muis[i]>100){
printf("Ei kelpaa!\n");
muis[i] = muis[i + 1];
printf("YRITÄ UUDELLEEN:\n ");
scanf("%d", &muis[i]);
}
}
printdistinct(muis, sizeof(muis)/sizeof(muis[0]));
fflush(stdout);
return 0;
}
void printdistinct(const int *muis, size_t size)
{
for(size_t s = 0; s < size; s++)
{
int a = muis[s];
int testi = 1;
for(size_t n = 0; n < size; n++){
if(s != n) {
if(a == muis[n]){
testi = 0;
break;
}
}
}
if(testi) {
printf("%d \n", a);
}
testi = 1;
}
printf("\n");
}
This approach uses some memory to keep track of which elements are duplicates. The memory cost is higher, but the processor time cost is lower. These differences will become significant at higher values of size.
char* duplicate = calloc(size, 1); // values are initialized to zero
for (unsigned i = 0; i < size; ++i)
{
if(!duplicate[i]) // skip any value that's known to be a duplicate
{
for (unsigned j = i + 1; j < size; ++j) // only look at following values
{
if (array[i] == array[j])
{
duplicate[i] = 1;
duplicate[j] = 1; // all duplicates will be marked
}
}
if (!duplicate[i])
{
printf("%d\n", array[i]);
}
}
}
What you can do is you can initialize a hashmap that will help you store the unique elements. Once you start iterating the array you check for that element in the hashmap. If it is not present in the hashmap add it to the hashmap. If it is already present keep iterating.
This way you would not have to iterate the loop twice. Your time complexity of the algorithm will be O(n).
unordered_map < int, int > map;
for (int i = 0; i < size; i++) {
// Check if present in the hashmap
if (map.find(arr[i]) == map.end()) {
// Insert the element in the hash map
map[arr[i]] = arr[i];
cout << arr[i] << " ";
}
}
I am writing a program which determines the intersection of 2 integer arrays (size of 10 elements). I think I got every other parts covered except for sorting out duplicates. Does anyone know a way of checking duplicates without making a function or using an external C library?
#include <stdio.h>
#define SIZE 10
int main(void){
//Initialization
int array1[SIZE];
for (int i = 0; i < SIZE; i++)
{
printf("Input integer %d of set A: ", i + 1);
scanf("%d", &array1[i]);
}
int array2[SIZE];
for (int i = 0; i < SIZE; i++)
{
printf("Input integer %d of set B: ", i + 1);
scanf("%d", &array2[i]);
}
int intersection[SIZE];
for (int i = 0; i < SIZE; i++)
{
intersection[i] = '\0';
}
//Intersection check
for (int i = 0; i < SIZE; i++)
{
for (int j = 0; j < SIZE; j++)
{
if (array1[i] == array2[j])
{
intersection[i] = array1[i];
break;
}
}
}
//duplicate check
int count = SIZE;
for (int i = 0; i < count; i++)
{
for (int j = i + 1; j < count; j++)
{
if (intersection[i] == intersection[j])
{
for (int k = j; j < count; i++)
{
intersection[k] = intersection[k + 1];
}
count--;
}
}
}
//printing set
for (int i = 0; i < SIZE ; i++)
{
//printf("%d\n", intersection[i]);
if (intersection[i] != '\0')
{
printf("%d\n", intersection[i]);
}
}
return 0;
}
In the code above i was trying one method although it didn't work and instead made the program stuck after inputting all the elements. I am open to other methods as long it doesn't require an external library to run. Thanks
As i see it now , in the third loop where you checking your duplicates i thing that you have to increese k not i :
for (int k = j; j < count; k++), also you must decrise the size of j in your code under the count--;.So your code for checking duplicates seems right but , you want the intersection of this two arrays you made , so you dont have to check for duplicates because in the array intersection[SIZE] you will put only one number from the two arrays, so you will not have duplicates .You should check for duplicates if you wanted to make the union of this two arrays .I make some changings to your code acording what you want to create and this code here find the intersection from two arrays.Try this and delete the duplicate check because that makes your code to run to infinity . One last thing your intersection check must be replace whith this :
//Intersection check
int i = 0, j = 0,k=0; // k is for the intersection array !
while (i < SIZE && j < SIZE) {
if (array1[i] < array2[j])
i++;
else if (array2[j] < array1[i])
j++;
else if(array1[i]==array2[j]) // if array1[i] == array2[j]
{
intersection[k]=array2[j];
//printf("intersection[%d]=%d\n",i,intersection[i]);
intersectCount++;
k++;
i++;
j++;
}
}
printf("intersectCount=%d\n",intersectCount);
I need to know a method to keep duplicate numbers from being stored in a new array when taking numbers from two different arrays. The function is supposed to store each 'unique' value once and not store duplicate values again.
Here is my function code so far:
int * arrayIntersect(int *sizeOfResult, const int *a, const int *b, int sizeOfA, int sizeOfB){
int i;
int j;
int k = 0;
int c[(sizeOfA + sizeOfB)];
for(j = 0; j < sizeOfB; j++){
for(i = 0; i < sizeOfA; i++){
if(a[i] == b[j]){
c[k] = a[i];
(*sizeOfResult)++;
k++;
}
}
}
int *d = (int *)malloc(sizeof(int) * *sizeOfResult);
for(i = 0; i < *sizeOfResult; i++){
d[i] = c[i];
}
return d;
}
It prints the values I need, but I want to eliminate the same number from showing up multiple times when printing the contents of the new dynamic array.
Any idea on how to improve my code to allow prevent duplication?
The proper way to do it is having the arrays ordered and then doing a binary search for each insertion like #Murilo Vasoncelos pointed out.
Below is a quick and dirty solution that loops through a and b and for each iteration checks if the number has been inserted before. If it isn't, it inserts it.
int duplicate = 0;
*sizeOfResult = 0;
for(j = 0; j < sizeOfA; j++){
for(i = 0; i < (*sizeOfResult); i++){
if(c[i] == a[j]){
duplicate = 1;
break;
}
}
if (!duplicate)
{
c[(*sizeOfResult)] = a[i];
(*sizeOfResult)++;
}
duplicate = 0;
}
for(j = 0; j < sizeOfB; j++){
for(i = 0; i < (*sizeOfResult); i++){
if(c[i] == b[j]){
duplicate = 1;
break;
}
}
if (!duplicate)
{
c[(*sizeOfResult)] = b[i];
(*sizeOfResult)++;
}
duplicate = 0;
}
If your arrays a and b are ordered, you can simply use this linear algorithm for array intersection:
int* inter(int* szr, int* a, int* b, int sza, int szb)
{
int c[MAX(sza, szb)];
int i, j, k = 0;
for (i = 0, j = 0; i < sza && j < szb;) {
if (a[i] == b[j]) {
if (k == 0 || c[k - 1] < a[i]) {
c[k++] = a[i];
}
i++;
j++;
}
else if (a[i] < b[j]) {
i++;
}
else {
j++;
}
}
*szr = k;
int* ans = (int*)malloc(sizeof(int) * k);
for (i = 0; i < k; ++i) {
ans[i] = c[i];
}
return ans;
}
I am working on a program that removes duplicate values from an array by ordering it and then removing duplicate, consecutive values. First I execute a selection sort sorting method, and then call a function removedup() that modifies the array and returns the size. Then I basically print the values in the array up to that size. However, when I execute it, it only prints the original array and then a bunch of blank space. Does anyone know why this is occurring?
My code: http://pastebin.com/uTTnnMHN
Just the de-duplication code:
int removedup(int a[])
{
int i, count, j;
count = n;
for (i = 0; i < (n - 1); i++) {
if (a[i] == a[i + 1]) {
for (j = 0; j < (n - i); j++) {
a[j] = a[j + 1];
}
count--;
i--;
}
}
return count;
}
-1 for(j=0;j<(n-i);j++)
Is your loop to shift left your array (thus removing the duplicate value), j should not be init to j but to i, and the condition does not seem right
A correct one could be:
for(j=i;j<n-1;j++)
{
a[j]=a[j+1];
}
a[n-1] = 0; // Because you shift your table to the left, the last value should not be used
first if i=0 and if a[i]==a[i+1] then i=-1
for(i=0;i<(n-1);i++)
{
if(a[i]==a[i+1])
{
for(j=0;j<(n-i);j++)
{
a[j]=a[j+1];
}
count--;
i--; //i=-1 if(a[i]==a[i+1]) && if(i==0)
}
}
In your duplicate removal function, you need to start the moving loop at i, as has been mentioned, and you must use count - 1 as the loop bound for both loops, otherwise you will have an infinite loop whenever there are duplicates, because then a[n-2] == a[n-1] always after the first moving loop.
int removedup(int a[])
{
int i, count, j;
count = n;
for(i = 0; i < (count-1); i++)
{
if(a[i] == a[i+1])
{
for(j = i; j < (count-1); j++)
{
a[j]=a[j+1];
}
count--;
i--;
}
}
return count;
}
works correctly.
Since you're creating another array anyway, why not simplify your function?
int removedup(int a[], int b[])
{
int i;
int count = 1;
b[0] = a[0]
for(i=1;i<(n-1);i++){
if(a[i-1] != a[i]){
b[count++] = a[i];
}
}
return count;
}
Then when you call the function,
count=removedup(a, OutArray);
int removedup(int a[])
{
int i;
count = n;
for (i = 0; i < (count-1); ++i) {
if (a[i] == a[i+1]) { /* found a duplicate */
int d = 0; /* count the duplicates */
do {
++d;
} while ((i+1+d) < count && a[i] == a[i+1+d]); /* probe ahead again for a duplicate */
/* at this point we have either run out of duplicates or hit the end of the array */
if ((i+1+d) < count)
memmove(&a[i+1], &a[i+1+d], sizeof(int)*(count-(i+1+d))); /* shift down rest of the array if there's still elements to look at */
count -= d; /* adjust the count down by the number of duplicates */
}
}
return count;
}
what about this one,without sort but traverse.finally print the effective values of the array and return its size.
int removedup(int a[])
{
int i, count, j;
count = n;
int b[n];
memset(b,0,sizeof(b));
for (i = 0; i < (n - 1); i++)
{
if (-1 != b[i])
{
for(j=i+1;j<n-1;j++)
{
if( a[i]==a[j])
{
b[j]=-1;
count--;
}
}
}
}
for(i=0;i<n-1;i++)
{
if(-1 != b[i])
{
printf("%d ",a[i]);
}
}
return count;
}