Related
I have two programs, compiled with g++ and executed on linux. Program 1 creates a 2D array and then measures how long it takes to access all of its elements 100000 times:
#include <time.h>
#include <iostream>
int main()
{
clock_t time;
int i, y, x;
int matrix[9][9]{{ 0, 1, 2, 3, 4, 5, 6, 7, 8},
{ 9, 10, 11, 12, 13, 14, 15, 16, 17},
{18, 19, 20, 21, 22, 23, 24, 25, 26},
{27, 28, 29, 30, 31, 32, 33, 34, 35},
{36, 37, 38, 39, 40, 41, 42, 43, 44},
{45, 46, 47, 48, 49, 50, 51, 52, 53},
{54, 55, 56, 57, 58, 59, 60, 61, 62},
{63, 64, 65, 66, 67, 68, 69, 70, 71},
{72, 73, 74, 75, 76, 77, 78, 79, 80}};
time = clock();
for (i = 0; i < 100000; i++)
{
for (x = 0; x < 9; x++)
{
for (y = 0; y < 9; y++)
{
matrix[x][y];
}
}
}
time = clock() - time;
std::cout << "Clicks: " << time << std::endl;
std::cout << "Time taken: " << (double) time / CLOCKS_PER_SEC << "s" << std::endl;
}
Program 2 creates a 1D array and also measures how long it takes to access all of its elements 100000 times:
#include <time.h>
#include <iostream>
int main()
{
clock_t time;
int i, j;
int vector[81] = { 0, 1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44,
45, 46, 47, 48, 49, 50, 51, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 62,
63, 64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79, 80};
time = clock();
for (i = 0; i < 100000; i++)
{
for (j = 0; j < 81; j++)
{
vector[j];
}
}
time = clock() - time;
std::cout << "Clicks: " << time << std::endl;
std::cout << "Time taken: " << (double) time / CLOCKS_PER_SEC << "s" << std::endl;
}
After executing program 1 my output is:
Clicks: 8106
Time taken: 0.008106s
After executing program 2 my output is:
Clicks: 15958
Time taken: 0.015958s
It is my understanding that a 1D array is stored in a continuous block of memory. Likewise the rows of a static 2D array are stored in contiguous blocks of memory. Conversely the rows of a dynamic 2d array might not be stored in contiguous blocks of memory. If this is true then program 2 should be at least similar in speed to program 1 therefore my question is why would program 1 be remarkably faster than program 2?
Here is what I found:
If you actually make use of the value then the run time is almost the same, for example, change matrix[x][y]; to matrix[x][y] += 1; and vector[j]; to vector[j] += 1;
> Clicks: 28519
> Time taken: 0.028519s
and
> Clicks: 29941
> Time taken: 0.029941s
Without the above changes, optimize while compiling, g++ -O3 <filename>.cpp, this results in same time, got the same following output for both programs:
$./a.out
> Clicks: 2
> Time taken: 2e-06s
So, what you are pointing out is compiler optimizations.
The loops are likely to be removed (kind of optimising) by compiler, because
You actually did nothing in loops.
The matrix can be treated as a const array.
program 1 is faster than program 2. ( :< )
To see whether the deletion happens to your code during compiling, you can increase the most outer loop by 100 times, and see whether the time needed for execution is increased significantly (not necessarily by exact 100 times).
If true, you can prevent this kind of optimising by doing some actual works in loop (calculate the sum, and don't forget printing it afterwards) and introduce some "unpredictable" changes to your matrix, for example:
srand(10);
for (int i=0; i<9; ++i) {
matrix[i][i] = rand()%100;
}
And further, compiler may conduct some other optimising to your code, for example, expand your loops, even the address of the element you are visiting (they are no longer calculated at run time), you can prevent this by making the executing times of loops "unpredictable" :
#include <chrono>
#include <iostream>
#include <cstdlib>
int array[100];
int array2[10][10];
int64_t Sum1D(int len) {
int64_t sum = 0;
for (int i=0; i<100000; ++i) {
for (int j=0; j<len; ++j) {
sum += array[j];
}
}
return sum;
}
int64_t Sum2D(int len1, int len2) {
int64_t sum = 0;
for (int i=0; i<100000; ++i) {
for (int j=0; j<len1; ++j) {
for (int k=0; k<len2; ++k)
sum += array2[j][k];
}
}
return sum;
}
int main()
{
for (int i=0; i<100; ++i) {
array[i] = rand();
array2[i%10][i/10] = rand();
}
auto time = std::chrono::steady_clock::now();
//int64_t sum = Sum1D(100);
int64_t sum = Sum2D(10,10);
auto duration = std::chrono::steady_clock::now()-time;
std::cout << sum << "!" << duration.count() << std::endl;
return 0;
}
which finally makes program1 slower than program2. ( :> )
Please help me use C++ to parse an array and only display numbers that are unique. I have written a program which answers most of the question below.
Question:
Use a one-demensional 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 and store it in the array only if it isn't 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 number are different. Use the smallest possible array to solve this problem.
What I've done:
My program creates a 20 item array. Prompts user for data, validates it and displays it. I have tried several way to only display unique data, however I have not accomplished what the question asks.
Sample User Input:
11, 12, 12, 12, 13, 14, 15, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27
My Program Output:
{ 11, 12, 12, 12, 13, 14, 15, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 }
Correct Program Output:
{ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 }
Any advice where to go with this. See below for code. Thank you for your help!
#include <iostream>
#include <array> // needed for c++11 arrays
using namespace std;
int main()
{
const int arraySize = 20; // limit array length to 20
array <int, arraySize userArray> = {};
//Populate array with user input and validate it to be between 10 and 100
for (int i = 0; i < userArray.size(); i++)
{
cout << "Enter a number between 10 and 100" << endl;
cin >> userArray[i]; // get user input assign it to proper array subscript
while(userArray[i] > 100 || userArray[i] < 10)//validate user input to be between 10 and 100
{
cout << "Number needs to be between 10 and 100. Enter a new number" << endl;
cin >> userArray[i]; //reassign the proper array subscript if needed
}
}
cout << endl;
//display the information to look like an array
//result looks like [ v, w, x, y, z ]
cout << "[ ";
//display array values
for (int i = 0; i < userArray.size() - 1; i++)
{
cout << userArray[i] << ", ";
}
//properly display last array item
cout << userArray[(userArray.size() - 1)] << " ]" << endl;
return 0; }
If you can use std::vector, then you can use following solution.
template <typename Type>
std::vector<Type> unique_entries (std::vector<Type> vec) {
for (auto iter = vec.begin (); iter != vec.end (); ++iter) {
auto f = std::find_if (iter+1, vec.end (), [&] (const Type& val) {
return *iter == val; // (X)
});
if (f != vec.end ()) {
vec.erase (std::remove (iter+1, vec.end (), *iter), vec.end ());
}
}
return vec;
}
template <typename T>
void show (std::vector<T> vec) {
for (const auto& v : vec) {
std::cout << v << " ";
}
std::cout << std::endl;
}
And example would be like that:
std::vector<int> vec {11, 12, 12, 12, 13, 14, 15, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27};
std::vector<short> vec2 {1, 1, 1, 2, 3, 2, 1, 2, 1, 2, 3, 2, 1, 2, 3, 2, 1, 2, 10};
std::vector<std::string> vec3 {"a", "a", "a", "aa", "b", "b", "bb", "c"};
show (vec);
show (unique_entries (vec));
show (vec2);
show (unique_entries (vec2));
show (vec3);
show (unique_entries (vec3));
And the output:
11 12 12 12 13 14 15 15 16 17 18 19 20 21 22 23 24 25 26 27
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
1 1 1 2 3 2 1 2 1 2 3 2 1 2 3 2 1 2 10
1 2 3 10
a a a aa b b bb c
a aa b bb c
Look at the line (X), basically you can use this unique_entries for all types which offer operator==, but you have to keep in mind that this will probably fail if you use this function for floating point types.
Hope this is what you are looking for........... Basically I use an another array to store the elements already entered by the user. So when the user enters a number it checks whether it is already in the array of 'entered elements' or not.
#include<iostream>
#define MAX 20
using namespace std;
int main()
{
int list[MAX],visitedElements[MAX];
int noElements,element,currentIndex;
bool flag=false;
cout<<"Enter total no. of elements(MAX=20):"<<endl;
cin>>noElements;
for(int i=0; i<noElements; i++)
{
visitedElements[i] = -1;
}
for(int i=0;i<noElements;i++)
{
currentIndex=i;
cout<<"Enter Element:"<<endl;
cin>>element;
for(i=0;i<currentIndex;i++)
{
if(visitedElements[i] == element)
{
flag==true;
break;
}
}
if(flag == false)
{
list[i]=element;
visitedElements[i] = element;
}
flag = false;
}
cout<<"Elements in list are"<<endl;
for(int i=0 ; i<noElements ;i++)
cout<<list[i]<<endl;
return 0;
}
#include <iostream>
using namespace std;
int main(){
int tab[10];
int i=0,j;
int number=0;
int counter=1;
bool flag=true;
int tries=0;
while(tries<10){
do{
cin>>number;
tries++;
if((number>100)||(number<10)){
cout<<"Wrong number, has to be between 10 and 100"<<endl;
}
}
while((number>100)||(number<10));
flag=true;
if(i==0){
tab[i]=number;
}
else{
for(j=0; j<counter; j++){
if(tab[j]==number){
flag=false;
i--;
break;
}
}
}
if(flag==true){
tab[i]=number;
counter++;
}
i++;
}
for(i=0; i<counter-1; i++){
cout<<tab[i]<<", ";
}
}
I kinda meesed it up probably. I'm new to programing but this is my solution.
So. You said it has to take 20 digits, mine takes 10, after 10 inputs it will list the array. So if my input is "10, 10, 10, 12, 13, 15, 15, 18, 22, 22"
the output is: "10, 12, 13, 15, 18, 22"
I could probably erase half of the code but like i said I'm a beginner and i was writing it in a hurry.
EDIT: Ups, small mistake in the array declaration. I was testing it for 5 elements and forgot to make a bigger array.
The question asked to use one array, so I would loop over the numbers already in the array after reading in each number and check for duplicates. It would look something like this:
#include <iostream>
constexpr int ARRAY_SIZE = 20;
int main()
{
int userArray[ARRAY_SIZE], validNumbers = 0;
for(int i = 0; i < ARRAY_SIZE; i++)
{
int num;
bool isGood = true;
std::cin >> num;
//code to check if input is in range here
for(int j = 0; j < validNumbers; j++)
{
if(userArray[j] == num)
{
isGood = false;
break;
}
}
if(isGood)
{
userArray[validNumbers] = num;
validNumbers++;
}
}
//userArray now contains all unique numbers in the order that they were entered
for(int i = 0; i < validNumbers; i++)
{
std::cout << userArray[i];
if(i < validNumbers - 1)
{
std::cout << ' ';
}
}
std::cout << '\n';
}
inside of your for loop, instead of makign the cin go directly into the array, add another int variable and set it to equal the input
cin >> variable
then make a for loop that iterates through your current array to make sure its not a duplicate; use the line below as your for loop
for(int j = 0; j < i; j++)
if the number is already in the array, just continue. Else, add it in.
Also, instead of using a for loop in the beginning, I would use a while loop with
while(i < arraysize)
Then deincrement array size every time you see a duplicate and only increment i when you add an element
#include <iostream>
using namespace std;
int f[33] = {3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54,
57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99};
int b[20] = {5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85,
90, 95, 100};
int main (){
for (int x=100; x >= 1; x-- ){
if (x == f){
cout << "fizz" << endl;
} else {
if(x ==b){
cout << "buzz" << endl;
}else{
if(x==f & x==b){
cout << "fizzbuzz" << endl;
}else{
cout << x << endl;
}
}
}
}
}
I am still learning, so this may not be the best way to solve this problem. I just want to know wahts wrong with this code. Thanks
As others have pointed out, you've precomputed your multiples of 3 and 5 in arrays, but then doing direct comparisons between an int and these arrays - this will always fail (ISO C++ forbids comparison between pointer and integer). If you persist with precomputed arrays, you could use std::find or std::any_of to check if either array contains the current number.
However, you would likely gain more credibility if you also included knowledge of how to determine whether a number is divisible by 3 or 5 in your code, rather than pre-populate the multiples of 3 and 5. This is done with the modulo operator, %. Any number % x will return zero if it is naturally divisible by x.
There's another logical flaw in your code. In order to be divisible by both 3 and 5 (i.e. 15, since 3 and 5 are both primes), you will need to change the order of precedence of your checks such that the check for 15 is done first, otherwise you will never reach the fizbuzz branch (since the 3 and 5 branches would also be hit, instead).
Fizzbuzz is usually done incrementally from 1 to 100, but here's your original 'count down' fizzbuzz rewritten:
for (int x=100; x >= 1; x--){
bool isDiv3 = x % 3 == 0;
bool isDiv5 = x % 5 == 0;
if (isDiv3 && isDiv5){
cout << "fizzbuzz" << endl;
} else if (isDiv5) {
cout << "buzz" << endl;
} else if (isDiv3) {
cout << "fizz" << endl;
} else {
cout << x << endl;
}
}
It's also possible to eliminate one of the if branches, by running the printed fizz and buzz into eachother on a factor of 15, although this isn't necessarily as easy to read:
for (int x=100; x >= 1; x--){
bool isDiv3 = x % 3 == 0;
bool isDiv5 = x % 5 == 0;
if (isDiv3) {
cout << "fizz";
}
if (isDiv5) {
cout << "buzz";
}
if (!isDiv3 && !isDiv5)
cout << x;
}
cout << endl;
}
The error with your code is you can't compare integer and pointer , What you are trying to do is to find if x is in f or if x is in b or both .
But why do yo have to do that , you know the properties governing the sets f and b which are simply "%3==0" , "%5==0" .So you can do something pretty easy like
#include <iostream>
using namespace std;
int main (){
for (int x=100; x >= 1; x-- ){
if(x%3==0) cout<<"Fizz";
if(x%5==0) cout<<"Buzz";
else if(x%3 !=0) cout <<x;
cout<<endl;
}
}
x is an int, while f is an array. You cannot compare them this way:
if (x == f){
If your technique is to check whether x is in the array f, I suggest, you have to check for each value in f, like
if(x == f[i++]){
where i is an index used to traverse the f array.
Also, you might consider evaluating the condition of x in both f and b before their individual evaluation.
x is an integer whereas f and b are arrays of integers. If you want to test membership of the content of your variable x in the arrays f and b you probably want to define your own function to check it.
int is_in(int item, int[] list){
for(i = 0; i < sizeof(list) / sizeof(struct list); i++){
if(item==list[i]) return 1;
}
return 0;
}
And then change your conditions to if(is_in(x,b))
I'm currently coding a small heapify code that repeated runs bubble down but everytime it seems like nothing's happening. Not sure what's wrong here maybe I'm missing something?
template <class T>
void PriorityQueue<T>::heapify (int* arrs, int size){
int i = (size-1)/2;
while (i >= 0){
bubbleDown(arrs, i, (size));
i--;
}
}
template <class T>
void PriorityQueue<T>::bubbleDown (int* arrs, int i, int size)
{
//Each level node's are indexed at 2^(level) - 2 to 2^(level+2) - 2
//Children of these node's levels are indexed at 2i+1 and 2i+2
//The parent of node i, is indexed at (i-1)/2
int leftChildren = (2*i)+1;
int rightChildren = (2*i)+2;
int largest = i;
if (rightChildren < size)
{
if (arrs[leftChildren] < arrs[rightChildren]){
largest = rightChildren;
}
else{
largest = leftChildren;
}
if (arrs[i] > arrs[largest]){
largest = i;
}
}
else if (leftChildren < size)
{
if (arrs[i] < arrs[leftChildren]){
largest = leftChildren;
}
}
if (arrs[i] < arrs[largest])
{
int temp = arrs[i];
arrs[i] = arr[largest];
arrs[largest] = temp;
}
}
I'm calling it like this:
PriorityQueue<int> test;
int arr[] = {89, 29, 36, 48, 94, 13, 27, 70, 76, 37, 42, 58};
test.heapify(arr, 12);
for (int i = 0; i < 12; i++){
cout << arr[i] << endl;
}
Console prints out it the same way the array has been initialized.
UPDATED:
Still getting weird results
[89, -842150451, 36, 29, 94, 0, 27, 70, 48, 37, 42, 13]
The results I should be getting is
[94, 76, 89, 70, 48, 58, 13, 27, 36, 29, 37, 42, 23]
Basic typo error. Should really use more meaningful names
I'm working on a random exercise from my C++ book because I'm "re-learning" C++, but I'm getting some odd output from a program I wrote. I'm fairly certain there are no errors in the logic of the program, but where the sum of the elements in the "scoreCount" array should be 26, the same as the length of the scores array, it is only 20. I can't figure out what happened to the other 6 elements. The description of the exercise is in the code below. Can anyone spot what I might have done wrong?
/* Exercise 09 - 04
Write a program that reads a file consisting of students' test scores
in the range 0-200. It should then determine the number of students having
scores in each of the following ranges: 0-24, 25-49, 50-74, 75-99,
100-124, 125-149, 150-174, and 175-200. Output the score ranges and the
number of students. (Run your program with the following input data:
76, 89, 150, 135, 200, 76, 12, 100, 150, 28, 178, 189, 167, 200, 175,
150, 87, 99, 129, 149, 176, 200, 87, 35, 157, 189.) */
#include <cstdio>
int main(int argc, char ** argv) {
int scores[] = {76, 89, 150, 135, 200, 76, 12, 100, 150, 28, 178, 189,
167, 200, 175, 150, 87, 99, 129, 149, 176, 200, 87,
35, 157, 189};
int size = sizeof(scores) / sizeof(scores[0]);
int scoreCount[] = {0, 0, 0, 0, 0, 0, 0, 0};
printf("Number of Scores: %d\n\n", size);
for(int i = 0; i < size; i++) {
scoreCount[((int)(scores[i]/25))] += 1;
printf("%d - scoreCount Index: %d\n", i, ((int)(scores[i]/25)));
}
printf("\n");
int low = 0;
int high = 24;
size = sizeof(scoreCount) / sizeof(scoreCount[0]);
for(int i = 0; i < size; i++) {
printf("Range %d-%d: %d\n", low, high, scoreCount[i]);
low += 25;
high += 25;
if(high == 199) high = 200;
}
int sum = 0;
for(int i = 0; i < size; i++) {
sum += scoreCount[i];
}
if(sum < 26) printf("\n%d: Wrong number of scores counted.\n", sum);
else printf("\nAll students accounted for.\n");
return 0;
}
Thanks for any help!
Here's proper C++ style. I know the question has already been answered, but here's a bonus:
See it live on http://ideone.com/rBTi42
#include <vector>
#include <map>
#include <iostream>
int main(int argc, char ** argv)
{
const std::vector<int> scores = {76, 89, 150, 135, 200, 76, 12, 100, 150, 28, 178, 189,
167, 200, 175, 150, 87, 99, 129, 149, 176, 200, 87,
35, 157, 189
};
std::map<int, int> scoreCount;
std::cout << "Number of Scores: " << scores.size() << "\n";
for(auto score : scores)
{
scoreCount[score/25] ++;
std::cout << score << " - scoreCount Index: " << score/25 << "\n";
}
for(auto const& slot : scoreCount)
{
auto low = slot.first*25;
auto high = low+24;
std::cout << "Range " << low << "-" << high << ": " << slot.second << "\n";
}
int sum = 0;
for(auto const& slot : scoreCount)
sum += slot.second;
if(sum < 26)
printf("\n%d: Wrong number of scores counted.\n", sum);
else
printf("\nAll students accounted for.\n");
}
scoreCount[((int)(scores[i]/25))] += 1;
This would produce 8 if score[i] is 200. And currently your code does not handle this.
200 / 25 = 8 and
scoreCount[8] does not exist.
You are generating an index out of bounds for scoreCount here:
scoreCount[((int)(scores[i]/25))] += 1;
The valid indexes for scoreCount are from 0 to 7 but with your current scores you will generate indexes up to 8. A solution would be to extend scoreCount by one element or to check if the index is 8 and map it to index 7 since it seems like the problem limits your ranges.
The number of elements should be 9 rather than 8 in the scoreCount array.
As 200/25 will be evaluated to 8 and it results in index out of bound
EDIT:
As suggested by Andrew_CS, the element having value as 200 shoud be added to the last group itself.
scoreCount[(scores[i]/25)==8?7:(scores[i]/25)] += 1;
I ran the code on my machine.
I got 23 out of 26.
The reason for this is that there are 3 values of 200.
When the value is 200 the it will be under 8.
You need to increase the number of elements in the scoreCount array because 200/25 gives 8 and scoreCount[8] does not exists .
200/25 = 8 is out of bounds for scoreCount - only has indexes 0 - 7.
I personally wouldn't increase the number of elements in scoreCount since there are only 8 groups of valid scores. I would instead check for this one case that produces 8 as an index.
for(int i = 0; i < size; i++){
int theIndex = (scores[i]/25);
if(theIndex == 8)
scoreCount[7] += 1;
else
scoreCount[theIndex] += 1;
printf("%d - scoreCount Index: %d\n", i, theIndex;
}