Sorting - Tran Ba Tuan - HUS - VNU

I, Intuition

  • Students need to understand the mechanism and motivation behind common sorting algorithms such as Bubble Sort, Selection Sort, Insertion Sort, Merge Sort and Quick Sort.
  • Have the ability to comprehend pseudo code.
  • Knows what Sorting Algorithm to implement depending on certain situations.

II, Practice

Work 1. Write a program to evaluate sorting algorithms:

  • a, With a small integer array from keyboard input.
  • b, With \(N\) - size integer array in range \([1,10^5]\).
  • c, Implement Bubble Sort, Selection Sort, Insertion Sort, Merge Sort and Quick Sort with the requirements above.
  • d, Display the state of the array after each iteration to visualize said algorithms. Count comparative operations and swapping operations.
  • e, Compare time taken of each algorithms with \(N = [100, 1000, 10000, 100000]\). Conclude the motivation behind choosing suitable sorting algorithms based on use case and the characteristics of the data.
import mysort.*;

import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.Random;
import java.util.Scanner;

public class Work1 {

    static Scanner sc = new Scanner(System.in);
    static MySortingAlgorithm[] sortingAlgorithms = {new BubbleSort(), new SelectionSort(), new InsertionSort(), new MergeSort(), new QuickSort()};
    static Sorter sorter = new Sorter();

    public static void evaluateSortingAlgorithms(int[] arr) {
        for (MySortingAlgorithm algorithm : sortingAlgorithms) {
            int[] arrCopy = Arrays.copyOf(arr, arr.length);
            sorter.setSortingAlgorithm(algorithm);
            sorter.sort(arrCopy);
        }
    }

    // Small array from keyboard input
    public static void evaluateFromKeyboardInput() {
        int n = 0;
        System.out.println("Enter n for array size:");

        while (n <= 0) {
            try {
                n = sc.nextInt();
                if (n <= 0) System.out.println("Please enter a positive integer for n:");
            } catch (InputMismatchException e) {
                System.out.println("Please enter an integer n for array size n:");
                sc.next();
            }
        }

        int[] arr = new int[n];
        System.out.println("Enter the elements of " + n + " size array:");
        int i = 0;
        while (i < n) {
            try {
                arr[i] = sc.nextInt();
                i++;
            } catch (InputMismatchException e) {
                System.out.println("Invalid element, please add integer(s):");
                sc.next();
            }
        }

        System.out.println("Original: " + Arrays.toString(arr));
        evaluateSortingAlgorithms(arr);
    }

    // For N-size array ranging from [1, 10^5]
    public static void evaluateNsizeArray(int[] nValues) {
        Random random = new Random();
        for (int n : nValues) {
            System.out.println("Evaluating sorting algorithms for size " + n + " array:\n");
            int[] arr = new int[n];
            for (int i = 0; i < n; i++) {
                arr[i] = random.nextInt((int) Math.pow(10, 5));
            }
            evaluateSortingAlgorithms(arr);
        }
    }

    public static void main(String[] args) {
        evaluateFromKeyboardInput();
        int[] nValues = {100, 1000, 10000, 100000};
        sorter.setPrintIterations(false);
        evaluateNsizeArray(nValues);
    }

}

Output:

Enter n for array size:
10
Enter the elements of 10 size array:
5 4 8 7 1 3 9 2 0 -5
Original: [5, 4, 8, 7, 1, 3, 9, 2, 0, -5]
Bubble Sort iteration 1: [4, 5, 7, 1, 3, 8, 2, 0, -5, 9]
Bubble Sort iteration 2: [4, 5, 1, 3, 7, 2, 0, -5, 8, 9]
Bubble Sort iteration 3: [4, 1, 3, 5, 2, 0, -5, 7, 8, 9]
Bubble Sort iteration 4: [1, 3, 4, 2, 0, -5, 5, 7, 8, 9]
Bubble Sort iteration 5: [1, 3, 2, 0, -5, 4, 5, 7, 8, 9]
Bubble Sort iteration 6: [1, 2, 0, -5, 3, 4, 5, 7, 8, 9]
Bubble Sort iteration 7: [1, 0, -5, 2, 3, 4, 5, 7, 8, 9]
Bubble Sort iteration 8: [0, -5, 1, 2, 3, 4, 5, 7, 8, 9]
Bubble Sort iteration 9: [-5, 0, 1, 2, 3, 4, 5, 7, 8, 9]
Bubble Sort: 0ms for 10 element(s)
Movements: 33; Comparisons: 45

