Selection Sort on an Array of Objects - c++

Looked around online, but haven't been able to find anything concerning this.
I'm in a C++ introductory class and have a project that is dealing with Arrays of Objects. An object (called media) has a name and a rating. I have three different media objects put into an media object array. I need to find a way to sort them by name. I was given code for selection sort for c-strings, but haven't been able to figure out what exactly to do with this to change it over to dealing with the media objects. Here is my selection sort for the c-strings.
void selectsort(char str[][20], int N)
{
int pass, j, min;
char temp[20];
for (pass = 0; pass <= N - 2; pass++) // passes
{
min = pass;
for (j = pass + 1; j < N; j++) // in each pass
if (strcmp(str[min], str[j]) > 0)
min = j;
strcpy(temp, str[min]);
strcpy(str[min], str[pass]);
strcpy(str[pass], temp);
}
}
I have gotten rid of strcmp by overloading < with
int media::operator<(media med)
{
return strcmp(mname, med.mname);
}
and strcpy by overloading = with
void media::operator=(media med)
{
strcpy(mname, med.mname);
}
I believe that this would return the same results, yes?
So here is my code so far (have just been throwing myself at it non-understanding of how to do it).
void selsort(media mry[], int n) // mry[] is the object array, n is the
// number of objects in the array
{
int pass, j, min;
media temp[1];
for (pass = 0; pass <= n - 2; pass++) // passes
{
min = pass;
for (j = pass + 1; j < n; j++) // in each pass
if ((mry[min] < mry[j]) < 0)
min = j;
temp = mry[min];
mry[min] = mry[pass];
temp = mry[min];
}
}
I understand that there are a lot of flaws in this code. The temp comparison doesn't work and when I try to get it to using *temp or temp[0] (trying everything under the sun over here) I get corrupted data errors. I can't seem to figure it out though. I've always struggled with understanding sorts, and this just adds insult to injury.
(Also please note that some notations might not be correct, but this is what I was taught in this class and what this professor asks that we code in)
Thanks for any help!

There are 2 things wrong with your code:
media temp[1]; Why would you want your temporary media storage for swapping be an array of 1?
The swapping: temp = mry[min]; mry[min] = mry[pass]; temp = mry[min]; See anything wrong with it?
Here is the adjusted function, which BTW works fine:
void selsort(media mry[], int n) // mry[] is the object array, n is the
// number of objects in the array
{
int pass, j, min;
media temp;
for (pass = 0; pass <= n - 2; pass++) // passes
{
min = pass;
for (j = pass + 1; j < n; j++) // in each pass
if ((mry[min] < mry[j]) < 0)
min = j;
temp = mry[min];
mry[min] = mry[pass];
mry[pass] = temp;
}
}

Related

Class Function that Inserts values into a sorted array without ruining the order

So I am really confused on the logic here, I get the general Idea of taking my values in 1 by 1 and comparing them to the elements in the array. If the value is larger move on to the next element, if the value is smaller or equal to the element move over all the elements over 1 index and replace the original index with your value. My problem is I cant get that last part into code and I have been sitting here stooped for half an hour. Here is what I have gotten so far.
void SortedArray::insertVal(int val)
{
//check for size == capacity
// if so, use .Expand function to double array capacity, then continue to below.
//if not continue
//here is where I am having my issues because I cant get the logic down.
for (int i = 0; i < capacity; i++)
{
if (val > arr[i])
arr[i] = arr[i + 1];
else if (val <= arr[i])
{
for (int x = 0; x < capacity; x++)
{
int temp = arr[i+1];
arr[i + 1] = arr[i];
//right about here I realized If I just assign temp to arr[1+2] the value of that index is lost.
}
}
}
}
I am just stooped, I wanted to check here and see if anyone can help before I have to contact my professor for help as a last resort.
Thanks in advance for anything :)
If I understood what you want, reading the array backwards should solve the problem.
for (int i = 0; i < capacity; i++)
{
if (val > arr[i])
{
for(int x = capacity - 1; x > i; x--)
{
arr[x] = arr[x - 1];
}
arr[i] = val;
break;
}
}

Return the index for the maximum value

