The program should (and does) the following (paraphrased assignment):
There is a catalogue with a list of motorcycles.
They have a
- Name (spaceless string of 20 chars)
- Price (int < 99 999 999)
- Weight (int < 99 999 999)
- Speed (int < 99 999 999)I have to output two lists, the first list is ordered lexicographically by price, speed, weight and then name. The second list is ordered by speed, weight, price and then name. The input is first an integer n, followed by n lines of motorcycles. You have to use mergesort.
An example input:
4 // Name, price, speed, weight
Harley 7000 180 240
Yamaha 3000 150 100
Ford 10000 110 240
Jawa 3000 150 240Output: 4
Yamaha Ford
Jawa Yamaha
Harley Jawa
Ford HarleyThe actual output is outlined, so that the second list always has 21 characters preceding it.
Here is my code:
I read place the inputs into two jagged arrays, and the strings into a separate array. The elements of the first (integer) array are [price, speed, weight, id], and the second (integer) array [speed, weight, price, id]. Since I do not sort the nameList, I need to keep track of which element belongs to which name. I do this using a unique id.
static void Main(string[] args)
{
int n = Convert.ToInt32(Console.ReadLine().Split()[0]);
int[][] motorProperties = new int[n][]; //[price, speed, weight, id]
int[][] motorPropertiesSpeedFirst = new int[n][]; //[speed, weight, price, id]
string[] motorNames = new string[n];
//import inputs
for(int i = 0; i < n; i++)
{
string inputLine = Console.ReadLine();
//Element of motorProperties
int[] temp = new int[4];
//Element of motorPropertiesSpeedFirst
int[] temp2 = new int[4];
motorNames[i] = inputLine.Split()[0];
temp[0] = Convert.ToInt32(inputLine.Split()[1]);
temp[1] = Convert.ToInt32(inputLine.Split()[2]);
temp[2] = Convert.ToInt32(inputLine.Split()[3]);
temp[3] = i; //unique id, so name can be traced after sorting
temp2[0] = temp[1];
temp2[1] = temp[2];
temp2[2] = temp[0];
temp2[3] = i; //unique id, so name can be traced after sorting
motorProperties[i] = temp;
motorPropertiesSpeedFirst[i] = temp2;
}
//Sort arrays using merge sort.
mergeSort(motorProperties, motorNames, 0, motorProperties.Length - 1);
mergeSort(motorPropertiesSpeedFirst, motorNames, 0, motorProperties.Length - 1);
//Gives output in desired form
Console.WriteLine(n);
for(int i = 0; i < n; i++)
{
string name1 = motorNames[motorProperties[i][3]];
string name2 = String.Concat(Enumerable.Repeat(" ", 21 - name1.Length)) + motorNames[motorPropertiesSpeedFirst[i][3]];
Console.WriteLine(name1 + name2);
}
Console.ReadLine();
}
Then for the merge sort logic:
static void mergeSort(int[][] arr, string[] motorNames, int startIndex, int endIndex)
{
if(startIndex < endIndex)
{
int middle = (startIndex + endIndex) / 2;
mergeSort(arr, motorNames, startIndex, middle);
mergeSort(arr, motorNames, middle + 1, endIndex);
merge(arr, motorNames, startIndex, middle, endIndex);
}
}
static void merge(int[][] arr, string[] motorNames, int startIndex, int middle, int endIndex)
{
//This merge sorts creates two arrays of approximately the same size
//Then takes all elements in the main array left of the middle, and puts them into the leftArray
//Likewise, we add all elements from the right of the middle into the rightArray
int lengthLeftArray = middle - startIndex + 1;
int lengthRightArray = endIndex - middle;
//left and right array with extra element for sentinel card
int[][] leftArray = new int[lengthLeftArray + 1][];
int[][] rightArray = new int[lengthRightArray + 1][];
//puts everything before middle into left array, and the rest in right array
for (int i = 0; i < lengthLeftArray; i++)
{
leftArray[i] = arr[startIndex + i];
}
for(int i = 0; i < lengthRightArray; i++)
{
rightArray[i] = arr[middle + i +1];
}
//sentinel cards
leftArray[lengthLeftArray] = new int[] { int.MaxValue};
rightArray[lengthRightArray] = new int[] { int.MaxValue};
int indexLeftArray = 0;
int indexRightArray = 0;
//Compare elements from leftArray and rightArray
//Add the smaller one to the main array.
for(int i = startIndex; i <= endIndex; i++)
{
for(int j = 0; j < 4; j++)
{
if(j < 3)
{
if (leftArray[indexLeftArray][j] < rightArray[indexRightArray][j])
{
arr[i] = leftArray[indexLeftArray];
indexLeftArray++;
break;
}
else if (leftArray[indexLeftArray][j] > rightArray[indexRightArray][j])
{
arr[i] = rightArray[indexRightArray];
indexRightArray++;
break;
}
else
{
continue;
}
}
//Compares how the names of motorcycles should be ordered.
//Since speed, weight, price is the same
else
{
string nameMotor1 = motorNames[leftArray[indexLeftArray][j]];
string nameMotor2 = motorNames[rightArray[indexRightArray][j]];
//if < 0 => motor 1 comes first alphabetically. = 0 => same names. > 0 motor 2 comes first alphabetically.
int test = String.Compare(nameMotor1, nameMotor2 , true);
if(test <= 0)
{
arr[i] = leftArray[indexLeftArray];
indexLeftArray++;
break;
}
else
{
arr[i] = rightArray[indexRightArray];
indexRightArray++;
break;
}
}
}
}
}
My program runs in 8.3 seconds (multiple input tests -dumjudge). Some people have gotten it to run as fast as 3 seconds though. So I'm wondering where my program loses most time, and what changes I could implement to make it run faster.
I was thinking of perhaps using linked list, though I wouldn't be sure how to store multiple integers into one node, and then sorting by it. And I wasn't sure whether that would actually be faster.