Quicksort String Vector Alphabetically - c++

I was having trouble with my code. I pass in an array of strings (names) and I want to do a quick sort and sort them alphabetically. Then, what I would like to do is with my array of years and ages, is swap those values respectively with the values swapped in my names array. However, I'm having trouble trying to implement that.
In the main function, I pass in:
quicksort(names, names[0], names[names.size() - 1]);
And in that code contains
void quicksort(vector<string> &names, string min, string max){
cout << "\n\tSorting names...\n";
int temp = 0,
i = 0;
string lowMin = max,
lowMax = min,
highMin = max,
highMax = min,
pivot;
vector<string> below,
above;
if (min != max){
pivot = (max[i] + min[i]) / 2;
while (temp < names.size()){
if (names[temp] <= pivot){
if (lowMax.compare(names[temp]) < 0){
lowMax = names[temp];
}
if (lowMin.compare(names[temp]) > 0){
lowMin = names[temp];
}
below.push_back(names[temp]);
}
else {
if (highMax.compare(names[temp]) < 0){
highMax = names[temp];
}
if (highMin.compare(names[temp]) > 0){
highMin = names[temp];
}
above.push_back(names[temp]);
}
temp++;
}
if ((below.size() > 1) && (names.size() != below.size())){
quicksort(below, lowMin, lowMax);
}
if ((above.size() > 1) && (names.size() != above.size())){
quicksort(above, highMin, highMax);
}
for (size_t i = 0; i < below.size(); i++){
names[i] = below[i];
}
for (size_t i = below.size(); i < names.size(); i++){
names[i] = above[i - below.size()];
}
}
} // // End quicksort()
In this case, would it be better to make a swap function and send in two integers so I can swap values in my other vector arrays? For example, I was thinking swapValue(int i, int j){ /* do something */}
Also, can someone explain to me the difference between foobar[i].swap(foobar[j]) and swap(foobar[i], foobar[j])? Are these methods more efficient than say creating a temp variable and swapping values?

