Skip to content

Commit a3cceb1

Browse files
committed
feat: add LibrarySort implementation
1 parent b3fcb12 commit a3cceb1

2 files changed

Lines changed: 177 additions & 0 deletions

File tree

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package com.thealgorithms.sorts;
2+
// author: Vraj Prajapati @Rosander0
3+
4+
import java.util.Arrays;
5+
6+
/**
7+
* Library Sort (also known as Gapped Insertion Sort) is a sorting algorithm
8+
* that works like insertion sort but leaves gaps between elements to make
9+
* future insertions faster.
10+
* Time Complexity: O(n log n) average case
11+
* Space Complexity: O(n)
12+
*
13+
* @see <a href="https://en.wikipedia.org/wiki/Library_sort">
14+
* Wikipedia: Library Sort</a>
15+
*/
16+
public final class LibrarySort {
17+
18+
private LibrarySort() {
19+
// Utility class
20+
}
21+
22+
/**
23+
* Sorts an array using the Library Sort algorithm.
24+
*
25+
* @param array the array to sort (must not be null)
26+
* @return the sorted array
27+
*/
28+
public static int[] sort(final int[] array) {
29+
if (array == null) {
30+
throw new IllegalArgumentException("Input array must not be null!");
31+
}
32+
if (array.length <= 1) {
33+
return array;
34+
}
35+
36+
int n = array.length;
37+
int gapSize = 1;
38+
int[] library = new int[2 * n];
39+
boolean[] occupied = new boolean[2 * n];
40+
Arrays.fill(library, Integer.MAX_VALUE);
41+
42+
// Insert first element
43+
library[0] = array[0];
44+
occupied[0] = true;
45+
int occupiedCount = 1;
46+
47+
for (int i = 1; i < n; i++) {
48+
// Find insertion position using binary search
49+
int pos = binarySearch(library, occupied, array[i]);
50+
51+
// Shift elements to make room
52+
if (occupied[pos]) {
53+
// Find next free space
54+
int free = pos;
55+
while (free < 2 * n && occupied[free]) {
56+
free++;
57+
}
58+
if (free >= 2 * n) {
59+
// Rebalance if no space found
60+
rebalance(library, occupied, n);
61+
pos = binarySearch(library, occupied, array[i]);
62+
free = pos;
63+
while (free < 2 * n && occupied[free]) {
64+
free++;
65+
}
66+
}
67+
// Shift right to create gap
68+
for (int j = free; j > pos; j--) {
69+
library[j] = library[j - 1];
70+
occupied[j] = occupied[j - 1];
71+
}
72+
}
73+
library[pos] = array[i];
74+
occupied[pos] = true;
75+
occupiedCount++;
76+
gapSize++;
77+
}
78+
79+
// Collect sorted elements
80+
int idx = 0;
81+
for (int i = 0; i < 2 * n; i++) {
82+
if (occupied[i]) {
83+
array[idx++] = library[i];
84+
}
85+
}
86+
return array;
87+
}
88+
89+
/**
90+
* Binary search to find insertion position in the library array.
91+
*/
92+
private static int binarySearch(final int[] library, final boolean[] occupied, final int target) {
93+
int lo = 0;
94+
int hi = library.length - 1;
95+
while (lo < hi) {
96+
int mid = lo + (hi - lo) / 2;
97+
if (library[mid] <= target) {
98+
lo = mid + 1;
99+
} else {
100+
hi = mid;
101+
}
102+
}
103+
return lo;
104+
}
105+
106+
/**
107+
* Rebalances the library array by redistributing elements with gaps.
108+
*/
109+
private static void rebalance(final int[] library, final boolean[] occupied, final int n) {
110+
int[] temp = new int[n];
111+
int idx = 0;
112+
for (int i = 0; i < 2 * n; i++) {
113+
if (occupied[i]) {
114+
temp[idx++] = library[i];
115+
occupied[i] = false;
116+
library[i] = Integer.MAX_VALUE;
117+
}
118+
}
119+
// Redistribute with gaps
120+
for (int i = 0; i < idx; i++) {
121+
int pos = 2 * i;
122+
library[pos] = temp[i];
123+
occupied[pos] = true;
124+
}
125+
}
126+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.thealgorithms.sorts;
2+
// author: Vraj Prajapati @Rosander0
3+
4+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
5+
import static org.junit.jupiter.api.Assertions.assertThrows;
6+
7+
import org.junit.jupiter.api.Test;
8+
9+
public class LibrarySortTest {
10+
11+
@Test
12+
public void testBasicSort() {
13+
assertArrayEquals(new int[]{1, 2, 3, 4, 5},
14+
LibrarySort.sort(new int[]{5, 3, 1, 4, 2}));
15+
}
16+
17+
@Test
18+
public void testAlreadySorted() {
19+
assertArrayEquals(new int[]{1, 2, 3, 4, 5},
20+
LibrarySort.sort(new int[]{1, 2, 3, 4, 5}));
21+
}
22+
23+
@Test
24+
public void testReverseSorted() {
25+
assertArrayEquals(new int[]{1, 2, 3, 4, 5},
26+
LibrarySort.sort(new int[]{5, 4, 3, 2, 1}));
27+
}
28+
29+
@Test
30+
public void testDuplicates() {
31+
assertArrayEquals(new int[]{1, 2, 2, 3, 3},
32+
LibrarySort.sort(new int[]{3, 2, 1, 3, 2}));
33+
}
34+
35+
@Test
36+
public void testSingleElement() {
37+
assertArrayEquals(new int[]{1},
38+
LibrarySort.sort(new int[]{1}));
39+
}
40+
41+
@Test
42+
public void testEmptyArray() {
43+
assertArrayEquals(new int[]{},
44+
LibrarySort.sort(new int[]{}));
45+
}
46+
47+
@Test
48+
public void testNullArray() {
49+
assertThrows(IllegalArgumentException.class, () -> LibrarySort.sort(null));
50+
}
51+
}

0 commit comments

Comments
 (0)