My Linked List. Used Star wars Collectables

I developed a personalized LinkedList class below, with guidance from individuals on StackOverflow and ChatGPT, to elucidate its functionality. Throughout the code, I’ve included comments detailing each step and approach, providing clear explanations of the implementation process.

Initially, I designated the current node as the head once I confirmed that the LinkedList contained more than one item. For each item in the LinkedList:

  • a. I assigned the minimum value to the current node.
  • b. Iterating through each linked node using the Node’s .next, I checked if it was less than the current minimum.
  • c. If a node was found to be less than the current minimum, I updated the minimum.
  • d. If necessary, I swapped the recorded minimum value with the “current” node.
  • e. The “current” node was then adjusted to its .next, considering that all preceding nodes were already sorted.
  • This process continued until the LinkedList was completely sorted
// defining a LinkedList class that can hold elements (T)
// ChatGPT: "T can be any data type that extends Comparable"
public class LinkedList<T extends Comparable<T>> {
    // Node class represents individual list elements
    private static class Node<T> {
        T data; // the element's actual data
        Node<T> next; // referencing (linking to *winky face*) to the next node in the list

        // constructor to create a node with given data
        Node(T data) {
            this.data = data;
            this.next = null; // no next node exists initially
        }
    }

    private Node<T> head; // references the first node in the list
    private int size; // represents the size/length of the list

    // constructor to initialize the LinkedList
    public LinkedList() {
        head = null; // it's empty at first, so there's NOTHING
        size = 0; // the size starts out as 0, as there is NOTHING
    }

    // like .add() for ArrayList, this adds an element to the end of the list
    public void add(T element) {
        if (head == null) {
            head = new Node<>(element); // if the list is empty, this creates the first node
            // when I gave my concept, chatGPT said to add this condition here, credit <-
        } else {
            Node<T> current = head;
            while (current.next != null) {
                current = current.next; // using a while loop to approach the last node
            }
            current.next = new Node<>(element); // adding the new node at the end
        }
        size++; // increasing size of the list
    }

    // HERE'S MY CUSTOM SELECTION SORT
    public void selectionSort() {
        if (head == null || head.next == null) {
            return; // if the list is empty or has only one element, it's already sorted
            // again, this is an inclusion courtesy of ChatGPT and its incredible forethought
        }
        Node<T> current = head;
        while (current != null) {
            Node<T> min = current;
            Node<T> temp = current.next;
            while (temp != null) {
                if (temp.data.compareTo(min.data) < 0) {
                    min = temp; // finding the minimum element
                }
                temp = temp.next;
            }
            T tmpData = current.data; // swapping the current unsorted place with the minimum
            current.data = min.data;
            min.data = tmpData;
            current = current.next; // moving to the next element
        }
    }

    // this method overrides toString
    // it's used for printing the list
    // this was my reference: https://stackoverflow.com/questions/42676579/tostring-method-for-a-linkedlist
    // i shouldn't have needed a reference, but I wanted to make sure there wasn't anything special to do
    @Override
    public String toString() {
        String string = "["; // starting the list format
        Node<T> current = head; // start with head
        while (current != null) {
            string += current.data; // appending the current data to the string
            if (current.next != null) {
                string += ", "; // good punctuation = professionalism
            }
            current = current.next; // moving on
        }
        string += "]"; // capping off the list format
        return string;
    }

    // this is to return a JSON representation of the list
    // i basically did the same thign as I did for the toString() one
    public String toJSON() {
        String json = "{"; // starting format
        Node<T> current = head; // start with head
        while (current != null) {
            json += "\"" + current.data + "\""; // adding current data in quotations for JSON
            if (current.next != null) {
                json += ", "; // good punctuation again, this time very important
            }
            current = current.next; // moving on
        }
        json += "}"; // capping off
        return json;
    }

    // may be implemented? still researching
    public void changeSortKey() {
        // yet to come...
    }

    // main method for testing
    public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>();
        list.add(5);
        list.add(3);
        list.add(8);
        list.add(1);
        System.out.println("Original list: " + list);
        list.selectionSort();
        System.out.println("Sorted list: " + list);
        System.out.println("JSON representation: " + list.toJSON());
    }
}

