Sorting with two vectors - c++

I'm wondering if it's possible if you have, for example, a vector<string> and a vector<double> with corresponding pairs, to sort the vector<string> alphabetically while keeping the pairs matched up.
I know this can be done by creating a class that holds both values and just sorting that, but I'd rather keep two separate vectors.
Any ideas?
Final Code:
#include "std_lib_facilities.h"
struct Name_pairs
{
vector<string>names;
vector<double>ages;
void quicksort(vector<string>& num, vector<double>& num2, int top, int bottom);
int divide(vector<string>& array, vector<double>& array2, int top, int bottom);
bool test();
string read_names();
double read_ages();
void print();
};
string Name_pairs::read_names()
{
string name;
cout << "Enter name: ";
cin >> name;
names.push_back(name);
return name;
}
double Name_pairs::read_ages()
{
double age;
cout << "Enter corresponding age: ";
cin >> age;
ages.push_back(age);
cout << endl;
return age;
}
int Name_pairs::divide(vector<string>& array, vector<double>& array2, int top, int bottom)
{
string x = array[top];
int i = top-1;
int j = bottom+1;
string temp;
double temp2;
do{
do
{
j--;
}while(x<array[j]);
do
{
i++;
}while(x>array[i]);
if(i<j)
{
temp = array[i];
temp2 = array2[i];
array[i] = array[j];
array2[i] = array2[j];
array[j] = temp;
array2[j] = temp2;
}
}while(i<j);
return j;
}
void Name_pairs::quicksort(vector<string>& num, vector<double>& num2, int top, int bottom) // top is subscript of beginning of vector
{
int middle;
if(top < bottom)
{
middle = divide(num, num2, top, bottom);
quicksort(num, num2, top, middle);
quicksort(num, num2, middle+1, bottom);
}
return;
}
void Name_pairs::print()
{
for(int i = 0; i < (names.size()-1) && i < (ages.size()-1); ++i)
cout << names[i] << " , " << ages[i] << endl;
}
int main(){
Name_pairs np;
cout << "Enter names and ages. Use 0 to cancel.\n";
bool finished = false;
while(!finished){
finished = "0" == np.read_names();
finished = 0 == np.read_ages();}
np.quicksort(np.names, np.ages, 0, (np.names.size()-2));
np.print();
keep_window_open();}

If you manually sort them yourself, you can just swap the corresponding items in the double array along with the items in the string array that you would normally do. Or, you could have a third array:
vector<unsigned int> indices;
That just indexes into the string/double array, and sort that array instead (swapping based on the values in the string array).

You could create an auxiliary vector:
vector<unsigned int> indices;
Initialize it to to 0,1,2,...n-1, where n is the size of your vectors, and have the sort algorithm sort it using a functor that looks at the vector<string>, i.e., when asked to compare index1 and index2, the functor will look up the corresponding strings and compare them instead. Once you have indices sorted, you can easily sort your two arrays to conform to it in linear time.
Edit: I didn't see Jim Buck's second suggestion. My answer is just an expanded version of that.

Although the indices idea is effectively the same, you can in fact define a random access iterator type that knows the two vectors, and moves them (through assignment) in sync. The value_type of that iterator would be pair. In functional programming, you'd call this a "zip" (but not a zipper).
It's definitely not worth the hassle unless you're VERY tight on space. If you have the space, actually zipping the two vectors into a single vector of pairs, or using the indices approach, are both easier.
If you're able to get it right the first time, copy/pasting a 10 line quicksort with the obvious modifications will be the fastest way to what you want.
Ed's note: there is an already-written Zip Iterator available in Boost, as pointed out in this newer answer to the same question: "Locking" two vectors and sorting them

If you intend to use std::sort, you will need to use a datastructure like a pair.
You can, of course, manually sort the vectors, and essentially reimplement std::sort.
This question really depends on a great number of other questions, such as:
How many items will be in the vectors?
How critical is performance?
Do you REALLY want to implement your own sort algorithm?
Implementing a quicksort should be fairly painless, and will allow you to avoid moving the data around.

Related

Why does my quickSort not work properly, and rather leaves it as unsorted as the input vector?