Selection Sort iteration 1: [-5, 4, 8, 7, 1, 3, 9, 2, 0, 5]
Selection Sort iteration 2: [-5, 0, 8, 7, 1, 3, 9, 2, 4, 5]
Selection Sort iteration 3: [-5, 0, 1, 7, 8, 3, 9, 2, 4, 5]
Selection Sort iteration 4: [-5, 0, 1, 2, 8, 3, 9, 7, 4, 5]
Selection Sort iteration 5: [-5, 0, 1, 2, 3, 8, 9, 7, 4, 5]
Selection Sort iteration 6: [-5, 0, 1, 2, 3, 4, 9, 7, 8, 5]
Selection Sort iteration 7: [-5, 0, 1, 2, 3, 4, 5, 7, 8, 9]
Selection Sort iteration 8: [-5, 0, 1, 2, 3, 4, 5, 7, 8, 9]
Selection Sort iteration 9: [-5, 0, 1, 2, 3, 4, 5, 7, 8, 9]
Selection Sort: 0ms for 10 element(s)
Movements: 9; Comparisons: 45

Insertion Sort iteration 1: [4, 5, 8, 7, 1, 3, 9, 2, 0, -5]
Insertion Sort iteration 2: [4, 5, 8, 7, 1, 3, 9, 2, 0, -5]
Insertion Sort iteration 3: [4, 5, 7, 8, 1, 3, 9, 2, 0, -5]
Insertion Sort iteration 4: [1, 4, 5, 7, 8, 3, 9, 2, 0, -5]
Insertion Sort iteration 5: [1, 3, 4, 5, 7, 8, 9, 2, 0, -5]
Insertion Sort iteration 6: [1, 3, 4, 5, 7, 8, 9, 2, 0, -5]
Insertion Sort iteration 7: [1, 2, 3, 4, 5, 7, 8, 9, 0, -5]
Insertion Sort iteration 8: [0, 1, 2, 3, 4, 5, 7, 8, 9, -5]
Insertion Sort iteration 9: [-5, 0, 1, 2, 3, 4, 5, 7, 8, 9]
Insertion Sort: 0ms for 10 element(s)
Movements: 33; Comparisons: 33

Merge step: [4, 5, 8, 7, 1, 3, 9, 2, 0, -5]
Merge step: [4, 5, 8, 7, 1, 3, 9, 2, 0, -5]
Merge step: [4, 5, 8, 1, 7, 3, 9, 2, 0, -5]
Merge step: [1, 4, 5, 7, 8, 3, 9, 2, 0, -5]
Merge step: [1, 4, 5, 7, 8, 3, 9, 2, 0, -5]
Merge step: [1, 4, 5, 7, 8, 2, 3, 9, 0, -5]
Merge step: [1, 4, 5, 7, 8, 2, 3, 9, -5, 0]
Merge step: [1, 4, 5, 7, 8, -5, 0, 2, 3, 9]
Merge step: [-5, 0, 1, 2, 3, 4, 5, 7, 8, 9]
Merge Sort: 0ms for 10 element(s)
Movements: 34; Comparisons: 22

Partition step: [-5, 0, 1, 2, 3, 4, 5, 8, 7, 9]
Partition step: [-5, 0, 1, 2, 3, 4, 5, 8, 7, 9]
Partition step: [-5, 0, 1, 2, 3, 4, 5, 8, 7, 9]
Partition step: [-5, 0, 1, 2, 3, 4, 5, 7, 8, 9]
Partition step: [-5, 0, 1, 2, 3, 4, 5, 7, 8, 9]
Partition step: [-5, 0, 1, 2, 3, 4, 5, 7, 8, 9]
Partition step: [-5, 0, 1, 2, 3, 4, 5, 7, 8, 9]
Quick Sort: 0ms for 10 element(s)
Movements: 18; Comparisons: 29

Evaluating sorting algorithms for size 100 array:

Bubble Sort: 0ms for 100 element(s)
Movements: 2474; Comparisons: 4950

Selection Sort: 0ms for 100 element(s)
Movements: 99; Comparisons: 4950

Insertion Sort: 0ms for 100 element(s)
Movements: 2474; Comparisons: 2474

Merge Sort: 0ms for 100 element(s)
Movements: 672; Comparisons: 539

Quick Sort: 0ms for 100 element(s)
Movements: 392; Comparisons: 573

Evaluating sorting algorithms for size 1000 array:

Bubble Sort: 0ms for 1000 element(s)
Movements: 252098; Comparisons: 499500

Selection Sort: 0ms for 1000 element(s)
Movements: 999; Comparisons: 499500

Insertion Sort: 15ms for 1000 element(s)
Movements: 252098; Comparisons: 252098

Merge Sort: 0ms for 1000 element(s)
Movements: 9976; Comparisons: 8725

Quick Sort: 0ms for 1000 element(s)
Movements: 6777; Comparisons: 11240

Evaluating sorting algorithms for size 10000 array:

Bubble Sort: 67ms for 10000 element(s)
Movements: 25045625; Comparisons: 49995000

Selection Sort: 63ms for 10000 element(s)
Movements: 9999; Comparisons: 49995000

Insertion Sort: 15ms for 10000 element(s)
Movements: 25045625; Comparisons: 25045625

Merge Sort: 0ms for 10000 element(s)
Movements: 133616; Comparisons: 120484

Quick Sort: 0ms for 10000 element(s)
Movements: 89372; Comparisons: 161503

Evaluating sorting algorithms for size 100000 array:

