How do i "connect" array elements with other variables? - c++

So, I got this project that my teacher gave me and im pretty new so I came accross a little problem. Basically, I need to input a few citites and their population, and I need to output them in order from the one with the most people to the one with least people in it. I used structures to store information about each city and now I don't know how can I sort of "connect" population to each city if you know what I mean. Thank you!
This is what it looks like, and to people that didn't understand the question, I got the city population and sorted it from the highest to the lowest, and now I want to display the name of the city with it's population next to it but I don't know how can I now add them together.
struct city
{
string name;
int population;
}cityVar[10];
int main()
{
// Input
for (int i = 0; i < 5; i++)
{
cin >> cityVar[i].name;
cin >> cityVar[i].population;
}
int i, j;
int temp;
for (i = 0; i < 5; i++)
{
for (j = i + 1; j < 5; j++)
{
if (cityVar[i].population < cityVar[j].population)
{
temp = cityVar[i].population;
cityVar[i].population = cityVar[j].population;
cityVar[j].population = temp;
}
}
}
for (i = 0; i < 5; i++)
{
cout << cityVar[i].population << " ";
}
}

You do not connect two variables. You group them together when they belong to the same concept.
In this specific case I suggest you to create an abstraction for a city by creating a struct, and instruct it on how to to compare itself to other cities based solely (in this case) on the population.
You can do this by implementing the operator<
struct city{
unsigned population
bool operator<(const city& c1){
return this.population < c1.population;
}
};
You can then add your element into an array or even better a std::vector and sort them using std::sort.
Since this sounds like an homework, I will leave the rest to you. You should be able to continue on your own from here.

You lost the "connection" because you only swapped the populations when you should have swapped the entire cities:
city temp = cityVar[i];
cityVar[i] = cityVar[j];
cityVar[j] = temp;
Or, as we often write it
std::swap(cityVar[i], cityVar[j]);

You need to swap the full object, there are many ways to do this but depending on what you've been taught you'll need to be careful of which method you use. This is by no means an exhaustive list, I've only shown the simplest I can think of....
The simplest method (but requires another two lines) and depends on the data structure, so use a temp city instead of a temp int.
struct city temp;
:
:
:
if (cityVar[i].population < cityVar[j].population)
{
temp.population = cityVar[i].population;
temp.name = cityVar[i].name;
cityVar[i].population = cityVar[j].population;
cityVar[i].name = cityVar[j].name;
cityVar[j].population = temp.population;
cityVar[j].name = temp.name;
}
Another method would be to use a list of pointers for the sorted list
int main()
{
struct city *cityVarSorted[10];
for (int i = 0; i < 5; i++) // initialise list to point to current structs
{
cityVarSorted[i] = &cityVar[i];
}
:
:
struct city *temp;
:
if (cityVarSorted[i]->population < cityVarSorted[j]->population)
{
temp = cityVarSorted[i]; // we're swapping the pointer now and not the individual members
cityVarSorted[i] = cityVarSorted[j];
cityVarSorted[j] = temp;
}
}
of course that's if you've been taught pointers. You need to know how it works so you are able to explain it

Related

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.

Quicksort String Vector Alphabetically

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).

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 apply a sort function to a string.find( ) to print results alphabetically?

I have a program that reads a text file into a struct (members- str author and str title) and gives the user the option to display all records in the file, search for an author, or search for a title. Now I need to integrate a sort function into this process, so that when the user searches by author or title the results are listed alphabetically.
The following sort function works perfectly with my showAll function, but I have absolutely no idea how I can modify my search functions to alphabetize the results.
Sort function code:
void sortByTitle(int counter){
//variable
int a, b, minIndex;
string temp;
for (a = 0; a < counter; a++){
minIndex = a;
for (b = a + 1; b < counter - 1; b++){
if (books[b].title < books[minIndex].title){
minIndex = b;
}
}
if(minIndex != a) {
temp = books[a].title;
books[a].title = books[minIndex].title;
books[minIndex].title = temp;
cout << books[a].title << endl;
}
}
}
And this is my current title search function:
int showBooksByTitle(int counter, string bookTitle){
int recordCount = 0;
//find the user-input string inside bookTitle
for (int a = 0; a < counter; a++){ //loop through the whole file
if (books[a].title.find(bookTitle) != string::npos){
//print a matching record
cout << books[a].title << " " << "(" << books[a].author << endl;
//keep track of the number of matching records
recordCount++;
}
}
return recordCount;
}
My assignment specifies these function headers, that the search functions return the number of records found, and that the data be read into a struct (rather than a vector). So I have to leave those aspects as they are.
How can I apply the selection sort to the search function so that I can print the records in order?
Any help would be much appreciated!
Here you set
smallestIndex = index;
then you check if
books[index].title < books[smallestIndex].title
It appears you are trying to implement a selection sort. A good snippet can be found here.
Furhtermore:
I don't see the need for declaring loc outside the for-loop. say for(int loc....
There is an abundance of sorting algorithms on wikipedia and you can use std::sort.
In the second line you shadow index with the same variable in the
for-loop.
I don't know how you store books, but if you would use std::vector you don't have to pass counter every time. You can just use books.size().