I am a student completing a project right now and am making a larger version of this quick sort for objects within a vector, etc. I made this mini version to test out my quickSort algorithm, it should sort this vector of strings alphabetically (A->Z). I can't seem to get this to work:
#include<iostream>
#include<vector>
#include<string>
using namespace std;
int Partition1(vector<string> array, int low, int high){ //for lastName sort
string pivot = array[high]; //pivot element
int i = (low-1); //index of smaller element
for(int j = low; j <= high-1; j++){ //loop from low to high
//if current iteration is less than pivot, increment low AND swap elements at i and j
if(array[j] < pivot){
i++; //increment index of smaller element
swap(array[i], array[j]);
}
}
swap(array[i+1], array[high]);
return (i+1);
}
void sort(vector<string> array, int first, int last){
if(first < last){
//partition array
int pivot = Partition1(array, first, last);
sort(array, first, pivot-1);
sort(array, pivot+1, last);
}
}
void swap(string &input1, string &input2) {
string temp; //temp student object to hold info
temp = input1;
input1 = input2;
input2 = temp;
}
int main(){
vector<string> array = {"Eric", "Bob", "George", "Fred"};
sort(array, 0, array.size()-1);
for(int i = 0; i < array.size(); i++){
cout << array[i] << endl;
}
}
Instead of the desired output, it just leaves the list as is, and does not sort it alphabetically, which is what I'm aiming for (A->Z). What should I do to make it work? Is there anything I'm missing here?
You're taking vector<string> by value. That means, it's copied when you enter the function. Take it instead by reference: vector<string>&.
Also, I'd suggest not naming vector as array, as the latter is also a type in c++ and thus it's misleading.

How can I print the numbers in main function?

I am new to c++ language. I am trying to solve a problem using function. I have to print the pentagon numbers untill the integer input, but when function returns the values, it only prints one value. I would love some help with it.
#include<iostream>
using namespace std;
int pent(int num){
int p;
for(int i=1;i<=num;i++){
p=(i*(3*i-1)/2);
}
return p;
}
int main(){
int num;
cin>>num;
int sender=pent(num);
cout<<sender<<endl;
return 0;
}
Your function returns int, that is a single integer. To return more, you can use std::vector. As you probably are not familiar with it, I will give you some pointers...
The most simple constructor creates a vector with no entries:
std::vector<int> x;
You can reserve space for elements via reserve:
x.reserve(num);
The vector still has no elements, but it already allocated enough space to hold num elements. This is important, because when we will add elements the vector will grow and that potentially requires to copy all elements to a different place in memory. We can avoid such frequent reallocations by reserving enough space upfront.
To add elements to the vector you can use push_back:
x.push_back(42);
Eventually to print all elements of the vector we can use a range-based for loop:
for (auto element : x) std::cout << element << " ";
So you can rewrite your code like this:
#include <iostream>
#include <vector>
std::vector<int> pent(int num){
std::vector<int> result;
result.reserve(num);
for(int i=1;i<=num;i++){
result.push_back(i*(3*i-1)/2);
}
return result;
}
int main(){
int num;
std::cin >> num;
auto sender = pent(num);
for (auto number : sender) std::cout << number << " ";
}
In your program, from your pent() function you are only returning last calculated value. In you ever time, you are overwriting you variable p.
So there is a way which #asmmo is suggesting, to print in pent() function.
Or you can pass a vector to your pent() function and store values in that and print it in main function.
For your ref:
void pent(int num, vector<int> &arr) {
int p;
for (int i = 1; i <= num; i++) {
arr[i-1] = (i*(3 * i - 1) / 2);
}
}
int main() {
int num;
cin >> num;
vector<int> arr(num);
pent(num, arr);
for (int i = 0; i < num; i++) {
cout << arr[i] << endl;
}
return 0;
}

Is it possible to dynamically allocate a vector?