I have written the following which gets the index value for the maximum number.
int TravellingSalesMan::getMaximum(double *arr){
double temp = arr[0];
int iterator = 0;
for(int i = 0; i < 30; i++){
if(arr[i] > temp){
iterator = i;
}
}
return iterator;
}
But the output keeps stepping into the conditional statement and keeps printing out 29. I am not sure why this is happening
I also tried using max_element() but with no luck
EDIT
The above function is invoked as following
static unsigned int chromosome = 30;
double value[chromosome]
for(int i = 0; i < chromosomes; i++){
value[i] = estimateFitness(currPopultaion[i]);
}
int best = 0;
best = getMaximum(value);
cout<<best<<endl; // this just prints out 29
Okay, so I didn't plan on writing the answer, but I just saw too many logical mistakes in the code for me to write in the comments section!
First of all, your use of the variable name iterator is very
wrong. It's not used for iteration over the list. Why create confusion. Best to use something like max_index or something like that.
Why start from i=0? Your temp value is arr[0], so there is no use. of checking with first element again. Start from i=1!
temp is pointless in that function. The maximum index should initially be 0, and set to i if ever there is some arr[i] that is greater than arr[max_index].
Passing the length separately to the function is better coding as it makes the code more clearer.
The content in arr is not modified, and as such better safe than sorry: make the pointer const.
Re-writing the code, it should be:
int TravellingSalesMan::getMaximum(const double *arr,int len)
{
int max_index = 0;
for(int i = 1; i < len; i++)
{
if(arr[i] > arr[max_index])
max_index = i;
}
return max_index;
}
Worth noting, but unchanged in the code above, len, i, and the function result should all be an unsigned integer type. There is no reason, to allow signed integer indexing, so make it a warning-condition from the caller if they do so by hard-specifying unsigned or just size_t as the indexing variable types.
You should be assigning a new value to temp when you find a new maximum.
int TravellingSalesMan::getMaximum(double *arr){
double temp = arr[0];
int iterator = 0;
for(int i = 0; i < 30; i++){
if(arr[i] > temp){
iterator = i;
temp = arr[i]; // this was missing
}
}
return iterator;
}
Without this you are finding the largest index of a value greater than the value at index zero.
A much better solution is to simply use std::max_element instead. Pointers can be used as iterators in most (if not all) algorithms requiring iterators.
#include <algorithm>
static unsigned int chromosomes = 30;
double value[chromosomes];
for (int i=0; i<chromosomes; ++i) {
value[I] = estimate_fitness(current_population[i]);
}
double *max_elm = std::max_element(&value[0], &value[chromosomes]);
int best = int(max_elm - &value[0]);
std::cout << best << std::endl;

C++ Part of brute-force knapsack