Initializer is overwriting second array

I cannot solve this, I'm almost accepting the fact that it might be a memory issue with my machine at this point.
I have this initializer:
Search::Search(ifstream& inFile)
{
int id = 0;
int i = 0;
inFile >> id;
while (inFile) {
if(i < SEARCH_DATA_SIZE) {
SearchDataFirst[i] = id;
SearchDataFirstSorted[i] = id;
} else if(i >= SEARCH_DATA_SIZE) {
SearchDataLast[i] = id;
SearchDataLastSorted[i] = id;
}
i++;
inFile >> id;
}
}
And in my header i have private data like so:
const int SEARCH_DATA_SIZE = 20;
int SearchDataFirst[SEARCH_DATA_SIZE];
int SearchDataLast[SEARCH_DATA_SIZE];
int SearchDataFirstSorted[SEARCH_DATA_SIZE];
int SearchDataLastSorted[SEARCH_DATA_SIZE];
The initializer is getting the first 20 ints from inFile, storing them, and then going to the next records and storing those in separate arrays,
When I do a print of the arrays, SearchDataFirstSorted has the values of SearchDataLast, even though there is no possible way ever that this could happen. SearchDataLastSorted has weird funky numbers.
SearchedDataFirst is fine.
I have never been this frustrated with a programming language.
Hopefully you can help.
There is nothing else going on, only the initializer is being called at this point.
The problem is that if i >= SEARCH_DATA_SIZE, then SearchDataLast[i] is pointing outside SearchDataLast! What you really need is something like this:
for(int i = 0; i < SEARCH_DATA_SIZE; ++i)
{
inFile >> id;
SearchDataFirst[i] = id;
SearchDataFirstSorted[i] = id;
}
for(int i = 0; i < SEARCH_DATA_SIZE; ++i)
{
inFile >> id;
SearchDataLast[i] = id;
SearchDataLastSorted[i] = id;
}
That is, you need to reset i back to zero after you're done populating SearchDataFirst and before you start populating SearchDataLast.
Your logic doesn't make any sense. The best I can figure, you're trying to do something like this:
} else if(i >= SEARCH_DATA_SIZE) {
SearchDataLast[i - SEARCH_DATA_SIZE] = id;
SearchDataLastSorted[i - SEARCH_DATA_SIZE] = id;
}
in its current form every single element you try to write to in SearchDataLast and SearchDataLastSorted is beyond the array bounds (which does indeed lead to memory corruption).
Your problem is here:
else if(i >= SEARCH_DATA_SIZE) {
SearchDataLast[i] = id;
SearchDataLastSorted[i] = id;
}
You're going past the bounds of SearchDataLast and SearchDataLastSorted, since they're of size SEARCH_DATA_SIZE and i is greater than or equal to that amount. What you probably want is i - SEARCH_DATA_SIZE as the indexes.
Because of this you're causing undefined behaviour, where in your case the compiler has allocated memory for each of the arrays in order. So you're basically skipping SEARCH_DATA_SIZE elements in SearchDataLast, and storing the values you want there in SearchDataFirstSorted.
You don't ensure that you don't overrun the SearchDataLast and SearchDataLastSorted arrays.
When i gets beyond SEARCH_DATA_SIZE, you switch arrays, ...but... you continue indexing from SEARCH_DATA_SIZE which is bigger than the SearchDataLast array.
Presumably, you intended to write something like:
else if (i >= SEARCH_DATA_SIZE)
{
SearchDataLast[i-SEARCH_DATA_SIZE] = id;
SearchDataLastSorted[i-SEARCH_DATA_SIZE] = id;
}
You would still need to ensure that you do not overflow the end of these arrays (by ensuring that i is not 2 * SEARCH_DATA_SIZE or larger.