I was told on here to use vectors instead of arrays for this particular solution ( My original solution using to dynamically allocate arrays) my problem is I don't really understand vectors, my book only covers a small section. So, maybe I am doing something wrong? I'm just trying to learn a different way in solving it with vectors. So, when I ask is it possible to dynamically allocate a vector. What I mean is it legal to do this std::vector<int*> vect= nullptr;, if not why? Also it would be really helpful to see an example how to modify my original solution with vectors. I'm a beginner just trying to learn from my mistakes.
#include <iostream>
#include <vector>
void sortAscendingOrder(int*, int );
void LowestTestScore(int*, int);
void calculatesAverage(int*,int);
int main()
{
std::vector<int*> vect= nullptr;
int input;
std::cout << "Enter the number of testscores you want to enter." <<std::endl;
std::cin >> input;
vect = new int[input];
for(int count =0; count < input; count++)
{
std::cout << "Enter the test score" << (count +1) <<":" <<std::endl;
std::cin >> vect[count] ;
while( vect[count] < 0)
{
std::cout <<"You enter a negative number. Please enter a postive number." <<std::endl;
std::cin >> vect[count];
}
}
sortAscendingOrder(vect,input);
for(int count =0; count < input;count++)
{
std::cout << "\n" <<vect[count];
std::cout << std::endl;
}
LowestTestScore(vect,input);
calculatesAverage(vect,input);
return 0;
}
void sortAscendingOrder(int* input,int size)
{
int startScan,minIndex,minValue;
for(startScan =0; startScan < (size-1);startScan++)
{
minIndex = startScan;
minValue = input[startScan];
for(int index = startScan+1;index<size;index++)
{
if(input[index] < minValue)
{
minValue = input[index];
minIndex = index;
}
}
input[minIndex]=input[startScan];
input[startScan]=minValue;
}
}
void LowestTestScore(int* input, int size)
{
int count =0;
int* lowest = nullptr;
lowest = input;
for(count =1; count <size;count++)
{
if(input[count] < lowest[0])
{
lowest[0] = input[count];
}
}
std::cout << "Lowest score" << *lowest;
}
void calculatesAverage(int* input, int size)
{
int total = 0;
int average =0;
for(int count = 0; count < size; count++)
{
total += input[count];
}
average =(total/size-1);
std::cout << "Your average is" << average;
}
Dynamic allocation of an array is required when you want to increase the size of an array at run-time. Just like arrays, vectors used contiguous storage locations for their elements. But, unlike arrays, their size can change dynamically, with their storage being handled automatically by the container.
Vectors do not reallocate each time an element is added to the container. It pre-allocates some extra storage to accommodate future growth. Libraries can implement different strategies for growth to balance between memory usage and reallocation, but in any case, reallocation should only happen at logarithmically growing intervals of size so that the insertion of individual elements at the end of the vector can be provided with amortized constant time complexity (see push_back)
To answer your question:
Yes, it is possible to dynamically allocate a vector and no, it requires no extra effort as std:vector already does that. To dynamically allocate vectors is therefore, a redundant effort.
You can write:
#include<vector>
typedef std::vector< std::vector<double> >vec_array;
vec_array name(size_x, std::vector<double>(size_y));
This means: size instances of a std::vector<double>, each containing size_y doubles (initialized to 0.0).
Or, you can simply use vector to increase the container size (knowing it handles storage requirements by itself) like:
#include <vector>
vector<int> vec_array;
int i;
for(i=0;i<10;i++)
vec_array.push_back(i);

Sort numbers from smallest to biggest using vector instead of array in C++

