My problem is that I don't understand nested loops well enough to answer this problem. I'm supposed to right-align a stack that I've made on a left alignment using nested for loops, but I can't quite figure out the conditions on the two inner ones.
Correct answer:
Height = 8
.......#
......##
.....###
....####
...#####
..######
.#######
########
My answer:
Height = 8
.......#
.......#......#
.......#......#.....#
.......#......#.....#....#
.......#......#.....#....#...#
.......#......#.....#....#...#..#
.......#......#.....#....#...#..#.#
.......#......#.....#....#...#..#.##
I've played around with it, took it seriously and nothing. I did (k = 7, k > j, k--), (k = 0, k < n-1, k++), k < j+7, I drew tables and i know that the height is pretty much the same as the value of the spaces but inverted on each line. I also know that the value of the hashes and the spaces should be equal to the height input by user.
It's supposed to take in a value from user, but I've worked on it on a separate file with the value n being the height to simplify and work on it without the rest of the program.
#include <stdio.h>
int main(void) {
int n = 8;
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
for(int k = 7; k > j; k--) {
printf(".");
}
printf("#");
}
printf("\n");
}
}
It's actually pretty simple. Write a table with each line and how many spaces and '#' you need to print:
n == 8
| output | line | num_spaces | num_signs |
| -------- | ---- | ---------- | --------- |
| .......# | 1 | 7 | 1 |
| ......## | 2 | 6 | 2 |
| .....### | 3 | 5 | 3 |
| ....#### | 4 | 4 | 4 |
| ...##### | 5 | 3 | 5 |
| ..###### | 6 | 2 | 6 |
| .####### | 7 | 1 | 7 |
| ######## | 8 | 0 | 8 |
For line you can start from 0 or from 1 or from n and go backwards. Pick something that is the easiest. You will see that starting from 1 is the simplest in your example.
Now for each line we need to determine how many num_spaces and num_signs we print. They should depend on line and on n.
For num_spaces it's n - line and for num_signs it's line
So the code should look like this:
// for each line
for (int line = 1; line <= n; ++line)
{
// print n - line spaces
// print line # characters
// print \n
}
With loops the code will look like this:
// for each line
for (int line = 1; line <= n; ++line)
{
// print n - line spaces
for (int i = 0; i < n -line; ++i)
std::cout << ' ';
// print line # characters
for (int i = 0; i < line; ++i)
std::cout << '#';
std::cout << '\n';
}
std::cout.flush();
But that's actually not recommended. You can get rid of those inner loops. One good and easy way is to use strings:
// for each line
for (int line = 1; line <= n; ++line)
{
// print n - line spaces
std::cout << std::string(n - line, ' ');
// print line # characters
std::cout << std::string(line, '#');
std::cout << '\n';
}
std::cout.flush();
And you can go even one step further:
// for each line
for (int line = 1; line <= n; ++line)
{
// print n - line spaces and line # characters
std::cout << std::string(n - line, ' ') << std::string(line, '#') << '\n';
}
std::cout.flush();
Related
Before you read ahead or try to help, this question is regarding my homework so the requirements to this question will be very specific.
I am writing a code that has 2 functions. The first function creates or initializes a 5*5 matrix for an array with numbers from 1 - 25 in random positions.
The second function prints it. However, I am required to use a seed value of 233 in the srand() function which I am unsure of how to use, despite constantly searching for it online. Anyway, the printout should look something like this:
--------------------------
| 4 | 5 | 10 | 21 | 22 |
--------------------------
| 1| 11 | 3 | 19 | 20 |
--------------------------
| 24 | 18 | 16 | 14 | 9|
--------------------------
| 17 | 7 | 23 | 15 | 6|
--------------------------
| 2 | 12 | 13 | 25 | 8 |
--------------------------
The first and most easily explainable issue that I have is that all my display function is doing is printing all the values in a straight line and not in the format that I want it to be.
The other part is that when I use into srand(time(233)), it gives me an error and I'm not sure why even though it is required for my assignment.
The second issue is that some of the numbers start reoccurring in the matrix and they are not supposed to, is there a way to make sure there are no duplicates in the matrix?
Although this is in the C++ language, what I have learned is the C style syntax (no std:: kinds of code or stuff like that). So far I have learned basic arrays, loops, and functions.
#include <iostream>
#include <ctime>
using namespace std;
const int ROW_SIZE = 5;
const int COLUMN_SIZE = 5;
void createBoard(int matrix[][5]);
void display(int matrix[][5]);
int main()
{
srand(time(233)); //the seed value error
int matrix[5][5];
createBoard(matrix);
display(matrix);
}
void createBoard(int matrix[][5])
{
for (int i = 0; i < ROW_SIZE; i++)
{
for (int j = 0; j < COLUMN_SIZE; j++)
{
matrix[i][j] = 1 + rand() % 25;
}
}
}
void display(int matrix[][5])
{
cout << "--------------------------" << endl;
for (int i = 0; i < ROW_SIZE; i++)
{
for (int j = 0; j < COLUMN_SIZE; j++)
{
cout << "| " << matrix[i][j];
}
}
cout << "--------------------------" << endl;
}
Assuming the function time is a requirement, it receives the address of a time_t variable so you need something like:
time_t t = 233;
srand(time(&t));
Though the function will just replace the value of t, so, there is that.
If not, as suggested by molbdnilo, you can use srand(233)(which is probably what is being requested), but know that this will generate the same repeated sequence.
As for the repeated values in the array, a possible strategy is to go back in the array from the generated index and as soon as you find a repetition, stop, and generate a new one, repeat until no equal number is found, though you have better methods and algorithms.
Since you are not to use std:: kinds of code or stuff , as you so eloquently put it, here is a C post that may help:
Unique random number generation in an integer array
The array print formatting issue is just a matter of adjusting and printing the lines in the correct position, to keep a consistent spacing you should use <iomanip> library, setw():
#include <iomanip>
void display(int matrix[][5])
{
cout << " +------------------------+" << endl;
for (int i = 0; i < ROW_SIZE; i++)
{
for (int j = 0; j < COLUMN_SIZE; j++)
{
cout << " | " << setw(2) << matrix[i][j]; // set spacing
}
puts(" |\n +------------------------+");
}
}
Output:
+------------------------+
| 16 | 25 | 23 | 1 | 24 |
+------------------------+
| 11 | 4 | 23 | 7 | 22 |
+------------------------+
| 21 | 23 | 12 | 6 | 15 |
+------------------------+
| 18 | 10 | 8 | 22 | 11 |
+------------------------+
| 23 | 18 | 22 | 18 | 16 |
+------------------------+
Footnote:
There are much better ways to do this, not using rand, if not for your homework, you should take a look for future memory:
https://en.cppreference.com/w/cpp/numeric/random
You can use a Int Array with 26 element(cause its final index is 25)
then set all of the element to 0
use a while loop to try to generate a X number,if it hasnt been used(Check[X] =0), let matrix[i][j] = X and let Check[X] = 1, if it has been used (Check[X]=1) then break the while loop)
And with the seed 233, I dont know why its not run but when i replace it with 'NULL', its run pretty good :D
#include <iostream>
#include <ctime>
using namespace std;
const int ROW_SIZE = 5;
const int COLUMN_SIZE = 5;
int check[26]={0};
void createBoard(int matrix[][5]);
void display(int matrix[][5]);
int main(){
srand(time(NULL)); //the seed value error
int matrix [5][5];
createBoard(matrix);
display(matrix);
}
void createBoard(int matrix[][5])
{
for (int i = 0; i < ROW_SIZE; i++)
{
for(int j = 0; j < COLUMN_SIZE; j++)
{
while (true)
{
//random number X;
int x = 1 + rand() % 25;
if(!check[x]) // If X not used;
{
matrix[i][j] = x;//add to table;
check[x]=1; //Mark that X used;
break;
}
}
}
}
}
void display(int matrix[][5]){
cout<<"--------------------------"<< endl;
for(int i = 0; i < ROW_SIZE; i++){
for(int j = 0; j < COLUMN_SIZE; j++){
cout<<"| "<< matrix[i][j];
}
}
cout<<"--------------------------"<< endl;
}
For your display function, you just have to add line endings (std::endl) at the right place:
void display(int matrix[][5]){
cout<<"--------------------------"<< endl;
for(int i = 0; i < ROW_SIZE; i++){
for(int j = 0; j < COLUMN_SIZE; j++){
cout<<"| "<< matrix[i][j] << " ";
}
cout <<"|" << endl;
}
cout<<"--------------------------"<< endl;
}
For the creation, if you use C++, you can use shuffle: http://www.cplusplus.com/reference/algorithm/shuffle/
void createBoard(int matrix[][5]){
// Create an array { 1, 2 ... 25}
std::array<int,ROW_SIZE * COLUMN_SIZE> tmp;
for (int i = 0; i < ROW_SIZE * COLUMN_SIZE; i++)
{
tmp[i] = i + 1;
}
// define your seed
unsigned seed = 233;
// shuffle your array using that seed
shuffle (tmp.begin(), tmp.end(), std::default_random_engine(seed));
// store the elements in your matrix
for (int i = 0; i < ROW_SIZE; i++){
for(int j = 0; j < COLUMN_SIZE; j++){
matrix[i][j] = tmp[i * COLUMN_SIZE + j];
}
}
}
Note that if you're using C++, you can use STL containers to store your 5x5 board (like array, vector etc...). They come with very handy features (like shuffle).
Note also that the seed is just a number to initialize your random generator. Setting it to 233, makes sure that two different executions of your program will always generate the same sequence of number (that's how you understand that in computer world, it is not really random, but pseudo-random).
I am trying to do the permutations of 8 characters, but I am only interested in output which contains maximum of 3 same characters. So any output which contains any character in more than 3 occurrences should be skipped.
Character set: a, b, c, d, e, f, g, G
Example:
Not interested in output e.g. aaaaaaab , aabcdeaa, acdGGGGg, GGGGbbbb ...
Interested in output e.g. abcdefgG, aaabcdef, abacadGf ...
I tried to write a code where I evaluate in each cycle number of occurrence of each character and skip (break/continue) to next loop if more than 3 same character occurrences are present.
Here is problem with my code which I can't solve. The program do only permutations starting with character 'a' and stops at aaabgGGG and I can't manage it to continue with iterations starting with b, c, d, e etc...
I want to achieve filtering during cycle to avoid unneeded cycles to occur => achieve as fast processing as possible.
When commenting the the ">3 occurrences filter" code between ##### lines, all permutations are processed correctly.
My code:
#include <iostream>
// C++ program to print all possible strings of length k
using namespace std;
int procbreak = 0;
// The main recursive method to print all possible strings of length k
void printAllKLengthRec(char set[], int setn[], string prefix, int n, int k)
{
// Base case: k is 0, print prefix
//cout << "03. In printAllKLengthRec function" << endl;
if (k == 0)
{
//print table with characters and their count
cout << (prefix) << endl;
cout << " | ";
for (size_t b = 0; b < 8; b++)
{
cout << set[b] << " | ";
}
cout << endl;
cout << " | ";
for (size_t c = 0; c < 8; c++)
{
cout << setn[c] << " | ";
}
cout << endl;
return;
}
// One by one add all characters from set and recursively call for k equals to k-1
for (int i = 0; i < n; i++)
{
cout << "04. In for loop where one by one all chars are added. K = " << k << "; I = " << i << "; N = " << n << endl;
string newPrefix;
//update characters count table
setn[i] += 1;
if (i > 0)
{
setn[i - 1] -= 1;
}
else
{
if (setn[7] > 0)
{
setn[7] -= 1;
}
}
//#############################################################################################
//check if there is any character in a table with count more than 3, then break current cycle
for (size_t d = 0; d < 8; d++)
{
if (setn[d] > 3)
{
procbreak = 1;
break; // enough to find one char with >3, then we don't need to continue and break operation
}
}
if (procbreak == 1)
{
procbreak = 0; // reset procbreak
continue; // skip to next cycle
}
//#############################################################################################
// Next character of input added
newPrefix = prefix + set[i];
// k is decreased, because we have added a new character
printAllKLengthRec(set, setn, newPrefix, n, k - 1);
}
}
void printAllKLength(char set[],int setn[], int k, int n)
{
cout << "02. In printAllKLength function" << endl;
printAllKLengthRec(set, setn, "", n, k);
}
// Main code
int main()
{
cout << "Start" << endl;
char set1[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'G' };
int setn[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
int k = 8; // string length
printAllKLength(set1, setn, k, 8); // 8 = n => number of characters in the set1
}
Where is main mistake in my code logic?
The solution to your problem is pretty simple.
What you want to do is to take your character set: a, b, c, d, e, f, g, G
and construct a "fake" sequence with each character triplicated.
std::string perm{"GGGaaabbbcccdddeeefffggg"};
The key insight here is that you can compute your permutations as usual, e.g., using std::next_permutation. You just need to take the first 8 elements from that permutation to have the result that you need.
[Edit: In order to avoid computing permutations for the rightmost 16 values, since these will always yield duplicates for the leftmost 8 values, after each step set the rightmost 16 values to the last permutation. The next call to std::next_permutation will permute the first 8 values.]
[Edit2: Working example
#include <algorithm>
#include <chrono>
#include <iostream>
int main()
{
// Initial state
std::string perm{"GGGaaabbbcccdddeeefffggg"};
using clock = std::chrono::steady_clock;
auto start = clock::now();
do
{
// Output permutation
std::cout << perm.substr(0, 8) << "\n";
// Now reverse the last 16 values, so that the call to the next_permutation would change the top 8
std::reverse(std::next(perm.begin(), 8), perm.end());
} while (std::next_permutation(perm.begin(), perm.end()));
std::clog << "Elapsed: " << std::chrono::duration_cast<std::chrono::milliseconds>(clock::now() - start).count() << "ms\n";
return 0;
}
]
I have found where the problem with filtering was...
The whole permutation is done by running cycles within cycles, in other words the function is calling itself.
When passing from right hand character (right most) to the left hand character (one step to the left), function is doing empty 'k' cycles (1 empty 'k' cycle when going from position 8 to 7 .... up to 7 empty 'k' cycles when going from position 2 to 1).
<-----------|
12345678
My initial code was evaluating the count of each character during each of these empty 'k' cycles.
And that was the issue.
During the empty 'k' cycles, the count of each character is changing and when the empty cycle finishes, the count of the character is real and exactly as it should be.
So the solution is, to do the evaluation of count of each character and if any of the chars is in count >3, break only the last cycle when k = 1.
I was breaking the loop in very first empty cycle, where the count of the characters in string were incorrect.
01. In for loop where one by one all chars are added. K = 1; I = 7; N = 8 <--- OK, loop when the last G was added to form string aaaaabGG
table in for loop
| a | b | c | d | e | f | g | G |
| 5 | 1 | 0 | 0 | 0 | 0 | 0 | 2 |
aaaaabGG <--- aaaaabGG was formed
table in base <--- aaaaabGG shown in the final output
| a | b | c | d | e | f | g | G |
| 5 | 1 | 0 | 0 | 0 | 0 | 0 | 2 |
02. In for loop where one by one all chars are added. K = 3; I = 2; N = 8 <--- going one character UP, next string after aaaaabGG should be aaaaacaa
table in for loop
| a | b | c | d | e | f | g | G |
| 5 | 0 | 1 | 0 | 0 | 0 | 0 | 2 | <--- but as we can see, during the K = 3 empty loop, the string is aaaaacGG (updates only 3rd char from left)
03. In for loop where one by one all chars are added. K = 2; I = 0; N = 8 <--- second empty loop K = 2
table in for loop
| a | b | c | d | e | f | g | G |
| 6 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | <--- as we can see, during the K = 2 empty loop, the string is updating and is now aaaaacaG (now updates only 2nd char from left, 3rd is OK from previous empty loop)
04. In for loop where one by one all chars are added. K = 1; I = 0; N = 8 <--- Last loop K = 1 (string is updated 1st character in the left only, 2nd and 3rd were updated in previous empty loops respectively)
table in for loop
| a | b | c | d | e | f | g | G |
| 7 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
aaaaacaa <--- we can see that now the string is as it should be aaaaacaa
table in base <--- aaaaacaa shown in the final output
| a | b | c | d | e | f | g | G |
| 7 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
Let's say I have a file that looks like the following:
|----------------------------------------------|
| |
| |---------| |--------------| |
| |.........| |..............| |
| |.........| |..............| |
| |----+----| |----+---------| |
| # # |
| ################### |
| |
|----------------------------------------------|
(it will be a map file for a game)
In this case, MAX_WIDTH is 48 and MAX_HEIGHT is 10.
I made it so that it does not skip whitespace when reading with
infile.unsetf(ios_base::skipws);
Then I used get() in a loop like following:
char tile[MAX_HEIGHT][MAX_WIDTH];
char c;
for(int i=0; i<MAX_HEIGHT; i++) {
for(int j=0; j<MAX_WIDTH + 1; j++) {
infile.get(c);
if(c == '\n') {
continue;
}
tile[i][j] = c;
}
}
But then after each line, it looked like lines were being pushed when I printed the array.
|--------------------------------------------|
|
|| |--------| |-------------|
|| |........| |.............|
|| |........| |.............|
|| |----+---| |----+--------|
Not exact but something like this.
What could've gone wrong and what can I do about it?
(+) Printing the array goes like the following:
for(int i=0; y<MAX_HEIGHT; y++) {
for(int j=0; x<MAX_WIDTH; x++) {
cout << tile[y][x];
}
cout << endl;
}
If you have windows style linebreaks in your input file you need to read two characters for each linebreak. \r\n. That would explain your corrupted output.
A fix would be to use std::getline style functions instead of get. Or explicitly check for the \r\n combination.
I guess it should be that j < MAX_WIDTH + 1
since your first line is good, probelm start happen in your second row
try remove that + 1
Edit:
remove that +1
you may try to is to add a check on both \r \n when reading
I've been writing a program conducting some operations on two square matrixes. For the time being I've been thinking of a code which will read a matrix of a fixed (previously known size) and I'm writing these data into a 2-D array. However, I've got a problem, because when I'm debugging my code with addictional output messages everything seems fine, but the final output (the one in the for loop) I'm missing some numbers. It is really strange because when I'm prining all variables used in the process their values look fine.
#include <iostream>
#include <stdio.h>
using namespace std;
int main ()
{
int number = 0;
int index = 0;
int v_ind = 0; // vertical index
int h_ind = 0; // horizontal index
char c;
int size = 3; // temporary fixed size
int searched_number;
int matrix1 [size-1][size-1];
int matrix2 [size-1][size-1];
//scanf("%i %i", &size, &searched_number);
while (index < size)
{
c = getchar_unlocked();
if ( (c >= '0') && (c <= '9') )
{
number = (number * 10) + (c - '0');
continue;
}
if (c == ' ')
{
cout << "number on a space: " << number << endl;
matrix1[h_ind][v_ind] = number;
cout << "1 ) matrix1[" << h_ind << "][" << v_ind << "] : " << matrix1[h_ind][v_ind] << endl << endl;
v_ind ++ ;
number = 0;
continue;
}
if (c == '\n')
{
cout << "num on a newLine: " << number << endl;
matrix1[h_ind][v_ind] = number;
cout << "2) matrix1[" << h_ind << "][" << v_ind << "] : " << matrix1[h_ind][v_ind] << endl << endl;
h_ind ++ ;
v_ind = 0;
number = 0;
index ++ ;
continue;
}
}
for (int i = 0; i < size; i ++) {
for (int j = 0; j < size; j ++) {
int num = matrix1[i][j];
cout << "mat[" <<i <<"][" << j << "] : " << num << " " << endl;
}
}
}
Below I've pasted an exemplary output from Ideone.com of a matrix like this:
| 1 2 3 |
| 4 5 6 |
| 7 8 9 |
Sukces time: 0 memory: 3348 signal:0
number on space: 1
1 ) matrix1[0][0] : 1
number on space: 2
1 ) matrix1[0][1] : 2
num na newLine: 3
2) matrix1[0][2] : 3
number on space: 4
1 ) matrix1[1][0] : 4
number on space: 5
1 ) matrix1[1][1] : 5
num na newLine: 6
2) matrix1[1][2] : 6
number on space: 7
1 ) matrix1[2][0] : 7
number on space: 8
1 ) matrix1[2][1] : 8
num na newLine: 9
2) matrix1[2][2] : 9
mat[0][0] : 1
mat[0][1] : 2
mat[0][2] : 4
mat[1][0] : 4
mat[1][1] : 5
mat[1][2] : 7
mat[2][0] : 7
mat[2][1] : 8
mat[2][2] : 9
The problem looks simple - I'm missing all last numbers from every row, except from the last one. I suspect that somewhere I overwrite proper values but I've got no clue where.
you create the matrix as matrix1[size-1][size-1] which will have indices from 0 to size-2. Then you attempt to print the values from indices o to size-1. Try declaring the matrix as
int matrix1 [size][size]
Let's see the layout of the memory allocated for matrix1 and how you are using it.
You have
int matrix1[size-1][size-1];
Which is equivalent to:
int matrix1[2][2];
For rest of this discussion let me use m instead of matrix1 for illustration.
Memory allocated for m looks like:
m[0][0]
| m[0][1]
| | m[1][0]
| | | m[1][1]
| | | |
v v v v
+----+----+----+----+
| | | | |
+----+----+----+----+
Now let's see where m[0] and m[1] point
m[0]
| m[1]
| |
v v
+----+----+----+----+
| | | | |
+----+----+----+----+
After m[0][0] = 1; and m[0][1] = 2;, the values look like:
+----+----+----+----+
| 1 | 2 | | |
+----+----+----+----+
Things get strange when you set m[0][2] = 3;.
m[0][2] -- this is where the run time thinks m[0][2] points to.
|
v
+----+----+----+----+
| 1 | 2 | | |
+----+----+----+----+
and you get:
+----+----+----+----+
| 1 | 2 | 3 | |
+----+----+----+----+
Now, you execute m[1][0] = 4; If you recall where m[1][0] points to, you will see that the values now become (4 overwrites 3 in the location):
+----+----+----+----+
| 1 | 2 | 4 | |
+----+----+----+----+
After you execute m[1][1] = 5;, you get:
+----+----+----+----+
| 1 | 2 | 4 | 5 |
+----+----+----+----+
When you execute m[1][2] = 6;, you are reaching the memory past what was allocated for m.
m[1][2] -- this is where the run time thinks m[1][2] points to.
|
v
+----+----+----+----+----+
| 1 | 2 | 4 | 5 | |
+----+----+----+----+----+
Normally, you'd enter undefined behavior at this point. However, due to lucky (or unlucky depending your point of view) circumstances, your program does not crash but lets you use that memory. So, you get:
+----+----+----+----+----+
| 1 | 2 | 4 | 5 | 6 |
+----+----+----+----+----+
Now, you try to access memory by using m[2][0], m[2][2], and m[2][2]. Once again, the run time lets you use the memory after m[1][1] without crashing. By following pointer arithmetic, m[2] points to 2 addresses past m[1]
m[2]
|
v
+----+----+----+----+----+
| 1 | 2 | 4 | 5 | 6 |
+----+----+----+----+----+
m[2][0]
| m[2][0]
| | m[2][2]
| | |
v v v
+----+----+----+----+----+----+----+
| 1 | 2 | 4 | 5 | 6 | | |
+----+----+----+----+----+----+----+
After you execute, m[2][0] = 7;, m[2][1] = 8;, and m[2][2] = 9;, the values in memory look like:
+----+----+----+----+----+----+----+
| 1 | 2 | 4 | 5 | 7 | 8 | 9 |
+----+----+----+----+----+----+----+
Now you can see why you are getting the output. m[0][2] and m[1][0] point to the same address that holds the value 4. m[1][2] and m[2][0] point to the same address that holds the value 7.
My guess is that you are using the memory allocated for matrix2 when you are reaching beyond the memory allocated for matrix1 and the program does not crash. In other circumstances, the program might behave in unpredictable ways.
If you're doing anything interesting with your matrices, you should probably consider grabbing an existing library. Many of these will provide a heap of utilities for you, and they will still use either a 2D or 1D array for backing the data. the particular one you should choose will depend on what you're trying to use it for.
If you're determined to roll your own matrices I'd consider using a class with a 1D array. I've used something like this before
class Matrix {
int * values;
unsigned int nx;
unsigned int ny;
unsigned int x_stride;
unsigned int y_stride;
int& operator(int x, int y) {
return values[nx*x_stride+ny*y_stride];
}
... constructors etc...
};
Why use both x_stride and y_stride, when one will be 1 and the other nx? It allows you to do some nice tricks like copyless submatrix and copyless transpose on large matrices.
void transpose(Matrix &m) {
std::swap(m.nx, m.ny);
std::swap(m.x_stride, m.y_stride);
}
Matrix submatrix_slice(const Matrix &m, int start_x, int step_x, int start_y, int step_y) {
Matrix retval(m, Matrix::SharedData());
retval.start_x += start_x;
retval.x_stride *= step_x;
retval.start_y += start_y;
retval.y_stride *= step_y;
}
Why should you care about these? Well maybe you don't, but it can make the implementation of a lot of numerical algorithms neater without compromising speed. (E.g. I've used them to get neat versions of Gaussian elimination, Inverse, Determinant, least squares etc.)
One difference is that you need to use matrix(i,j) rather than matrix[i][j], but if you really care about that (and I've had to care about it before...) you can create a MatrixRow class that backs onto the same data, and is returned by a MatrixRow Matrix::operator[](int), which can also provide a int& MatrixRow::operator[](int), If you do this (and provide the const versions too) you'll be able to do matrix[i][j] as you might expect.
Another advantage of using a class based approach is that it becomes really easy to put debugging assertions into your accessor code, to ensure that you never access outside the matrix bounds.
Ok, I'm trying to make a vertical bar graph from the values in a file. The code below works, to a point that is, and prints horizontally, but one asterisk per line, meaning there are spaces (obviously). Not looking for a spoonfed answer, just a push in the right direction.
using namespace std;
int main()
{
int counter;
cout<<"Please enter a number"<< "\n";
counter=0;
char *fname = "C:/Users/Jordan Moffat/Desktop/coursework/problem2.txt";
int x;
ifstream infile(fname);
while (infile >> x)
{
if (x==0 && x<=10){
cout<<"*"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\n";
}
else if (x>=10 && x<=20){
cout<<"\t"<<"*"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\n";
}
else if (x>=20 && x<=30){
cout<<"\t"<<"\t"<<"*"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\n";
}
else if (x>=30 && x<=40){
cout<<"\t"<<"\t"<<"\t"<<"*"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\n";
}
else if (x>= 40 && x<=50){
cout<<"\t"<<"\t"<<"\t"<<"\t"<<"*"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\n";
}
else if (x>=50 && x<=60){
cout<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"*"<<"\t"<<"\t"<<"\t"<<"\t"<<"\n";
}
else if (x>=60 && x<=70){
cout<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"*"<<"\t"<<"\t"<<"\t"<<"\n";
}
else if (x>=70 && x<=80){
cout<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"*"<<"\t"<<"\t"<<"\n";
}
else if (x>=80 && x<=90){
cout<<"*"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"*"<<"\t"<<"\n";
}
else if (x>=90 && x<=100){
cout<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"\t"<<"*"<<"\n";
}
}
cout<<"====================================================================================="<< "\n";
cout<<"0-9"<<"10-19"<<"20-29"<<"30-39"<<"40-49"<<"50-59"<<"60-69"<<"70-79"<<"80-89"<<"90-100"<<"\n";
system("PAUSE");
}
You have two problems. Apparantly you want to build a histogram and you want to visualize this histogram.
Histogram
One approach to build the histogram requires you to pre-specify the number of bins (homogeneous width), the minimum value (inclusive) and the maximum value (non-inclusive). Then you can compute the index of the bin each item should be assigned to.
Here's an (untested) example:
const int nbins = 10;
const double minval = .0, maxval = 100.;
std::vector<int> bins(nbins, 0);
for (double x; infile >> x; ) {
if (x >= minval && x < maxval) {
// note that integer rounding is probably towards zero, not towards -inf
int idx = floor((x-minval)/(maxval-minval)*nbins);
bins[idx]++;
}
else {
// handle outlier
}
}
Visualization
The approach described in this answer seems appropriate. For large bin counts you may need some normalization procedure, i.e. scaling the values to a range of [0,10] or similar.
Have a look at this (untested) example:
const int chart_height = 10;
const int max_count = *std::max_element(bins.begin(), bins.end());
for (int current_height = chart_height; current_height > 0; --current_height) {
for (int count : bins) {
const int bar_height = (count*chart_height)/max_count;
if (bar_height < current_height)
std::cout << " "; // we're still above the bar
else if (bar_height == current_height)
std::cout << " _ "; // reached the top of the bar
else // bar_height > current_height
std::cout << " | | "; // now the rest of the bar ...
}
std::cout << '\n';
}
With a little bit of fiddling and formatting magic you can also extend it to produce a borderline flexible visualization like this:
11 | _______ _______
| | | | |
| | | | |
| | | | |
| | | | | _______
5 | | | | | | |
| | | | | | |
| | | | | | | _______
| _______ | | | | | | _______ | |
| | | | | | | | | | | | |
+------v----------v----------v----------v----------v----------v-----
3.7 - 4.3 4.3 - 4.9 4.9 - 5.6 5.6 - 6.2 6.2 - 6.8 6.8 - 7.4
To make your bars vertically you need:
get all numbers in an array
determine the range, i.e. compute the max and min value of the array
make a loop over range, printing rows, leaving spaces on columns associate to values lower than the current row is 'depicting'.
here I assume steps 1 & 2 as done, just show the loop and gloss over some detail (note the code doesn't use min and loop from 0)
int values[] = {2,5,1,9,3}, cols = 5, max = 9;
for (int r = 0; r < max; ++r) {
for (int c = 0; c < cols; ++c)
cout << (r + values[c] >= max ? '*' : ' ');
cout << endl;
}
here the output
*
*
*
*
* *
* *
* **
** **
*****
You should read your data into an std::vector
Use two nested loops:
Looping over lines you print where first line is "0->10", second line "10->20" etc.
Looping over the vector, if variable is larger than (linecount-linenumber)*10, print " ", else print "*".
If your data goes from 0 to 100, linecount should be 10.
linenumber is the loop variable from first loop
It is not clear to me how your data is organized in the file. If your data file doesn't contain values which say how many *s each column should have, you should calculate that first.
Just having fun and practicing :)
enter any number sequence you want up to 100 numbers and press 0 to stop and make the graph :)
#include <iostream>
#include <limits>
using namespace std;
int main()
{
const int MAX = 100;
int values[MAX];
int input_number;
int total_number =0;
int largest_number = 0;
for (int i = 0; i < MAX; i++)
{
cin >> input_number;
if (input_number != 0)
{
total_number++;
values[i] = input_number;
}
else if (input_number == 0){
for (int t = 0;t<total_number;t++){
if(values[t]>largest_number)
largest_number = values[t];
}
for (int j = 0; j <largest_number; ++j){
for (int i = 0; i <total_number; ++i)
cout << (j+values[i] >= largest_number ? '*' : ' ') ;
cout << endl;
}
break;
}
}
system ("PAUSE");
return 0; // everything ok
}
I guess only one loop for each if condition you have written is sufficient.
And I agree with Kleist that Looping over variables and print * for each variable
(Similar to the answer of Kleist)
Make an array to define the y-axis (or a formula, based on an index)
Read the numbers from a file a save in a container, so you also know the number of values (x-axis)
double loop, 1 for the y-axis, 1 for the x-axis and find out whether an asterisk must be printed, based on 1.
Let the y-axis counter decrement, so your bars are rising.