Bubble Sort: 11569ms for 100000 element(s)
Movements: 2500400343; Comparisons: 4999950000

Selection Sort: 2188ms for 100000 element(s)
Movements: 99999; Comparisons: 4999950000

Insertion Sort: 1624ms for 100000 element(s)
Movements: 2500400343; Comparisons: 2500400343

Merge Sort: 16ms for 100000 element(s)
Movements: 1668928; Comparisons: 1536358

Quick Sort: 0ms for 100000 element(s)
Movements: 1024666; Comparisons: 1985279

Work 2.

  • Generalize on Work 1. with data type Comparable<T>.
import mygenericsort.*;

import java.util.Arrays;
import java.util.ArrayList;

public class Work2 {

    public static class Student implements Comparable<Student>{

        String name;
        int age;

        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public int compareTo(Student o) {
            return Integer.compare(this.age, o.age);
        }

        @Override
        public String toString() {
            return "[" + name + "; age: " + age + "]";
        }

        public static void printStudents(Student[] students) {
            StringBuilder sb = new StringBuilder("[");
            for (int i = 0; i < students.length; i++) {
                sb.append(students[i]).append(i == students.length - 1 ? "]" : ", ");
            }
            System.out.println(sb);
        }

    }

    static ArrayList<MySortingAlgorithm<Student>> sortingAlgorithms = new ArrayList<>();
    static Sorter<Student> sorter = new Sorter<>();

    public static void evaluateSortingAlgorithms(Student[] arr) {
        for (MySortingAlgorithm<Student> algorithm : sortingAlgorithms) {
            Student[] arrCopy = Arrays.copyOf(arr, arr.length);
            sorter.setSortingAlgorithm(algorithm);
            sorter.sort(arrCopy);
        }
    }

    public static void main(String[] args) {
        String[] names = {"Kisaki", "Ibuki", "Hare", "Hina", "Arona", "Plana", "Iroha"};
        int[] ages = {17, 11, 16, 17, 12, 13, 16};
        Student[] students = new Student[names.length];
        for (int i = 0; i < names.length; i++) {
            students[i] = new Student(names[i], ages[i]);
        }

        MySortingAlgorithm<Student> bubbleSort = new BubbleSort<>();
        MySortingAlgorithm<Student> selectionSort = new SelectionSort<>();
        MySortingAlgorithm<Student> insertionSort = new InsertionSort<>();
        MySortingAlgorithm<Student> mergeSort = new MergeSort<>();
        MySortingAlgorithm<Student> quickSort = new QuickSort<>();

        sortingAlgorithms.add(bubbleSort);
        sortingAlgorithms.add(selectionSort);
        sortingAlgorithms.add(insertionSort);
        sortingAlgorithms.add(mergeSort);
        sortingAlgorithms.add(quickSort);

        System.out.println("Original list:");
        Student.printStudents(students);
        evaluateSortingAlgorithms(students);
    }

}

Output:

Original list:
[[Kisaki; age: 17], [Ibuki; age: 11], [Hare; age: 16], [Hina; age: 17], [Arona; age: 12], [Plana; age: 13], [Iroha; age: 16]]
Bubble Sort iteration 1: [[Ibuki; age: 11], [Hare; age: 16], [Kisaki; age: 17], [Arona; age: 12], [Plana; age: 13], [Iroha; age: 16], [Hina; age: 17]]
Bubble Sort iteration 2: [[Ibuki; age: 11], [Hare; age: 16], [Arona; age: 12], [Plana; age: 13], [Iroha; age: 16], [Kisaki; age: 17], [Hina; age: 17]]
Bubble Sort iteration 3: [[Ibuki; age: 11], [Arona; age: 12], [Plana; age: 13], [Hare; age: 16], [Iroha; age: 16], [Kisaki; age: 17], [Hina; age: 17]]
Bubble Sort iteration 4: [[Ibuki; age: 11], [Arona; age: 12], [Plana; age: 13], [Hare; age: 16], [Iroha; age: 16], [Kisaki; age: 17], [Hina; age: 17]]
Bubble Sort iteration 5: [[Ibuki; age: 11], [Arona; age: 12], [Plana; age: 13], [Hare; age: 16], [Iroha; age: 16], [Kisaki; age: 17], [Hina; age: 17]]
Bubble Sort iteration 6: [[Ibuki; age: 11], [Arona; age: 12], [Plana; age: 13], [Hare; age: 16], [Iroha; age: 16], [Kisaki; age: 17], [Hina; age: 17]]
Bubble Sort: 0ms for 7 element(s)
Movements: 10; Comparisons: 21