So I am new to C++ and I am working on this problem that asks me to sort numbers with the insertion sort using vectors instead of arrays. I have worked sorting using the array and then I just made some minor changes in the code trying to solve the problem with vector. Here's what I've got now:
#include <cstdlib>
#include <iostream>
#include <vector>
using namespace std;
void fill_array(vector<int> v,int size, int& number_used);
void sort(vector<int> v, int number_used);
void swap_values(int& v1, int& v2);
int main()
{
cout << "This program sorts numbers from lowest to highest.\n";
vector<int> sample;
int number_used;
fill_array(sample,10,number_used);
sort(sample,number_used);
cout << "In sorted order the numbers are:\n";
for (int index =0; index < number_used; index++)
cout << sample[index] << " ";
cout << endl;
system("PAUSE");
return 0;
}
void fill_array(vector<int> v, int size, int& number_used)
{
cout << "This program sorts numbers from lowest to highest.\n";
cout << "Enter up to " << size << " nonnegative whole number.\n"
<< "Mark the end of the list with a negative number.\n";
int index = 0,next;
cin >> next;
while ((next >= 0) && (index < size))
{
v[index]=next;
index++;
cin >> next;
}
number_used = index;
}
void sort(vector<int> v, int number_used)
{
int index;
int index_backwards;
for(index=0;index<number_used;index++)
{
for(index_backwards=index;index_backwards>0;index_backwards--)
{
if(v[index_backwards-1]>v[index_backwards])
{
swap_values(v[index_backwards-1], v[index_backwards]);
}
}
}
}
void swap_values(int& v1, int& v2)
{
int temp;
temp = v1;
v1=v2;
v2=temp;
}
It went through the compile just fine. But when i run it, after i had input the numbers and hit enter, the program just stops running and shuts down. Is there anyone could help me fix the problem? Thanks.
When you are using std::vector like an array, you are misusing them. There is no point in passing the size "on a side" of the vector, because vectors keep their own size.
You should pass your vector by reference, use its size() member function instead of a count(), and use push_back() to add values to it. The signatures of your functions should be as follows:
// Pass by ref; no "size", no "number_used"
void fill_array(vector<int> &v);
// Pass by ref; no "number_used"
void sort(vector<int> &v);
Use v.push_back(next) instead of v[index]=next inside fill_array implementation.
In your fill_array function, you aren't adding the values that have been input to the vector v correctly. You should change v[index] = next to v.push_back(next).
You can either change
v[index]=next;
by
v.push_back(next);
Or you can keep it like v[index]=next; and allocate the memory when you declare your vector.
vector<int> sample(10); // This allocates 10 element. DON'T use push_back in this case
When you go the push_back way and you know the number of element your vector will eventually have, it is a good thing to call reserve before starting filling the vector. So you want to do:
vector<int> sample;
sample.reserve(10);
...
// Now fill it with push_back
reserve will set the capacity or your vector (capacity is always >= to your vector size). When capacity is == to the size, a call to push_back (or any function that insert elements) will need to reallocate the memory and then you get some performance hit. Using reserve will prevent that.
Also, there is no point in having your own swap function. The standard library has already a swap function. Instead of
swap_values(v[index_backwards-1], v[index_backwards]);
You can do
std::swap(v[index_backwards-1], v[index_backwards]);

Problems implementing a quicksort