LinkedList.main(null);
Original list: [5, 3, 8, 1]
Sorted list: [1, 3, 5, 8]
JSON representation: {"1", "3", "5", "8"}
interface Collectable<T> extends Comparable<T> {
    // implementing compareTo method to define natural ordering
    @Override
    int compareTo(T other);

    String toString(); // needed for LL printing
}
// defining the StarWarsCharacter class implementing Collectable interface
class StarWarsCharacter implements Collectable<StarWarsCharacter> {
    private String name;
    private String species;
    private int powerLevel;

    // basic constructor
    public StarWarsCharacter(String name, String species, int powerLevel) {
        this.name = name;
        this.species = species;
        this.powerLevel = powerLevel;
    }

    // getters methods
    public String getName() { return name; }
    public String getSpecies() { return species; }
    public int getPowerLevel() { return powerLevel; }

    // implementing the interface compareTo method
    // i definde natural ordering based on power level
    @Override
    public int compareTo(StarWarsCharacter other) {
        return Integer.compare(this.powerLevel, other.powerLevel);
    }

    // overriding toString method for better representation of the Star Wars character
    @Override
    public String toString() {
        return name + " (" + species + ") - Power Level: " + powerLevel;
    }

    public static void main(String[] args) {
        // Create an array of Star Wars characters
        StarWarsCharacter[] charactersArray = new StarWarsCharacter[] {
            new StarWarsCharacter("Luke Skywalker", "Human", 9000),
            new StarWarsCharacter("Darth Vader", "Human", 9500),
            new StarWarsCharacter("Yoda", "Unknown", 10000),
            new StarWarsCharacter("Han Solo", "Human", 8500)
        };

        // Create a LinkedList of Star Wars characters
        LinkedList<StarWarsCharacter> charactersList = new LinkedList<>();

        // Add characters to the LinkedList
        for (StarWarsCharacter character : charactersArray) {
            charactersList.add(character);
        }

        // Sort and display the LinkedList
        charactersList.selectionSort();
        System.out.println("Sorted list: " + charactersList);
        System.out.println("JSON representation: " + charactersList.toJSON());
    }
}

StarWarsCharacter.main(null);
Sorted list: [Han Solo (Human) - Power Level: 8500, Luke Skywalker (Human) - Power Level: 9000, Darth Vader (Human) - Power Level: 9500, Yoda (Unknown) - Power Level: 10000]
JSON representation: {"Han Solo (Human) - Power Level: 8500", "Luke Skywalker (Human) - Power Level: 9000", "Darth Vader (Human) - Power Level: 9500", "Yoda (Unknown) - Power Level: 10000"}
public class Main {
    public static void main(String[] args) {
        LinkedList<StarWarsCharacter> characters = new LinkedList<>();
        characters.add(new StarWarsCharacter("Luke Skywalker", "Human", 9000));
        characters.add(new StarWarsCharacter("Darth Vader", "Human", 9500));
        characters.add(new StarWarsCharacter("Yoda", "Unknown", 10000));
        characters.add(new StarWarsCharacter("Han Solo", "Human", 8500));

        System.out.println("Original list: " + characters);
        characters.selectionSort();
        System.out.println("Sorted list: " + characters);
        System.out.println("JSON representation: " + characters.toJSON());
    }
}
Main.main(null);
Original list: [Luke Skywalker (Human) - Power Level: 9000, Darth Vader (Human) - Power Level: 9500, Yoda (Unknown) - Power Level: 10000, Han Solo (Human) - Power Level: 8500]
Sorted list: [Han Solo (Human) - Power Level: 8500, Luke Skywalker (Human) - Power Level: 9000, Darth Vader (Human) - Power Level: 9500, Yoda (Unknown) - Power Level: 10000]
JSON representation: {"Han Solo (Human) - Power Level: 8500", "Luke Skywalker (Human) - Power Level: 9000", "Darth Vader (Human) - Power Level: 9500", "Yoda (Unknown) - Power Level: 10000"}