Selection Sort iteration 1: [[Ibuki; age: 11], [Kisaki; age: 17], [Hare; age: 16], [Hina; age: 17], [Arona; age: 12], [Plana; age: 13], [Iroha; age: 16]]
Selection Sort iteration 2: [[Ibuki; age: 11], [Arona; age: 12], [Hare; age: 16], [Hina; age: 17], [Kisaki; age: 17], [Plana; age: 13], [Iroha; age: 16]]
Selection Sort iteration 3: [[Ibuki; age: 11], [Arona; age: 12], [Plana; age: 13], [Hina; age: 17], [Kisaki; age: 17], [Hare; age: 16], [Iroha; age: 16]]
Selection Sort iteration 4: [[Ibuki; age: 11], [Arona; age: 12], [Plana; age: 13], [Hare; age: 16], [Kisaki; age: 17], [Hina; age: 17], [Iroha; age: 16]]
Selection Sort iteration 5: [[Ibuki; age: 11], [Arona; age: 12], [Plana; age: 13], [Hare; age: 16], [Iroha; age: 16], [Hina; age: 17], [Kisaki; age: 17]]
Selection Sort iteration 6: [[Ibuki; age: 11], [Arona; age: 12], [Plana; age: 13], [Hare; age: 16], [Iroha; age: 16], [Hina; age: 17], [Kisaki; age: 17]]
Selection Sort: 0ms for 7 element(s)
Movements: 6; Comparisons: 21

Insertion Sort iteration 1: [[Ibuki; age: 11], [Kisaki; age: 17], [Hare; age: 16], [Hina; age: 17], [Arona; age: 12], [Plana; age: 13], [Iroha; age: 16]]
Insertion Sort iteration 2: [[Ibuki; age: 11], [Hare; age: 16], [Kisaki; age: 17], [Hina; age: 17], [Arona; age: 12], [Plana; age: 13], [Iroha; age: 16]]
Insertion Sort iteration 3: [[Ibuki; age: 11], [Hare; age: 16], [Kisaki; age: 17], [Hina; age: 17], [Arona; age: 12], [Plana; age: 13], [Iroha; age: 16]]
Insertion Sort iteration 4: [[Ibuki; age: 11], [Arona; age: 12], [Hare; age: 16], [Kisaki; age: 17], [Hina; age: 17], [Plana; age: 13], [Iroha; age: 16]]
Insertion Sort iteration 5: [[Ibuki; age: 11], [Arona; age: 12], [Plana; age: 13], [Hare; age: 16], [Kisaki; age: 17], [Hina; age: 17], [Iroha; age: 16]]
Insertion Sort iteration 6: [[Ibuki; age: 11], [Arona; age: 12], [Plana; age: 13], [Hare; age: 16], [Iroha; age: 16], [Kisaki; age: 17], [Hina; age: 17]]
Insertion Sort: 0ms for 7 element(s)
Movements: 10; Comparisons: 10

Merge step: [[Ibuki; age: 11], [Kisaki; age: 17], [Hare; age: 16], [Hina; age: 17], [Arona; age: 12], [Plana; age: 13], [Iroha; age: 16]]
Merge step: [[Ibuki; age: 11], [Kisaki; age: 17], [Hare; age: 16], [Hina; age: 17], [Arona; age: 12], [Plana; age: 13], [Iroha; age: 16]]
Merge step: [[Ibuki; age: 11], [Hare; age: 16], [Kisaki; age: 17], [Hina; age: 17], [Arona; age: 12], [Plana; age: 13], [Iroha; age: 16]]
Merge step: [[Ibuki; age: 11], [Hare; age: 16], [Kisaki; age: 17], [Hina; age: 17], [Arona; age: 12], [Plana; age: 13], [Iroha; age: 16]]
Merge step: [[Ibuki; age: 11], [Hare; age: 16], [Kisaki; age: 17], [Hina; age: 17], [Arona; age: 12], [Plana; age: 13], [Iroha; age: 16]]
Merge step: [[Ibuki; age: 11], [Arona; age: 12], [Plana; age: 13], [Hare; age: 16], [Iroha; age: 16], [Kisaki; age: 17], [Hina; age: 17]]
Merge Sort: 0ms for 7 element(s)
Movements: 20; Comparisons: 13

Partition step: [[Ibuki; age: 11], [Arona; age: 12], [Plana; age: 13], [Iroha; age: 16], [Kisaki; age: 17], [Hare; age: 16], [Hina; age: 17]]
Partition step: [[Ibuki; age: 11], [Arona; age: 12], [Plana; age: 13], [Iroha; age: 16], [Kisaki; age: 17], [Hare; age: 16], [Hina; age: 17]]
Partition step: [[Ibuki; age: 11], [Arona; age: 12], [Plana; age: 13], [Iroha; age: 16], [Hare; age: 16], [Hina; age: 17], [Kisaki; age: 17]]
Partition step: [[Ibuki; age: 11], [Arona; age: 12], [Plana; age: 13], [Iroha; age: 16], [Hare; age: 16], [Hina; age: 17], [Kisaki; age: 17]]
Quick Sort: 0ms for 7 element(s)
Movements: 11; Comparisons: 11

Work 3.

  • a, Design object Card with 2 fields: rank and suit. Initialize a deck with 52 cards.
  • b, Create instance object comparecard which implements Comparator<Card>. Use the method sort(T[] a, Comparator<? super T> c) in package Arrays of Java to sort the deck.
  • c, Configure the Comparable interface for Card, use methods in Work 2. to sort the deck.
