I was hoping to get some input on how to correctly find the mode of a sorted array in C. Here's what I'm working with. First, my freqDistrib function:
void freqDistrib(int t[], int num) {
int i, j, x;
static int f[SIZE];
printf("\n\n");
printf("Part C:\n");
printf(" %-5s %-16s\n", "score", "frequency");
printf(" %-5s %-16s\n", "-----", "---------");
for (i = 1; i < num; i++) {
x = t[i];
j = i - 1;
while (j >= 0 && x > t[j]) {
t[j + 1] = t[j];
j = j - 1;
}
t[j + 1] = x;
} // sorts input in descending order
for (i = 0; i < num; i++) {
++f[t[i]];
if (t[i] != t[i + 1])
printf(" %3d %7d\n", t[i], f[t[i]]);
} // finds the frequency of each input and prints
}
and my mode function:
void modeScore(int t[], int num) {
int i, j, max, mode;
int f[SIZE];
for (i = 0; i < num; i++) {
f[t[i]]++;
}
mode = 0;
max = 0;
for (j = 0; j < num; j++) {
if (f[j] > max) {
max = f[j];
mode = j;
}
}
printf("\n\n");
printf("Part F:\n");
printf("%3d is mode\n", mode);
}
Output right now:
0 is mode
I realize that I need to compare the current frequency tally to a max, and if it is higher than set it equal to max. I just can't for the life of my figure out why this isn't working. Any input would be appreciated thanks.
As noted in a comment, the principal problem was that you did not initialize f in the function.
Here's working code which shows that was all the change that was necessary:
#include <stdio.h>
enum { SIZE = 100 };
static void modeScore(int t[], int num)
{
int f[SIZE] = { 0 };
for (int i = 0; i < num; i++)
f[t[i]]++;
int mode = 0;
int max = 0;
for (int j = 0; j < num; j++)
{
if (f[j] > max)
{
max = f[j];
mode = j;
}
}
printf("Part F: %3d is mode (count %d)\n", mode, max);
}
int main(void)
{
int data[] =
{
/* random -n 40 0 9 | commalist -b ' ' -l 38 */
7, 8, 3, 8, 5, 9, 5, 8, 9, 6,
8, 0, 1, 8, 2, 0, 3, 4, 3, 3,
3, 0, 2, 7, 5, 4, 6, 5, 9, 0,
1, 9, 1, 7, 8, 0, 5, 4, 0, 8,
};
enum { DATA_SIZE = sizeof(data) / sizeof(data[0]) };
modeScore(data, DATA_SIZE);
return 0;
}
For the given data, the output is:
Part F: 8 is mode (count 7)
(Funny coincidence: the first time I ran it — with slightly different data — the answer came back as Part F: 0 is mode (count 7). This was actually correct; I changed one of the zeros into an eight to produce the current result.)
Note that I would normally design the function to return the modal value, rather than have it do the printing. As it stands, it can't be reused because the printing is not material to most code that wants to determine the mode.
The code also does not check that the values in t fall in the range 0..SIZE-1 (but it should).
The parameter order you use is traditional, but there is at least nominally some advantage to using:
void modeScore(int num, int t[num])
to express explicitly that the array t has num elements in it. The size must precede its use in the array dimentson, though.
Since you say the array is sorted, you don't need to create a temporary array to count the values. Instead, you just need to traverse the input, keeping count of how many identical values you've seen in the current run. At the end of the run, then compare the length of the run to the previous longest run, and update if the new run is longer.
(Actually, we update whenever the current run is longer, so we don't forget to update if the mode is the very last value).
Notice that we no longer need SIZE to bound our values; we can now work with the full range of int if we wish.
#include <stdio.h>
static void modeScore(const int t[], int num)
{
int start = 0;
int mode = t[0];
int score = 0;
for (int i = 1; i < num; ++i) {
if (i - start > score) {
// a longer run than the previous candidate
score = i - start;
mode = t[start];
}
if (t[start] != t[i])
// we've reached a change in value
start = i;
}
printf("Part F: %3d is mode (count %d)\n", mode, score);
}
You didn't provide a main(), so I adapted Jonathan Leffler's:
int main(void)
{
int data[] =
{
/* random -n 40 0 9 | commalist -b ' ' -l 38 */
0, 0, 0, 0, 0, 0, 1, 1, 1, 2,
2, 3, 3, 3, 3, 3, 4, 4, 4, 5,
5, 5, 5, 5, 6, 6, 7, 7, 7, 8,
8, 8, 8, 8, 8, 8, 9, 9, 9, 9,
};
modeScore(data, sizeof data / sizeof data[0]);
return 0;
}
Related
I'm trying to solve a problem where I have to identify the number of pairs in an array that have the same mean/average as the original array.
Though I have solved the problem with nested loops(refer to the code below), I wanted to reduce the complexity of my solution, and I'm not getting any ideas so far.
Update: 'T' is just a variable representing the number of test cases. You can assume that to be 1.
#include <stdio.h>
#include <stdlib.h>
int comparator(const void *p, const void *q) {
int l = *(int *)p;
int r = *(int *)q;
return (l-r);
}
int fSum(int *Arr, int N){
int sum = 0;
for(int i=0; i<N; i++){
sum+=Arr[i];
}
return sum;
}
int main(void) {
int i=1, T, N, pos = 1, j=0, k=0, c = 0, sum;
int Arr[100000];
scanf("%d",&T);
while(i<=T){
scanf("%d", &N);
c = 0;
j = 0;
while(j<N){
scanf("%d", &Arr[j]);
++j;
}
qsort(Arr, N, sizeof(int), comparator);
sum = fSum(Arr, N);
for(j=0; j<N-1; j++){
for(k=N-1; k>=j+1; k--){
if(sum*2 == ((Arr[j]+Arr[k])*N)) {
c++;
}
else{
if(sum*2 > ((Arr[j]+Arr[k])*N))
break;
}
}
}
printf("%d\n", c);
++i;
}
return 0;
}
The general approach to problems like this is a single loop that maintains two indexes. One index starts at the beginning of the array, the other at the end. When the indexes meet in the middle, the loop is finished. In the body of the loop, the code must decide whether to update one index, or the other, or both.
For this particular problem, there are couple of additional wrinkles, which are caused by duplicates in the array.
For example, given the array { 1, 1, 1, 4, 5, 12, 15, 15, 18 }, there are 7 pairs. There are three 1's that can be matched with either of the two 15's, giving 6 possible pairs. The 4,12 pair is the seventh pair. So when the code finds a pair of distinct number that have the correct average, it must count the number of duplicates of each number. The number of pairs is then updated by the product of the two counts.
Given the array { 2, 3, 4, 8, 8, 8, 12, 12, 15 }, there are 5 pairs. Three pairs due to the three 8's, plus two ways to pair a 4 with a 12. When the average value is present in the array, and is duplicated, one index will reach the first instance of the average while the other will reach the last. The duplicate count can be computed from the two indexes, and the number of pairs is the number of ways to choose any two of the duplicates.
Here's a sample implementation using a single loop that updates two indexes:
#include <stdio.h>
void showArray(int Arr[], int N)
{
printf("Arr[] = {");
if (N > 0)
printf(" %d", Arr[0]);
for (int i = 1; i < N; i++)
printf(", %d", Arr[i]);
printf(" }\n");
}
int computeSum(int Arr[], int N)
{
int sum = 0;
for (int i=0; i < N; i++)
sum += Arr[i];
return sum;
}
int solve(int Arr[], int N)
{
showArray(Arr, N);
int sum = computeSum(Arr, N);
printf("N=%d sum=%d\n", N, sum);
int pairs = 0;
for (int j=0, k=N-1; k > j; )
{
if ((Arr[j] + Arr[k])*N > sum*2)
{
// the average is too high, so skip the larger value
k--;
}
else if ((Arr[j] + Arr[k])*N < sum*2)
{
// the average is too low, so skip the smaller value
j++;
}
else if (Arr[j] == Arr[k])
{
// handle the case where the average value is present and duplicated
int repeat = k - j + 1;
pairs += (repeat * (repeat-1)) / 2;
break;
}
else
{
// handle the case where two distinct numbers in the array have the correct average
// note that if there are duplicates of the numbers, the indexes are updated to the next non-duplicate
int oldj = j++;
while (Arr[j] == Arr[oldj])
j++;
int oldk = k--;
while (Arr[k] == Arr[oldk])
k--;
pairs += (j - oldj) * (oldk - k);
}
}
return pairs;
}
#define len(arr) (sizeof(arr) / sizeof(arr[0]))
int main(void)
{
int Arr1[] = { 1, 4, 5, 6, 6, 7, 7, 11, 15, 18 };
printf("pairs=%d\n\n", solve(Arr1, len(Arr1)));
int Arr2[] = { 1, 1, 1, 4, 5, 12, 15, 15, 18 };
printf("pairs=%d\n\n", solve(Arr2, len(Arr2)));
int Arr3[] = { 2, 3, 4, 8, 8, 8, 12, 12, 15 };
printf("pairs=%d\n\n", solve(Arr3, len(Arr3)));
}
Output from the code:
Arr[] = { 1, 4, 5, 6, 6, 7, 7, 11, 15, 18 }
N=10 sum=80
pairs=2
Arr[] = { 1, 1, 1, 4, 5, 12, 15, 15, 18 }
N=9 sum=72
pairs=7
Arr[] = { 2, 3, 4, 8, 8, 8, 12, 12, 15 }
N=9 sum=72
pairs=5
I want to check if two integer type arrays have the same set of digits. For example, if array 1 is 5 1 2 3 3 4 6 1, and array 2 is 1 2 3 4 5 6, the program returns 1. If any number from either array isn't in the second one, the program returns a 0.
I tried doing something like this, but I can't get it to work:
#include <stdio.h>
int main()
{
int i, j, a[8]={5, 1, 2, 3, 3, 4, 6, 1}, b[6]={1, 2, 3, 4, 5, 6}, x=0;
for(i=0; i<6; i++)
{
for(j=0; j<8; j++)
{
if(a[j]==b[i])
{
x=1;
continue;
}
else
{
x=0;
break;
}
}
}
return x;
}
EDIT:
Thank you Some programmer dude
#include <stdio.h>
void sort(int arr[], int n)
{
int i, j, a;
for (i=0; i<n; i++)
{
for (j=i+1; j<n; j++)
{
if (arr[i]>arr[j])
{
a=arr[i];
arr[i]=arr[j];
arr[j]=a;
}
}
}
}
int main()
{
int i, j, k;
int a[8]={5, 1, 2, 3, 3, 4, 6, 1};
int b[6]={1, 2, 3, 4, 5, 6};
int na=8, nb=6;
for(i=0; i<na; i++) // removing duplicates from a
{
for(j=i+1; j<na; j++)
{
if(a[i]==a[j])
{
for(k=j; k<na; k++)
{
a[k]=a[k+1];
}
na--;
j--;
}
}
}
for(i=0; i<nb; i++) // removing duplicates from b
{
for(j=i+1; j<nb; j++)
{
if(b[i]==b[j])
{
for(k=j; k<nb; k++)
{
b[k]=b[k+1];
}
nb--;
j--;
}
}
}
sort(a, na);
sort(b, nb);
if(na!=nb)
return 0;
for(i=0; i<na; i++)
{
if(a[i]!=b[i])
return 0;
}
return 1;
}
You have several ways you can approach this, you can use two sets of nested loops swapping the order you loop over the two arrays validating each element is found in the other. Two full sets of nested loops are needed as you have a 50/50 chance any single outlier will be contained in either of the arrays. This is the brute-force method and has the potential worst-case number of iterations.
Since an outlier is what drove the need for looping with one arrays as outer and the other inner and then swapping a repeating, e.g. to catch 5, 1, 2, 3, 3, 4, 6, 1 and 1, 2, 3, 4, 5, 6, 7, if you can catch the outlier with another method that requires fewer iterations you can make your algorithm more efficient.
An outlier would be detected in a comparison of the min and max from each array, and to find min and max only requires a single linear traversal of each array. Much better than the worst-case nested loop over all elements.
The min and max check provide a way to shorten your work, but do not eliminate the need to press forward with a second set of nested loops if the result is inconclusive at that point. Why? Consider the following sets, where the min and max are equal, but one element within the range is not included in both arrays, e.g.:
int a[] = { 5, 1, 2, 3, 3, 4, 6, 112 },
b[] = { 1, 2, 3, 4, 5, 6, 7, 112 };
The only way the 7 will be detected is by nested loop with the array containing 7 being the outer loop.
So you could write a short function to test for the common set as:
#include <stdio.h>
#include <limits.h>
int commonset (int *a, int *b, int sza, int szb)
{
int maxa = INT_MIN, maxb = INT_MIN,
mina = INT_MAX, minb = INT_MAX;
for (int i = 0; i < sza; i++) { /* find max/min of elements of a */
if (a[i] > maxa)
maxa = a[i];
if (a[i] < mina)
mina = a[i];
}
for (int i = 0; i < szb; i++) { /* find max/min of elements of b */
if (b[i] > maxb)
maxb = b[i];
if (b[i] < minb)
minb = b[i];
}
if (maxa != maxb || mina != minb) /* validate max & mins equal or return 0 */
return 0;
for (int i = 0; i < sza; i++) { /* compare of each element between arrays */
int found = 0;
for (int j = 0; j < szb; j++)
if (a[i] == b[j]) {
found = 1;
break;
}
if (!found)
return 0;
}
for (int i = 0; i < szb; i++) { /* compare of each element between arrays */
int found = 0;
for (int j = 0; j < sza; j++)
if (a[j] == b[i]) {
found = 1;
break;
}
if (!found)
return 0;
}
return 1;
}
Adding a short example program:
int main (void) {
int a[] = { 5, 1, 2, 3, 3, 4, 6, 1 },
sza = sizeof a / sizeof *a,
b[] = { 1, 2, 3, 4, 5, 6 },
szb = sizeof b / sizeof *b,
result;
result = commonset (a, b, sza, szb);
if (result)
puts ("arrays have common set of numbers");
else
puts ("arrays have no common set of numbers");
return result;
}
Example Use/Output
$ ./bin/arr_commonset
arrays have common set of numbers
$ echo $?
1
With b[] = { 1, 2, 3, 4, 5, 6, 7 }:
$ ./bin/arr_commonset
arrays have no common set of numbers
$ echo $?
0
With a[] = { 5, 1, 2, 3, 3, 4, 6, 112 } and b[] = { 1, 2, 3, 4, 5, 6, 7, 112 }:
$ ./bin/arr_commonset
arrays have no common set of numbers
$ echo $?
0
There are probably even ways to combine the two and shave off a few iterations, and, if you have a guaranteed range for your input sets, you can use a simple frequency array for each and then two simple linear iterations would be needed to increment the element that corresponds to the index for each value in the array, and then a third linear iteration over both frequency arrays comparing that like indexes either both are non-zero or both are zero to confirm the common set -- that is left to you.
Look things over and let me know if you have any further questions.
It might seem like long but I over explained it.
So I have my problem is not necessarily finding the palindromes it is just the finding the length of the palindrome I can't figure out and my code doesn't work for single digit palindromes (yes we count them too) so here is the code and the explanation:
#include <stdio.h>
#define LEN 9
int *lastEqual(int *p, int *q) {
int *rightmost;
int *temp;
int *zero = p;
while (p <= q) {
if (*zero == *(p + 1)) {
temp = p + 1;
if (temp < q) {
rightmost = temp;
}
}
p++;
}
return rightmost;
}
What this funtion does or suppose to do:
*For the given array: {3,6,7,8,7,6,5,3,5} If lastEqual is called by the references of the
bold numbers, it returns a pointer to 3.(The one closest to the end of array)*
*For the given array: {3,6,7,8,7,6,5,3,5} If lastEqual is called by the references of the
bold numbers it returns a pointer to 6.*
Here is the second function:
int isPalindromic(int *p, int *q) {
int *left = p;
int *right = q;
int pali;
while (left < right) {
if (*left == *right) {
pali = 1;
} else {
pali = 0;
}
left++;
right--;
}
return pali;
}
Here is what it does or is supposed to do:
For the given array: {3,6,7,8,7,6,5,3,5} If isPalindromic is called by the references of
the bold numbers it returns 0, since the numbers between those addresses do not
represent a palindrome.
For the given array: {3,6,7,8,7,6,5,3,5} If isPalindromic is called by the references of
the bold numbers it returns 1, since the numbers between those addresses represent
a palindrome.
And here is the main function:
int main() {
int *p, *q, *rightmost;
int arr[LEN] = { 3, 6, 7, 8, 7, 6, 5, 3, 5 };
p = arr;
q = p + (LEN - 1);
for (int i = 0; i < LEN; i++) {
if (isPalindromic(p + i, lastEqual(p + i, q)) == 1) {
rightmost = lastEqual(p + i, q);
printf("Palindrome at index %d, length %ld\n", i, &p - &rightmost);
}
}
return 0;
}
And the output should be like these but I cant figure out how to find lenght and why it doesnt count the single digit number as a palindrome like this 8 :
{3,6,7,8,7,6,5,3,5} so 3 to 3 is not a palindrome 6 to 6 is 7 to 7 is and 8 should be counted as well because there is not a pair of 8
The output Should be like these:
Input Array: {1}
Output: “palindrome at index 0, length: 1”
Input Array: {5, 6, 7, 8, 7, 6, 5, 2, 5}
Output: “palindrome at index 0, length: 7”
Input Array: {2, 7, 6, 11, 10, 11, 6, 5, 3}
Output: “palindrome at index 2, length: 5”
Input Array: {7, 8, 9, 8, 7}
Output: “palindrome at index 0, length: 5”
Input Array: {2, 7, 4, 3, 2, 6, 1, 2, 1}
Output: “palindrome at index 6, length: 3”
Here is a simpler version of isPalindromic with the same arguments, and a much simpler version of main() to find all palindromes:
#include <stdio.h>
int isPalindromic(int *p, int *q) {
while (p < q) {
if (*p++ != *q--)
return 0;
}
return 1;
}
int main() {
int arr[] = { 3, 6, 7, 8, 7, 6, 5, 3, 5 };
int len = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < len; i++) {
for (int j = i; j < len; j++) {
if (isPalindromic(arr + i, arr + j))
printf("Palindrome at index %d, length %d\n", i, j - i + 1);
}
}
return 0;
}
If you just want to output the longest palindrome, change the main function to this:
int main() {
int arr[] = { 3, 6, 7, 8, 7, 6, 5, 3, 5 };
int len = sizeof(arr) / sizeof(arr[0]);
int max_pos = 0, max_len = 1;
for (int i = 0; i < len; i++) {
for (int j = i + max_len; j < len; j++) {
if (isPalindromic(arr + i, arr + j)) {
max_pos = i;
max_len = j - i + 1;
}
}
}
printf("Longest palindrome at index %d, length %d\n", max_pos, max_len);
return 0;
}
I want to iterate through any array starting at an index that's close to the middle, go to the end then go to the beginning.As an example:
#include <stdio.h>
int main(){
int a[]= {1, 2, 3, 4, 5, 6, 7,};
int i = 0;
for (i = 2; i < 6; i++){
if (i == 6){
i = 0;
}
printf("%d\n", a[i]);
}
return 0;
}
How can I "reassign" the index to be zero when it reaches the end (index 6)
Here is a simple write-up. Not tested so adjust as needed. The idea is have the counter start at 0 and add the value of start each time using modulus to make it relative.
int a[]= {1, 2, 3, 4, 5, 6, 7};
int length = sizeof(a)/sizeof(a[0]);
int start = length/2;
for (int i = 0; i < length; i++)
{
printf("%d\n", a[(i+start)%length]);
}
And props to #SouravGhosh for pointing out modulus in the comments before I got this answer up.
If I well understood the question you want two for loops, one starting from the middle of your array and going to the end of the array and the second starting from the middle (minus one) and decreasing to the beginning of the array.
This is the code you can use, it is quite easy and works fine for me:
#include <stdio.h>
int main() {
int a[] = { 1, 2, 3, 4, 5, 6, 7, };
int max = (int)(sizeof(a)/sizeof(a[0]));
int middle = (int)(max / 2);
int i;
for (i = middle; i < max ; i++) {
printf("%d\n", a[i]);
}
for (i = middle - 1; i >= 0; i--) {
printf("%d\n", a[i]);
}
}
I need to generated random numbers in the range [0, 10] such that:
All numbers occur once.
No repeated results are achieved.
Can someone please guide me on which algorithm to use?
The algorithm in Richard J. Ross's answer is incorrect. It generates n^n possible orderings instead of n!. This post on Jeff Atwood's blog illustrates the problem: http://www.codinghorror.com/blog/2007/12/the-danger-of-naivete.html
Instead, you should use the Knuth-Fisher-Yates Shuffle:
int values[11] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
srand(time(NULL));
for (int i = 10; i > 0; i--)
{
int n = rand() % (i + 1);
int temp = values[n];
values[n] = values[i];
values[i] = temp;
}
Try out this algorithm for pseudo-random numbers:
int values[11] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
srand(time(NULL));
for (int i = 0; i < 11; i++)
{
int swap1idx = rand() % 11;
int swap2idx = rand() % 11;
int tmp = values[swap1idx];
values[swap1idx] = values[swap2idx];
values[swap2idx] = tmp;
}
// now you can iterate through the shuffled values array.
Note that this is subject to a modulo bias, but it should work for what you need.
Try to create a randomize function, like this:
void randomize(int v[], int size, int r_max) {
int i,j,flag;
v[0] = 0 + rand() % r_max; // start + rand() % end
/* the following cycle manages, discarding it,
the case in which a number who has previously been extracted, is re-extracted. */
for(i = 1; i < size; i++) {
do {
v[i]= 0 + rand() % r_max;
for(j=0; j<i; j++) {
if(v[j] == v[i]) {
flag=1;
break;
}
flag=0;
}
} while(flag == 1);
}
}
Then, simply call it passing an array v[] of 11 elements, its size, and the upper range:
randomize(v, 11, 11);
The array, due to the fact that it is passed as argument by reference, will be randomized, with no repeats and with numbers occur once.
Remember to call srand(time(0)); before calling the randomize, and to initialize int v[11]={0,1,2,3,4,5,6,7,8,9,10};