I am trying to make a c++ console application that tries to show you how merge sort looks like. I understand merge sort, and I created a program that organizes a vector of strings called sort_visualize, and each string in it is filled with many #. This is completely randomized for every string. The merge sort will organize them depending on length, instead of the traditional number organizing people do with it. Every time I make a change to the vector, I also clear the screen and print out the entire vector through a draw function, to give the effect of it actively visualizing the sort every frame. The problem is that when I use the draw function to print out the entire sort_visualize string, it does not print out any changes that I have made to it, and prints out the same thing over and over again until the end, when it finally prints the sorted order. What is going on? I Don't understand. I even tried changing the draw(sort_visualize) to draw(sort_visualize_), and that shows small areas of the vector it is working on. Makes no sense. Please try this code and tell me any solutions. Thank you.
Here's the code:
#include <vector>
#include <iostream>
#include <ctime>
#include "stdlib.h"
#include "windows.h"
using namespace std;
void merge_sort(vector<string> &sort_visual_);
void merge_halves(vector<string>&left, vector<string>& right, vector<string>& sort_visual_);
void draw(vector <string> &sort_visual_);
vector <string> sort_visual;
int main()
{
srand(time(NULL));
//vector
vector<int> num_list;
//fill vector with random integers
for (int i = 0; i < 40; i++)
num_list.push_back(rand() % 40);
//Fill the visualizer strings which will be bars with #'s
for (int i = 0; i < num_list.size(); i++)
{
sort_visual.push_back("");
string temp;
for (int j = 0; j < num_list.at(i); j++)
{
temp.push_back('#');
}
sort_visual.at(i) = temp;
}
draw(sort_visual);
system("pause");
//sort function
merge_sort(sort_visual);
}
void merge_sort(vector<string> &sort_visual_)
{
//dont do anything if the size of vector is 0 or 1.
if (sort_visual_.size() <= 1) return;
//middle of vector is size/2
int mid = sort_visual_.size() / 2;
//2 vectors created for left half and right half
vector<string> left;
vector<string> right;
//divided vectors
for (int j = 0; j < mid; j++)
{
left.push_back(sort_visual_[j]); //add all the elements from left side of original vector into the left vector
}
for (int j = 0; j < (sort_visual_.size()) - mid; j++)
{
right.push_back(sort_visual_[mid + j]);//add all the elements from right side of original vector into the right vector
}
//recursive function for dividing the left and right vectors until they are length of 1
merge_sort(left);
merge_sort(right);
//do the actual merging function
merge_halves(left, right, sort_visual_);
}
void merge_halves(vector<string>&left, vector<string>&right, vector<string>& sort_visual_) //pass in 3 vectors
{
// sizes of each vector (left and right)
int nL = left.size();
int nR = right.size();
//declaring variables pointint to elements for each vector. i will represent finished produce vector
int i = 0, j = 0, k = 0;
//as long as j and k are less than the left and right sizes
while (j < nL && k < nR)
{
if (left[j].length() < right[k].length()) //if the string in the left vector is smaller than string in right vector
{
sort_visual_[i] = left[j];//ad the string from left vector in the sort_visuals vector(which is the final product)
j++;//increment j to move on
}
else
{
sort_visual_[i] = right[k];//otherwise add the string from right vector in the sort_visual vector
k++; //increment k to move on
}
i++; //i is the final vector, and we have to increment it to set it up to take in the next number
system("CLS");
draw(sort_visual);
Sleep(15);
}
while (j < nL)
{
sort_visual_[i] = left[j];
j++; i++;
system("CLS");
draw(sort_visual);
Sleep(15);
}
while (k < nR)
{
sort_visual_[i] = right[k];
k++; i++;
system("CLS");
draw(sort_visual);
Sleep(15);
}
}
void draw(vector <string> &sort_visual)
{
for (int i = 0; i < sort_visual.size(); i++)
{
cout << sort_visual.at(i) << endl;
}
}
In merge_halves you work on sort_visual_ but draw sort_visual which is a global that does not seem to be changed. Make sure there are no globals and it will be harder to make mistakes.
Related
I have a vector with a block of text read from a txt file. I need to use a window function to find the number of unique words in a sliding window of size K. I've found this count online which uses a similar technique but with an int array. However, when I try to adjust to code to fit my situation I'm getting an error:
"no match for ‘operator+’ (operand types are ‘std::vectorstd::__cxx11::basic_string<char >’ and ‘int’)gcc"
My question is, should I not be using a vector here? Should I be trying to figure out how to convert to an array? I didn't think there was too much of a difference between the two that I wouldn't be able to adapt the code, but perhaps I am wrong. I literally just started to learn C++ last night. Please help :(
// Counts distinct elements in window of size K
int countWindowDistinct(vector<string> text, int K)
{
int dist_count = 0;
// Traverse the window
for (int i = 0; i < K; i++) {
// Check if element arr[i] exists in arr[0..i-1]
int j;
for (j = 0; j < i; j++)
if (text[i] == text[j])
break;
if (j == i)
dist_count++;
}
return dist_count;
}
// Counts distinct elements in all windows of size k
void countDistinct(vector<string> text, int N, int K)
{
// Traverse through every window
for (int i = 0; i <= N - K; i++)
cout << countWindowDistinct(text + i, K) << endl;
}
int main()
{
//Declares two vectors
std::vector<std::string> book;
std::vector<std::string> unqWords;
//reads a text file and stores the contents in the vector book
book = readFile("test.txt");
//Ensures that all words in the text are lowercase
makeLower(book);
//Loops through the text (one word at a time) and removes all alphanumeric characters
for(int i = 0; i < book.size(); i++)
{
//Function used to remove alphanumeric characters from words
book[i] = removeAlpha(book[i]);
}
int K = 4;
int N = calculate_size(book);
// Function call
countDistinct(book, N, K);
}
Hello everyone I am starting to learn Data structures and Algorithms and implemented bubble sort myself after learning the concept. Following is the code I have written with my understanding but the problem is it runs for only one cycle and does not sort recursively.
For example:
{ 5,1,4,2,8} is sorted one time -> {1,4,2,5,8,}
What can be the problem?
vector<int> bubble_sort(vector<int> vec){
int temp = 0;
for(int i = 0; i < vec.size()-1; i++){
temp = vec.at(i+1); // holds the adjacent element.
// the following loop swaps the adjacent elements if the previous one is big
if(vec.at(i) > vec.at(i+1)){
vec.at(i+1) = vec.at(i);
vec.at(i) = temp;
}
temp = 0;
}
for(int i = 0; i < vec.size()-1; i++){
if(vec.at(i) > vec.at(i+1)){
bubble_sort(vec);
}
}
return vec;
}
Your function takes a vector<int> vector by copy, hence after first swaps only this copy is send to recursively sort.
Just add & to your function parameter: vector<int> bubble_sort(vector<int> &vec) and it should work
If you want to implement recursion fully and do not want to use for loop in the code, then follow this example. It will be helpful.
#include <iostream>
using namespace std;
/* Function to print an array */
void printArray(int arr[], int n)
{
for (int i=0; i <= n; i++)
cout<<arr[i];
}
void bubble_sort_recursive(int arr[], int j, int n) {
// base case
if (n==0 || j>n){
return;
}
// single pass has been completed and the higher element moved to right for that subarray
// now call the recursive function by keeping aside the already sorted positioned element
//i.e next pass wil start from this call
if (j == n){
bubble_sort_recursive(arr,0,n-1);
}
// swap consecutive 2 elements - main basic of bubble sort
if (arr[j]>arr[j+1]){
int t = arr[j];
arr[j] = arr[j+1];
arr[j+1] =t;
}
// go forward for next element of a single pass
bubble_sort_recursive(arr,j+1,n);
}
int main() {
int arr[] = {5,4,3,2,1};
// get the length of array
int n = sizeof(arr)/sizeof(arr[0]);
// call from 0 to len-1 as index starts from 0
bubble_sort_recursive(arr,0,n-1);
// print the sorted array
cout<<"Sorted array:"<<endl;
printArray(arr, n-1);
}
I'm working on my first few algorithms to build my C++ skills and am currently coding up a method of counting inversions with merge sort. I've managed to get a working merge sort together but I'm having a bit of trouble keeping track of the number of inversions. Any ideas of where to go from here? How can I keep track of the number of inversions on a recursive algorithm like this? Additionally I've seen a couple different implementations of this in my internet travels and have found most people stray away from the std::vector method, any idea why? Thanks for any help, my code is below!
#include <iostream>
#include <math.h>
#include <vector>
using namespace std;
vector<int> print(vector<int> input){
for(int i=0; i<input.size(); i++){
cout<<input[i]<<",";
}
cout<<endl;
return input;
}
vector<int> merge(vector<int> left,vector<int> right){
//set up some varibles
vector<int> output;
int i=0;
int j=0;
//loop through the lists and merge
while(i<left.size() && j<right.size()){
//push the smallest of the two to the vector output
if(left[i]<=right[j]){
output.push_back(left[i]);
i+=1;
}
if(left[i]>right[i]){
output.push_back(right[j]);
j+=1;
}
}
//push the remnants of the vectors to output
for(i; i<left.size(); i++){
output.push_back(left[i]);
}
for(j; j<right.size(); j++){
output.push_back(right[j]);
}
return output;
}//end merge
vector<int> merge_sort(vector<int> input){
//check the size of the vector
if(input.size()<2){
return input;
}
else{
//int new vectors
vector<int> left;
vector<int> right;
vector<int> output;
//find the middle of the input vector
int middle=(input.size())/2;
//build the left vector
for(int i=0; i<middle; i++){
left.push_back(input[i]);
}
//build the right vector
for(int i=middle; i<input.size(); i++){
right.push_back(input[i]);
}
//make recursive calls
left=merge_sort(left);
right=merge_sort(right);
//call merge
output=merge(left,right);
return output;
}
}
int main()
{
vector<int> output;
vector<int> input;
input.push_back(2);
input.push_back(1);
input.push_back(10);
input.push_back(4);
output=merge_sort(input);
print(output);
}
Good news: counting inversions is pretty easy from here.
Think about your "merge" method. Every time you put an element from the left vector into output, you are not changing its position relative to elements from the right. On the other hand, every time you add an element from the right vector, you are putting it "before" all elements still to be processed in the left vector, when it was prevously "after" them, i.e. creating (left.size - i) "inversions".
You can prove this easily by induction if needed.
So the answer is simply : pass an int* to your merge method, and increment it by (left.size - i) every time you push an element from the right vector.
EDIT: Working code sample
#include <iostream>
#include <vector>
// removed useless dependency math.h
using namespace std;
// void type -> does not return anything
void print (vector<int> input) {
// range-based for loop (since C++ 11)
// no brackets -> only one instruction in for loop
for(int i : input)
cout << i << ",";
}
vector<int> merge (vector<int> left, vector<int> right, int * inv_count) {
vector<int> output;
// multiple variable definition of the same type
int i=0, j=0;
// spaces around "<", after "while", before "{" for readability
while (i < left.size() && j < right.size()) {
// one-instruction trick again
if (left[i] <= right[j])
// i++ is evaluated to <previous value of i> and then increments i
// this is strictly equivalent to your code, but shorter
// check the difference with ++i
output.push_back(left[i++]);
// else because the two conditions were complementary
else {
output.push_back(right[j++]);
// pointer incrementation
*inv_count += (left.size() - i);
}
}
// first field of for ommited because there is no need to initialize i
for(; i < left.size(); i++)
output.push_back(left[i]);
for(; j < right.size(); j++)
output.push_back(right[j]);
return output;
}
vector<int> merge_sort (vector<int> input, int * inv_count) {
// no-braces-idiom again
// spaces around "<" and after "if" for readability
if (input.size() < 2)
return input;
// no need for else keyword because of the return
// multiple variable definition
vector<int> left, right;
int middle = input.size() / 2;
// one-instruction for loop
for(int i=0; i < middle; i++)
left.push_back(input[i]);
for(int i=middle; i < input.size(); i++)
right.push_back(input[i]);
// no need for intermediate variable
return merge( merge_sort(left, inv_count),
merge_sort(right, inv_count),
inv_count);
}
// consistent convention : brace on the same line as function name with a space
int main () {
// vector initialization (valid only since C++ 11)
vector<int> input = {2, 1, 10, 4, 42, 3, 21, 7};
int inv_count = 0;
// No need for intermediate variables again, you can chain functions
print( merge_sort(input, &inv_count) );
// The value inv_count was modified although not returned
cout << "-> " << inv_count << " inversions" << endl;
}
I modified your code to include a few usual C++ idioms. Because you used the C++14 tag, I also used tricks available only since C++11. I do not recommend using all of these tricks everywhere, they are included here because it is a good learning experience.
I suggest you read about pointers before diving deeper into C++.
Also note that this code is in no way optimal : too many intermediate vectors are created, and vectors are not useful here, arrays would be enough. But I'll leave this for another time.
Since I'm Italian, the function names are in Italian but really simple to understand: immagine=image, inserisci=insert, altezza=height, larghezza=width,mosaico =mosaic, righe=rows, colonne=columns.
So this program has 2 classes: an image with its attributes and a mosaic, which contains n images and this is represented through a 2D vector of obj Image (Immagine). The 2D vector has to be initialized in the constructor with r rows and c columns and using the inserisci (insert/add) function will then grow its dimension. Then if the element passed in the insert function has more rows/columns the insert function has to add the needed rows and columns in order to insert the element.
The problem is that even though I used pointers/references, every time I try to insert an element with a size that is bigger than the one initialized in the constructor, it gives me an error, meaning that the 2D vector that I modify in the insert function is not really edited... (look at the main when I insert: m2.inserisci(i4, 4, 4, &m2.immagini) since 4 rows > inital size of rows and same for columns gives me a runnning error..) Hope it is clear. This is my code:
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;
class Immagine{
private:
string nome;
public:
int altezza;
int larghezza;
Immagine(string,int,int);
string toString();
};
Immagine::Immagine(string n, int a, int l){
nome = n;
altezza = a;
larghezza= l;
}
string Immagine::toString(){
return nome;
}
class Mosaico{
public:
Mosaico(int, int,Immagine,vector< vector<Immagine> >*);
int getRighe();
int getColonne();
string getImmagine(int,int);
bool exist(int, int);
Immagine getIm(int,int);
void inserisci(Immagine,int,int,vector< vector<Immagine> >*);
vector< vector<Immagine> > immagini;
vector< vector<Immagine> >* aPointer= &immagini;
};
Mosaico::Mosaico(int r, int c,Immagine imm, vector< vector<Immagine> >* immag ){
(*immag).resize(r);
for(int i=0; i<(*immag).size(); i++)
for(int j=0; j<c; j++)
(*immag)[i].insert((*immag)[i].begin()+j,imm);
}
bool Mosaico::exist(int r, int c){
for(int i = 0; i < getRighe(); i++){
for(int j=0; j<getColonne(); j++){
if(i==r && j==c && immagini[r][c].toString()!= " "){
return true;
}
}
}
return false;
}
int Mosaico::getRighe(){
return immagini.size();
}
int Mosaico::getColonne(){
return immagini[1].size();
}
string Mosaico::getImmagine(int r, int c){
if(exist(r,c))
return immagini[r][c].toString();
}
Immagine Mosaico::getIm(int r, int c){
return immagini[r][c];
}
void Mosaico::inserisci(Immagine imm,int r, int c, vector< vector<Immagine> >* immag){
if(r<(*immag).size() && c<(*immag)[0].size()){
(*immag)[r][c]=imm;
}
else if(r>=(*immag).size() && c>=(*immag)[0].size()){
(*immag).resize(r);
for(int i=0; i<r; i++){
for(int j=(*immag)[0].size(); j<c; j++){
(*immag)[i].insert((*immag)[i].begin()+j, imm);
}
}
(*immag)[r][c]=imm;
}
else if(r>=(*immag).size() && c<(*immag)[0].size()){
(*immag).resize(r);
(*immag)[r][c]=imm;
}
else if(r<(*immag).size() && c>=(*immag)[0].size()){
for(int i=0; i<(*immag).size(); i++){
for(int j=(*immag)[0].size(); j<c; j++){
(*immag)[i].insert((*immag)[i].begin()+j, imm);
}
}
(*immag)[r][c]=imm;
}
}
int main() {
Immagine i1 ("I01",300,200);
Immagine i2 ("I02",300,400);
Immagine i3 ("I03",400,200);
Immagine i4 ("I04",400,400);
cout << "Creo un mosaico 2x2 con quattro immagini" <<endl;
Mosaico m2(2,2,i1,&m2.immagini) ;
cout<<m2.getRighe()<<endl;
cout<<m2.getColonne()<<endl;
for (int i=0; i < m2.getRighe(); i++) {
for (int j=0; j < m2.getColonne(); j++){
//if(m1.exist(i,j))
cout<<m2.getImmagine(i,j);
}
cout<<endl;
}
m2.inserisci(i1, 0, 0, &m2.immagini);
m2.inserisci(i2, 0, 1, &m2.immagini);
m2.inserisci(i3, 1, 0, &m2.immagini);
m2.inserisci(i4, 4, 4, &m2.immagini); //HERE IS WHERE I GET THE ERROR
cout <<"Stampa mosaico: "<<endl;
for (int i=0; i < m2.getRighe(); i++) {
for (int j=0; j < m2.getColonne(); j++){
cout<<m2.getImmagine(i,j);
}
cout<<endl;
}
}
By the way, this was a Java exercise and I tried to do it in C++. Thanks in advance!
Before I'll get to the details of the issues, let me first state that there are a lot of things in the code I'd do differently. Most prominently, I'd probably use a flat vector<Image> for storage instead of a vector<vector<..>>. But such things are better suited for CodeReview in my opinion (once the code is working).
The biggest problems in the OP's code are within the implementation of the inserisci function:
void Mosaico::inserisci(Immagine imm,int r, int c,
vector< vector<Immagine> >* immag) {
if(r < (*immag).size() && c < (*immag)[0].size()){
(*immag)[r][c]=imm;
}
This part is fine, if we assume that (*immag)[i].size() is the same for all i in [0, (*immag).size()). Let us call this assumption A. The [x, y) notation stands for a half-open-on-right interval (x is within that interval, y is not). Note that you can replace (*e).m with e->m, which I'll do in the following.
The assumption A is a class invariant: after every member function (except for the destructor), this class invariant must hold. Continuing with the inserisci function:
else if(r>=(*immag).size() && c>=(*immag)[0].size()){
(*immag).resize(r);
The *immag vector now has r elements. This is insufficient if you want to access the rth element, since indexing starts with 0. You need to have at least r+1 elements. Replace the above resize with:
int newRowCount = r+1;
(*immag).resize(newRowCount);
Continuing with the OP's function:
for(int i=0; i<r; i++){
This has the same off-by-one bug: replace r with newRowCount, or simply immag->size().
for(int i=0; i<immag->size(); i++){
Continuing with the OP's function:
for(int j=(*immag)[0].size(); j<c; j++){
(*immag)[i].insert((*immag)[i].begin()+j, imm);
}
}
With the above resize, we have added newRowCount - immag->size() new elements to the immag vector. Those new elements are vectors of the size 0. To be able to access the cth element of such a vector, we need to add at least c+1 elements to it.
The value of (*immag)[0].size() however changes after the first iteration of the outer loop such that (*immag)[0].size() == c for the remaining (*immag)[i] elements where i is in [1, newRowCount). This code won't add any new columns to those rows. A simple fix is:
int newColumnCount = c+1;
for(int j=(*immag)[i].size(); j < newColumnCount; j++){
(*immag)[i].insert((*immag)[i].begin()+j, imm);
}
}
(*immag)[r][c]=imm;
}
A note related to code review: You can very easily resize the inner elements as well, using the resize-overload which takes an additional argument:
(*immag)[i].resize(newColumnCount, imm);
Continuing with the OP:
else if(r>=(*immag).size() && c<(*immag)[0].size()){
(*immag).resize(r);
This suffers from the same off-by-one bug again. You need to have at least r+1 elements to access the rth element in the following
(*immag)[r][c]=imm;
}
And in the following piece of code, the same issues appear as in the second branch (that is, (*immag)[0].size() instead of referring to the current element's size, and j < c instead of j < newColumnCount).
else if(r<(*immag).size() && c>=(*immag)[0].size()){
for(int i=0; i<(*immag).size(); i++){
for(int j=(*immag)[0].size(); j<c; j++){
(*immag)[i].insert((*immag)[i].begin()+j, imm);
}
}
(*immag)[r][c]=imm;
}
}
well ive been trying to edit the element of an array so lets assume that we have a 2d array
so
a 2d array 9 x 9;
for(... ... ... ++)
{
for(.. ... ...++){}
}
lets say that the code will use another set of for loops to display the 2d array its a simple array nothing fancy
00000000
00000000
00000000...
so if i wanted to to display an E from elements[1][0] to [2][3] how would i do that?
00000000
eeeeeeee
eeee0000
00000000
what i had in mind was something like while(x < y)
{ array[x++][y];}
but this idea doesnt seem to work.
would gladly take any help. thx
for(int i=0; i<9; i++) //This loops on the rows.
{
for(int j=0; j<9; j++) //This loops on the columns
{
board[i][j] = grid; // set the array to the char on grid '0'.
}
}
board[s_col][s_row] = 'Z';
while(s_col < e_col)//s_col is the start of the rows and columns
//{
//if(s_col != e_col)
{
++s_col;
board[s_col][s_row];
}
//}
//cout << board[s_col][s_row++] <<endl;
// display the array
for(int i=0; i<9; i++) //This loops on the rows.
{
for(int j=0; j<9; j++) //This loops on the columns
{
cout << board[i][j] << " ";
}
cout << endl;
}
You were on the right track with the approach:
for(... ... ... ++)
{
for(.. ... ...++){}
}
Here is some code that should help you:
#include <stdio.h>
#include <memory.h>
#define MAX_ROW 4
#define MAX_COL 8
void fillRange(char fillChar, int startRow, int startCol, int count);
char myArray[MAX_ROW][MAX_COL];
void printArray();
int main(int argc, char *argv[])
{
memset(myArray, '0', sizeof(myArray));
printf("\nBefore:\n");
printArray();
fillRange('e', 1, 0, 12);
printf("\nAfter:\n");
printArray();
}
void fillRange(char fillChar, int startRow, int startCol, int count)
{
int i, j, filledChars = 0;
for(i = startRow; i < MAX_ROW; i++)
{
for(j = startCol; j < MAX_COL; j++)
{
myArray[i][j] = fillChar;
if(++filledChars == count)
return;
}
}
}
void printArray()
{
int i, j;
for(i = 0; i < MAX_ROW; i++)
{
for(j = 0; j < MAX_COL; j++)
putchar(myArray[i][j]);
printf("\n");
}
}
If you instead wanted to end at a particular point in the array then you just need to change the condition that triggers the return.
This is one of the many reasons why the more coding you do the more you tend to avoid 2D arrays of the sort you have.
Instead you use a 1D array like this: board[i][j] == board_1D[i*num_columns+j]. That also means you can just iterate through the entire board in a single for loop.
Now you simply calculate the begin and end indices of your e range, and simply test if your counter is within that range. In other words, you have a single if statement inside your inner-most loop.
You can, of course, convert your i,j 2D indices into the equivalent 1D index and take the same approach. index_1D = i*9+j;
I'll leave the code to you.
Dealing with a sequence of adjacent values is easiest done when you have an underlying contiguous array and you don't need to deal with double indexing (see Adam's answer on that). However, in your simple case it also quite doable:
You'd initialize your row and column variables with the start row and column (in your case 0 and 1). You then walk with your column until you reached either the target column (2) and you are on the target row (3) or you reached the end of the matrix in which case you set the column to 0 and increment the row.