import mygenericsort.*;

import java.util.*;

public class Work3 {

    public static class Card implements Comparable<Card> {
        char suit;
        char rank;

        public Card(int rank, int suit) {
            initSuitAndRank(rank, suit);
        }

        private void initSuitAndRank(int rank, int suit) {
            if (rank >= 2 && rank < 10) {
                this.rank = Character.forDigit(rank, 10);
            } else {
                switch (rank) {
                    case 1:
                        this.rank = 'A'; // Ace
                        break;
                    case 10:
                        this.rank = '1'; // 10
                        break;
                    case 11:
                        this.rank = 'J'; // Jack
                        break;
                    case 12:
                        this.rank = 'Q'; // Queen
                        break;
                    case 13:
                        this.rank = 'K'; // King
                        break;
                    default:
                        throw new IllegalArgumentException("Invalid rank value: " + rank);
                }
            }

            switch (suit) {
                case 1:
                    this.suit = '♠'; // Spades
                    break;
                case 2:
                    this.suit = '♡'; // Hearts
                    break;
                case 3:
                    this.suit = '♢'; // Diamonds
                    break;
                case 4:
                    this.suit = '♣'; // Clubs
                    break;
                default:
                    throw new IllegalArgumentException("Invalid suit value: " + suit);
            }
        }

        private int getRankValue() {
            return switch (rank) {
                case 'A' -> 1;
                case '1' -> 10;
                case 'J' -> 11;
                case 'Q' -> 12;
                case 'K' -> 13;
                default -> rank - '0';
            };
        }

        public static Card[] getDeck() {
            Card[] deck = new Card[52];

            // Suits: 1 to 4 (♠, ♥, ♦, ♣)
            int index = 0;
            for (int suit = 1; suit <= 4; suit++) {
                // Ranks: 1 (Ace), 2-10, 11 (Jack), 12 (Queen), 13 (King)
                for (int rank = 1; rank <= 13; rank++) {
                    deck[index++] = new Card(rank, suit);
                }
            }

            return deck;
        }

        public static void shuffleDeck(Card[] deck) {
            Random random = new Random();

            for (int i = deck.length - 1; i > 0; i--) {
                int j = random.nextInt(i + 1);

                Card temp = deck[i];
                deck[i] = deck[j];
                deck[j] = temp;
            }
        }

        public static void printDeck(Card[] deck) {
            StringBuilder sb = new StringBuilder("[");
            for (int i = 0; i < deck.length; i++) {
                sb.append(deck[i]).append(i == deck.length - 1 ? "]" : ", ");
            }
            System.out.println(sb);
        }

        @Override
        public int compareTo(Card o) {
            if (this.suit == o.suit) {
                return Integer.compare(this.getRankValue(), o.getRankValue());
            } else return Integer.compare(this.suit, o.suit);
        }

        @Override
        public String toString() {
            String rankString;

            if (rank == 'A' || rank == 'J' || rank == 'Q' || rank == 'K') {
                rankString = String.valueOf(rank);
            } else if (rank == '1') {
                rankString = "10";
            } else {
                rankString = String.valueOf(rank);
            }

            return rankString + suit;
        }

    }

    public static class CardComparator implements Comparator<Card> {

        @Override
        public int compare(Card o1, Card o2) {
            return o1.compareTo(o2);
        }

    }

    public static void evaluateSortingAlgorithms(Card[] deck, Sorter<Card> sorter, ArrayList<MySortingAlgorithm<Card>> sortingAlgorithms) {
        for (MySortingAlgorithm<Card> algorithm : sortingAlgorithms) {
            Card[] deckCopy = Arrays.copyOf(deck, deck.length);
            sorter.setSortingAlgorithm(algorithm);
            sorter.sort(deckCopy);
        }
    }

    public static void main(String[] args) {
        Card[] deck = Card.getDeck();
        System.out.println("Standard 52 cards deck:");
        Card.printDeck(deck);
        System.out.println("Shuffled 52 cards deck:");
        Card.shuffleDeck(deck);
        Card.printDeck(deck);

        CardComparator comparecard = new CardComparator();

        // Using sort from package Arrays
        Card[] sortedDeck = Arrays.copyOf(deck, deck.length);
        Arrays.sort(sortedDeck, comparecard);

        System.out.println("Sorted 52 cards deck:");
        Card.printDeck(sortedDeck);

        // Using methods from Work 2.
        System.out.println("\nEvaluating sorting card deck with 5 sorting algorithms:");
        ArrayList<MySortingAlgorithm<Card>> sortingAlgorithms = new ArrayList<>();

        MySortingAlgorithm<Card> bubbleSort = new BubbleSort<>();
        MySortingAlgorithm<Card> selectionSort = new SelectionSort<>();
        MySortingAlgorithm<Card> insertionSort = new InsertionSort<>();
        MySortingAlgorithm<Card> mergeSort = new MergeSort<>();
        MySortingAlgorithm<Card> quickSort = new QuickSort<>();

        sortingAlgorithms.add(bubbleSort);
        sortingAlgorithms.add(selectionSort);
        sortingAlgorithms.add(insertionSort);
        sortingAlgorithms.add(mergeSort);
        sortingAlgorithms.add(quickSort);

        Sorter<Card> sorter = new Sorter<>();
        sorter.setPrintIterations(false);

        evaluateSortingAlgorithms(deck, sorter, sortingAlgorithms);
    }

}