I'm trying to implement a quicksort and am having some trouble. Ultimately, the sort will alphabetize a string vector and in turn synchronize a second vector with it so they stay matched (which should be easy since it's just repeating the same line with a different vector argument.)
At first when I compiled and ran the program, it was just generating the same output as before. I realized that this was because when I declared the vectors I didn't use the object.member notation. I modified it, and now I'm getting a compiler error.
in function int main
in lookup_member, at cp/search.c:1288
Obviously, there's a problem when it's trying to look at the vectors, but I'm not sure what.
I got my implementation of the quicksort code from Quick Sort (MathBits.com).
I am not sure what's wrong. Here's the code.
#include "std_lib_facilities.h"
struct Name_pairs
{
vector<string>names;
vector<double>ages;
void quicksort(vector<string>& num, int top, int bottom);
void divide(vector<string>& array, int top, int bottom);
bool test();
string read_names();
double read_ages();
void print();
};
string Name_pairs::read_names()
{
string name;
cout << "Enter name: ";
cin >> name;
names.push_back(name);
return name;
}
double Name_pairs::read_ages()
{
double age;
cout << "Enter corresponding age: ";
cin >> age;
ages.push_back(age);
cout << endl;
return age;
}
int Name_pairs::divide(vector<string>& array, int top, int bottom)
{
string x = array[top];
int i = top-1;
int j = bottom-1;
string temp;
do{
do
{
j--;
} while(x>array[j]);
do
{
i++;
} while(x<array[i]);
if(i<j)
{
temp = array[i];
array[i] = array[j];
array[j] = temp;
}
} while(i<j);
return j;
}
void Name_pairs::quicksort(vector<string>& num, int top, int bottom) // top is subscript of beginning of vector.
{
int middle;
if(top < bottom)
{
middle = divide(num, top, bottom);
quicksort(num, top, middle);
quicksort(num, middle+1, bottom);
}
return;
}
void Name_pairs::print()
{
for(int i = 0; i < (names.size()-1) && i < (ages.size()-1); ++i)
cout << names[i] << " , " << ages[i] << endl;
}
int main()
{
Name_pairs np;
vector<string>names;
vector<double>ages;
cout << "Enter names and ages. Use 0 to cancel.\n";
bool finished = false;
while(!finished){
finished = "0" == np.read_names();
finished = 0 == np.read_ages();
}
np.quicksort(names, 0, (names.size()-2));
np.print();
keep_window_open();
}
If you're trying to define additional vector variables within main, then the lines
np.vector<string>names; // error possibly here?
np.vector<double>ages;
Should be:
vector<string> names;
vector<double> ages;
You're redefining your struct members, or so it seems. But I don't see where you'd actually use those. Also, size() returns an unsigned variable of some sort, so you may need to cast it, or change the way you're comparing it to prevent compiler errors/warnings.
It's also worth noting, that if you want a couple more vectors declared within main() then it's good practice to name them something unique instead of having them share names with the struct members. Also, your main() doesn't have a return (needs to return int).
Get rid of the following lines in main() which are apparently causing your compiler to crash:
np.vector<string>names; // error possibly here?
np.vector<double>ages;
Then, a couple of your function definitions need to have their signatures changed:
int divide(vector<string>& array, int top, int bottom)
and
void quicksort(vector<string>& num, int top, int bottom)
need to change to
int Name_pairs::divide(vector<string>& array, int top, int bottom)
void Name_pairs::quicksort(vector<string>& num, int top, int bottom)
so they are seen as part of the Name_pairs struct instead of free functions.
I got it working. The final code: Pushes back data and sorts both in synchronization,
#include "std_lib_facilities.h"
struct Name_pairs
{
vector<string>names;
vector<double>ages;
void quicksort(vector<string>& num, vector<double>& num2, int top, int bottom);
int divide(vector<string>& array, vector<double>& array2, int top, int bottom);
bool test();
string read_names();
double read_ages();
void print();
};
string Name_pairs::read_names()
{
string name;
cout << "Enter name: ";
cin >> name;
names.push_back(name);
return name;
}
double Name_pairs::read_ages()
{
double age;
cout << "Enter corresponding age: ";
cin >> age;
ages.push_back(age);
cout << endl;
return age;
}
int Name_pairs::divide(vector<string>& array, vector<double>& array2, int top, int bottom)
{
string x = array[top];
int i = top-1;
int j = bottom+1;
string temp;
double temp2;
do{
do
{
j--;
} while(x<array[j]);
do
{
i++;
} while(x>array[i]);
if(i<j)
{
temp = array[i];
temp2 = array2[i];
array[i] = array[j];
array2[i] = array2[j];
array[j] = temp;
array2[j] = temp2;
}
} while(i<j);
return j;
}
void Name_pairs::quicksort(vector<string>& num, vector<double>& num2, int top, int bottom)
{
int middle;
if(top < bottom)
{
middle = divide(num, num2, top, bottom);
quicksort(num, num2, top, middle);
quicksort(num, num2, middle+1, bottom);
}
return;
}
void Name_pairs::print()
{
for (int i = 0; i < (names.size()-1) && i < (ages.size()-1); ++i)
cout << names[i] << " , " << ages[i] << endl;
}
int main(){
Name_pairs np;
cout << "Enter names and ages. Use 0 to cancel.\n";
bool finished = false;
while(!finished){
finished = "0" == np.read_names();
finished = 0 == np.read_ages();}
np.quicksort(np.names, np.ages, 0, (np.names.size()-2));
np.print();
keep_window_open();
}
(This was listed as an answer in the edits (to the original question) from the OP. It should have been posted as an answer, and I'm reposting it here.)
The following lines in main() should be deleted:
np.vector<string>names; // error possibly here?
np.vector<double>ages;
They already exist as part of instantiating Name_pairs.
Also, remove the parameter names from quicksort since it isn't really necessary and will make your code not function the way you think it should. The names you want to sort are members of Name_pairs. The ones you declared in main() are not the ones you read in with read_names().
EDIT: Actually, it might be easier for you if you declare a single vector with a struct that contains the age and name and sort that array. The entirety of your program implies that you want to sort the names and then print out each name with the associated age, but you only sort the name array.
EDIT2: And from the other answers, I think you need to learn more about how to declare member functions before you can fully solve this problem.
If you don't mind extra memory used but a little higher speed you could use a structure or pair in witch the int is the index in the second vector which you set before you sort.
Or if you don't actually need the vector operator[] and you can just iterate over the elements you could use a map.