reader,
Well, I think I just got brainfucked a bit.
I'm implementing knapsack, and I thought about I implemented brute-force algorithm like 1 or 2 times ever. So I decided to make another one.
And here's what I chocked in.
Let us decide W is maximum weight, and w(min) is minimal-weighted element we can put in knapsack like k=W/w(min) times. I'm explaining this because you, reader, are better know why I need to ask my question.
Now. If we imagine that we have like 3 types of things we can put in knapsack, and our knapsack can store like 15 units of mass, let's count each unit weight as its number respectively. so we can put like 15 things of 1st type, or 7 things of 2nd type and 1 thing of 1st type. but, combinations like 22222221[7ed] and 12222222[7ed] will mean the same for us. and counting them is a waste of any type of resources we pay for decision. (it's a joke, 'cause bf is a waste if we have a cheaper algorithm, but I'm very interested)
As I guess the type of selections we need to go through all possible combinations is called "Combinations with repetitions". The number of C'(n,k) counts as (n+k-1)!/(n-1)!k!.
(while I typing my message I just spotted a hole in my theory. we will probably need to add an empty, zero-weighted-zero-priced item to hold free space it's probably just increases n by 1)
so, what's the matter.
https://rosettacode.org/wiki/Combinations_with_repetitions
as this problem is well-described up here^ I don't really want to use stack this way, I want to generate variations in single cycle, which is going from i=0 to i<C'(n,k).
so, If I can make it, how it works?
we have
int prices[n]; //appear mystically
int weights[n]; // same as previous and I guess we place (0,0) in both of them.
int W, k; // W initialized by our lord and savior
k = W/min(weights);
int road[k], finalroad[k]; //all 0
int curP = curW = maxP = maxW = 0;
for (int i = 0; i < rCombNumber(n, k); i ++) {
/*guys please help me to know how to generate this mask which is consists of indices from 0 to n (meaning of each element) and k is size of mask.*/
curW = 0;
for (int j = 0; j < k; j ++)
curW += weights[road[j]];
if (curW < W) {
curP = 0;
for (int l = 0; l < k; l ++)
curP += prices[road[l]];
if (curP > maxP) {
maxP = curP;
maxW = curW;
finalroad = road;
}
}
}
mask, road -- is an array of indices, each can be equal from 0 to n; and have to be generated as C'(n,k) (link about it above) from { 0, 1, 2, ... , n } by k elements in each selection (combination with repetitions where order is unimportant)
that's it. prove me wrong or help me. Much thanks in advance _
and yes, of course algorithm will take the hell much time, but it looks like it should work. and I'm very interesting in it.
UPDATE:
what do I miss?
http://pastexen.com/code.php?file=EMcn3F9ceC.txt
The answer was provided by Minoru here https://gist.github.com/Minoru/745a7c19c7fa77702332cf4bd3f80f9e ,
it's enough to increment only the first element, then we count all of the carries, set where we did a carry and count reset value as the maximum of elements to reset and reset with it.
here's my code:
#include <iostream>
using namespace std;
static long FactNaive(int n)
{
long r = 1;
for (int i = 2; i <= n; ++i)
r *= i;
return r;
}
static long long CrNK (long n, long k)
{
long long u, l;
u = FactNaive(n+k-1);
l = FactNaive(k)*FactNaive(n-1);
return u/l;
}
int main()
{
int numberOFchoices=7,kountOfElementsInCombination=4;
int arrayOfSingleCombination[kountOfElementsInCombination] = {0,0,0,0};
int leftmostResetPos = kountOfElementsInCombination;
int resetValue=1;
for (long long iterationCounter = 0; iterationCounter<CrNK(numberOFchoices,kountOfElementsInCombination); iterationCounter++)
{
leftmostResetPos = kountOfElementsInCombination;
if (iterationCounter!=0)
{
arrayOfSingleCombination[kountOfElementsInCombination-1]++;
for (int anotherIterationCounter=kountOfElementsInCombination-1; anotherIterationCounter>0; anotherIterationCounter--)
{
if(arrayOfSingleCombination[anotherIterationCounter]==numberOFchoices)
{
leftmostResetPos = anotherIterationCounter;
arrayOfSingleCombination[anotherIterationCounter-1]++;
}
}
}
if (leftmostResetPos != kountOfElementsInCombination)
{
resetValue = 1;
for (int j = 0; j < leftmostResetPos; j++)
{
if (arrayOfSingleCombination[j] > resetValue)
{
resetValue = arrayOfSingleCombination[j];
}
}
for (int j = leftmostResetPos; j != kountOfElementsInCombination; j++)
{
arrayOfSingleCombination[j] = resetValue;
}
}
for (int j = 0; j<kountOfElementsInCombination; j++)
{
cout<<arrayOfSingleCombination[j]<<" ";
}
cout<<"\n";
}
return 0;
}
thanks a lot, Minoru

Bubble Sort Using Slides instead of swaps

currently I'm being asked to design four sorting algorithms (insertion, shell, selection, and bubble) and I have 3 of the 4 working perfectly; the only one that isn't functioning correctly is the Bubble Sort. Now, I'm well aware of how the normal bubble sort works with using a temp var to swap the two indexes, but the tricky part about this is that it needs to use the array index[0] as a temp instead of a normal temp, which is used in swapping, and slide the lower array variables down to the front of the list and at the end of the pass assign the last index to the temp which is the greatest value.
I've been playing around with this for a while and even tried to look up references but sadly I cannot find anything. I'm hoping that someone else has done this prior and can offer some helpful tips. This is sort of a last resort as I've been modifying and running through the passes with pen and paper to try and find my fatal error. Anyways, my code is as follows...
void BubbleSort(int TheArray[], int size)
{
for (int i = 1; i < size + 1; i++)
{
TheArray[0] = TheArray[i];
for (int j = i + 1; j < size; j++)
{
if (TheArray[j] > TheArray[0])
TheArray[0] = TheArray[j];
else
{
TheArray[j - 1] = TheArray[j];
}
}
TheArray[size- 1] = TheArray[0];
}
}
Thanks for any feedback whatsoever; it's much appreciated.
If I understand the problem statement, I think you're looking for something along these lines :
void BubbleSort(int theArray[], int size)
{
for (int i = 1; i < size + 1; i++)
{
theArray[0] = theArray[1];
for (int j = 1; j <= size + 1 - i; j++)
{
if (theArray[j] > theArray[0])
{
theArray[j-1] = theArray[0];
theArray[0] = theArray[j];
}
else
{
theArray[j - 1] = theArray[j];
}
}
theArray[size-i+1] = theArray[0];
}
}
The piece that you're code was missing, I think, was that once you find a new maximum, you have to put it back in the array before placing the new maximum in theArray[0] storage location (see theArray[j-1] = theArray[0] after the compare). Additionally, the inner loop wants to run one less each time since the last element will be the current max value so you don't want to revisit those array elements. (See for(int j = 1 ; j <= size + 1 - i ; j++))
For completeness, here's the main driver I used to (lightly) test this :
int main()
{
int theArray[] = { 0, 5, 7, 3, 2, 8, 4, 6 };
int size = 7;
BubbleSort(theArray, size);
for (int i = 1; i < size + 1; i++)
cout << theArray[i] << endl;
return 0;
}

c++ counting sort

I tried to write a countingsort, but there's some problem with it.
here's the code:
int *countSort(int* start, int* end, int maxvalue)
{
int *B = new int[(int)(end-start)];
int *C = new int[maxvalue];
for (int i = 0; i < maxvalue; i++)
{
*(C+i) = 0;
}
for (int *i = start; i < end; i++)
{
*(C+*i) += 1;
}
for (int i = 1; i < maxvalue-1 ; i++)
{
*(C+i) += *(C+i-1);
}
for (int *i = end-1; i > start-1; i--)
{
*(B+*(C+(*i))) = *i;
*(C+(*i)) -= 1;
}
return B;
}
In the last loop it throws an exception "Acces violation writing at location: -some ram address-"
Where did I go wrong?
for (int i = 1; i < maxvalue-1 ; i++)
That's the incorrect upper bound. You want to go from 1 to maxvalue.
for (int *i = end-1; i > start-1; i--)
{
*(B+*(C+(*i))) = *i;
*(C+(*i)) -= 1;
}
This loop is also completely incorrect. I don't know what it does, but a brief mental test shows that the first iteration sets the element of B at the index of the value of the last element in the array to the number of times it shows. I guarantee that that is not correct. The last loop should be something like:
int* out = B;
int j=0;
for (int i = 0; i < maxvalue; i++) { //for each value
for(j<C[i]; j++) { //for the number of times its in the source
*out = i; //add it to the output
++out; //in the next open slot
}
}
As a final note, why are you playing with pointers like that?
*(B + i) //is the same as
B[i] //and people will hate you less
*(B+*(C+(*i))) //is the same as
B[C[*i]]
Since you're using C++ anyway, why not simplify the code (dramatically) by using std::vector instead of dynamically allocated arrays (and leaking one in the process)?
std::vector<int>countSort(int* start, int* end, int maxvalue)
{
std::vector<int> B(end-start);
std::vector<int> C(maxvalue);
for (int *i = start; i < end; i++)
++C[*i];
// etc.
Other than that, the logic you're using doesn't make sense to me. I think to get a working result, you're probably best off sitting down with a sheet of paper and working out the steps you need to use. I've left the counting part in place above, because I believe that much is correct. I don't think the rest really is. I'll even give a rather simple hint: once you've done the counting, you can generate B (your result) based only on what you have in C -- you do not need to refer back to the original array at all. The easiest way to do it will normally use a nested loop. Also note that it's probably easier to reserve the space in B and use push_back to put the data in it, rather than setting its initial size.