Advantages
A very good characteristic of your algorithm is that it iterates through the elements of the array only once.
The next loop begins from where the previous one left the iterator i
.
Disadvantages
However, as it was mentioned in the other 2 answers until now, your code does not take into consideration the case of arrays with 0 or 1 elements.
Moreover, it is not covering the case that all the elements of the array are equal (e.g. [5,5,5,5,5]).
Another disadvantage is that the loop for ascending and the loop for descending are almost duplicated, with the difference of the direction of the inequality sign.
Additionally, I would say that it's not a good practice to return from inside a loop, especially when there are more than one loops in the same method.
It's preferable to declare a variable that will hold the returning value, use break/continue in the loops and then return the value of the variable, only once at the end of the method.
As a last point to highlight, when it's possible, I personally prefer using an external value that walks the values of the array rather than manipulating the iterator.
In this case the iterator and the walking variable are of type int
, so, the memory footprint is the same.
In a different case that the array would contain large objects, then it would be better to access random elements of the array by index, rather than copying and creating instances of that class.
Solution
For brevity and for maintainability reasons, I would choose a slightly different approach to solve this problem.
Checking if the first element is bigger than the last, we can safely assume that the array would be sorted descending (or ascending respectively).
So, in a single iteration, I wrote a loop that examines every element in the array, if it complies with the ascending or descending order that was deducted at the beginning.
In order to achieve that a variable that is walking the values of the array is used edge
.
public class Sorted {
public static boolean isSorted(int[] arr) {
boolean isSorted = true;
// zero length and 1 length arrays can be
// considered already sorted by default
if (arr.length > 1) {
// keep the first value as an edge
int edge = arr[0];
// if the array is sorted then it should be either ascending(true)
// or descending(false)
boolean ascending = arr[0] <= arr[arr.length-1];
for (int a : arr) {
// check if the relation between the edge and the current element
// complies with ascending or descending
if ((ascending == (edge < a))
|| edge == a) {
edge = a;
} else {
isSorted = false;
break;
}
}
}
return isSorted;
}
}
In order to test the above code I wrote the below test cases:
public static void main(String[] args) {
Assert.assertTrue(isSorted(new int[]{}));
Assert.assertTrue(isSorted(new int[]{1}));
Assert.assertTrue(isSorted(new int[]{0,1}));
Assert.assertTrue(isSorted(new int[]{1,2,3,4,5}));
Assert.assertTrue(isSorted(new int[]{2,2,3,4,5}));
Assert.assertTrue(isSorted(new int[]{2,2,2,2,2}));
Assert.assertTrue(isSorted(new int[]{1,0}));
Assert.assertTrue(isSorted(new int[]{5,4,3,2,1}));
Assert.assertTrue(isSorted(new int[]{5,4,3,2,2}));
Assert.assertTrue(isSorted(new int[]{5,4,4,4,4}));
Assert.assertFalse(isSorted(new int[]{1,2,3,4,1}));
Assert.assertFalse(isSorted(new int[]{5,3,1,2,4}));
Assert.assertFalse(isSorted(new int[]{5,4,3,2,4}));
Assert.assertTrue(isSorted(new int[]{5,3,3,3,1}));
Assert.assertTrue(isSorted(new int[]{5,5,3,3,1}));
Assert.assertTrue(isSorted(new int[]{15,11,11,3,3,3,1}));
}
Additional remarks
We should always have in mind that when importing libraries to do part of the work, we should be very careful because we may introduce performance penalties.
If the library can do exactly what we want, with some configuration, then we should prefer doing it using the library, because someone has already worked to tune the implemented algorithm.