Output:

Standard 52 cards deck:
[A♠, 2♠, 3♠, 4♠, 5♠, 6♠, 7♠, 8♠, 9♠, 10♠, J♠, Q♠, K♠, A♡, 2♡, 3♡, 4♡, 5♡, 6♡, 7♡, 8♡, 9♡, 10♡, J♡, Q♡, K♡, A♢, 2♢, 3♢, 4♢, 5♢, 6♢, 7♢, 8♢, 9♢, 10♢, J♢, Q♢, K♢, A♣, 2♣, 3♣, 4♣, 5♣, 6♣, 7♣, 8♣, 9♣, 10♣, J♣, Q♣, K♣]
Shuffled 52 cards deck:
[10♢, 9♠, Q♡, A♣, 3♣, 4♢, 7♢, J♡, J♠, 3♠, 5♡, 8♡, 6♢, 9♣, A♡, J♣, A♢, 7♣, 5♠, 4♠, K♢, 5♣, 7♡, 5♢, 2♡, 8♣, 6♣, 2♣, 8♠, 7♠, 3♡, 10♣, 2♠, 6♠, 6♡, Q♠, K♡, 10♠, Q♢, 4♡, 2♢, 9♢, 8♢, A♠, K♠, 9♡, 4♣, 3♢, K♣, 10♡, Q♣, J♢]
Sorted 52 cards deck:
[A♠, 2♠, 3♠, 4♠, 5♠, 6♠, 7♠, 8♠, 9♠, 10♠, J♠, Q♠, K♠, A♡, 2♡, 3♡, 4♡, 5♡, 6♡, 7♡, 8♡, 9♡, 10♡, J♡, Q♡, K♡, A♢, 2♢, 3♢, 4♢, 5♢, 6♢, 7♢, 8♢, 9♢, 10♢, J♢, Q♢, K♢, A♣, 2♣, 3♣, 4♣, 5♣, 6♣, 7♣, 8♣, 9♣, 10♣, J♣, Q♣, K♣]

Evaluating sorting card deck with 5 sorting algorithms:
Bubble Sort: 0ms for 52 element(s)
Movements: 644; Comparisons: 1326

Selection Sort: 0ms for 52 element(s)
Movements: 51; Comparisons: 1326

Insertion Sort: 0ms for 52 element(s)
Movements: 644; Comparisons: 644

Merge Sort: 1ms for 52 element(s)
Movements: 300; Comparisons: 224

Quick Sort: 0ms for 52 element(s)
Movements: 187; Comparisons: 254

Work 4. Students are required to solve at least 4 problems on Sorting Algorithms at: codelearn.io.

Note: For this site, if you want to use Java then you’ll have to add the class, the main method to handle input and everything, its not like on LeetCode where you just need to finish the method. Example:

import java.util.*;

public class InsertionSort {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = sc.nextInt();
        }
        System.out.println(insertionSort(arr));
    }

    public static String insertionSort(int[] arr) {
        int n = arr.length;
        for (int i = 1; i < n; ++i) {
            int key = arr[i];
            int j = i - 1;

            while (j >= 0 && arr[j] > key) {
                arr[j + 1] = arr[j];
                j = j - 1;
            }
            arr[j + 1] = key;
        }
        return Arrays.toString(arr).replaceAll(",", "").replaceAll("\\[", "").replaceAll("]", " ");
    }

}

Bubble Sort:

public static String bubbleSort(int[] arr) {
    int n = arr.length;
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
    return Arrays.toString(arr).replaceAll(",", "").replaceAll("\\[", "").replaceAll("]", " ");
}

Selection Sort:

public static String selectionSort(int[] arr) {
    int n = arr.length;
    for (int i = 0; i < n - 1; i++) {
        int minIndex = i;
        for (int j = i + 1; j < n; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        int temp = arr[minIndex];
        arr[minIndex] = arr[i];
        arr[i] = temp;
    }
    return Arrays.toString(arr).replaceAll(",", "").replaceAll("\\[", "").replaceAll("]", " ");
}

Insertion Sort:

public static String insertionSort(int[] arr) {
    int n = arr.length;
    for (int i = 1; i < n; ++i) {
        int key = arr[i];
        int j = i - 1;

        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j = j - 1;
        }
        arr[j + 1] = key;
    }
    return Arrays.toString(arr).replaceAll(",", "").replaceAll("\\[", "").replaceAll("]", " ");
}

Merge Sort:

public static String mergeSort(int[] arr) {
    mergeSort(arr, 0, arr.length - 1);
    return Arrays.toString(arr).replaceAll(",", "").replaceAll("\\[", "").replaceAll("]", " ");
}

