Using Selection Sort With A Two Dimensional Array

Hey guys,
I know how to use selection sort with a one dimensional array, but I can't figure out how to change it so that it will work with my two dimensional array. My program assignment requires me to write a list of first and last names from a file into a two dimensional array and then sort them by last name using selection sort. I'm also having problems outputting the array so that one row (a first name and a last name) displays on one line. In case anyone needs to know I'm using Visual Studio 2015.
Thanks for any help.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <iostream>
#include <string>
#include <fstream>

using namespace std;

const int ROWS = 50;
const int COLUMNS = 2;

int getData(string, string[ROWS][COLUMNS]);

void selectionSort(string[ROWS][COLUMNS], int);

void displayArray(string[ROWS][COLUMNS], int);

int main()
{
	string fileName;
	string arrayOfName[ROWS][COLUMNS];
	int numberOfNamesInArray = 0;

	cout << "Enter the name of the file: " << endl;
	cin >> fileName;

	numberOfNamesInArray = getData(fileName, arrayOfName);

	selectionSort(arrayOfName, numberOfNamesInArray);

	displayArray(arrayOfName, numberOfNamesInArray);

	return 0;
}

//Opens the user specified file and writes the integers from it to the array.
int getData(string fileName, string arrayOfName[ROWS][COLUMNS])
{
	ifstream inputFile;
	int counter = 0;
	string x, y;

	inputFile.open(fileName.c_str());

	if (inputFile)
	{
		while (inputFile >> x >> y && counter < ROWS)
		{
			arrayOfName[counter][0] = x;
			arrayOfName[counter][1] = y;
			counter++;
		}

		inputFile.close();
	}

	else
	{
		cout << "There was a problem opening the file." << endl;
	}

	return counter;
}


//Sorts names in array by last name 
void selectionSort(string arrayOfName[ROWS][COLUMNS], int numberOfNamesInArray)
{
	int startScan, minIndex;
	string minValue;

	for (startScan = 0; startScan < (numberOfNamesInArray - 1); startScan++)
	{
		minIndex = startScan;
		minValue = arrayOfName[startScan];

		for (int index = startScan + 1; index < numberOfNamesInArray; index++)
		{
			if (arrayOfName[index] < minValue)
			{
				minValue = arrayOfName[index];
				minIndex = index;
			}
		}
		arrayOfName[minIndex] = arrayOfName[startScan];
		arrayOfName[startScan] = minValue;
	}
}


void displayArray(string arrayOfName[ROWS][COLUMNS], int numberOfNamesInArray)
{
	for (int i = 0; i < numberOfNamesInArray; i++)
	{
		for (int j = 0; j < numberOfNamesInArray; j++)
		{
			cout << arrayOfName[i][j] << endl;
		}
	}
}
Whenever you have multi-dimensional data i.e. an object with various attributes like first name, last name, age, gender, IQ, etc it helps to define a custom data type for the object and then there are at least 4 ways you can sort by any one of the attributes, in your case last name:
(a) overloading operator < for the custom data type as this is the default comparator used by std::sort
(b) writing your custom comparator and passing it to std::sort through (i) lambda function, (ii) constructing a function object or (iii) using a named function object. The last 2 methods require a further definition of a comparison struct.
Confusing? Well let's see some actual code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

struct Person
{
    std::string m_firstName;
    std::string m_lastName;
    Person (const std::string& firstName, const std::string& lastName)
        : m_firstName(firstName), m_lastName(lastName){}//member initialization list
    bool operator < (const Person & p)//operator < overload
    {
        return m_lastName < p.m_lastName;
    }
};
std::ostream& operator << (std::ostream& os, const Person& p)
{
    os << p.m_firstName << " " << p.m_lastName << '\n';
    return os;
}
struct customSort // struct for comparison
{
    bool operator ()(const Person& lhs, const Person& rhs)
    {
        return lhs.m_lastName < rhs.m_lastName;
    }
}cS;//named function object

int main()
{
   std::vector<Person> vec {{"John", "Smith"}, {"Jane", "Doe"}, {"Just", "Other"}, {"Some", "Boy"}, {"Some", "Gal"}};
	//uniform initialization using initializer lists

   //std::sort (vec.begin(), vec.end());
   //uses overloaded < operator as default std::sort predicate

   // std::sort(vec.begin(), vec.end(), [](const Person& lhs, const Person& rhs)
//{return lhs.m_lastName < rhs.m_lastName;});
   //uses lambda as std::sort predicate

  // std::sort (vec.begin(), vec.end(), customSort());
   //construct a function object as std::sort predicate;

  // std::sort (vec.begin(), vec.end(), cS);
   //use a named function object as std::sort predicate;

   for (auto& elem : vec){std::cout << elem ;}//can print Person objects directly as operator << is overloaded above
}

In the above program you can un-comment any one of the std::sort(...) statements to see how it works
Last edited on
Heh, I don't suppose you are talking about Gordan Shamblins class? Because I have literally the exact same assignment.
As @gunnerfunner pointed out, the coding would probably be a lot simpler if you had an array of Person objects that you sorted on one attribute (data member), i.e. lastName.

However, let's assume that you want to keep your multi-d array form. (Parallel arrays for firstName[] and lastName[] instead of second indices 0 and 1 would work similarly).

In
void selectionSort(string arrayOfName[ROWS][COLUMNS], int numberOfNamesInArray)
you correctly pass a 2-d array arrayOfName[ROWS][COLUMNS].

Then, however, you revert to 1-d arrays:
minValue = arrayOfName[startScan];
and so on, throughout the rest of your function.
If you keep your array structure (your decision, note) and the sort order is done on the lastname, which I assume is the second item, then this line should be
minValue = arrayOfName[startScan][1];
Note, however, that to do the swaps of both parts of the name later you will also have to store the first name as well, even though it isn't being used for sorting; say, declare a string variable minFirst and
minFirst = arrayOfName[startScan][0];

Check every occurence of arrayOfName in your function and make sure that it has the correct number of [].

In displayArray you don't need the inner j loop - there are only 2 columns, [0] and [1]. Just replace the j loop with
cout << arrayOfName[i][0] << " " << arrayOfName[i][1] <<endl;


I reiterate, this is if you want to keep your 2-d array form (or the equivalent parallel-array form with first names and last names in separate arrays). @gunnerfunner's approach of having arrays of Person objects makes for much simpler code, even if you aren't allowed, or don't want to, follow up his use of the standard library sorting functions.





Last edited on
Thanks gunnerfunner, but unfortunately we can't use std functions for this.

Yes ryovash I am in there!

Thank you lastchance, I understand where I went wrong much better now.
Topic archived. No new replies allowed.