I desired to integrate SortKeys within the LinkedList class, primarily because I believed that leveraging enums in Java would be beneficial for my skill development. While I’ve employed enums in Java once before, my exposure to them has mostly been in GML, a coding language exclusive to GameMaker Studio.

Modified Star Wars Collectable

I aimed to enable a LinkedList object to inspect the class it’s working with, identify its sorting criteria, and then utilize them accordingly. The adaptation for Star Wars characters is provided below:

// defining the StarWarsCharacter class implementing Collectable interface
class StarWarsCharacter implements Collectable<StarWarsCharacter> {
    private String name;
    private String species;
    private int powerLevel;

    // my attempt at SortKey implementation
    enum SortKey {
        NAME,
        SPECIES,
        POWER_LEVEL
    }

    private static SortKey currentSortKey = SortKey.POWER_LEVEL; // default sort key is power level

    // basic constructor
    public StarWarsCharacter(String name, String species, int powerLevel) {
        this.name = name;
        this.species = species;
        this.powerLevel = powerLevel;
    }

    // getters methods
    public String getName() { return name; }
    public String getSpecies() { return species; }
    public int getPowerLevel() { return powerLevel; }

    // special sort key setter method for static context
    public static void setCurrentSortKey(SortKey sortKey) {
        currentSortKey = sortKey;
    }

    // implementing the interface compareTo method
    // trying to make it founded on the StarWarsCharacter class's defined current sort key
    @Override
    public int compareTo(StarWarsCharacter other) {
        switch (currentSortKey) {
            case NAME: // sorts alphabetically by name
                return this.name.compareTo(other.name);
            case SPECIES: // sorts alphabetically by species
                return this.species.compareTo(other.species);
            case POWER_LEVEL: // sorts by increasing power level
                return Integer.compare(this.powerLevel, other.powerLevel);
            default:
                throw new IllegalArgumentException("Invalid sort key");
        }
    }

    // overriding toString method for better representation of the Star Wars character
    @Override
    public String toString() {
        return name + " (" + species + ") - Power Level: " + powerLevel;
    }

    public static void main(String[] args) {
        // Create an array of Star Wars characters
        StarWarsCharacter[] charactersArray = new StarWarsCharacter[] {
            new StarWarsCharacter("Luke Skywalker", "Human", 9000),
            new StarWarsCharacter("Darth Vader", "Human", 9500),
            new StarWarsCharacter("Yoda", "Unknown", 10000),
            new StarWarsCharacter("Han Solo", "Human", 8500)
        };

        // Create a LinkedList of Star Wars characters
        LinkedList<StarWarsCharacter> charactersList = new LinkedList<>();

        // Add characters to the LinkedList
        for (StarWarsCharacter character : charactersArray) {
            charactersList.add(character);
        }

        // Sort and display the LinkedList with different sort keys
        for (StarWarsCharacter.SortKey sortKey : StarWarsCharacter.SortKey.values()) {
            // setting the current sort key
            StarWarsCharacter.setCurrentSortKey(sortKey);
            
            // selection sort called for the LinkedList class
            charactersList.selectionSort();
            
            // displaying the sorted LinkedList
            System.out.println("Sorted by " + sortKey + ": " + charactersList);
        }
    }
}

StarWarsCharacter.main(null);

Sorted by NAME: [Darth Vader (Human) - Power Level: 9500, Han Solo (Human) - Power Level: 8500, Luke Skywalker (Human) - Power Level: 9000, Yoda (Unknown) - Power Level: 10000]
Sorted by SPECIES: [Darth Vader (Human) - Power Level: 9500, Han Solo (Human) - Power Level: 8500, Luke Skywalker (Human) - Power Level: 9000, Yoda (Unknown) - Power Level: 10000]
Sorted by POWER_LEVEL: [Han Solo (Human) - Power Level: 8500, Luke Skywalker (Human) - Power Level: 9000, Darth Vader (Human) - Power Level: 9500, Yoda (Unknown) - Power Level: 10000]