public static void mergeSort(int[] arr, int left, int right) {
    if (left < right) {
        int mid = left + (right - left) / 2;
        mergeSort(arr, left, mid);
        mergeSort(arr, mid + 1, right);
        merge(arr, left, mid, right);
    }
}

private static void merge(int[] arr, int left, int mid, int right) {
    int n1 = mid - left + 1;
    int n2 = right - mid;
    int[] leftArray = new int[n1];
    int[] rightArray = new int[n2];
    System.arraycopy(arr, left, leftArray, 0, n1);

    for (int j = 0; j < n2; ++j) {
        rightArray[j] = arr[mid + 1 + j];
    }

    int i = 0, j = 0;
    int k = left;
    while (i < n1 && j < n2) {
        if (leftArray[i] <= rightArray[j]) {
            arr[k] = leftArray[i];
            i++;
        } else {
            arr[k] = rightArray[j];
            j++;
        }
        k++;
    }

    while (i < n1) {
        arr[k] = leftArray[i];
        i++;
        k++;
    }

    while (j < n2) {
        arr[k] = rightArray[j];
        j++;
        k++;
    }
}

Quick Sort:

public static String quickSort(int[] arr) {
    quickSort(arr, 0, arr.length - 1);
    return Arrays.toString(arr).replaceAll(",", "").replaceAll("\\[", "").replaceAll("]", " ");
}

private static void quickSort(int[] arr, int low, int high) {
    if (low < high) {
        int pi = partition(arr, low, high);
        quickSort(arr, low, pi - 1);
        quickSort(arr, pi + 1, high);
    }
}

private static int partition(int[] arr, int low, int high) {
    int pivot = arr[high];
    int i = low - 1;
    for (int j = low; j < high; j++) {
        if (arr[j] < pivot) {
            i++;
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    int temp = arr[i + 1];
    arr[i + 1] = arr[high];
    arr[high] = temp;
    return i + 1;
}

Shell Sort:

public static String shellSort(int[] arr) {
    int n = arr.length;

    for (int gap = n / 2; gap > 0; gap /= 2) {
        for (int i = gap; i < n; i++) {
            int key = arr[i];
            int j = i;

            while (j >= gap && arr[j - gap] > key) {
                arr[j] = arr[j - gap];
                j -= gap;
            }
            arr[j] = key;
        }
    }
    return Arrays.toString(arr).replaceAll(",", "").replaceAll("\\[", "").replaceAll("]", " ");
}

Find Smallest Int Not Present:

  • Given n-size integer array, find the smallest integer that is not present in the array.
  • Example: Input: [1, 2, 3, 5], Output: 4.

1) Sorting approach

public static int smallestMissingInt(int[] arr) {
    // Use sorting algorithm of your choice
    Arrays.sort(arr);
    int smallestMissing = 0;

    for (int num : arr) {
        if (num < 0) {
            continue;
        }
        if (num == smallestMissing) {
            smallestMissing++;
        }
    }
    return smallestMissing;
}

2) HashSet approach

public static int smallestMissingInt(int[] arr) {
    // Use sorting algorithm of your choice, preferably O(nlogn)
    HashSet<Integer> set = new HashSet<>();
    for (int num : arr) {
        set.add(num);
    }

    int smallestMissing = 0;
    while (set.contains(smallestMissing)) {
        smallestMissing++;
    }
    return smallestMissing;
}

Minimal Informants:

  • Given n-size integer array and range k, find the minimal number of elements that can reach all other element within range k with given distance formula: |a[i] - a[j]|.
  • Example: Input: a = [1, 3, 2, 5, 10, 8], k = 2, Output: 2.
public static int minInitialInformants(int[] a, int k) {
    // Use sorting algorithm of your choice, preferably O(nlogn)
    Arrays.sort(a);
    
    int count = 0;
	for (int i = 1; i < a.length; i++){
		if (a[i] - a[i-1] > k){
			count ++;
		}
	}
	return count + 1;
}

Ascending Squares:

  • Given n-size integer array, print out all unique perfect squares in ascending order, if none then output NULL.
  • Example: Input: [16, 1, 2, 1, 10, 8], Output: 1 16.

1) Sorting and HashSet approach

public static String findPerfectSquares(int[] arr) {
    Set<Integer> perfectSquares = new HashSet<>();
    
    for (int num : arr) {
        if (num >= 0) {
            int sqrt = (int) Math.sqrt(num);
            if (sqrt * sqrt == num) {
                perfectSquares.add(num);
            }
        }
    }

    if (perfectSquares.isEmpty()) {
        return "NULL";
    } else {
        List<Integer> sortedPerfectSquares = new ArrayList<>(perfectSquares);
        Collections.sort(sortedPerfectSquares); // Sorting happens here
        StringBuilder result = new StringBuilder();
        for (int square : sortedPerfectSquares) {
            result.append(square).append(" ");
        }
        return result.toString().replaceAll(",", "").replaceAll("\\[", "").replaceAll("]", " ");
    }
}

