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.
Related
The Problem:
A company is distributing phone numbers to its employees to make things easier. the next digit cannot be equal to the last is the only rule for example 0223 is not allowed while 2023 is allowed. At least three digits will be excluded every time. Write a function that takes in a length of the phone number and the digits that will be excluded. The function should print all possible phone numbers.
I got this question in an interview and I have seen one like it before at my university. It is a permutation problem. My question is what is the best way or decent way to solve this without a million for loops.
I do understand that this is technically how it works
length of phone number = 3;
[0-9], [0-9] excluding the last digit, [0-9] excluding the last digit
but I am unsure on how the best way to turn this into code. Any language is accepted!
thank you:
Also I might be asking this in the wrong place. please let me know if I am.
A simple way to solve this problem could be using Recursion. Here's my commented C++ code:
void solve(int depth, int size, vector <int> &curr_seq){
// If the recursion depth is equal to size, that means we've decided size
// numbers, which means that curr_seq.size() == size. In other words, we've
// decided enough numbers at this point to create a complete phone number, so
// we print it and return.
if(depth == size){
for(int item : curr_seq){
cout << item;
}
cout << "\n";
return;
}
// Try appending every possible digit to the current phone number
for(int i = 0; i <= 9; ++i){
// Make sure to only append the digit i if it is not equal to the last digit
// of the phone number. We can also append it, however, if curr_seq
// is empty (because that means that we haven't decided the 1st digit yet).
if(curr_seq.empty() || curr[curr.size() - 1] != i){
curr_seq.push_back(i);
solve(depth + 1, size, curr);
curr_seq.pop_back();
}
}
}
I think I like the recursive solution, but you can also just generate all permutations up to the limit (iterate), filter out any with repeating digits, and print the successful candidates:
#include <iomanip>
#include <iostream>
#include <sstream>
using namespace std;
// Because C/C++ still has no integer power function.
int ipow(int base, int exp) {
int result = 1;
for (;;) {
if (exp & 1)
result *= base;
exp >>= 1;
if (!exp)
return result;
base *= base;
}
}
void noconsec(const int len) {
int lim = ipow(10, len);
// For e.g. len 4 (lim 10000),
// obviously 00xx won't work, so skip anything smaller than lim / 100.
int start = (len <= 2) ? 0 : (lim / 100);
for (int num = start;num < lim;num++) {
// Convert to string.
std::stringstream ss;
ss << std::setw(len) << std::setfill('0') << num;
std::string num_s = ss.str();
// Skip any consecutive digits.
bool is_okay = true;
auto prev_digit = num_s[0];
for (int digit_idx = 1;digit_idx < num_s.length();digit_idx++) {
auto digit = num_s[digit_idx];
if (prev_digit == digit) {
is_okay = false;
}
prev_digit = digit;
}
// Output result.
if (is_okay) {
cout << num_s << "\n";
}
}
}
int main(const int argc, const char * const argv[]) {
noconsec(4);
}
Differences to note, this needs an integer power function to compute the limit. Converting an int to a string and then checking the string is more complex than constructing the string directly. I guess it could be useful if you have a list of integers already, but mostly I did it for fun.
I am using a Constructor to take an unsigned int as an argument, break it into digits and assign the appropriate true and false values to a vector object. But the problem is that, my poor logic assigns the values in reverse order as the last digit is separated first and so on. The Code I have written is:
vector<bool> _bits;
uBinary(unsigned int num){
int i = 1;
while(num > 0)
{
int d = num%10;
num /= 10;
_bits.resize(i++);
if(d == 1)
{
_bits[_bits.size() - 1] = true;
}
else if(d==0)
{
_bits[_bits.size() - 1] = false;
}
}
}
For example: if argument 10011 is passed to the function uBinary() the vector object will be assigned the values in this order 11001 or true,true,false,false,true which is reversed.
All I need to do here is that, I want to assign the values without reversing the order and I don't want to use another loop for this purpose.
One way is to start at the highest possible digit (unsigned int can only hold values up to 4294967295 on most platforms) and ignore leading zeros until the first actual digit is found:
for (uint32_t divisor = 1000000000; divisor != 0; divisor /= 10) {
uint32_t digit = num / divisor % 10;
if (digit == 0 && _bits.size() == 0 && divisor != 1)
continue; // ignore leading zeros
_bits.push_back(digit == 1);
}
But finding the digits in reverse and then simply reversing them is much simpler (and at least as efficient):
do {
_bits.push_back(num % 10 == 1);
num /= 10;
} while (num != 0);
std::reverse(_bits.begin(), _bits.end());
One way you can do the reversing with another loop or std::reverse is to use recursion. With recursion you can walk down the int until you hit the last digit and then you add the values to the vector as the calls return. That would look like
void uBinary(unsigned int num)
{
if (num == 0)
return;
uBinary(num / 10);
_bits.push_back(num % 10 ? true : false);
}
Which you can see working with
int main()
{
uBinary(10110);
for (auto e : _bits)
std::cout << e << " ";
}
Live Example
Do note that it is advisable not to use leading underscores in variables names. Some names are reserved for the implementation and if you use one it is undefined behavior. For a full explanation of underscores in names see: What are the rules about using an underscore in a C++ identifier?
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
How can I generate all combinations of n elements in groups of k?
For example, takig "abcd" in groups of 3, from [aaa] to [ddd]?
EDIT: What I've "accomplished" so far:
int main (int argc, char * argvc[]) {
int tComb = 0, array[7] = { 48 , 48 , 48 , 48 , 48 , 48 , 48 };
while ( tComb < atoi(argvc[1]) ) {
for (int i = 6 ; i>0 ; i--) {
if (array[i] == 58)
array[i] = 65;
if (array[i] == 91)
array[i] = 97;
if (array[i] == 123){
array[i] = 48;
array[i-1]++;
}
}
std::cout << "Current Combination: ";
std::cout << array;
std::cout << "\n";
tComb++;
array[6]++;
}
}
It'll try and generate backward the latest combination of alphanumeric characters, but it's hardcoded and won't work well.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
unsigned powu(unsigned base, unsigned exp){
unsigned result = 1;
while(exp > 0){
if(exp & 1)
result *= base;
base = base * base;
exp >>=1;
}
return result;
}
int main(int argc, char *argv[]){
if(argc != 3){
fprintf(stderr, "Usage : RepeatedPermutation abcd 3\n");
return -1;
}
char *list = argv[1];
unsigned gp_len = atoi(argv[2]);
unsigned list_len = strlen(list);
char *gp = calloc(gp_len+1, sizeof(char));
int total_n = powu(list_len, gp_len);
int i, j;
for(i=0;i<total_n;++i){
int n = i;
for(j=0;j<gp_len;++j){
gp[gp_len -j -1] = list[n % list_len];
n /= list_len;
}
printf("[%s]\n", gp);
}
free(gp);
return 0;
}
Am not sure but i think this is the answer to your question. If you want three groups than you should have 3 different loops.Its pretty simple when you see the output of this program.
You just need to increment the value of what ever you want to generate there possible combination.
The below Code will generate all possible combination of "abcd" in groups of 3, from [aaa] to [ddd].
int main()
{
char ch1;
char ch2;
char ch3;
for(ch1='a';ch1<='d';ch1++)
{
for(ch2='a';ch2<='d';ch2++)
{
for(ch3='a';ch3<='d';ch3++)
{
printf("%c %c %c\n",ch1,ch2,ch3);
}
printf("\n"); //just to have clean and understandable output
}
printf("\n\n\n"); //just to have clean and understandable output
}
return 0;
}
One method to generate all the combinations is to treat this as a number counting program.
The Counting Algorithm
Let's take the case of "digits": a, b, c, and d.
The first number is: aaaa. Much like decimal: 0000.
The second number is: aaab. Decimal: 0001.
The third number is: aaac, decimal: 0002.
The fourth number is: aaad, decimal: 0003.
This process is known as incrementing, e.g. adding a constant value each time.
Now comes the tricky part, incrementing the last digit. According to number counting rules, when the last digit is reached, the last digit is replaced by the first and the digit in the next column is replaced. This is equivalent of a decimal number incrementing from 09 to 10.
So in the example above, the next number in the sequence is: aaba.
This is known as carry, as you are carrying the overflow to the next digit.
Converting Algorithm to Code
Looks like there is a loop to count from first digit to last digit:
#define MAXIMUM_DIGIT_POSITIONS 4
const char FIRST_CHAR = 'a';
const char LAST_CHAR = 'd';
std::vector<char> number(MAXIMUM_DIGIT_POSITIONS); // Reserve some slots.
void Print_Number(const std::vector<char>& number);
int main(void)
{
// Initialize the number
int position = 0;
for (position = 0; position < MAXIMUM_DIGIT_POSITIONS; ++position)
{
number.push_back(FIRST_CHAR);
}
Print_Number(number);
// Loop: incrementing
position = MAXIMUM_DIGIT_POSITIONS - 1; // Because arrays are zero based indexing
while (number[position] < LAST_CHAR)
{
number[position] = number[position] + 1; // Increment to next digit, same position.
Print_Number(number);
}
// Pause before closing
std::cout << "Paused. Press ENTER to close.\n";
std::cin.ignore(100000, '\n');
return EXIT_SUCCESS;
}
void Print_Number(const std::vector<char>& number)
{
for (std::vector<char>::const_iter iter = number.begin();
iter != number.end();
++iter)
{
std::cout << *iter;
}
cout << "\n";
}
Handling Carry
The above program demonstrates counting in a single column. But how to handle the incrementing of the last digit?
Looks like we need to increment the digit in the previous position.
Looking ahead, the value in the previous column will be incremented, until it too, needs to be increment. Thus the carry will be propagate to the previous column. Looks like another loop:
// Loop: number of positions
int propagation_position = position - 1;
while (propagation_position >= 0)
{
while (number[position] < LAST_CHAR)
{
number[position] = number[position] + 1; // Increment to next digit, same position.
Print_Number(number);
}
// Propagate the carry.
while (propagation_position >= 0)
{
if (number[propagation_position] != LAST_CHAR)
{
++number[propagation_position];
number[propagation_position + 1] = FIRST_CHAR;
break;
}
--propagation_position;
}
position = 0;
}
The above new fragment has an outer while loop and a second inner while loop. The outer while loop controls the digit position. The second inner while loop handles the carry.
The whole program is designed so that you can adjust the number of digit positions and the number of digits in the sequence.
Summary
The brute force method for printing all the combinations is like counting numbers. The same principles apply: when the last digit is incremented, it is replaced by the first digit and the digit of the next column is incremented. This is repeated until all positions have been counted.
Walk through the above code with debugger or pen and paper to find any defects and understand the algorithm.
After you understand the algorithm, search your favorite C++ reference for "c++ combination permutation algorithm".
Is there any technique for finding the reverse when there are zeros at the end.
While following the algorithm of %10 technique the result is 52. And the 0's are missing.
I have got the reverse by just printing the reminders (with 0's). But I am not satisfied as I wish to display the answer as the value in a variable.
Kindly tell me is there any technique to store a value 005 to a variable and also to display 005 (please don't use String or Character or array).
Numbers are stored as binary 0 and 1 and so they always have leading 0's which are chopped off. e.g. a 64-bit integer has 64-bit bits, always and when it is printed these leading 0's are dropped.
You need to know how many leading zeros you want to keep and only use that many when you print. i.e. you can record how many leading zeros there were in a normal number without encoding it e.g. by adding a 1 at the start. i.e. 0052 is recorded as 10052 and you skip the first digit when you print.
If you need to store a single value you can do the following. I use do/while so that 0 becomes 10 and is printed as 0. The number 0 is the one place where not all leading zeros are dropped (as it would be empty otherwise)
This appears to be the solution you want and it should be basically the same in C or C++
static long reverse(long num) {
long rev = 1; // the 1 marks the start of the number.
do {
rev = rev * 10 + num % 10;
num /= 10;
} while(num != 0);
return rev;
}
// make the reversed number printable.
static String toStringReversed(long num) {
return Long.toString(num).substring(1);
}
long l = reverse(2500); // l = 10052
An alternative is to print the digits as you go and thus not need to store it.
e.g.
static void printReverse(long l) {
do {
System.out.print(l % 10);
l /= 10;
} while(l != 0);
}
or you can have the input record the number of digits.
static void printReverse(long l, int digits) {
for(int i = 0; i < digits; i++) {
System.out.print(l % 10);
l /= 10;
}
}
// prints leading zero backwards as well
printReverse(2500, 6); // original number is 002500
prints
005200
You cannot represent an integer with leading zeros as a single integer variable, that information is simply not part of the way bits are allocated in an integer. You must use something larger, i.e. a string or an array of individual (small integer) digits.
You can't store them in a simple integer variable because in binary format
00101 is same as 000101 which is same as 101 which only results into 5. The convertion between a decimal number and binary numbers don't consider leading zeroes so it is not possible to store leading zeroes with the same integer variable.
You can print it but you can't store the leading zeroes unless you use array of ints...
int num = 500;
while(num > 0)
{
System.out.print(num%10);
num = num/10;
}
Alternatively you can store the count of leading zeroes as a separate entity and combine them when ever you need to use. As shown below.
int num = 12030;
boolean leading=true;
int leadingCounter = 0;
int rev = 0;
while(num > 0)
{
int r = num%10;
if(r == 0 && leading == true)
leadingCounter++;
else
leading = false;
rev = rev*10 + r;
num = num/10;
}
for(int i = 1; i <= leadingCounter ; i++)
System.out.print("0");
System.out.println(rev);
I think the accepted answer is a good one, in that it both refutes the parts of the question that are wrong and also offers a solution that will work. However, the code there is all Java, and it doesn't expose the prettiest API. Here's a C++ version that based on the code from the accepted answer.
(Ha ha for all my talk, my answer didn't reverse the string! Best day ever!)
After going back to school and getting a degree, I came up with this answer: it has the makes the somewhat dubious claim of "not using strings" or converting any values to string. Can't avoid characters, of course, since we are printing the value in the end.
#include <ostream>
#include <iostream>
class ReverseLong {
public:
ReverseLong(long value) {
long num = value;
bool leading = true;
this->value = 0;
this->leading_zeros = 0;
while (num != 0) {
int digit = num % 10;
num = num / 10;
if (leading && digit == 0) {
this->leading_zeros += 1;
} else {
this->value = this->value * 10 + digit;
leading = false;
}
}
};
friend std::ostream & operator<<(std::ostream& out, ReverseLong const & r);
private:
long value;
int leading_zeros;
};
std::ostream & operator<<(std::ostream& out, ReverseLong const & r) {
for (int i =0; i < r.leading_zeros; i++) {
out << 0;
}
out << r.value;
return out;
};
int main () {
ReverseLong f = ReverseLong(2500); // also works with numbers like "0"!
std::cout << f << std::endl; / prints 0052
};
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.