Don't implement quicksort if you do it only because you need some sorting algorithm to use.
You seem to have three std::vector for name, age and year, where elements at the same position are related. Why not combine everything?
struct Person //or some name
{
std::string name;
int age;
int year;
int operator<(const Person &other) //comparison
{
return name.compare(other.name);
}
};
Of course, you could make a full class with the Big5 etc. too, if you want.
Now, with a vector<Person> v;, you can use std::sort:
std::sort(v.begin(), v.end());
That's all.
...If you still want to have a quicksort function, take eg. this, and change the lines with the swaps so that swaps are made on all three vectors.
About your other question:
The swap of std::string and the independent function swap with string paramters do the same thing (technically they don't have to, they are completely independent, but they do).
And why swap(a,b) is better than c=a;a=b;b=c;:
In the second code, values are copied three times. For std::string, this means three times allocating new memory and copying the whole content. Swap can do it without any content copy (it can access the internal pointers etc. and exchange only these).

Related

Sort Array By Parity the result is not robust

I am a new programmer and I am trying to sort a vector of integers by their parities - put even numbers in front of odds. The order inside of the odd or even numbers themselves doesn't matter. For example, given an input [3,1,2,4], the output can be [2,4,3,1] or [4,2,1,3], etc. Below is my c++ code, sometimes I got luck that the vector gets sorted properly, sometimes it doesn't. I exported the odd and even vectors and they look correct, but when I tried to combine them together it is just messed up. Can someone please help me debug?
class Solution {
public:
vector<int> sortArrayByParity(vector<int>& A) {
unordered_multiset<int> even;
unordered_multiset<int> odd;
vector<int> result(A.size());
for(int C:A)
{
if(C%2 == 0)
even.insert(C);
else
odd.insert(C);
}
merge(even.begin(),even.end(),odd.begin(),odd.end(),result.begin());
return result;
}
};
If you just need even values before odds and not a complete sort I suggest you use std::partition. You give it two iterators and a predicate. The elements where the predicate returns true will appear before the others. It works in-place and should be very fast.
Something like this:
std::vector<int> sortArrayByParity(std::vector<int>& A)
{
std::partition(A.begin(), A.end(), [](int value) { return value % 2 == 0; });
return A;
}
Because the merge function assumes that the two ranges are sorted, which is used as in merge sort. Instead, you should just use the insert function of vector:
result.insert(result.end(), even.begin(), even.end());
result.insert(result.end(), odd.begin(), odd.end());
return result;
There is no need to create three separate vectors. As you have allocated enough space in the result vector, that vector can be used as the final vector also to store your sub vectors, storing the separated odd and even numbers.
The value of using a vector, which under the covers is an array, is to avoid inserts and moves. Arrays/Vectors are fast because they allow immediate access to memory as an offset from the beginning. Take advantage of this!
The code simply keeps an index to the next odd and even indices and then assigns the correct cell accordingly.
class Solution {
public:
// As this function does not access any members, it can be made static
static std::vector<int> sortArrayByParity(std::vector<int>& A) {
std::vector<int> result(A.size());
uint even_index = 0;
uint odd_index = A.size()-1;
for(int element: A)
{
if(element%2 == 0)
result[even_index++] = element;
else
result[odd_index--] = element;
}
return result;
}
};
Taking advantage of the fact that you don't care about the order among the even or odd numbers themselves, you could use a very simple algorithm to sort the array in-place:
// Assume helper function is_even() and is_odd() are defined.
void sortArrayByParity(std::vector<int>& A)
{
int i = 0; // scanning from beginning
int j = A.size()-1; // scanning from end
do {
while (i < j && is_even(A[i])) ++i; // A[i] is an even at the front
while (i < j && is_odd(A[j])) --j; // A[j] is an odd at the back
if (i >= j) break;
// Now A[i] must be an odd number in front of an even number A[j]
std::swap(A[i], A[j]);
++i;
--j;
} while (true);
}
Note that the function above returns void, since the vector is sorted in-place. If you do want to return a sorted copy of input vector, you'd need to define a new vector inside the function, and copy the elements right before every ++i and --j above (and of course do not use std::swap but copy the elements cross-way instead; also, pass A as const std::vector<int>& A).
// Assume helper function is_even() and is_odd() are defined.
std::vector<int> sortArrayByParity(const std::vector<int>& A)
{
std::vector<int> B(A.size());
int i = 0; // scanning from beginning
int j = A.size()-1; // scanning from end
do {
while (i < j && is_even(A[i])) {
B[i] = A[i];
++i;
}
while (i < j && is_odd(A[j])) {
B[j] = A[j];
--j;
}
if (i >= j) break;
// Now A[i] must be an odd number in front of an even number A[j]
B[i] = A[j];
B[j] = A[i];
++i;
--j;
} while (true);
return B;
}
In both cases (in-place or out-of-place) above, the function has complexity O(N), N being number of elements in A, much better than the general O(N log N) for sorting N elements. This is because the problem doesn't actually sort much -- it only separates even from odd. There's therefore no need to invoke a full-fledged sorting algorithm.

Unable to change the elements in an array using a function

I have been working on a project for school to develop a poker game. I have the code that randomly generates the cards, but I am having problems using functions to sort them. I believe the algorithm itself works, but I am not sure about how to properly access the variables in an array. Visual Studio gives me the errors argument of type "int (*)[5] is incompatible with parameter of type int *(*)[5] and 'void sortPokerHand(int *[][5])': cannot convert argument 1 from 'int [2][5]' to 'int *[][5]'.
The declaration of pokerHand within main()
int pokerHand[2][5];
My functions
//swap the two values
void swap(int* pokerHand, int* x, int* y)
{
int tempVal = pokerHand[0][x];
int tempSuit = pokerHand[1][x];
pokerHand[0][x] = pokerHand[0][y];
pokerHand[1][x] = pokerHand[1][y];
pokerHand[0][y] = tempVal;
pokerHand[1][y] = tempSuit;
}
void sortPokerHand(int* pokerHand[2][5])
{
//bubble sort poker hand
bool swapped;
for (int i = 0; i < 4; i++)
{
swapped = false;
for (int j = 0; j < (5 - i - 1); j++)
{
if (pokerHand[0][j] > pokerHand[0][j + 1])
{
swap(pokerHand[2][5], pokerHand[0][j], pokerHand[0][j + 1]);
swapped = true;
}
}
// If no two elements were swapped by inner loop, then break
if (swapped == false)
break;
}
}
How I am attempting to use the function
sortPokerHand(pokerHand);
Thanks for any help
You're making this much, much harder than it should be. Consider the following pre-conditions:
A "hand" is a sequence of five int values
Only cards in a single hand are sorted relative to each other.
Given that, your swap routine is completely wrong. It should take two int by address (so, pointers to int), and use those to swap contents:
void swapInt(int *left, int *right)
{
int tmp = *left;
*left = *right;
*right = tmp;
}
Next, when sorting, we're sorting a single hand. That means a single sequence of five int. Therefore, there is no need to pass arrays of arrays, pointers to arrays, arrays of pointers, or any of that. Just do this, clean and basic:
// assumption: a hand has five cards
void sortPokerHand(int hand[])
{
// bubble sort sequence of int
size_t len = 5;
bool swapped = true;
while (swapped && len-- > 0)
{
swapped = false;
for (size_t i = 0; i < len; ++i)
{
if (hand[i] > hand[i + 1])
{
swapInt(hand + i, hand + i + 1); // note: uses our new swap function
swapped = true;
}
}
}
}
Finally, we need somehands, both needing sorting. For the sake of this example I'm declaring them in main() as inline array of arrays, then making two calls to actually sort them, one at a time. First, however, we need a print function:
void printHand(const int hand[])
{
fputc('{', stdout);
for (size_t i = 0; i < 5; ++i)
printf("%d ", hand[i]);
puts("}");
}
Simple enough. Now main()
int main()
{
int hands[2][5] =
{
{ 5,10,7,4,1 },
{ 3,6,8,2,9 }
};
for (size_t i = 0; i < 2; ++i)
{
sortPokerHand(hands[i]);
printHand(hands[i]);
}
return EXIT_SUCCESS;
}
The output of this program is:
{1 4 5 7 10 }
{2 3 6 8 9 }
Exactly as we expect.
That's it. In more general solutions we would have an arbitrary hand-size an have to ripple that through the sort and print functions to ensure complete and proper activity. Knowing it is statically size five makes that a little easier.
Also note that you can completely change the definition of hands to use pointers-to-arrays rather than arrays of arrays, or even pointers to pointers, and it will still work, so long as the thing going to sortHand and/or printHand is int* pointing to five int values.
The real question would be how you're ending up with something like int *pokerHand[2][5] in the first place.
One of the strengths of C++ is a fairly rich type system. If I were doing this, I'd probably start by defining a type for a card:
class card {
enum { clubs, diamonds, spades, hearts } suit;
int value; // 1-13 = Ace - King
public:
bool operator<(card const &other) {
if (suit < other.suit)
return true;
if (other.suit < suit)
return false;
return value < other. value;
}
};
So, that operator< sorts first by suit, then by value within the suit, so all the cards in the same suit will get sorted together.
From there, a poker hand is typically going to be five cards, so we just have:
std::vector<card> poker_hand;
Sorting the hand is something like:
std::sort(poker_hand.begin(), poker_hand.end());
If you want to write your own sort routine you obviously can, but it still ends up pretty trivial--a single-dimension vector of cards, which you just compare directly, such as:
if (secondCard < firstCard)
swap(secondCard, firstCard);
Change int* pokerHand[2][5] to int** pokerHand.

Count Inversions with merge sort in C++

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.

C++ Adding Elements to a List in Alphabetic Order

I have an array of Students, and I am trying to add another student to the list. I am writing the add method which will add a student to the list in alphabetic order based on their name. All the other elements in the list then will shift accordingly. This is my attempt to write it:
void Array::add(Student* student)
{
if (size == MAX_STUDENTS)
return;
if(size == 0){
students[0] = student;
size ++;
}
if (size != 0){
for(int i = 0; i < MAX_STUDENTS; ++i){
if(students[i]->getName() >= student->getName()){
students[i-1] = student;
size ++;
}
}
}
}
students is an array of pointers to the Student objectStudent** students;it is initialized in the constructor along with size
This however, does not sort the elements. I am guessing my logic is incorrect. I also do not know how to shift the elements down the array. Any help will be highly appreciated.
When shifting items down, start with the last item in the list and work your way up to the insertion point. Should be something along the lines of:
int i;
for (i = size - 1; students[i]->getName() >= student->getName(); i--)
{
students[i+1] = students[i];
}
students[i] = student;
size++;
Better approaches are to have Student implement the < operator and use a std::set or std::priority_queue. Why reinvent the wheel?

How to sort an array in C++ in a specific way

I want somehow sort an array, so that it looks like -
a[0]>=a[1]<=a[2]>=a[3]<=a[4]
I don't know where to start.
Any suggestion would be appreciated!
Sort the entire array (Choose any sort algorithm you wish to). Then take each pair from the beginning and swap the elements in the pair
2,4,1,5,6,3,7,9,8,10
Sorted to : 1,2,3,4,5,6,7,8,9,10
Pair and swap : (2,1),(4,3),(6,5),(8,7),(10,9)
result : 2,1,4,3,6,5,8,7,10,9
Here's the code, obviously you can alter the array length and numbers to meet your specifications.
#include <iostream>
#include <algorithm>
using namespace std;
void special_Sort(int *array, int size){
//doesn't return a value, changes the values inside the array
int temp;
//for swapping purposes
sort(array, array+size);
//sorts the array in ascending order
for(int i=0; i<size; i=i+2){
temp=array[i];
array[i]=array[i+1];
array[i+1]=temp;
}
//array is now sorted
}
int main(){
// array declaration, call the function, etc...
int array[10]={2,4,1,5,6,3,7,9,8,10};
int *pointer;
pointer=&array[0];
special_Sort(pointer, 10);
// if you want to print the result
// for(int i =0; i<10; i++)
// cout<<array[i]<<" ";
return 0;
}
I'm assuming here that the relations are inclusive (in the sense that they continue to the end of the line - a[0]>=max(a[1],a[2],...), and a[1]<=min(a[2],a[3],..) and so on). Otherwise this isn't uniquely defined, as {5,4,3,2,1} can get sorted for example into {5,1,4,3,2} or {3,2,5,1,4}.
So, assuming this is the case, it's easily solved by sorting the entire array in descending order, then just interleave them -
a[0], a[n-1], a[1], a[n-2], ...
and so on. Just loop with two indices, one starting from the beginning and one from the end, or use something like this -
for (i=0; i<n/2; i++) {
result[i*2] = sorted[i];
result[i*2+1] = sorted[n-i];
}
if (n%2)
result[n-1] = sorted[n/2]
If you are only sorting it in a way that you want values to rise and fall arbitrarily, you can achieve this by checking values in your array and swapping elements if they do not satisfy the constraints of your sort.
Don't have a compiler on me at the moment and you'd have to implement the swap but something like this could work:
for(i=0; i < a.length(); i++){
//If index is even
if(i%2 == 0){
if(a[i] < a[i+1]){
swap(a[i], a[i+1]);
}
} else { ///If index is odd
if(a[i]>a[i+1]){
swap(a[i], a[i+1];
}
}
}
I don't disagree with the other answers posted here so you will have to find what you need depending on the relation of the even and odd indexed elements.
Steps taken:
1) generate some random array
2) sort array
3) switch elements as needed with alternate <=, >= comparisons
Here's the code that does that: (disregard the random generator, its just an easy way to generate an array)
#define sizeArr 50
int main(void)
{
int array[sizeArr];
int i, temp;
for(i=0;i<sizeArr;i++)
{
array[i]=randomGenerator(1, 1000);
Sleep(2);//force clock tick for new srand() to be effective in rand() generator
}
//sort array
qsort(array, sizeArr, sizeof(int), cmpfunc);
//pick the first non repeat 90th percent and print
for(i=0;i<sizeArr-1;i++)
{
if(i%2==0)//alternate between >= && <=
{
if(array[i+1] >= array[i])
{
temp = array[i+1];
array[i+1]=array[i];
array[i]=temp;
}
}
else
{
if(array[i+1] <= array[i])
{
temp = array[i+1];
array[i+1]=array[i];
array[i]=temp;
}
}
}
getchar();
return 0;
}
int cmpfunc (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
int randomGenerator(int min, int max)
{
int random=0, trying=0;
trying = 1;
srand(clock());
while(trying)
{
random = (rand()/32767.0)*(max+1);
(random >= min) ? (trying = 0) : (trying = 1);
}
return random;
}