I am making a blackjack game and have created an array to act as the hand the user is dealt. I want to be able to sort it so that the hand is sorted in numerical order so it will be simpler to determine what type of hand the user has. Here is my sturct for the cards:
struct ACard{
int num;
const char *pic;
};
I want to sort the array by int num. I have tried to just use a simple insertion sort to complete the sort but I believe I need overload the operator to do so but I'm having trouble doing so as I've never overloaded a struct like this before. Here is what I have for the sort so far:
int i,j;
ACard key;
for(int i = 1; i < 5; i++){
key = userHand[i].num;
j = i - 1;
while(j >= 0 && userHand[j].num > key){
userHand[j + 1] = userHand[j];
j = j - 1;
}
userHand[j + 1] = key;
}
*Note userHand is the array of ACard's that I wish to sort.
With STL containers you can use std::sort function. First two arguments define the range of elements to be sorted. Third argument defines a LessThan function used for your custom elements comparison (you can use lambda expression for that).
std::vector<ACard> userHand; // or another stl container
// initialize userHand somehow
std::sort(userHand.begin(), userHand.end(),
[](const ACard& left, const ACard& right)
{
return left.num < right.num;
});
Related
Suppose, we have a vector of unordered map as vector<unordered_map<char,int>> recordset;;
my code looks like this,
std::vector<string> inputStrings;
for(int i =0;i<6;i++)
{
string tmp;
cin >> tmp;
inputStrings.push_back(tmp);
}
vector<unordered_map<char,int>> recordset;
for(int i=0;i<(int)inputStrings.size();++i)
{
for(int j = 0; j < (int)inputStrings[i].length(); j++)
{
(recordset[i])[(inputStrings[i])[j]]++;
}
}
Which will be the efficient way to sort above vector recordset in ascending order by size of its map elements.
std::sort can take 3rd argument to specify how to order elements. Passing lambda function there should be good way. The function shold return true if 1st argument should be come before 2nd argument and false otherwise.
std::sort(recordset.begin(), recordset.end(),
[](const unordered_map<char,int>& a, const unordered_map<char,int>& b) -> bool {
return a.size() < b.size();
}
);
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.
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.
I have an array of structs where I keep track of how many times each unique word was seen in a given text:
struct List {
char word[20];
int repeat;
};
Now I need to sort this:
as 6
a 1
appetite 1
angry 1
are 2
and 4
...
To this:
a 1
as 6
and 4
are 2
angry 1
appetite 1
...
(By alphabetically I mean only by first letter)
So far, I have come up with this:
for (i = 0; i < length - 1; i++) {
min_pos = i;
for (j = i + 1; j < length; j++) // find min
if (array[j].word[0] < array[min_pos].word[0]) {
min_pos = j;
}
swap = array[min_pos]; // swap
array[min_pos] = array[i];
array[i] = swap;
}
This code works perfectly for sorting alphabetically, but I just can't write proper code to sort BOTH alphabetically and by length.
Make a comparator function.
Add an operator< to your List:
bool operator<(const List &lhs) const {
if(word[0] != lhs.word[0]) {
return word[0] < lhs.word[0];
}
return strlen(word) < strlen(lhs.word);
}
And now use this operator to sort, using whichever algorithm strikes your fancy.
Others have pointed out that there are faster and cleaner ways to sort. But if you want to use your own selection sort, as you've written, then you just need to make a few changes to your code.
Separate the "do I need to swap" logic from the swapping logic itself. Then the code becomes much cleaner and it's more clear where to add the extra check.
I've only copied the inner loop here. You'd want to replace your existing inner loop with this one. I'm not clear on why you need swap_pos and min_pos, so I've left the semantics alone.
for (j = i + 1; j < length; j++) { // find min
// first, determine whether you need to swap
// You want to swap if the first character of the new word is
// smaller, or if the letters are equal and the length is smaller.
bool doSwap = false;
if (array[j].word[0] < array[min_pos].word[0]) {
doSwap = true;
}
else if (array[j].word[0] == array[min_pos].word[0] &&
strlen(array[j].word) < array[min_pos].word) {
doSwap = true;
}
// do the swap if necessary
if (doSwap) {
swap_pos = j;
swap = array[min_pos]; // swap
array[min_pos] = array[i];
array[i] = swap;
}
}
To more clearly illustrate the necessary logic changes, I've purposely avoided making major style changes or simple optimizations.
You can pass a lambda to sort to do this:
sort(begin(array), end(array), [](const auto& lhs, const auto& rhs){ return *lhs.word < *rhs.word || *lhs.word == *rhs.word && (strlen(lhs.word) < strlen(rhs.word) || strlen(lhs.word) == strlen(rhs.word) && strcmp(lhs.word, rhs.word) < 0); });
Live Example
Use tuple lexicographical compare operators
An easy way to not write this condition is to
#include <tuple>
Then std::tie can be used:
std::tie(array[j].word[0], array[j].repeat) < std::tie(array[min_pos].word[0], array[min_pos].repeat)
This works because std::tie creates a tuple of lvalue references to its arguments. (Which means std::tie requires variables. If You want to compare results from functions std::make_tuple or std::forward_as_tuple would be better)
And std::tuple has operators which
Compares lhs and rhs lexicographically, that is, compares the first elements, if they are equivalent, compares the second elements, if those are equivalent, compares the third elements, and so on.
And the above description is also the idea how to make a comparison of more than value.
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).