diff --git a/src/main/java/com/thealgorithms/sorts/TagSort.java b/src/main/java/com/thealgorithms/sorts/TagSort.java
new file mode 100644
index 000000000000..2f7d890eb6a9
--- /dev/null
+++ b/src/main/java/com/thealgorithms/sorts/TagSort.java
@@ -0,0 +1,72 @@
+package com.thealgorithms.sorts;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * Tag Sort (also known as Index Sort or Dictionary Sort).
+ *
+ *
Tag Sort is a sorting technique that does not modify the original array.
+ * Instead, it creates an array of indices (tags) and sorts those indices based
+ * on the corresponding values in the original array. This is useful when you
+ * need to know the original positions of elements after sorting.
+ *
+ *
Time Complexity: O(n log n)
+ * Space Complexity: O(n)
+ *
+ * @see Tag Sort - GeeksForGeeks
+ */
+public class TagSort implements SortAlgorithm {
+
+ /**
+ * Sorts the given array using Tag Sort.
+ * Returns the sorted array (copy), leaving the original array unchanged.
+ *
+ * @param array the array to be sorted
+ * @param the type of elements, must be Comparable
+ * @return a new sorted array
+ */
+ @Override
+ public > T[] sort(final T[] array) {
+ if (array.length == 0) {
+ return array;
+ }
+
+ Integer[] tags = createTags(array);
+ sortTags(tags, array);
+
+ @SuppressWarnings("unchecked")
+ T[] sortedArray = (T[]) new Comparable[array.length];
+ for (int i = 0; i < array.length; i++) {
+ sortedArray[i] = array[tags[i]];
+ }
+
+ System.arraycopy(sortedArray, 0, array, 0, array.length);
+ return array;
+ }
+
+ /**
+ * Returns the sorted indices (tags) of the given array without modifying it.
+ *
+ * @param array the input array
+ * @param the type of elements, must be Comparable
+ * @return an array of indices representing the sorted order
+ */
+ public > Integer[] getSortedTags(final T[] array) {
+ Integer[] tags = createTags(array);
+ sortTags(tags, array);
+ return tags;
+ }
+
+ private > Integer[] createTags(final T[] array) {
+ Integer[] tags = new Integer[array.length];
+ for (int i = 0; i < array.length; i++) {
+ tags[i] = i;
+ }
+ return tags;
+ }
+
+ private > void sortTags(final Integer[] tags, final T[] array) {
+ Arrays.sort(tags, Comparator.comparing(i -> array[i]));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/sorts/TagSortTest.java b/src/test/java/com/thealgorithms/sorts/TagSortTest.java
new file mode 100644
index 000000000000..f66ad46dcc53
--- /dev/null
+++ b/src/test/java/com/thealgorithms/sorts/TagSortTest.java
@@ -0,0 +1,98 @@
+package com.thealgorithms.sorts;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+public class TagSortTest {
+
+ private TagSort tagSort;
+
+ @BeforeEach
+ public void setUp() {
+ tagSort = new TagSort();
+ }
+
+ @Test
+ @DisplayName("TagSort empty array")
+ public void testEmptyArray() {
+ Integer[] input = {};
+ Integer[] result = tagSort.sort(input);
+ assertArrayEquals(new Integer[] {}, result);
+ }
+
+ @Test
+ @DisplayName("TagSort single element array")
+ public void testSingleElement() {
+ Integer[] input = {42};
+ Integer[] result = tagSort.sort(input);
+ assertArrayEquals(new Integer[] {42}, result);
+ }
+
+ @Test
+ @DisplayName("TagSort non-duplicate integer array")
+ public void testNonDuplicateIntegers() {
+ Integer[] input = {5, 3, 8, 1, 9, 2};
+ Integer[] result = tagSort.sort(input);
+ assertArrayEquals(new Integer[] {1, 2, 3, 5, 8, 9}, result);
+ }
+
+ @Test
+ @DisplayName("TagSort integer array with duplicates")
+ public void testDuplicateIntegers() {
+ Integer[] input = {4, 2, 7, 2, 4, 1};
+ Integer[] result = tagSort.sort(input);
+ assertArrayEquals(new Integer[] {1, 2, 2, 4, 4, 7}, result);
+ }
+
+ @Test
+ @DisplayName("TagSort negative integers")
+ public void testNegativeIntegers() {
+ Integer[] input = {-3, 5, -1, 0, 2, -8};
+ Integer[] result = tagSort.sort(input);
+ assertArrayEquals(new Integer[] {-8, -3, -1, 0, 2, 5}, result);
+ }
+
+ @Test
+ @DisplayName("TagSort already sorted array")
+ public void testAlreadySorted() {
+ Integer[] input = {1, 2, 3, 4, 5};
+ Integer[] result = tagSort.sort(input);
+ assertArrayEquals(new Integer[] {1, 2, 3, 4, 5}, result);
+ }
+
+ @Test
+ @DisplayName("TagSort reverse sorted array")
+ public void testReverseSorted() {
+ Integer[] input = {5, 4, 3, 2, 1};
+ Integer[] result = tagSort.sort(input);
+ assertArrayEquals(new Integer[] {1, 2, 3, 4, 5}, result);
+ }
+
+ @Test
+ @DisplayName("TagSort string array")
+ public void testStringArray() {
+ String[] input = {"banana", "apple", "cherry", "date"};
+ String[] result = tagSort.sort(input);
+ assertArrayEquals(new String[] {"apple", "banana", "cherry", "date"}, result);
+ }
+
+ @Test
+ @DisplayName("TagSort getSortedTags returns correct indices")
+ public void testGetSortedTags() {
+ Integer[] input = {30, 10, 20};
+ Integer[] tags = tagSort.getSortedTags(input);
+ // index 1 (value 10), index 2 (value 20), index 0 (value 30)
+ assertArrayEquals(new Integer[] {1, 2, 0}, tags);
+ }
+
+ @Test
+ @DisplayName("TagSort all equal elements")
+ public void testAllEqualElements() {
+ Integer[] input = {7, 7, 7, 7};
+ Integer[] result = tagSort.sort(input);
+ assertArrayEquals(new Integer[] {7, 7, 7, 7}, result);
+ }
+}