Skip to content

Commit 3f7e4d3

Browse files
authored
Simplify Tim Sort (TheAlgorithms#3780)
1 parent 6c9090f commit 3f7e4d3

File tree

3 files changed

+135
-206
lines changed

3 files changed

+135
-206
lines changed

src/main/java/com/thealgorithms/sorts/InsertionSort.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,15 @@ class InsertionSort implements SortAlgorithm {
1515
*/
1616
@Override
1717
public <T extends Comparable<T>> T[] sort(T[] array) {
18-
for (int i = 1; i < array.length; i++)
19-
for (int j = i; j > 0 && less(array[j], array[j - 1]); j--)
18+
return sort(array, 0, array.length);
19+
}
20+
21+
public <T extends Comparable<T>> T[] sort(T[] array, int lo, int hi) {
22+
for (int i = lo; i < hi; i++) {
23+
for (int j = i; j > lo && less(array[j], array[j - 1]); j--) {
2024
swap(array, j, j - 1);
25+
}
26+
}
2127
return array;
2228
}
2329

Lines changed: 32 additions & 204 deletions
Original file line numberDiff line numberDiff line change
@@ -1,224 +1,52 @@
11
package com.thealgorithms.sorts;
22

3-
import java.util.Random;
3+
import static com.thealgorithms.sorts.SortUtils.less;
44

55
/**
6-
* @author [Hemanth Kotagiri](https://github.com/hemanth-kotagiri)
7-
* @see [Tim Sort](https://en.wikipedia.org/wiki/Tim_sort)
6+
* This is simplified TimSort algorithm implementation. The original one is more complicated.
7+
* <p>
8+
* For more details @see <a href="https://en.wikipedia.org/wiki/Timsort">TimSort Algorithm</a>
89
*/
9-
class TimSort {
10+
class TimSort implements SortAlgorithm {
11+
private static final int SUB_ARRAY_SIZE = 32;
12+
@SuppressWarnings("rawtypes")
13+
private static Comparable[] aux;
1014

11-
int array[];
12-
int array_length;
13-
int RUN = 32;
15+
@Override
16+
public <T extends Comparable<T>> T[] sort(T[] a) {
17+
int n = a.length;
1418

15-
/**
16-
* @brief A constructor which takes in the array specified by the user.
17-
* @param array : Array given by the user.
18-
*/
19-
public TimSort(int[] array) {
20-
this.array = array;
21-
this.array_length = array.length;
22-
}
23-
24-
/**
25-
* @brief A constructor which takes in an array length and randomly
26-
* initializes an array.
27-
* @param array_length length given by the user.
28-
*/
29-
public TimSort(int array_length) {
30-
Random rand = new Random();
31-
32-
this.array_length = array_length;
33-
this.array = new int[this.array_length];
34-
35-
for (int i = 0; i < this.array_length; i++) {
36-
int random_number = rand.nextInt(1000);
37-
this.array[i] = random_number;
19+
InsertionSort insertionSort = new InsertionSort();
20+
for (int i = 0; i < n; i += SUB_ARRAY_SIZE) {
21+
insertionSort.sort(a, i, Math.min(i + SUB_ARRAY_SIZE, n));
3822
}
39-
}
40-
41-
/**
42-
* @brief A method to change the size of the run.
43-
* @param run : Value specified by the user to change the run.
44-
*/
45-
public void change_run(int run) {
46-
this.RUN = run;
47-
}
48-
49-
/**
50-
* @brief A default constructor when no parameters are given. Initializes
51-
* the array length to be 100. Generates a random number array of size 100.
52-
*/
53-
public TimSort() {
54-
this.array_length = 100;
55-
this.array = new int[this.array_length];
56-
57-
Random rand = new Random();
58-
for (int i = 0; i < this.array_length; i++) {
59-
int random_number = rand.nextInt(1000);
60-
this.array[i] = random_number;
61-
}
62-
}
6323

64-
/**
65-
* @brief Performs Insertion Sort Algorithm on given array with bounded
66-
* indices.
67-
* @param array: The array on which the algorithm is to be performed.
68-
* @param start_idx: The starting index from which the algorithm is to be
69-
* performed.
70-
* @param end_idx: The ending index at which the algorithm needs to stop
71-
* sorting.
72-
*/
73-
public void insertion_sort(int[] array, int start_idx, int end_idx) {
74-
for (int i = start_idx; i <= end_idx; i++) {
75-
int current_element = array[i];
76-
int j = i - 1;
77-
while (j >= start_idx && array[j] > current_element) {
78-
array[j + 1] = array[j];
79-
j--;
80-
}
81-
array[j + 1] = current_element;
82-
}
83-
}
84-
85-
/**
86-
* @brief A method to merge two runs(chunks of array).
87-
* @param array: The origin array which is to be sorted.
88-
* @param start: Starting index of the first run(chunk).
89-
* @param mid: The ending index of the first run(chunk).
90-
* @param end: Ending index of the second run(chunk).
91-
*/
92-
public void merge_runs(int array[], int start, int mid, int end) {
93-
int first_array_size = mid - start + 1, second_array_size = end - mid;
94-
int array1[] = new int[first_array_size], array2[] = new int[second_array_size];
95-
int i = 0, j = 0, k = 0;
96-
97-
// Building the two sub arrays from the array to merge later
98-
for (i = 0; i < first_array_size; i++) {
99-
array1[i] = array[start + i];
100-
}
101-
for (i = 0; i < second_array_size; i++) {
102-
array2[i] = array[mid + 1 + i];
103-
}
104-
105-
i = 0;
106-
j = 0;
107-
k = start;
108-
109-
while (i < first_array_size && j < second_array_size) {
110-
if (array1[i] <= array2[j]) {
111-
array[k] = array1[i];
112-
i++;
113-
} else {
114-
array[k] = array2[j];
115-
j++;
24+
aux = new Comparable[n];
25+
for (int sz = SUB_ARRAY_SIZE; sz < n; sz = sz + sz) {
26+
for (int lo = 0; lo < n - sz; lo += sz + sz) {
27+
merge(a, lo, lo + sz - 1, Math.min(lo + sz + sz - 1, n - 1));
11628
}
117-
k++;
11829
}
11930

120-
while (i < first_array_size) {
121-
array[k] = array1[i];
122-
k++;
123-
i++;
124-
}
125-
126-
while (j < second_array_size) {
127-
array[k] = array2[j];
128-
k++;
129-
j++;
130-
}
31+
return a;
13132
}
13233

133-
/**
134-
* @brief Tim Sort Algorithm method.
135-
*/
136-
public void algorithm() {
137-
// Before Sorting
138-
System.out.println("Before sorting the array: ");
139-
this.showArrayElements();
140-
System.out.println();
141-
142-
// Applying insertion sort on RUNS.
143-
for (int i = 0; i < this.array_length; i += this.RUN) {
144-
this.insertion_sort(
145-
this.array,
146-
i,
147-
Math.min(i + this.RUN, (this.array_length - 1))
148-
);
149-
}
150-
151-
for (
152-
int split = this.RUN;
153-
split < this.array_length;
154-
split = 2 * split
155-
) {
156-
for (
157-
int start_idx = 0;
158-
start_idx < this.array_length;
159-
start_idx += 2 * split
160-
) {
161-
int mid = start_idx + split - 1;
162-
int end_idx = Math.min(
163-
(start_idx + 2 * split - 1),
164-
(this.array_length - 1)
165-
);
34+
@SuppressWarnings("unchecked")
35+
private static <T extends Comparable<T>> void merge(T[] a, int lo, int mid, int hi) {
36+
int i = lo, j = mid + 1;
37+
System.arraycopy(a, lo, aux, lo, hi + 1 - lo);
16638

167-
this.merge_runs(this.array, start_idx, mid, end_idx);
39+
for (int k = lo; k <= hi; k++) {
40+
if (j > hi) {
41+
a[k] = (T) aux[i++];
42+
} else if (i > mid) {
43+
a[k] = (T) aux[j++];
44+
} else if (less(aux[j], aux[i])) {
45+
a[k] = (T) aux[j++];
46+
} else {
47+
a[k] = (T) aux[i++];
16848
}
16949
}
170-
// After sorting
171-
System.out.println("After sorting the array: ");
172-
this.showArrayElements();
173-
System.out.println();
174-
}
175-
176-
/**
177-
* @brief A method to show the elements inside the array.
178-
*/
179-
public void showArrayElements() {
180-
for (int i = 0; i < this.array.length; i++) {
181-
System.out.print(this.array[i] + " ");
182-
}
183-
System.out.println();
18450
}
18551

186-
/**
187-
* @brief A method to test the sorting algorithm
188-
*/
189-
static void test() {
190-
int[] array = { 4, 1, 3, 17, 12, 11, 8 };
191-
TimSort sorterObj1 = new TimSort();
192-
TimSort sorterObj2 = new TimSort(50);
193-
TimSort sorterObj3 = new TimSort(array);
194-
195-
sorterObj1.algorithm();
196-
sorterObj2.algorithm();
197-
sorterObj3.algorithm();
198-
199-
// Testing the first array
200-
for (int i = 0; i < sorterObj1.array_length - 1; i++) {
201-
assert (
202-
(sorterObj1.array[i] <= sorterObj1.array[i + 1])
203-
) : "Array is not sorted";
204-
}
205-
206-
// Testing the second array.
207-
for (int i = 0; i < sorterObj2.array_length - 1; i++) {
208-
assert (
209-
(sorterObj2.array[i] <= sorterObj2.array[i + 1])
210-
) : "Array is not sorted";
211-
}
212-
213-
// Testing the third array.
214-
for (int i = 0; i < sorterObj3.array_length - 1; i++) {
215-
assert (
216-
(sorterObj3.array[i] <= sorterObj3.array[i + 1])
217-
) : "Array is not sorted";
218-
}
219-
}
220-
221-
public static void main(String[] args) {
222-
test();
223-
}
22452
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package com.thealgorithms.sorts;
2+
3+
import org.junit.jupiter.api.BeforeEach;
4+
import org.junit.jupiter.api.Test;
5+
6+
import static org.junit.jupiter.api.Assertions.*;
7+
8+
class TimSortTest {
9+
10+
private TimSort timSort;
11+
12+
@BeforeEach
13+
void setUp() {
14+
timSort = new TimSort();
15+
}
16+
17+
@Test
18+
void shouldAcceptWhenEmptyArrayIsPassed() {
19+
Integer [] array = new Integer[]{};
20+
Integer [] expected = new Integer[]{};
21+
22+
Integer []sorted = timSort.sort(array);
23+
24+
assertArrayEquals(expected, sorted);
25+
}
26+
27+
@Test
28+
void shouldAcceptWhenSingleValuedArrayIsPassed() {
29+
Integer [] array = new Integer[]{2};
30+
Integer [] expected = new Integer[]{2};
31+
32+
Integer [] sorted = timSort.sort(array);
33+
34+
assertArrayEquals(expected, sorted);
35+
}
36+
37+
@Test
38+
void shouldAcceptWhenArrayWithAllPositiveValuesIsPassed() {
39+
Integer [] array = new Integer[]{60, 7, 55, 9, 999, 3};
40+
Integer [] expected = new Integer[]{3, 7, 9, 55, 60, 999};
41+
42+
Integer [] sorted = timSort.sort(array);
43+
44+
assertArrayEquals(expected, sorted);
45+
}
46+
47+
@Test
48+
void shouldAcceptWhenArrayWithAllNegativeValuesIsPassed() {
49+
Integer [] array = new Integer[]{-60, -7, -55, -9, -999, -3};
50+
Integer [] expected = new Integer[]{-999, -60, -55, -9, -7, -3};
51+
52+
Integer [] sorted = timSort.sort(array);
53+
54+
assertArrayEquals(expected, sorted);
55+
}
56+
57+
@Test
58+
void shouldAcceptWhenArrayWithRealNumberValuesIsPassed() {
59+
Integer [] array = new Integer[]{60, -7, 55, 9, -999, -3};
60+
Integer [] expected = new Integer[]{-999, -7, -3, 9, 55, 60};
61+
62+
Integer [] sorted = timSort.sort(array);
63+
64+
assertArrayEquals(expected, sorted);
65+
}
66+
67+
@Test
68+
void shouldAcceptWhenArrayWithDuplicateValueIsPassed() {
69+
Integer [] array = new Integer[]{60, 7, 55, 55, 999, 3};
70+
Integer [] expected = new Integer[]{3, 7, 55, 55, 60, 999};
71+
72+
Integer [] sorted = timSort.sort(array);
73+
74+
assertArrayEquals(expected, sorted);
75+
}
76+
77+
@Test
78+
void shouldAcceptWhenStringValueArrayIsPassed() {
79+
String[] array = {"z", "a", "x", "b", "y"};
80+
String[] expected = {"a", "b", "x", "y", "z"};
81+
82+
String[] sorted = timSort.sort(array);
83+
84+
assertArrayEquals(expected, sorted);
85+
}
86+
87+
@Test
88+
void shouldAcceptWhenRandomArrayIsPassed() {
89+
int randomSize = SortUtilsRandomGenerator.generateInt(10_000);
90+
Double[] array = SortUtilsRandomGenerator.generateArray(randomSize);
91+
Double[] sorted = timSort.sort(array);
92+
assertTrue(SortUtils.isSorted(sorted));
93+
}
94+
95+
}

0 commit comments

Comments
 (0)