2) TreeSet approach

public static String findAscendingPerfectSquares(int[] arr) {
    Set<Integer> perfectSquares = new TreeSet<>();
    
    for (int num : arr) {
        if (num >= 0) {
            int sqrt = (int) Math.sqrt(num);
            if (sqrt * sqrt == num) {
                perfectSquares.add(num);
            }
        }
    }

    if (perfectSquares.isEmpty()) {
        return "NULL";
    } else {
        StringBuilder result = new StringBuilder();
        for (int square : perfectSquares) {
            result.append(square).append(" ");
        }
        return result.toString().replaceAll(",", "").replaceAll("\\[", "").replaceAll("]", " ");
    }
}

Frequencies:

1) Sorting approach

public static String countFrequencies(int[] arr) {
    // Use sorting algorithm of your choice, preferably O(nlogn)
    Arrays.sort(arr);
    
    StringBuilder result = new StringBuilder();
    for (int i = 0; i < arr.length; ) {
        int count = 0;
        int currentNumber = arr[i];

        while (i < arr.length && arr[i] == currentNumber) {
            count++;
            i++;
        }
        result.append(currentNumber).append(" ").append(count).append("; ");
    }
    return result.toString().replaceAll(",", "").replaceAll("\\[", "").replaceAll("]", " ");
}

2) HashMap approach

public static String countFrequencies(int[] arr) {
    Map<Integer, Integer> frequencyMap = new HashMap<>();
    for (int num : arr) {
        frequencyMap.put(num, frequencyMap.getOrDefault(num, 0) + 1);
    }

    Integer[] uniqueNumbers = frequencyMap.keySet().toArray(new Integer[0]);
    Arrays.sort(uniqueNumbers);

    StringBuilder result = new StringBuilder();
    for (int key : uniqueNumbers) {
        result.append(key).append(" ").append(frequencyMap.get(key)).append("; ");
    }

    return result.toString().replaceAll(",", "").replaceAll("\\[", "").replaceAll("]", " ");
}

Positive Up, Negative Down:

  • Given n-size integer array, if present then the position of 0 remains unchanged.
  • Sort elements that are < 0 in descending order and elements that are > 0 in ascending order.
public static String positiveUpNegativeDown(int[] arr) {
    List<Integer> negativeNumbers = new ArrayList<>();
    List<Integer> positiveNumbers = new ArrayList<>();

    for (int num : arr) {
        if (num < 0) {
            negativeNumbers.add(num);
        } else if (num > 0) {
            positiveNumbers.add(num);
        }
    }

    Collections.sort(negativeNumbers, Collections.reverseOrder());
    Collections.sort(positiveNumbers);

    StringBuilder result = new StringBuilder();
    int negIndex = 0, posIndex = 0;

    for (int num : arr) {
        if (num == 0) {
            result.append("0 ");
        } else if (num < 0) {
            result.append(negativeNumbers.get(negIndex++)).append(" ");
        } else {
            result.append(positiveNumbers.get(posIndex++)).append(" ");
        }
    }

    return result.toString().replaceAll(",", "").replaceAll("\\[", "").replaceAll("]", " ");
}

Work 5.

Work 6.

public static int findKthSmallest(int[] arr, int k) {
    Arrays.sort(arr);
    return arr[k - 1];
}

public static int findKthLargest(Integer[] arr, int k) {
    Arrays.sort(arr, Collections.reverseOrder());
    return arr[k - 1];
}

Work 7.

  • Pair sum: Pair sum.
  • Given n-size array, target x, print out all the possible pair of integers that sums up to x.
  • Example: Input: a = [1 2 4 3 4 5 3], x = 7, Output: 4
public static int findPairs(int[] arr, int target) {
    List<int[]> pairs = new ArrayList<>();
    Map<Integer, Integer> complementMap = new HashMap<>();

    for (int i = 0; i < arr.length; i++) {
        int complement = target - arr[i];
        if (complementMap.containsKey(complement)) {
            pairs.add(new int[]{complement, arr[i]});
        }
        complementMap.put(arr[i], i);
    }

    return pairs.size();
}

Work 8. String sorting

  • Sort the digits in a given string in ascending order.
  • Given the small range of digit values, choose an appropriate sorting algorithm.
  • Iterate through the string to count the frequency of each digit.
  • Use the frequency counts to construct the sorted string.

Work 9.

  • Find new pos: Find new pos.
  • Given n-size array, position of x as i, find the position of x after ascending sort.
  • Example: a = [8, 1, 7, 2], i = 1, so x = 8, Output: 4;
public static int findNewPosition(int[] arr, int i) {
    int x = arr[i];
    int[] sortedArr = arr.clone();
    Arrays.sort(sortedArr);
    return binarySearch(sortedArr, x);
}

private static int binarySearch(int[] sortedArr, int x) {
    int left = 0;
    int right = sortedArr.length - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (sortedArr[mid] == x) {
            return mid + 1;
        } else if (sortedArr[mid] < x) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    return -1;
}