Java • Data Structures • Radix Sort • IPv4

Sorting IP Addresses with Java Radix Sort

This was a small data structures class project where I used Java to demonstrate radix sort on IPv4 addresses. Instead of sorting normal decimal numbers, the program treats each IP address as a 32-bit integer and sorts it one byte at a time.

I liked this project because it connects a class algorithm to networking. IPv4 addresses already have four byte-sized parts, so base-256 radix sort maps naturally to the way IP addresses are written and stored.

Project context: this is a simple Java data structures project, but it has a strong networking angle: IP addresses, bytes, bit shifts, queues, and radix sorting.
IPv4 address Example: 192.168.15.200
32-bit integer Store the address as four bytes.
Base-256 buckets Use 256 queues for byte values 0 through 255.
Four passes Sort last byte to first byte.
IPv4 addresses are four bytes, so the radix sort runs four byte-level passes.

What I built

I built a Java program called RadixIP. It stores several IPv4 addresses, converts each dotted-decimal address into an integer, then uses a base-256 radix sort to sort them.

Java

Algorithm demo

The program demonstrates radix sort using Java classes, lists, queues, loops, and helper methods.

Networking

IPv4 addresses

Instead of sorting generic numbers, the program sorts IP addresses like 10.0.143.92 and 192.168.15.200.

Data structures

Queues as buckets

Each byte value gets its own queue. The queues preserve ordering inside each bucket, which keeps the radix sort stable.

Why IP addresses fit radix sort

An IPv4 address is made of four octets. Each octet is one byte, and one byte can hold values from 0 to 255. That makes base 256 a natural match.

192.168.15.200

192  = first byte
168  = second byte
15   = third byte
200  = fourth byte
Main idea: radix sort can sort the IPs byte-by-byte instead of comparing each full address as a string.

The sorting workflow

The program performs four sorting passes. It starts with the least significant byte, which is the last octet, and works toward the most significant byte, which is the first octet.

01

Pass 0

Sort by the last octet, such as the 200 in 192.168.15.200.

02

Pass 1

Sort by the third octet, such as the 15 in 192.168.15.200.

03

Pass 2

Sort by the second octet, such as the 168 in 192.168.15.200.

04

Pass 3

Sort by the first octet, such as the 192 in 192.168.15.200.

Data structures used

The project is small, but the data-structure choices matter.

Structure Used for Why it fits
List<Integer> Stores the IP addresses as integers. The list is the main sequence being sorted and rewritten after each radix pass.
ArrayList<Queue<Integer>> Stores 256 radix buckets. The array-style list gives direct access to bucket numbers from 0 through 255.
Queue<Integer> Stores IPs inside each bucket. Queues preserve insertion order, which is important because radix sort depends on stable bucket collection.
LinkedList<Integer> Implements each queue. Java's LinkedList can act as a queue with add() and poll().

Code walkthrough

The main radix-sort class stores the list being sorted, creates 256 queues, distributes values into buckets, then collects them back into the list.

class RadixSortBase256 {
    List<Integer> toSort;
    ArrayList<Queue<Integer>> bins;
    final int BASE = 256;
    final int numBytes = 4;

    RadixSortBase256(List<Integer> toSort) {
        this.toSort = toSort;
        bins = new ArrayList<>(BASE);

        for (int i = 0; i < BASE; i++) {
            bins.add(new LinkedList<>());
        }
    }
}

How one byte is selected

This line is the key part of the program. It uses bit shifting to select one byte from the integer representation of the IP address.

int bucket = (ip >>> (8 * bytePass)) & 0xFF;
Part What it does Why it matters
bytePass Chooses which byte to inspect. There are four passes: 0, 1, 2, and 3.
8 * bytePass Calculates how many bits to shift. Each byte is 8 bits.
>>> Performs an unsigned right shift. Moves the target byte into the lowest byte position.
& 0xFF Keeps only the lowest 8 bits. Produces a bucket number from 0 to 255.

Distribute and collect

Each pass has two main steps. First, distribute each IP into the correct byte bucket. Then, collect the buckets back into the main list in order.

Distribute

Put each IP into a bucket

public void distribute(int bytePass) {
    for (Integer ip : toSort) {
        int bucket = (ip >>> (8 * bytePass)) & 0xFF;
        bins.get(bucket).add(ip);
    }
}
Collect

Rebuild the list in bucket order

public void collect() {
    toSort.clear();

    for (Queue<Integer> b : bins) {
        while (!b.isEmpty()) {
            toSort.add(b.poll());
        }
    }
}

Converting IP strings to integers

The program starts with readable dotted-decimal IP strings, splits them on periods, parses each octet, then packs the four octets into one integer using bit shifts.

private static int ip(String s) {
    String[] p = s.split("\\.");

    return (Integer.parseInt(p[0]) << 24)
            | (Integer.parseInt(p[1]) << 16)
            | (Integer.parseInt(p[2]) << 8)
            |  Integer.parseInt(p[3]);
}
Improvement to make later: this helper assumes valid input. A stronger version should check that there are exactly four octets and that each octet is between 0 and 255.

Converting integers back to IP strings

For readable output, the program converts each sorted integer back into normal dotted-decimal form.

private static String intToIp(int x) {
    return ((x >>> 24) & 0xFF) + "."
            + ((x >>> 16) & 0xFF) + "."
            + ((x >>> 8) & 0xFF) + "."
            + (x & 0xFF);
}
Same idea in reverse: shift the byte into position, mask with 0xFF, and print each octet.

Sample input

The demo sorts a small list of hardcoded IPv4 addresses.

ips.add(ip("10.0.143.92"));
ips.add(ip("10.12.8.77"));
ips.add(ip("172.16.0.14"));
ips.add(ip("192.168.15.200"));
ips.add(ip("172.31.254.9"));
ips.add(ip("192.168.0.3"));
ips.add(ip("203.0.113.45"));

Final sorted output

After four passes, the addresses are sorted numerically by IPv4 value.

10.0.143.92
10.12.8.77
172.16.0.14
172.31.254.9
192.168.0.3
192.168.15.200
203.0.113.45

What I learned

This project helped connect sorting algorithms, Java data structures, and networking basics.

Algorithms

Radix sort is different

Instead of repeatedly comparing two full values, radix sort processes one digit or byte position at a time.

Binary

Bit operations matter

Shifts and masks are easier to understand when they are connected to something real, like extracting octets from an IPv4 address.

Networking

IPs are structured data

An IPv4 address is not just text. It can be represented as a 32-bit value made from four separate bytes.

Future improvements

This is a simple demo, but it could become more practical with a few upgrades.

Code improvements

Make the demo stronger

  • Rename the file to RadixIP.java so it matches the public class name.
  • Add validation for invalid IPv4 addresses.
  • Reject octets below 0 or above 255.
  • Move sorting logic and IP helpers into separate classes.
Project upgrades

Make it more realistic

  • Load IP addresses from a text file.
  • Sort source IPs from a log file.
  • Count duplicate IP addresses.
  • Group sorted IPs by private ranges like 10.0.0.0/8 and 192.168.0.0/16.
Related class project: this pairs well with the Java Movie CLI because both projects show data-structure choices with practical examples.

Run it locally

Since the public class is named RadixIP, the file should be saved as RadixIP.java before compiling.

javac RadixIP.java
java RadixIP

Final idea

This is a tiny project, but it has a clean LaunchShell lesson: data structures and algorithms become easier to understand when they are connected to real technical systems. Sorting IP addresses with radix sort turns an abstract classroom algorithm into something tied to networking, bytes, queues, and binary representation.