Skip to content

Commit da8340b

Browse files
committed
Add TagSort algorithm with tests
Tag Sort (Index Sort) creates an array of sorted indices without modifying the original array. Useful when original positions need to be preserved. Time complexity: O(n log n), Space complexity: O(n).
1 parent 7eea9a5 commit da8340b

File tree

2 files changed

+170
-0
lines changed

2 files changed

+170
-0
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package com.thealgorithms.sorts;
2+
3+
import java.util.Arrays;
4+
import java.util.Comparator;
5+
6+
/**
7+
* Tag Sort (also known as Index Sort or Dictionary Sort).
8+
*
9+
* <p>Tag Sort is a sorting technique that does not modify the original array.
10+
* Instead, it creates an array of indices (tags) and sorts those indices based
11+
* on the corresponding values in the original array. This is useful when you
12+
* need to know the original positions of elements after sorting.
13+
*
14+
* <p>Time Complexity: O(n log n)
15+
* Space Complexity: O(n)
16+
*
17+
* @see <a href="https://www.geeksforgeeks.org/tag-sort/">Tag Sort - GeeksForGeeks</a>
18+
*/
19+
public class TagSort implements SortAlgorithm {
20+
21+
/**
22+
* Sorts the given array using Tag Sort.
23+
* Returns the sorted array (copy), leaving the original array unchanged.
24+
*
25+
* @param array the array to be sorted
26+
* @param <T> the type of elements, must be Comparable
27+
* @return a new sorted array
28+
*/
29+
@Override
30+
public <T extends Comparable<T>> T[] sort(final T[] array) {
31+
if (array.length == 0) {
32+
return array;
33+
}
34+
35+
Integer[] tags = createTags(array);
36+
sortTags(tags, array);
37+
38+
@SuppressWarnings("unchecked")
39+
T[] sortedArray = (T[]) new Comparable[array.length];
40+
for (int i = 0; i < array.length; i++) {
41+
sortedArray[i] = array[tags[i]];
42+
}
43+
44+
System.arraycopy(sortedArray, 0, array, 0, array.length);
45+
return array;
46+
}
47+
48+
/**
49+
* Returns the sorted indices (tags) of the given array without modifying it.
50+
*
51+
* @param array the input array
52+
* @param <T> the type of elements, must be Comparable
53+
* @return an array of indices representing the sorted order
54+
*/
55+
public <T extends Comparable<T>> Integer[] getSortedTags(final T[] array) {
56+
Integer[] tags = createTags(array);
57+
sortTags(tags, array);
58+
return tags;
59+
}
60+
61+
private <T extends Comparable<T>> Integer[] createTags(final T[] array) {
62+
Integer[] tags = new Integer[array.length];
63+
for (int i = 0; i < array.length; i++) {
64+
tags[i] = i;
65+
}
66+
return tags;
67+
}
68+
69+
private <T extends Comparable<T>> void sortTags(final Integer[] tags, final T[] array) {
70+
Arrays.sort(tags, Comparator.comparing(i -> array[i]));
71+
}
72+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package com.thealgorithms.sorts;
2+
3+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
4+
5+
import org.junit.jupiter.api.BeforeEach;
6+
import org.junit.jupiter.api.DisplayName;
7+
import org.junit.jupiter.api.Test;
8+
9+
public class TagSortTest {
10+
11+
private TagSort tagSort;
12+
13+
@BeforeEach
14+
public void setUp() {
15+
tagSort = new TagSort();
16+
}
17+
18+
@Test
19+
@DisplayName("TagSort empty array")
20+
public void testEmptyArray() {
21+
Integer[] input = {};
22+
Integer[] result = tagSort.sort(input);
23+
assertArrayEquals(new Integer[] {}, result);
24+
}
25+
26+
@Test
27+
@DisplayName("TagSort single element array")
28+
public void testSingleElement() {
29+
Integer[] input = {42};
30+
Integer[] result = tagSort.sort(input);
31+
assertArrayEquals(new Integer[] {42}, result);
32+
}
33+
34+
@Test
35+
@DisplayName("TagSort non-duplicate integer array")
36+
public void testNonDuplicateIntegers() {
37+
Integer[] input = {5, 3, 8, 1, 9, 2};
38+
Integer[] result = tagSort.sort(input);
39+
assertArrayEquals(new Integer[] {1, 2, 3, 5, 8, 9}, result);
40+
}
41+
42+
@Test
43+
@DisplayName("TagSort integer array with duplicates")
44+
public void testDuplicateIntegers() {
45+
Integer[] input = {4, 2, 7, 2, 4, 1};
46+
Integer[] result = tagSort.sort(input);
47+
assertArrayEquals(new Integer[] {1, 2, 2, 4, 4, 7}, result);
48+
}
49+
50+
@Test
51+
@DisplayName("TagSort negative integers")
52+
public void testNegativeIntegers() {
53+
Integer[] input = {-3, 5, -1, 0, 2, -8};
54+
Integer[] result = tagSort.sort(input);
55+
assertArrayEquals(new Integer[] {-8, -3, -1, 0, 2, 5}, result);
56+
}
57+
58+
@Test
59+
@DisplayName("TagSort already sorted array")
60+
public void testAlreadySorted() {
61+
Integer[] input = {1, 2, 3, 4, 5};
62+
Integer[] result = tagSort.sort(input);
63+
assertArrayEquals(new Integer[] {1, 2, 3, 4, 5}, result);
64+
}
65+
66+
@Test
67+
@DisplayName("TagSort reverse sorted array")
68+
public void testReverseSorted() {
69+
Integer[] input = {5, 4, 3, 2, 1};
70+
Integer[] result = tagSort.sort(input);
71+
assertArrayEquals(new Integer[] {1, 2, 3, 4, 5}, result);
72+
}
73+
74+
@Test
75+
@DisplayName("TagSort string array")
76+
public void testStringArray() {
77+
String[] input = {"banana", "apple", "cherry", "date"};
78+
String[] result = tagSort.sort(input);
79+
assertArrayEquals(new String[] {"apple", "banana", "cherry", "date"}, result);
80+
}
81+
82+
@Test
83+
@DisplayName("TagSort getSortedTags returns correct indices")
84+
public void testGetSortedTags() {
85+
Integer[] input = {30, 10, 20};
86+
Integer[] tags = tagSort.getSortedTags(input);
87+
// index 1 (value 10), index 2 (value 20), index 0 (value 30)
88+
assertArrayEquals(new Integer[] {1, 2, 0}, tags);
89+
}
90+
91+
@Test
92+
@DisplayName("TagSort all equal elements")
93+
public void testAllEqualElements() {
94+
Integer[] input = {7, 7, 7, 7};
95+
Integer[] result = tagSort.sort(input);
96+
assertArrayEquals(new Integer[] {7, 7, 7, 7}, result);
97+
}
98+
}

0 commit comments

Comments
 (0)