I'm C++ begginer. I did this excercise from Deitel's book:
Use a one-dimensional array to solve
the following problem. Read in 20
numbers, each of which is between 10
and 100, inclusive. As each number is
read, validate it and store it in the
array only if it is not a duplicate of
a number already read. After reading
all the values, display only the
unique values that the user entered.
Provide for the "worst case" in which
all 20 numbers are different. Use the
smallest possible array to solve this
problem.
Here is my code:
#include <iostream>
using namespace std;
bool compare(int arrayNum[],int arraySize,int element);
int main()
{
const int size=20;
int i=1;
int num[size];
int arrayElement;
int counter=0;
while(i<=20)
{
cin>>arrayElement;
if(i==1) //stores first element in array
num[0]=arrayElement;
//compare new element with stored elements
//if element is not a duplicate store it in array
else if (compare(num,size,arrayElement))
{
counter++;
num[counter]=arrayElement;
}
i++;
}
//displays array elements
for(int k=0;k<=counter;k++)
cout<<num[k]<<endl;
return 0;
}
//compare elements in array
bool compare(int arrayNum[],int arraySize,int element)
{
for(int j=0;j<arraySize;j++)
{
if(arrayNum[j]==element)
return false;
}
return true;
}
It works, but I'm not sure if I have interpreted the task correctly. I assume then I don't have to include conditional statement for range of numbers (10 to 100 inclusive), as this will be read from the keyboard and input by me. Therefore why was this instruction included? Also at the end it says
use the smallest possible array
I assume the max size has to be 20,but I don't think there is a way to dynamically expand array size (for example while storing new elements) as array size is const. I would appreciate if someone could help me with this. Any comments regarding code, or better solution are welcome.
As each number is read, validate
it and store it in the array
Emphasis mine. The text clearly says that your program has to validate the input. In other words, it has to check that the entered number is between 10 and 100, and if it is not, handle the error appropriately. So yes, you do need a conditional, although exactly what you do to handle the error is up to you.
And you're right, since arrays aren't dynamically resizable, the array size has to be at least 20.
You do need a conditional. Basically it's saying to take in a number between 10 and 100. If it's not a number between those ranges, don't store it. Also, if that number already exists in the array, don't store it. Then just print out the values in the array.
You assume correct about the array size, it's maximum size would be 20, although you may not store all 20 values (again, because some input might be bad).
The smallest possible array is a char[12], where the individual bits are used as flags.
char data[12]; // memset(data, 0, sizeof(data)); in main();
void set(int n_raw;)
{
int n = n_raw - 10;
int index = n/8;
int offset = n-8*index;
data[index] |= 1 << offset; // added "1 <<"
}
Reading the values back is left as an exercise for the student.
I assume then I don't have to include
conditional statement for range of
numbers (10 to 100 inclusive), as this
will be read from the keyboard and
input by me. Therefore why was this
instruction included?
Sure, in this case you wrote the code and know to enter numbers within the range expected; however, it is a standard best-practice to always validate input data from a user, always. That way erroneous values are handled gracefully (with an appropriate error message) and helps to make your program more robust.
Also at the end it says
use the smallest possible array
I assume the max size has to be 20,,,
I think what they might have been getting at here is that you could have used an array of 91 bytes as shown below.
int cnt = 0; // count of unique values entered
byte values[91]; // values entered indicator array
int valIdx; // used as values array index
memset((void *)values, 0, sizeof(values)); // initialize array to all zeros
while ( cnt < 20 )
{
// [code for the following comments not shown]
// have user input a number
// validate the number (>= 10 && <= 100)
// subtract 10 from the number and store it in valIdx
// (now valIdx will contain a number >= 0 <= 90)
if ( !values[valIdx] )
{
values[valIdx] = 1;
++cnt;
}
}
// then to show the unique values...
for ( valIdx = 0; valIdx < sizeof(values); valIdx++ )
{
if ( values[valIdx] )
{
cout << valIdx + 10 << endl;
}
}
That solution however, would not have met the "use the smallest array possible" requirement.
Back to your code...
I would go ahead and add the user input validation, just for completeness (and to get into the habit of never trusting users (especially yourself).
As far as improvements go, here is one thing to think about. The compare routine goes through every array element when a unique number has been entered. It only needs to check against those that have a stored value in them. Making that change should lead you to refactor the contents of your while loop as well.
I'm studying C++ in the same book!!
My first implementation for solving this problem was one that don't use any complementar array.. it uses a linear search to find duplicates..
take a look:
#include <iostream>
using namespace std;
// remember: size_t = unsigned int
const size_t arraySize = 20;
size_t _array[ arraySize ];
// global variable to keep track of the last used
// position in the _array
size_t counter = 0;
// the argument is not changed, so pass it by
// const reference
bool dupSearch( const int & );
int main()
{
// disregard this
ios_base::sync_with_stdio( false );
// "temp" variable declared outside the loop to
// avoid repeated allocation and deallocation
int i = arraySize, temp;
// look at the loop condition below " ( i-- ) "
// remember:
// false = ( every expression evaluated to 0 )
// true = ( every expression evaluated to a non-zero result )
// more details on pag. 108 of the book. 8/e Portability tip 4.1
while ( i-- )
{
// read the number from the user
cin >> temp;
// if the number entered is valid, put the
// number on _array[ counter ] and increment 'counter'
if ( dupSearch( temp ))
{
_array[ counter ] = temp;
++counter;
}
}
// print the result in column format
cout << endl;
for ( size_t j = 0; j < counter; ++j )
cout << _array[ j ] << endl;
}
// validation: if the value is out of the described range, return false
// if is in the range, check for duplicates using linear search.
// if a duplicate is found, return false
// otherwise, return true.
bool dupSearch( const int &a )
{
if ( a < 10 || a > 100 )
return false;
else
for ( size_t i = 0; i < counter; ++i )
if ( _array[ i ] == a )
return false;
return true;
}
the number of comparisons is
n = ( n * ( n + 1 )) / 2
where n = counter. worst case --> counter = 20 numbers --> loop 210 times through the program execution.
Related
Disclaimer: This question is more of a challenge, and the post is also quite long. Read only in free time!
The Problem:
Basically, suppose there is a single line of integer inputs:
32352\n // assuming single digits only and no spaces for simplification
We have to remove duplicates from the inputs, and then display them. So, output should be:
After removing duplicates: 2, 3, 5 // display them in any order
However, there is a catch:
Do not use any data structures containers.
Edit: I believe containers are what I meant (thanks Vlad!).
So, my question is: What is the error in my implementation, and is there another (better) way to do it?
My thought process:
Since we are not allowed use of any data structure, we cannot store the inputs (I think?).
However, since it is already stored in memory on input, that is not a problem.
More of a problem is removing the duplicates. We will have to manipulate the input stream.
The first thing that struck me is that we can sort the inputs. That is,
32352
becomes:
22335
And now, simply print the first element of each range.
Working on this idea, I came across the std::cin.get() and std::cin.putback() methods, both accepting a char.
I also realized I would have to use recursion.
And hence, the code becomes (I have used insertion sort):
The Code:
The sort() function is where the error is. It uses a running index ala arrays, and this is used to uniquely identify each element.
In each iteration, the index_of_element element is found and selected, and we determine where in the remaining (virtual) array, we need to place it. For example, if in our original input:
32352 // S = sorted subarray
SU--U // U = unsorted subarray
, the first 2 is selected, we "shift" 3 (as 3 < 2).
Now, there are no more elements left to shift, we "place" 2.
The result should become:
23352
SSU-U
The (buggy) implementation:
bool sort(int index_of_element, int index = 0, char prev_element = 0)
{
static char element;
char digit;
// retrieve an element from memory
std::cin.get(digit);
// If not end of input
if(digit != '\n')
{
// store the element for comparision
if(index == index_of_element)
{
element = digit;
}
// continue forward until '\n'
bool result = sort(index_of_element, index + 1, digit);
// if we are in sorted subarray
if(index <= index_of_element)
{
// If element belongs here(also if this is first element(prev_element is 0)), place it
if(element > prev_element)
{
digit = element;
// Signal that element has been placed
element = 0;
}
// Else, if element not already placed, we need to shift elements
else if(element != 0)
{
// Place the previous element here
digit = prev_element;
}
}
// Put it back in memory
std::cin.putback(digit);
// And return the result
return result;
}
// Which is generated here when end of input is reached
else
{
// If sorted all elements, break loop
if(index_of_element == index)
{
return false;
}
// Else, continue sorting
else
{
return true;
}
}
}
(A wall of code, but I didn't want to skip anything relevant), and it should be used as:
...
int index_of_element = 0;
while(sort(index_of_element++));
...
The display function is ready, and it works properly.
What I do know is that it gets stuck in an infinite loop and the values are lost.
What is going wrong?
And should I add the output (The post is already very long)?
The problem seems to be that you don't put the newline back into the stream, while your code assumes that it will be there.
That is, after your first pass, digit != '\n' is always true.
Put the newline back into the stream, or break when you've reached the true end-of-stream.
(There could also be problems with (ab)using std::cin like this, but I'm not sure, and that's another matter anyway.)
You can do it with only function objects, in a single pass.
#include <iostream>
#include <sstream>
#include <functional>
void print_unique_ints(std::istream & in, std::ostream & out, std::function<bool(int)> unseen) {
for (int i; in >> i;) {
if (unseen(i)) {
out << i << ' ';
print_unique_ints(in, out, [&](int j){ return (i != j) && unseen(j); });
return; // not actually needed, previous call only ends when input is exhausted
}
}
}
int main() {
print_unique_ints(std::cin, std::cout, [](int){ return true; });
}
See it live
Each call to print_unique_ints skips previously seen ints, prints the unseen int, and adds to the filter
Substituting values for variables; and function calls for expressions; in the first call
for (int i; in >> i;) { // i = 3
if (true) {
out << 3 << ' ';
print_unique_ints(...) // see below
}
}
The second
for (int i; in >> i;) { // i = 2
if ((3 != i) && true) {
out << 2 << ' ';
print_unique_ints(...) // see below
}
}
The third
for (int i; in >> i;) { // i = 3, 5
if ((2 != i) && (3 != i) && true) { // skips over the 3
out << 5 << ' ';
print_unique_ints(...) // see below
}
}
The forth
for (int i; in >> i;) { // i = 2
if ((5 != i) && (2 != i) && (3 != i) && true) { // skips the 2 and finds the end of input
}
}
Note that && true never changes the result in the if
A variation of bitset (or mask) implem...using the commutative property of multiplication
Take a function f which maps every digit to a unique prime p_i
0 1 2 3 4 5 6 7 8 9
2,3,5,7,9,11,13,17,19,23
If all numbers are found the total amount to N=2*3*5*7*9*11*13*17*19*23=2007835830
Consume cin as c, if f(c) divides N, print c and update N /= f(c)
#include <iostream>
#include <sstream>
int f(char c){
if(c=='0') return 2;
if(c=='1') return 3;
if(c=='2') return 5;
if(c=='3') return 7;
if(c=='4') return 9;
if(c=='5') return 11;
if(c=='6') return 13;
if(c=='7') return 17;
if(c=='8') return 19;
if(c=='9') return 23;
}
int main() {
std::istringstream in("2 2 2 3 5");
int N = 2007835830;
char c;
while(in >> c){
if(c=='\n') break;
int p_i = f(c);
if(N % p_i == 0){
N = N/p_i;
std::cout<<c<<" ";
}
}
}
I am sure that this phrase
Remove duplicates from input without use of any data structures
means that you shall not use any container like for example std::string or an ordinary array.
The assignment is not simple for a beginner.
Here are my five cents.
#include <iostream>
#include <type_traits>
template <typename T>
T remove_duplicates( T n )
{
static_assert ( std::is_integral<T>::value );
const T Base = 10;
T result = n % Base;
for ( T multiplier = 1; n /= Base; )
{
T digit = n % Base;
T tmp = result;
bool unique = true;
while ( ( unique = tmp % Base != digit ) && ( tmp /= Base ) );
if ( unique )
{
multiplier *= Base;
result = digit == 0 ? result * multiplier + digit
: digit * multiplier + result;
}
}
return result;
}
int main()
{
for ( int n : { 0, 1, 10, 101, 100, 10203, -1, -10, -101, -100, - 10203 } )
{
std::cout << n << ": " << remove_duplicates( n ) << '\n';
}
return 0;
}
The program output is
0: 0
1: 1
10: 10
101: 10
100: 10
10203: 1230
-1: -1
-10: -10
-101: -10
-100: -10
-10203: -1230
That is you are building a new number from the source number by checking whether the new number already contains a digit from the source number.
The function can work with any integer type signed or unsigned. It correctly processes digits equal to 0.
It was said not to use any arrays, vectors, stacks, queues etc and neither our own implementations of it. I simplified the condition.
Well I've got bad news for you; this is not possible.
Given an input of length N you will need to somehow remember the previous N - 1 values to decide whether to print the Nth value or not. This is not possible with constant space.
So you need some data structure.
Now ...
Since we are not allowed use of any data structure, we cannot store the inputs (I think?).
However, since it is already stored in memory on input, that is not a problem.
So let's assume the existence of a (mutable) array of length N, containing the input values. Now we can solve this without using additional storage / data structures:
Select some value as special value
Iterate over the numbers until you find a value which is not that special value. print that value. Write the special value to the array where you found the value you just printed. finish iterating over the numbers, overwritte each occurrence of the just printed value with the special value.
repeat (from 2) until the input consists only of special values.
You just need to think about a way to handle the case where the special value was present in the input from the start.
So, I have a cycle that goes over an array and should reverse the sequence of consecutive positive numbers, but it seems to count excess negative number as a part of a sequence, thus changing its position. I can't figure the error myself, and will be happy to hear any tips!
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
int Arr[100];
int Arr2[100];
int main()
{
srand(time(NULL));
int n, x;
bool seq = false;
int ib = 0;
printf("Starting array\n");
for (n = 0; n < 100; Arr[n++] = (rand() % 101) - 50);
for (n = 0; n < 100; printf("%3d ", Arr[n++]));
putchar('\n');
for (n = 0; n < 100; n++) //sorting
{
if (Arr[n] > 0) //check if the number is positive
{
if (seq == false) //if it isn't the part of a sequence
{
seq = true; ib = n; //declare it now is, and remember index of sequence's beginning
}
else
seq = true; //do nothing if it isn't first
}
else //if the number is negative
{
if (seq==true) //if sequence isn't null
for (x = n; ib <= n; ib++, x--) //new variable so that n will stay unchanged,
number of iterations = length of sequence
{
Arr2[x] = Arr[ib]; //assigning array's value to a new one,
reversing it in the process
}
seq = false; //declaring sequence's end
Arr2[n + 1] = Arr[n + 1]; //assigning negative numbers at the same place of a new array
}
}
printf("Modified array\n");
for (n = 0; n < 100; printf("%3d ", Arr2[n++]));
putchar('\n');
system('pause');
return 0;
}
following what we discussed in comments, i listed couple of rules here to shape my answer around it.
Rules :
the sequence of elements can be varied. so if there are 5 positive numbers in a row within an array, we would be reversing the 5 elements. for example
array[5] = {1,2,3,4,5} would become array[5]{5,4,3,2,1}
if single positive number neighboured by negatives, no reverse can happen
array[4] = {-1,0,-2,1} would result the same array
no processing happens when a negative number is discovered.
based on these rules.
here is what I think going wrong in your code.
Problems :
1- consider thisarray = {1,2,-1}. notice that the last value is negative. because of this. the following code would run when the 3rd index of the array is processed;
` Arr2[n + 1] = Arr[n + 1]; //assigning negative numbers at the same place of a new array`
this is a no-no. since you are already at the end of the Arr2 n+1 would indicate that there is a 4th element in the array. (in your case 101h element of the array) this would cause an undefined behaviour.
2 - consider the same array mentioned above. when that array is looped, the outcome would be array = {-1,2,1} . the -1 and 1 are swapped instead of 1 and 2.
3 - you are assigning ib = n whenever a negative number is found. because whenever a negative value is hit, seq=false is forced. But the ib, never been put into use until a next negative number is found. here is an example;
array = {...2, 6}
in such scenario, 2 and 6 would never get reversed because there is no negative value is following this positive sequence.
4 - consider this scenario arr = {-10,-1,....} this would result in arr = {0,-1,....}. This happens because of the same code causing the undefined behaviour problem mentioned above.
`Arr2[n + 1] = Arr[n + 1];`
Suggestion
Most of the problems mentioned above is happening because you are trying to figure out the sequence of the positive numbers when a negative number is found.
else //if the number is negative
{
if (seq==true) //if sequence isn't null
for (x = n; ib <= n; ib++, x--) //new variable so that n will stay unchanged,
number of iterations = length of sequence
{
Arr2[x] = Arr[ib]; //assigning array's value to a new one,
reversing it in the process
}
you should completely get rid of that and completely ignore the negative numbers unless you forgot to mention in your question some key details. instead just focus on the positive numbers. I'm not going to send you the entire code but here is how I approached the problem. feel free to let me know if you need help and I would be more then happy to go through in detail.
start your for loop as usual.
for (n = 0; n < 100; n++) //sorting
{
don't try to do anything when an element in an array is a negative value.
if (Arr[n] > 0) //check if the number is positive
if the number is positive. create recording the sequence indices. for one, we know the sequence will start at n once the `if (Arr[n] > 0) true. so we can do something like this;
int sequenceStart = n;
we also need to know when the positive number sequence ends.
int sequenceEnd = sequenceStart;
the reason for int sequenceEnd = sequenceStart; is because we going to start using the same n value to start with. we can now loop through the array and increment the sequenceEnd until we reach to a negative number or to the end of the array.
while (currentElement > 0)
{
n++;//increment n
if(n < arraySiz) //make sure we still in the range
{
currentElement = Arr[n]; // get the new elemnet
if (currentElement > 0)
{
sequenceEnd++;
}
}
else
break; // we hit to a negative value so stop the while loop.
}
notice the n++;//increment n this would increment the n++ until we reach to the negative number. which is great because at the end of the sequence the for loop will continue from the updated n
after the while loop, you can create an array that has the same size as the number of sequences you iterated through. you can then store the elements from starting arr[sequenceStart] and arr[sequenceEnd] this will make the reversing the sequence in the array easier.
EDIT Took a different approach and found the solution, updated the function to correctly find the mode or modes
I've been at this algorithm all day and night, I've looked at about 12 code examples 10x over but none of them seem to go above and beyond to address my problem.
Problem: Find the mode(s) in an array, if the array has more than one mode, display them all. (This is a homework assignment so I must use arrays/pointers)
Sample array:
-1, -1, 5, 6, 1, 1
Sample output:
This array has the following mode(s): -1, 1
The problem I'm having is trying to figure how to store and display just the highest mode OR the multiple modes if they exist.
I have used a lot of approaches and so I will post my most recent approach:
void getMode(int *arr, int size)
{
int *count = new int[size]; // to hold the number of times a value appears in the array
// fill the count array with zeros
for (int i = 0; i < size; i++)
count[i] = 0;
// find the possible modes
for (int x = 0; x < size; x++)
{
for (int y = 0; y < size; y++)
{
// don't count the values that will always occur at the same element
if (x == y)
continue;
if (arr[x] == arr[y])
count[x]++;
}
}
// find the the greatest count occurrences
int maxCount = getMaximum(count, size);
// store only unique values in the mode array
int *mode = new int[size]; // to store the mode(s) in the list
int modeCount = 0; // to count the number of modes
if (maxCount > 0)
{
for (int i = 0; i < size; i++)
{
if (count[i] == maxCount)
{
// call to function searchList
if (!searchList(mode, modeCount, arr[i]))
{
mode[modeCount] = arr[i];
modeCount++;
}
}
}
}
// display the modes
if (modeCount == 0)
cout << "The list has no mode\n";
else if (modeCount == 1)
{
cout << "The list has the following mode: " << mode[0] << endl;
}
else if (modeCount > 1)
{
cout << "The list has the following modes: ";
for (int i = 0; i < modeCount - 1; i++)
{
cout << mode[i] << ", ";
}
cout << mode[modeCount - 1] << endl;
}
// delete the dynamically allocated arrays
delete[]count;
delete[]mode;
count = NULL;
mode = NULL;
}
/*
definition of function searchList.
searchList accepts a pointer to an int array, its size, and a value to be searched for as its arguments.
if searchList finds the value to be searched for, searchList returns true.
*/
bool searchList(int *arr, int size, int value)
{
for (int x = 0; x < size; x++)
{
if (arr[x] == value)
{
return true;
}
}
return false;
}
It's best to build algorithms from smaller building blocks. The standard <algorithm> library is a great source of such components. Even if you're not using that, the program should be similarly structured with subroutines.
For homework at least, the reasoning behind the program should be fairly "obvious," especially given some comments.
Here's a version using <algorithm>, and std::unique_ptr instead of new, which you should never use. If it helps to satisfy the homework requirements, you might implement your own versions of the standard library facilities.
// Input: array "in" of size "count"
// Output: array "in" contains "count" modes of the input sequence
void filter_modes( int * in, int & count ) {
auto end = in + count;
std::sort( in, end ); // Sorting groups duplicate values.
// Use an ordered pair data type, <frequency, value>
typedef std::pair< int, int > value_frequency;
// Reserve memory for the analysis.
auto * frequencies = std::make_unique< value_frequency[] >( count );
int frequency_count = 0;
// Loop once per group of equal values in the input.
for ( auto group = in; group != end; ++ group ) {
auto group_start = group;
// Skip to the last equal value in this subsequence.
group = std::adjacent_find( group, end, std::not_equal_to<>{} );
frequencies[ frequency_count ++ ] = { // Record this group in the list.
group - group_start + 1, // One unique value plus # skipped values.
* group // The value.
};
}
// Sort <frequency, value> pairs in decreasing order (by frequency).
std::sort( frequencies.get(), frequencies.get() + frequency_count,
std::greater<>{} );
// Copy modes back to input array and set count appropriately.
for ( count = 0; frequencies[ count ].first == frequencies[ 0 ].first; ++ count ) {
in[ count ] = frequencies[ count ].second;
}
}
There's no real answer because of the way the mode is defined. Occasionally you see in British high school leaving exams the demand to identify the mode from a small distribution which is clearly amodal, but has one bin with excess count.
You need to bin the data, choosing bins so that the data has definite peaks and troughs. The modes are then the tips of the peaks. However little subsidiary peaks on the way up to the top are not modes, they're a sign that your binning has been too narrow. It's easy enough to eyeball the modes, a bit more difficult to work it out in a computer algorithm which has to be formal. One test is to move the bins by half a bin. If a mode disappears, it's noise rather than a real mode.
So, this is a weekly project for school, and I have got it completely working, but feel as if the way I did it, probably isn't one of of the best ways to do it ( or even a good way ). I was hoping you guys could help optimize it / give a better solution. I have already submitted this version, but would like to know a more optimal solution to the problem.
So to start, here's the problem...
It's almost Halloween and Linus is setting out to the garden to wait for the Great Pumpkin. Unfortunately, due to diversification, there are lots of other gourds in the garden this year, so he needs you to write a program to tell him how many patches of pumpkins there are and how big they are.
The input to this program will be a number of different gardens. The first line of the input for each garden will be the dimensions of the garden, r, the number of rows in the garden, and c, the number of columns, where 0 ≤ r ≤ 40 and 0 ≤ c ≤ 40. Following the dimensions will be r lines with c characters on each line. Each of these characters will be a lower case letter representing the type of gourd grown in the square. A lower case 'p' will represent pumpkins. A garden with 0 for the number of rows and/or columns indicates the end of input and should not be processed.
Example input:
10 10
pzzzzzzzzp
pyypzzzzzy
ppppssssyy
ssspssssyy
ssssppssyy
ssssppsspy
zzzzzzsspy
zzzzzzsspy
yyyypzsspy
yyyypppppy
3 4
pppp
pppp
pppp
1 7
zzzzzzz
0 0
For each garden, output the number of the garden (with the first input set being garden 1), the number of pumpkin patches in the garden, and the size of the pumpkin patches in order from smallest to largest. If there is more than one patch of a given size, print the size as many times as it occurs. Use the following format:
Example Output:
Garden # 1: 4 patches, sizes: 1 4 8 10
Garden # 2: 1 patches, sizes: 12
Garden # 3: 0 patches, sizes:
Note: Even though the problem says to input from a file, our professor told us to input through the keyboard.
My approach to this was to put the garden into a 2d array with a border of x's around it. I would then use a function to find a pumpkin patch ( and return its coordinates ). I would then use another function that recursively found if a pumpkin was attached to that one through above, below, left, and right, and returned the size of the pumpkin patch. This function also 'deletes' each pumpkin when it finds it by replacing it by an 'x'. This allowed me to not have to worry about finding pumpkins multiple times.
So here's my code, pretty well commented so that you guys could hopefully understand what I was trying to do.
#include <iostream>
#include <fstream>
using namespace std;
const int MAX_ROW = 41;
const int MAX_COL = 41;
char input ();
int checkForPatchSize ( char arr[][MAX_COL], int numOne, int numTwo );
bool findPatch ( char arr[][MAX_COL], int &row, int&col );
void sort ( int arr[], int size);
int main ()
{
int inputNumOne = -1; // Defaulted to -1, First number for Patch Size
int inputNumTwo = -1; // Defaulted to -1, Second number for Patch Size
int i, j; // i, j are indexes for loops, number
int numArr[MAX_ROW][MAX_COL]; // Array for storing Data
int indexGarden = 0;
int index = 1;
while ( inputNumOne != 0 )
{
cin >> inputNumOne; // User inputs Dimension
cin >> inputNumTwo; // Of Garden...
if ( inputNumOne != 0 and inputNumTwo != 0 ) // End case is that both are 0.
{
char pumpkinPatch[MAX_ROW][MAX_COL]; // Array for storing pumpkin patch info.
for ( i = 0; i < inputNumOne+2; i++ )
{
for ( j = 0; j < inputNumTwo+2; j++ )
{
// This if statement surrounds the garden in X's so that I have a border (allows me to not have to worry about test cases.
if ( i == 0 or j == 0 or i == inputNumOne + 1 or j == inputNumTwo + 1 )
{
pumpkinPatch[i][j] = 'x';
}
else // This is the input of the garden into a 2d array.
{
pumpkinPatch[i][j] = input();
}
}
}
int row, col, size, numberOfPatches = 0;
bool foundPatch = true;
index = 1;
while ( foundPatch == true )
{
row = inputNumOne+2; // Because I added a border to the garden
col = inputNumTwo+2; // the size is +2 of what the user input.
foundPatch = findPatch ( pumpkinPatch, row, col ); // Finds the start of a pumpkin patch, and returns the coordinates ( as row and col ).
if ( foundPatch == true ) // If a patch is found....
{
numberOfPatches++; // Increase number of patches
size = checkForPatchSize ( pumpkinPatch, row, col); // find size of particular patch
numArr[indexGarden][index] = size; // put size into data arr (to be printed to screen later).
index++;
}
}
numArr[indexGarden][0] = numberOfPatches; // Put number of patches as first item in each column of data arr.
indexGarden++;
}
}
for ( index = 0; index < indexGarden; index++ ) // Print out Garden Info
{
cout << "Garden # " << index + 1 <<": " << numArr[index][0] << " patches, sizes: ";
int temp = numArr[index][0]; // temp is the number of patches in particular garden.
int tempArr[temp]; // temp array to be used for sorting
int indexTwo;
for ( indexTwo = 0; indexTwo < temp; indexTwo++ )
{
tempArr[indexTwo] = numArr[index][indexTwo+1]; // Transfer sizes into a temp array so that they can be sorted.
}
sort (tempArr, temp); // Sort ( Sorts arr from smalles to larges )
for ( indexTwo = 0; indexTwo < temp; indexTwo++ ) // Output sorted array to screen.
{
cout << tempArr[indexTwo] << " ";
}
cout << endl;
}
}
char input()
{
char letter;
cin >> letter;
return letter;
}
/////////////// findPatch /////////////////////////////////////////////////
// Requirements: a 2D array of garden, and the size of it (row and col). //
// Returns a bool, true if patch is found, false if no patches found. //
// row and col are returned by reference to be the coordinates of one //
// of the pumpkins in the patch. //
///////////////////////////////////////////////////////////////////////////
bool findPatch ( char arr[][MAX_COL], int &row, int&col )
{
int rowIndex = 0;
int colIndex = 0;
while ( arr[rowIndex][colIndex] != 'p' and rowIndex < row )
{
colIndex = 0;
while ( arr[rowIndex][colIndex] != 'p' and colIndex < col )
{
colIndex++;
}
if ( arr[rowIndex][colIndex] != 'p' )
{
rowIndex++;
}
}
if ( arr[rowIndex][colIndex] != 'p' )
{
return false;
}
row = rowIndex;
col = colIndex;
return true;
}
/////////////// checkForPatchSize /////////////////////////////////////////
// Requirements: a 2D array of garden, and the coordinates of the start //
// of a patch. (Gotten from findPatch) //
// Returns an int, which is the size of the patch found //
// All p's or pumpkins are changed to x's so that they are not used //
// multiple times. //
///////////////////////////////////////////////////////////////////////////
int checkForPatchSize ( char arr[][MAX_COL], int numOne, int numTwo )
{
int index = 0;
if ( arr[numOne][numTwo] == 'p' )
{
index++;
arr[numOne][numTwo] = '0';
// Check Above
index += checkForPatchSize ( arr, numOne - 1, numTwo );
// Check to Left
index += checkForPatchSize ( arr, numOne, numTwo - 1 );
// Check Below
index += checkForPatchSize ( arr, numOne + 1, numTwo );
// Check to Right
index += checkForPatchSize ( arr, numOne, numTwo + 1 );
return index;
}
return 0;
}
/////////////// sort //////////////////////////////////////////////////////
// Requirements: an integer array, and the size of it (amount of //
// numbers in it). //
// //
// Sorts an array from smalles to largest numbers //
///////////////////////////////////////////////////////////////////////////
void sort ( int arr[], int size )
{
int index = 0;
bool changeMade = true;
while ( changeMade == true )
{
changeMade = false;
for ( index = 0; index < size - 1; index++ )
{
if ( arr[index] > arr[index+1] )
{
int temp = arr[index];
arr[index] = arr[index+1];
arr[index+1] = temp;
changeMade = true;
}
}
}
}
Alright, after reading through your code, I see your approach. Generally, I would approach this from a visual perspective. As it is, your code should work just fine, and is quite an elegant solution. The single weakness of your algorithm is the fact that it iterates over the same patch each time it moves. For example, when it moves upwards, it checks downwards. Avoiding redundancy is the surest sign of an optimal algorithm, but in terms of the small-scale at which you are deploying the algorithm, it need not be optimal.
In a way, the recursive nature of your code makes it quite beautiful because it traverses the pumpkin patch like little sparks that die out, which I really do like. Recursion is something which I don't often bother myself with, mostly because I don't think recursively, but after spending a moment wrapping my head around your algorithm, I really do see its value in cases like this. I would love to see the algorithm at work with dynamic visuals.
As for the accuracy of your algorithm, I can not imagine that it would fail in any manner to count the pumpkins correctly because it functions by making a small wave around the picked pumpkin in which the algorithm repeats itself, effectively propagating through the patch until it is all counted. As I said, the only shortcoming of your algorithm is that it would fall into an infinite loop if you did not somehow mark pumpkins as found (it checks the position it was called from). Beyond that, I can only say that you've proposed an excellent solution and that your doubts are almost entirely misplaced. Using a recursive algorithm was an excellent choice in this regard because it doesn't require a long list of cases in order to 'count'; it simply jumps into adjacent positions, returning to itself with the full count.
Use a single-subscripted array to solve the following problem: Read in 20 numbers, each of which is between 10 and 100, inclusive. As each number is read, print it only if it is not a duplicate of a number already read. Provide for the "worst case" in which all 20 numbers are different. Use the smallest possible array to solve this problem.
here is what I have so far:
#include <stdio.h>
#define SIZE 20
int duplicate (int num[] );
int main ()
{
int i, numbers[ SIZE ];
printf( " Enter 20 numbers between 10 and 100:\n " );
scanf_s( "%d\n" );
for (int i = 0; i < SIZE - 1; i++ );
{
int duplicate( int num[] )
{
int i, hold;
for ( i = 0; i <= SIZE - 1; i++ )
if ( num[i] == num[i=1] ){
hold = num[i];
else
hold = num[i+1];
}
printf( "%3d\n," num[ i ] );
}
Your professor is, unfortunately, probably not smart enough to solve his own problem. The smallest possible array for this problem is size 2 (Assuming a 64-bit data type, which is the largest the standard provides for. With 32-bit integers it would need three elements, and with 128-bit integers, just 1).
#include <stdint.h>
#include <stdio.h>
int main(void)
{
int_fast64_t visited[2] = { 0 };
int inputs_left = 20;
do {
int input, slot;
int_fast64_t mask;
puts("Enter an integer between 10 and 100: ");
if (!scanf("%d", &input)) {
puts("That's not a number!\n");
continue;
}
if (input < 10 || input > 100) {
puts("Out of range!\n");
continue;
}
slot = (input - 10) >> 6;
mask = 1 << ((input - 10) & 0x3F);
if (visited[slot] & mask) {
puts("Already seen, it is a duplicate.\n");
}
else {
visited[slot] |= mask;
printf("%d is new\n", input);
}
inputs_left--;
} while (inputs_left);
return 0;
}
You are welcome to use this code in your assignment, if you are able to correctly explain how it works (I hope your professor taught you how to write comments).
This is what I came up with, thanks for everybody's help:
#include <stdio.h>
#define MAX 20
int main()
{
int a[ MAX ] = { 0 }; /* user input */
int i; /* counter */
int j; /* counter */
int k = 0; /* number of integers entered */
int duplicate; /* notify of duplicates */
int value;
printf( "Enter 20 numbers between 10 - 100;\n" );
/* ask user for 20 numbers */
for ( i = 0; i <= MAX - 1; i++ ){
duplicate = 0;
scanf( "%d", &value);
/* decide if integer is duplicate */
for ( j = 0; j < k; j++ ) {
/* notify and stop loop if duplicate */
if ( value == a[ j ] ) {
duplicate = 1;
break;
{ /* end if */
/* enter number into array if it's not a duplicate */
if ( !duplicate )
a[ k++ ] = value;
} /* end if */
There are a few problems with your code:
The duplicate function is inside the main function.
i is declared multiple times
There should not be a semicolon after your first for loop.
The hold variable is not being used for anything. It is only being assigned a value.
num[i=1] - not sure what you are trying to do here, but the i=1 is setting i to 1.
In your first for loop, your condition is i < SIZE - 1, meaning it will loop 19 times, not 20. It should be i < SIZE or i <= SIZE - 1.
Your if statements should use braces ({}) for each if/else, or not at all.
if (test) {
// code
}
else {
// code
}
or
if (test)
// code
else
// code
As for the logic:
You are only getting one integer, which you are not putting in the numbers array. You will need to get 20 integers one by one and check the array each time the user enters a number.
The duplicate function should probably take a second parameter, the number that you want to check for. The if statement would check if num[i] equals the number you are looking for.
Remember to initialize the array values and only check values that you have set. For example, when the user enters the third number, you only want to check the first 2 numbers in the array to see if it already exists.
PS: Please try to indent your code properly. Many people will not even try to help if it is not indented properly.
My C is pretty rusty, so here's a pseudo-code solution (since this is homework you should do some of it for yourself):
print initial prompt;
declare nums[ array size 20 ]; // I later assume a 0-based index
declare boolean found;
for (i=0; i < 20; i++) {
// prompt for next number if desired
read next number into nums[i];
found = false;
// compare against all previously read numbers
for (j=0; j < i; j++) {
if (nums[j] == nums[i]) {
found = true;
break;
}
}
if (!found) {
print nums[i];
}
}
Note: the question as stated doesn't say the numbers have to be integers. Also, it says "use the smallest possible array" - you could do it with a 19 element array if you introduce a non-array variable for the current number (since the 20th number read only needs to be checked against the previous 19, not against itself), but that makes the code more complicated.
See also the comment I posted above that mentions some specific things wrong with your code. And check that all of your brackets match up.