{"id":24358752,"url":"https://github.com/eduardob-programador/dsa-learning","last_synced_at":"2026-04-29T09:32:13.517Z","repository":{"id":272065136,"uuid":"915420617","full_name":"EduardoB-Programador/DSA-Learning","owner":"EduardoB-Programador","description":"A project where I build data structures and algorithms, and test them","archived":false,"fork":false,"pushed_at":"2025-04-18T22:35:13.000Z","size":83,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-07T00:38:24.947Z","etag":null,"topics":["algorithms","algorithms-datastructures","data-structures","dsa","java","junit-jupiter","junit5","searching-algorithms","sorting-algorithms"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EduardoB-Programador.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-01-11T19:56:20.000Z","updated_at":"2025-04-18T22:35:16.000Z","dependencies_parsed_at":"2025-04-20T10:30:16.754Z","dependency_job_id":null,"html_url":"https://github.com/EduardoB-Programador/DSA-Learning","commit_stats":null,"previous_names":["eduardob-programador/dsa-learning"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/EduardoB-Programador/DSA-Learning","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EduardoB-Programador%2FDSA-Learning","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EduardoB-Programador%2FDSA-Learning/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EduardoB-Programador%2FDSA-Learning/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EduardoB-Programador%2FDSA-Learning/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EduardoB-Programador","download_url":"https://codeload.github.com/EduardoB-Programador/DSA-Learning/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EduardoB-Programador%2FDSA-Learning/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32419882,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-29T06:29:02.080Z","status":"ssl_error","status_checked_at":"2026-04-29T06:29:00.631Z","response_time":110,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["algorithms","algorithms-datastructures","data-structures","dsa","java","junit-jupiter","junit5","searching-algorithms","sorting-algorithms"],"created_at":"2025-01-18T20:22:14.715Z","updated_at":"2026-04-29T09:32:13.510Z","avatar_url":"https://github.com/EduardoB-Programador.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Navegação/Navigation\n\n|[Português](#portugues)|[English](#english)|[Português](#português)|[English](#english)|[Português](#português)|[English](#english)|\n|:-|:-|:-|:-|:-|:-|\n|[Visão Geral](#visao-geral)|[Overview](#overview)|[Algoritmos de Organização](#organizacao)|[Sort Algorithms](#sorting)|[Estruturas de Dados](#estruturas-de-dados)|[Data Structures](#data-structures)|\n|[Algoritmos de Procura](#procura)|[Search Algorithms](#searching)|[BubbleSort](#bubblesort-pt)|[BubbleSort](#bubblesort-en)|[Stack](#stack-pt)|[Stack](#stack-en)|\n|[Linear Search](#linearsearch-pt)|[Linear Search](#linearsearch-en)|[SelectionSort](#selectionsort-pt)|[SelectionSort](#selectionsort-en)|[Static Stack](#static-stack-pt)|[Static Stack](#static-stack-en)|\n|[Binary Search](#binarysearch-pt)|[Binary Search](#binarysearch-en)|[InsertionSort](#insertionsort-pt)|[InsertionSort](#insertionsort-en)|[Dynamic Stack](#dynamic-stack-pt)|[Dynamic Stack](#dynamic-stack-en)|\n|||[QuickSort](#quicksort-pt)|[QuickSort](#quicksort-en)|[Linked List](#linked-list-pt)|[Linked List](#linked-list-en)|\n|||[MergeSort](#mergesort-pt)|[MergeSort](#mergesort-en)|[Queue](#queue-pt)|[Queue](#queue-en)|\n|||||[Binary Tree](#binary-tree-pt)|[Binary Tree](#binary-tree-en)|\n\n\u003ca id=\"portugues\"\u003e\u003c/a\u003e\n# Português\n\u003ca id=\"visao-geral\"\u003e\u003c/a\u003e\n## Visão Geral\n\nO objetivo desse projeto foi entender e praticar o uso de **estruturas de dados** e **algoritmos**, aqui eu utilizo diferentes estruturas de dados e **algoritmos de organização e procura**.\n\nPor mais que a organização dos diretórios não seja a melhor, eu pelo menos tentei deixar o mais intuitivo possível.\n\nOs algoritmos se encontram em:\n- [Searching](./src/main/java/com/eduardo/Searching.java)\n- [Sorting](./src/main/java/com/eduardo/Sorting.java)\n\nEnquanto as estruturas de dados se encontram em:\n- [Estruturas de dados](./src/main/java/com/eduardo/dataStructures/)\n  - [Stack](./src/main/java/com/eduardo/dataStructures/Stack.java)\n  - [Static Stack](./src/main/java/com/eduardo/dataStructures/StaticStack.java)\n  - [Dynamic Stack](./src/main/java/com/eduardo/dataStructures/DynamicStack.java)\n  - [Linked List](./src/main/java/com/eduardo/dataStructures/LinkedList.java)\n  - [Queue](./src/main/java/com/eduardo/dataStructures/Queue.java)\n  - [Binary Tree](./src/main/java/com/eduardo/dataStructures/BinaryTree.java)\n\n## Algoritmos\n\n\u003ca id=\"procura\"\u003e\u003c/a\u003e\n### Algoritmos de Procura/Search\n\nNo arquivo [Searching.java](./src/main/java/com/eduardo/Searching.java) temos 3 métodos referentes a algorimos de procura, onde 2 são referentes a **Binary Search** enquanto o outro faz referência à **Linear Search**. Abaixo estão as características dos métodos:\n\n```.java\npublic static int linearSearch(int[] nums, int target)\npublic static int binarySort(int[] nums, int target)\npublic static int binarySortRecursive(int[] nums, int target, int left, int right)\n//Acabei de perceber que esse último método está como \"sort\", não como search que é o que deveria estar escrito, mas pelo motivo de no arquivo original estar da mesma forma eu deixarei assim\n```\n\u003ca id=\"linearsearch-pt\"\u003e\u003c/a\u003e\n### LinearSearch\n\n```.java\npublic static int linearSearch(int[] nums, int target){\n  int step = 0;\n  for (int i = 0; i \u003c nums.length; i++) {\n    step++;\n    if (nums[i] == target) {\n      System.out.println(\"Amount of operations: \" + step);\n      return i;\n    }\n  }\n  System.out.println(\"Amount of operations: \" + step);\n  return -1;\n}\n```\n\nO algoritmo de **busca linear** percorre sequencialmente cada elemento de uma estrutura de dados (como um array ou lista), comparando um a um com o valor desejado. Ele é simples e funciona para qualquer tipo de dado, ordenado ou não, mas pode ser ineficiente em listas grandes.\n\nImportante dizer que no código existe uma variável **step**, onde ela conta a quantidade de iterações para encontrar o *target*.\n\nA complexidade temporal desse método é O(n)\n\n\u003ca id=\"binarysearch-pt\"\u003e\u003c/a\u003e\n### BinarySearch\n\n```.java\npublic static int binarySort(int[] nums, int target) {\n  int left = 0;\n  int right = nums.length -1;\n  int step = 0;\n\n  while (left \u003c= right) {\n    step++;\n    int mid = (left + right) / 2;\n\n    if (nums[mid] == target) {\n      System.out.println(\"Amount of operations: \" + step);\n      return mid;\n    } else if (target \u003e nums[mid])\n      left = mid+1;\n    else\n      right = mid-1;\n\n\n  }\n  System.out.println(\"Amount of operations: \" + step);\n  return -1;\n}\n\npublic static int binarySortRecursive(int[] nums, int target, int left, int right) {\n  if (left \u003c= right) {\n    int mid = (left + right) /2;\n\n    if (nums[mid] == target)\n      return mid;\n    else if (target \u003e nums[mid])\n      return binarySortRecursive(nums, target, mid+1, right);\n    else\n      return binarySortRecursive(nums, target, left, mid-1);\n  }\n  return -1;\n}\n```\n\nBusca binária é um algoritmo eficiente para encontrar elementos em listas ordenadas. A ideia é dividir o array ao meio a cada iteração, descartando metade do espaço de busca. Isso o torna muito mais rápido que a busca linear para grandes volumes de dados.\n\nNovamente, temos a variável step marcando a quantidade de iterações até que seja encontrado o *target*.\n\nExiste também o método BinarySearchRecursive, onde, ao invés de iterações temos recurções, mas na sua base os métodos funcionam da mesma forma.\n\nA complexidade temporal desse método é O(log2 n)\n\n\u003ca id=\"organizacao\"\u003e\u003c/a\u003e\n### Algoritmos de Organização/Sort\n\nNo arquivo [Sorting.java](./src/main/java/com/eduardo/Sorting.java) estão reunidos 5 métodos de organização diferentes, dentre eles: **BubbleSort**, **SelectionSort**, **InsertSort**, **QuickSort** e **MergeSort**. Abaixo estão as características de cada método.\n\n```.java\npublic static void bubbleSort(int[] nums)\npublic static void selectionSort(int[] nums)\npublic static void insertionSort(int[] nums)\n\npublic static void quickSort(int[] nums, int low, int high)\nprivate static int partition(int[] nums, int low, int high)\n\npublic static void mergeSort(int[] nums, int left, int right)\nprivate static void merge(int[] nums, int left, int mid, int right)\n```\n\u003ca id=\"bubblesort-pt\"\u003e\u003c/a\u003e\n### BubbleSort\n\n```.java\npublic static void bubbleSort(int[] nums) {\n  int size = nums.length;\n\n  for (int i = 0; i \u003c size; i++) {\n    for (int j = 0; j \u003c size-1-i; j++) {\n      if (nums[j] \u003e nums[j+1]) {\n        int temp = nums[j];\n        nums[j] = nums[j+1];\n        nums[j+1] = temp;\n      }\n    }\n  }\n}\n```\n\nO algoritmo percorre o array diversas vezes, comparando pares de elementos adjacentes e trocando-os se estiverem fora de ordem. O processo se repete até que nenhuma troca seja necessária. É um dos algoritmos mais simples, mas também um dos menos eficientes.\n\nA complexidade temporal desse método é O(n²)\n\n\u003ca id=\"selectionsort-pt\"\u003e\u003c/a\u003e\n### SelectionSort\n\n```.java\npublic static void selectionSort(int[] nums) {\n  final int size = nums.length;\n  int index = 0;\n  int temp = 0;\n\n  for (int i = 0; i \u003c size-1; i++) {\n    for (int j = 0; j \u003c size-i; j++) {\n      if (nums[j] \u003e nums[index])\n        index = j;\n    }\n\n    temp = nums[size-1-i];\n    nums[size-1-i] = nums[index];\n    nums[index] = temp;\n    index = 0;\n  }\n}\n```\n\nO **Selection Sort** encontra o último elemento da lista e o coloca na última posição, depois repete o processo com os elementos restantes não organizados. Embora seja mais eficiente que o Bubble Sort em certos casos, ainda é considerado ineficiente para grandes volumes de dados.\n\nA complexidade temporal desse método é O(n²)\n\n\u003ca id=\"insertionsort-pt\"\u003e\u003c/a\u003e\n### InsertionSort\n\n```.java\npublic static void insertionSort(int[] nums) {\n  final int size = nums.length;\n\n  for (int i = 1; i \u003c size; i++) {\n    int value = nums[i];\n\n    int j = i-1;\n    while (j\u003e=0 \u0026\u0026 nums[j] \u003e value) {\n      nums[j+1] = nums[j];\n      j--;\n    }\n    nums[j+1] = value;\n  }\n}\n```\n\nO **Insertion Sort** constrói a lista ordenada gradualmente, inserindo cada novo elemento na posição correta em relação aos já ordenados. É bastante eficiente para listas pequenas ou parcialmente ordenadas.\n\nA complexidade temporal desse método é O(n²), mas no melhor dos casos (caso a lista aleatoriamente seja criada em ordem crescente) pode chegar à O(n).\n\n\u003ca id=\"quicksort-pt\"\u003e\u003c/a\u003e\n### QuickSort\n\n```.java\npublic static void quickSort(int[] nums, int low, int high) {\n\n  if (low \u003c high) {\n    int pi = partition(nums, low, high);\n\n    quickSort(nums, low, pi -1);\n    quickSort(nums, pi +1, high);\n  }\n}\n\nprivate static int partition(int[] nums, int low, int high) {\n  int pivot = nums[high];\n  int i = low -1;\n\n  for (int j = low; j \u003c high; j++) {\n    if (nums[j] \u003c pivot) {\n      i++;\n\n      int temp = nums[i];\n      nums[i] = nums[j];\n      nums[j] = temp;\n    }\n  }\n  nums[high] = nums[i+1];\n  nums[i+1] = pivot;\n\n  return i+1;\n}\n```\n\nDivide e conquista. O **Quick Sort** escolhe um elemento chamado \"pivô\" e o usa para dividir a lista em duas partes: uma com elementos menores e outra com maiores. Depois, ordena cada parte recursivamente. É muito eficiente na prática.\n\nA complexidade temporal desse método é O(n • log2 n) na maioria dos casos, e O(n²) no pior dos casos (onde a array ocasionalmente já esteja organizada).\n\n\u003ca id=\"mergesort-pt\"\u003e\u003c/a\u003e\n### MergeSort\n\n```.java\npublic static void mergeSort(int[] nums, int left, int right) {\n  int mid = (left + right) /2;\n\n  if (left \u003c right){\n    mergeSort(nums, left, mid);\n    mergeSort(nums, mid +1, right);\n    merge(nums, left, mid, right);\n  }\n}\n\nprivate static void merge(int[] nums, int left, int mid, int right) {\n  int[] leftArr = new int[mid - left +1];\n  int[] rightArr = new int[right - mid];\n\n  for (int i = 0; i \u003c leftArr.length; i++)\n    leftArr[i] = nums[left+i];\n\n  for (int i = 0; i \u003c rightArr.length; i++)\n    rightArr[i] = nums[mid+1+i];\n\n  int i = 0;\n  int j = 0;\n  int k = left;\n\n  while (i \u003c leftArr.length \u0026\u0026 j \u003c rightArr.length) {\n\n    if (leftArr[i] \u003c= rightArr[j]) {\n      nums[k] = leftArr[i];\n      i++;\n    } else {\n      nums[k] = rightArr[j];\n      j++;\n    }\n\n    k++;\n  }\n\n  while (i\u003cleftArr.length) {\n    nums[k] = leftArr[i];\n    i++;\n    k++;\n  }\n\n  while (j\u003crightArr.length) {\n    nums[k] = rightArr[j];\n    j++;\n    k++;\n  }\n}\n```\n\nOutro algoritmo baseado em dividir e conquistar. Ele divide a lista até restarem listas unitárias, e então começa a mesclá-las de forma ordenada. É estável, excelente desempenho mesmo em grandes volumes.\n\nA complexidade temporal desse método é O(n • log2 n).\n\u003ca id=\"estruturas-de-dados\"\u003e\u003c/a\u003e\n## Estruturas de Dados\n\nNo diretório [dataStructures](./src/main/java/com/eduardo/dataStructures) se encontram todas as classes de estruturas de dados, onde existem 8 classes diferentes, dentre elas existem 5 estruturas de dados, essas são: **Static Stack**, **Dynamic Stack**, **Linked List**, **Queue** e **Binary Tree**. Enquanto o restante das classes são complementares para essas estruturas.\n\n\u003ca id=\"stack-pt\"\u003e\u003c/a\u003e\n### Stack\n\n```.java\npublic abstract sealed class Stack\u003cT\u003e permits StaticStack, DynamicStack {\n    protected int top = 0;\n    protected Object[] stack;\n    protected int currentSize = 0;\n    public static final int DEFAULT_SIZE = 5;\n\n    public Stack(int size) {\n        if (size \u003c= 0)\n            this.stack = new Object[DEFAULT_SIZE];\n\n        else\n            this.stack = new Object[size];\n    }\n\n    public Stack() {\n        this.stack = new Object[DEFAULT_SIZE];\n    }\n\n    public abstract void push(T t);\n\n    public abstract T pop();\n\n    @SuppressWarnings(\"unchecked\")\n    public T peek() {\n        return (T) this.stack[top];\n    }\n\n    public int getCurrentSize() {\n        return this.currentSize;\n    }\n\n    @Override\n    public String toString() {\n        return \"\";\n    }\n\n    public void clear() {\n        this.top = 0;\n        this.currentSize = 0;\n\n        Arrays.fill(this.stack, null);\n\n    }\n\n    public void show() {\n        System.out.println(toList().toString());\n    }\n\n    //For test purposes\n    @SuppressWarnings(\"unchecked\")\n    public List\u003cT\u003e toList() {\n        return (List\u003cT\u003e) Arrays.stream(this.stack)\n                .filter(Objects::nonNull)\n                .toList();\n    }\n\n    public int getStackCapacity() {\n        return this.stack.length;\n    }\n\n}\n```\n\nSuperclasse de todos os tipos de stack no pacote.\n\n\u003ca id=\"static-stack-pt\"\u003e\u003c/a\u003e\n### Static Stack\n\n```.java\npublic non-sealed class StaticStack\u003cT\u003e extends Stack\u003cT\u003e {\n\n    public StaticStack(int size) {\n        super(size);\n    }\n\n    public StaticStack() {\n        super();\n    }\n\n    @Override\n    public void push(T t) {\n        if (top+1 \u003e stack.length)\n            throw new ArrayIndexOutOfBoundsException(\"Current size:\" + currentSize + \" Capacity:\" + stack.length);\n\n        if (stack[top] != null)\n            top++;\n\n        stack[top] = t;\n        currentSize++;\n\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public T pop() {\n        if (currentSize -1 \u003c= -1)\n            throw new ArrayIndexOutOfBoundsException(\"Current size:\" + currentSize);\n\n        T lastTop = (T) stack[top];\n        stack[top] = null;\n\n        if (top -1 \u003c= -1)\n            top = 0;\n        else\n            top--;\n\n        currentSize--;\n\n        return lastTop;\n    }\n\n}\n```\n\nPilha com tamanho fixo, baseada em um array. Suporta operações LIFO (Last In, First Out), como push (inserir) e pop (remover). Boa para quando o tamanho da pilha pode ser previamente conhecido.\n\n\u003ca id=\"dynamic-stack-pt\"\u003e\u003c/a\u003e\n### Dynamic Stack\n\n```.java\npublic non-sealed class DynamicStack\u003cT\u003e extends Stack\u003cT\u003e {\n\n    public DynamicStack(int size) {\n        super(size);\n    }\n\n    public DynamicStack() {\n        super();\n    }\n\n    @Override\n    public void push(T t) {\n        if (top +1 \u003e= stack.length)\n            grow();\n\n        if (stack[top] != null)\n            top++;\n\n        stack[top] = t;\n        currentSize++;\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public T pop() {\n        if (currentSize -1 \u003c= -1)\n            throw new ArrayIndexOutOfBoundsException(\"Current size:\" + currentSize);\n\n        T lastTop = (T) stack[top];\n        stack[top] = null;\n\n        if (top \u003c= stack.length /4)\n            shrink();\n\n        if (top -1 \u003c= -1)\n            top = 0;\n        else\n            top--;\n        currentSize--;\n\n        return lastTop;\n    }\n\n    //doubles the stack's capacity\n    protected void grow() {\n        Object[] newStack = new Object[stack.length *2];\n\n        System.arraycopy(stack, 0, newStack, 0, stack.length);\n\n        stack = newStack;\n    }\n\n    //halves the stack's capacity\n    protected void shrink() {\n        Object[] newStack = new Object[stack.length /2];\n\n        if (top + 1 \u003e= 0) System.arraycopy(stack, 0, newStack, 0, top + 1);\n\n        stack = newStack;\n    }\n\n}\n```\n\nPilha dinâmica baseada em lista encadeada. Não possui limite de tamanho pré-definido, sendo alocada conforme a necessidade. Também segue o padrão LIFO.\n\n\u003ca id=\"linked-list-pt\"\u003e\u003c/a\u003e\n### Linked List\n\n```.java\npublic class LinkedList\u003cT\u003e {\n    private Node\u003cT\u003e head;\n    private Integer size = 0;\n\n    public LinkedList() {}\n\n    public void add(T value) {\n        Node\u003cT\u003e newNode = new Node\u003c\u003e(value);\n\n        if (this.head == null)\n            this.head = newNode;\n\n        else {\n            Node\u003cT\u003e lastNode = this.head;\n            while (lastNode.next != null)\n                lastNode = lastNode.next;\n\n            lastNode.next = newNode;\n        }\n\n        this.size++;\n    }\n\n    public void add(int index, T value) {\n\n        if (index \u003c= 0)\n            this.addFirst(value);\n\n        else if (index \u003e= this.size) {\n            this.add(value);\n\n        } else {\n            Node\u003cT\u003e indexNode = new Node\u003c\u003e(value);\n\n            Node\u003cT\u003e n = this.head;\n            for (int i = 0; i \u003c index-1; i++) {\n                n = n.next;\n            }\n            indexNode.next = n.next;\n            n.next = indexNode;\n            this.size++;\n        }\n    }\n\n    public void addFirst(T value) {\n        Node\u003cT\u003e temp = this.head;\n        this.head = new Node\u003c\u003e(value);\n        this.head.next = temp;\n        this.size++;\n    }\n\n    public T get(int index) {\n        if (this.head == null)\n            return null;\n\n        Node\u003cT\u003e n = this.head;\n\n        if (index \u003c= 0)\n            return this.head.value;\n\n        else if (index \u003e= this.size) {\n            while (n.next != null) {\n                n = n.next;\n            }\n        } else {\n            for (int i = 0; i \u003c index; i++)\n                n = n.next;\n        }\n\n        return n.value;\n    }\n\n    public void remove() {\n        if (this.head == null)\n            return ;\n\n        Node\u003cT\u003e n = this.head;\n        while (n.next.next != null)\n            n = n.next;\n\n        n.next = null;\n\n        this.size--;\n    }\n\n    public void remove(int index) {\n\n        if (this.head == null)\n            return ;\n\n        if (index \u003c= 0)\n            this.removeFirst();\n\n        else if (index \u003e= size)\n            this.remove();\n\n        else {\n            Node\u003cT\u003e n = this.head;\n\n            for (int i = 0; i \u003c index-1; i++)\n                n = n.next;\n\n            n.next = n.next.next;\n\n            this.size--;\n        }\n    }\n\n    public void removeFirst() {\n\n        if (this.head == null)\n            return ;\n\n        this.head = this.head.next;\n\n        this.size--;\n    }\n\n    public void show() {\n        if (this.head == null) {\n            System.out.println(\"null\");\n            return ;\n        }\n\n        StringBuilder sb = new StringBuilder(\"[ \");\n\n        Node\u003cT\u003e n = this.head;\n        do {\n            sb.append(n.value).append(\" \");\n            n = n.next;\n        } while (n != null \u0026\u0026 n.next != null);\n\n        if (n != null)\n            sb.append(n.value).append(\" \");\n\n        sb.append(\"]\");\n        System.out.println(sb);\n    }\n\n    public void clear() {\n        this.head = null;\n        this.size = 0;\n    }\n\n    @Override\n    public String toString() {\n        if (this.head == null)\n            return null;\n\n        return this.head.toString();\n    }\n\n}\n```\n\nEstrutura linear onde cada elemento (node) contém um valor e uma referência para o próximo. Permite inserções e remoções eficientes em qualquer posição da lista.\n\n\u003ca id=\"queue-pt\"\u003e\u003c/a\u003e\n### Queue\n\n```.java\npublic class Queue\u003cT\u003e {\n    protected int end = 0;\n    protected int start = 0;\n    protected Object[] queue;\n    protected int currentSize = 0;\n    public static final int DEFAULT_SIZE = 5;\n\n    public Queue() {\n        this.queue = new Object[DEFAULT_SIZE];\n    }\n\n    public Queue(int size) {\n        this.queue = new Object[size];\n    }\n\n    public void enqueue(T t) {\n        if (currentSize +1 \u003e getQueueCapacity())\n            throw new ArrayIndexOutOfBoundsException(\"Capacity exceeded\\ncurrent size: \" + currentSize + \"\\ncapacity:\" + getQueueCapacity());\n\n\n        if (queue[end] == null)\n            queue[end] = t;\n\n        else\n            queue[start] = t;\n\n        start = (start+1) % getQueueCapacity();\n        currentSize++;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public T dequeue() {\n        if (currentSize -1 \u003c= -1)\n            throw new ArrayIndexOutOfBoundsException(\"index -1\");\n\n        T t = (T) queue[end];\n        queue[end] = null;\n\n        end = (end+1) % getQueueCapacity();\n        currentSize--;\n\n        return t;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public T peek() {\n        return (T) this.queue[end];\n    }\n\n    public void clear() {\n        this.end = 0;\n        this.currentSize = 0;\n\n        Arrays.fill(queue, null);\n    }\n\n    public void show() {\n        System.out.println(toList().toString());\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public List\u003cT\u003e toList() {\n        List\u003cT\u003e l = new ArrayList\u003c\u003e();\n\n        for (int i = 0; i \u003c currentSize; i++) {\n            l.add((T) queue[(end+i) % getQueueCapacity()]);\n        }\n\n        return l;\n    }\n\n    public int getCurrentSize() {\n        return this.currentSize;\n    }\n\n    public int getQueueCapacity() {\n        return this.queue.length;\n    }\n\n}\n```\n\nEstrutura de dados que segue o princípio FIFO (First In, First Out). Elementos são inseridos no final da fila e removidos do início. Ideal para processamento sequencial.\n\n\u003ca id=\"binary-tree-pt\"\u003e\u003c/a\u003e\n### Binary Tree\n\n```.java\npublic class BinaryTree\u003cT extends Comparable\u003cT\u003e\u003e {\n\n    private TreeNode\u003cT\u003e root;\n\n    public BinaryTree() {}\n\n    public void insert(T data) {\n        root = insertRec(root, data);\n    }\n\n    private TreeNode\u003cT\u003e insertRec(TreeNode\u003cT\u003e newRoot, T data) {\n\n        if (newRoot == null)\n            newRoot = new TreeNode\u003c\u003e(data);\n\n        else if (data.compareTo(newRoot.value) \u003c 0)\n            newRoot.left = insertRec(newRoot.left, data);\n\n        else\n            newRoot.right = insertRec(newRoot.right, data);\n\n        return newRoot;\n    }\n\n    public void inOrder() {\n        inOrderRec(root);\n        System.out.println();\n    }\n\n    private void inOrderRec(TreeNode\u003cT\u003e node) {\n\n        if (node != null) {\n            inOrderRec(node.left);\n            System.out.print(node.value + \" \");\n            inOrderRec(node.right);\n        }\n    }\n\n    public void preOrder() {\n        preOrderRec(root);\n        System.out.println();\n    }\n\n    private void preOrderRec(TreeNode\u003cT\u003e node) {\n\n        if (node != null) {\n            System.out.print(node.value + \" \");\n            preOrderRec(node.left);\n            preOrderRec(node.right);\n        }\n    }\n}\n```\n\nEstrutura hierárquica onde cada node possui até dois filhos. Utilizada em diversas aplicações como busca, ordenação e expressões matemáticas. Permite variações como árvores balanceadas, binárias de busca, entre outras.\n\n# English\n\n## Overview\n\nMy goal with this project was to understand and practice using **data structures** and **algorithms**, here I utilize different data structures, **searching and sorting algorithms**.\n\nAlthough the project's directory organization isn't the best, I at least tried to make it the most intuitive as possible.\n\nHere you can find the algorithms:\n- [Searching](./src/main/java/com/eduardo/Searching.java)\n- [Sorting](./src/main/java/com/eduardo/Sorting.java)\n\nHere you can find the data structures:\n- [Data Structures](./src/main/java/com/eduardo/dataStructures/)\n  - [Stack](./src/main/java/com/eduardo/dataStructures/Stack.java)\n  - [Static Stack](./src/main/java/com/eduardo/dataStructures/StaticStack.java)\n  - [Dynamic Stack](./src/main/java/com/eduardo/dataStructures/DynamicStack.java)\n  - [Linked List](./src/main/java/com/eduardo/dataStructures/LinkedList.java)\n  - [Queue](./src/main/java/com/eduardo/dataStructures/Queue.java)\n  - [Binary Tree](./src/main/java/com/eduardo/dataStructures/BinaryTree.java)\n\n## Algorithms\n\n\u003ca id=\"searching\"\u003e\u003c/a\u003e\n### Search Algorithms\n\nInside class [Searching.java](./src/main/java/com/eduardo/Searching.java) you can find 3 distinct search algorithms, 2 **Binary Search** (and Binary Search Recursive) and 1 **Linear Search**. You can see their details below:\n\n```.java\npublic static int linearSearch(int[] nums, int target)\npublic static int binarySort(int[] nums, int target)\npublic static int binarySortRecursive(int[] nums, int target, int left, int right)\n//I just realized that I named the binary searches wrong, but I truly don't want to make these changes now, so I'll leave it as it is.\n```\n\n\u003ca id=\"linearsearch-en\"\u003e\u003c/a\u003e\n### Linear Search\n\n```.java\npublic static int linearSearch(int[] nums, int target){\n  int step = 0;\n  for (int i = 0; i \u003c nums.length; i++) {\n    step++;\n    if (nums[i] == target) {\n      System.out.println(\"Amount of operations: \" + step);\n      return i;\n    }\n  }\n  System.out.println(\"Amount of operations: \" + step);\n  return -1;\n}\n```\n\nThe linear search algorithm sequentially checks each element in a data structure (such as an array or list), comparing one by one with the target value. It is simple and works for both sorted and unsorted data, but can be inefficient for large lists.\n\nThis algorithm's time complexity is O(n).\n\n\u003ca id=\"binarysearch-en\"\u003e\u003c/a\u003e\n### Binary Search\n\n```.java\npublic static int binarySort(int[] nums, int target) {\n  int left = 0;\n  int right = nums.length -1;\n  int step = 0;\n\n  while (left \u003c= right) {\n    step++;\n    int mid = (left + right) / 2;\n\n    if (nums[mid] == target) {\n      System.out.println(\"Amount of operations: \" + step);\n      return mid;\n    } else if (target \u003e nums[mid])\n      left = mid+1;\n    else\n      right = mid-1;\n\n\n  }\n  System.out.println(\"Amount of operations: \" + step);\n  return -1;\n}\n\npublic static int binarySortRecursive(int[] nums, int target, int left, int right) {\n  if (left \u003c= right) {\n    int mid = (left + right) /2;\n\n    if (nums[mid] == target)\n      return mid;\n    else if (target \u003e nums[mid])\n      return binarySortRecursive(nums, target, mid+1, right);\n    else\n      return binarySortRecursive(nums, target, left, mid-1);\n  }\n  return -1;\n}\n```\n\nBinary search is an efficient algorithm for finding elements in sorted lists. It works by repeatedly dividing the array in half and discarding one half of the search space. This makes it much faster than linear search for large datasets.\n\nThis algorithm's time complexity is O(log2 n).\n\n\u003ca id=\"sorting\"\u003e\u003c/a\u003e\n### Sort Algorithms\n\nInside class [Sorting.java](./src/main/java/com/eduardo/Sorting.java) you can find 5 distinct sorting algorithms, those are: **BubbleSort**, **SelectionSort**, **InsertSort**, **QuickSort** and **MergeSort**. You can see their details below.\n\n```.java\npublic static void bubbleSort(int[] nums)\npublic static void selectionSort(int[] nums)\npublic static void insertionSort(int[] nums)\n\npublic static void quickSort(int[] nums, int low, int high)\nprivate static int partition(int[] nums, int low, int high)\n\npublic static void mergeSort(int[] nums, int left, int right)\nprivate static void merge(int[] nums, int left, int mid, int right)\n```\n\n\u003ca id=\"bubblesort-en\"\u003e\u003c/a\u003e\n### BubbleSort\n\n```.java\npublic static void bubbleSort(int[] nums) {\n  int size = nums.length;\n\n  for (int i = 0; i \u003c size; i++) {\n    for (int j = 0; j \u003c size-1-i; j++) {\n      if (nums[j] \u003e nums[j+1]) {\n        int temp = nums[j];\n        nums[j] = nums[j+1];\n        nums[j+1] = temp;\n      }\n    }\n  }\n}\n```\n\nThe algorithm traverses the array multiple times, comparing pairs of adjacent elements and swapping them if they are out of order. The process repeats until no more swaps are needed. It is one of the simplest sorting algorithms, but also one of the least efficient.\n\nThis algorithm's time complexity is O(n²).\n\n\u003ca id=\"selectionsort-en\"\u003e\u003c/a\u003e\n### SelectionSort\n\n```.java\npublic static void selectionSort(int[] nums) {\n  final int size = nums.length;\n  int index = 0;\n  int temp = 0;\n\n  for (int i = 0; i \u003c size-1; i++) {\n    for (int j = 0; j \u003c size-i; j++) {\n      if (nums[j] \u003e nums[index])\n        index = j;\n    }\n\n    temp = nums[size-1-i];\n    nums[size-1-i] = nums[index];\n    nums[index] = temp;\n    index = 0;\n  }\n}\n```\n\nSelection Sort finds the biggest element in the list and places it in the last position, then repeats the process with the remaining unsorted elements. Although slightly more efficient than Bubble Sort in some cases, it is still inefficient for large datasets.\n\nThis algorithm's time complexity is O(n²).\n\n\u003ca id=\"insertionsort-en\"\u003e\u003c/a\u003e\n### InsertionSort\n\n```.java\npublic static void insertionSort(int[] nums) {\n  final int size = nums.length;\n\n  for (int i = 1; i \u003c size; i++) {\n    int value = nums[i];\n\n    int j = i-1;\n    while (j\u003e=0 \u0026\u0026 nums[j] \u003e value) {\n      nums[j+1] = nums[j];\n      j--;\n    }\n    nums[j+1] = value;\n  }\n}\n```\n\nInsertion Sort builds the sorted list gradually by inserting each new element into its correct position relative to the already sorted part. It is quite efficient for small or partially sorted lists.\n\nThis algorithm's time complexity is O(n²), but in the best case scenario (in which the list is already sorted) it can reach up to O(n).\n\n\u003ca id=\"quicksort-en\"\u003e\u003c/a\u003e\n### QuickSort\n\n```.java\npublic static void quickSort(int[] nums, int low, int high) {\n\n  if (low \u003c high) {\n    int pi = partition(nums, low, high);\n\n    quickSort(nums, low, pi -1);\n    quickSort(nums, pi +1, high);\n  }\n}\n\nprivate static int partition(int[] nums, int low, int high) {\n  int pivot = nums[high];\n  int i = low -1;\n\n  for (int j = low; j \u003c high; j++) {\n    if (nums[j] \u003c pivot) {\n      i++;\n\n      int temp = nums[i];\n      nums[i] = nums[j];\n      nums[j] = temp;\n    }\n  }\n  nums[high] = nums[i+1];\n  nums[i+1] = pivot;\n\n  return i+1;\n}\n```\n\nDivide and conquer. Quick Sort selects a \"pivot\" element and uses it to divide the list into two parts: one with elements smaller than the pivot and one with larger elements. Then it recursively sorts each part. Very efficient in practice.\n\nThis algorithm's time complexity is O(n • log2 n), but in the worst case scenario (in which the list is already sorted) it can reach up to O(n²).\n\n\u003ca id=\"mergesort-en\"\u003e\u003c/a\u003e\n### MergeSort\n\n```.java\npublic static void mergeSort(int[] nums, int left, int right) {\n  int mid = (left + right) /2;\n\n  if (left \u003c right){\n    mergeSort(nums, left, mid);\n    mergeSort(nums, mid +1, right);\n    merge(nums, left, mid, right);\n  }\n}\n\nprivate static void merge(int[] nums, int left, int mid, int right) {\n  int[] leftArr = new int[mid - left +1];\n  int[] rightArr = new int[right - mid];\n\n  for (int i = 0; i \u003c leftArr.length; i++)\n    leftArr[i] = nums[left+i];\n\n  for (int i = 0; i \u003c rightArr.length; i++)\n    rightArr[i] = nums[mid+1+i];\n\n  int i = 0;\n  int j = 0;\n  int k = left;\n\n  while (i \u003c leftArr.length \u0026\u0026 j \u003c rightArr.length) {\n\n    if (leftArr[i] \u003c= rightArr[j]) {\n      nums[k] = leftArr[i];\n      i++;\n    } else {\n      nums[k] = rightArr[j];\n      j++;\n    }\n\n    k++;\n  }\n\n  while (i\u003cleftArr.length) {\n    nums[k] = leftArr[i];\n    i++;\n    k++;\n  }\n\n  while (j\u003crightArr.length) {\n    nums[k] = rightArr[j];\n    j++;\n    k++;\n  }\n}\n```\n\nAnother divide-and-conquer algorithm. It splits the list until only single-element lists remain, then merges them in a sorted manner. It is stable and performs well even on large datasets.\n\nThis algorithm's time complexity is O(n • log2 n).\n\n\u003ca id=\"data-structures\"\u003e\u003c/a\u003e\n## Data Structures\n\nInside package [dataStructures](./src/main/java/com/eduardo/dataStructures) you can find all classes regarding data structures, there you can find 8 classes, which are 5 data structures: **Static Stack**, **Dynamic Stack**, **Linked List**, **Queue** e **Binary Tree**. While the remaining are complementary to those data structures.\n\n\u003ca id=\"stack-en\"\u003e\u003c/a\u003e\n### Stack\n\n```.java\npublic abstract sealed class Stack\u003cT\u003e permits StaticStack, DynamicStack {\n    protected int top = 0;\n    protected Object[] stack;\n    protected int currentSize = 0;\n    public static final int DEFAULT_SIZE = 5;\n\n    public Stack(int size) {\n        if (size \u003c= 0)\n            this.stack = new Object[DEFAULT_SIZE];\n\n        else\n            this.stack = new Object[size];\n    }\n\n    public Stack() {\n        this.stack = new Object[DEFAULT_SIZE];\n    }\n\n    public abstract void push(T t);\n\n    public abstract T pop();\n\n    @SuppressWarnings(\"unchecked\")\n    public T peek() {\n        return (T) this.stack[top];\n    }\n\n    public int getCurrentSize() {\n        return this.currentSize;\n    }\n\n    @Override\n    public String toString() {\n        return \"\";\n    }\n\n    public void clear() {\n        this.top = 0;\n        this.currentSize = 0;\n\n        Arrays.fill(this.stack, null);\n\n    }\n\n    public void show() {\n        System.out.println(toList().toString());\n    }\n\n    //For test purposes\n    @SuppressWarnings(\"unchecked\")\n    public List\u003cT\u003e toList() {\n        return (List\u003cT\u003e) Arrays.stream(this.stack)\n                .filter(Objects::nonNull)\n                .toList();\n    }\n\n    public int getStackCapacity() {\n        return this.stack.length;\n    }\n\n}\n```\n\nSuperclass for all stack classes in the package.\n\n\u003ca id=\"static-stack-en\"\u003e\u003c/a\u003e\n### Static Stack\n\n```.java\npublic non-sealed class StaticStack\u003cT\u003e extends Stack\u003cT\u003e {\n\n    public StaticStack(int size) {\n        super(size);\n    }\n\n    public StaticStack() {\n        super();\n    }\n\n    @Override\n    public void push(T t) {\n        if (top+1 \u003e stack.length)\n            throw new ArrayIndexOutOfBoundsException(\"Current size:\" + currentSize + \" Capacity:\" + stack.length);\n\n        if (stack[top] != null)\n            top++;\n\n        stack[top] = t;\n        currentSize++;\n\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public T pop() {\n        if (currentSize -1 \u003c= -1)\n            throw new ArrayIndexOutOfBoundsException(\"Current size:\" + currentSize);\n\n        T lastTop = (T) stack[top];\n        stack[top] = null;\n\n        if (top -1 \u003c= -1)\n            top = 0;\n        else\n            top--;\n\n        currentSize--;\n\n        return lastTop;\n    }\n\n}\n```\n\nFixed-size stack based on an array. Supports LIFO (Last In, First Out) operations such as push (insert) and pop (remove). Good when the stack size can be known in advance.\n\n\u003ca id=\"dynamic-stack-en\"\u003e\u003c/a\u003e\n### Dynamic Stack\n\n```.java\npublic non-sealed class DynamicStack\u003cT\u003e extends Stack\u003cT\u003e {\n\n    public DynamicStack(int size) {\n        super(size);\n    }\n\n    public DynamicStack() {\n        super();\n    }\n\n    @Override\n    public void push(T t) {\n        if (top +1 \u003e= stack.length)\n            grow();\n\n        if (stack[top] != null)\n            top++;\n\n        stack[top] = t;\n        currentSize++;\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public T pop() {\n        if (currentSize -1 \u003c= -1)\n            throw new ArrayIndexOutOfBoundsException(\"Current size:\" + currentSize);\n\n        T lastTop = (T) stack[top];\n        stack[top] = null;\n\n        if (top \u003c= stack.length /4)\n            shrink();\n\n        if (top -1 \u003c= -1)\n            top = 0;\n        else\n            top--;\n        currentSize--;\n\n        return lastTop;\n    }\n\n    //doubles the stack's capacity\n    protected void grow() {\n        Object[] newStack = new Object[stack.length *2];\n\n        System.arraycopy(stack, 0, newStack, 0, stack.length);\n\n        stack = newStack;\n    }\n\n    //halves the stack's capacity\n    protected void shrink() {\n        Object[] newStack = new Object[stack.length /2];\n\n        if (top + 1 \u003e= 0) System.arraycopy(stack, 0, newStack, 0, top + 1);\n\n        stack = newStack;\n    }\n\n}\n```\n\nDynamic stack based on a linked list. It has no predefined size limit and grows as needed. Also follows the LIFO pattern.\n\n\u003ca id=\"linked-list-en\"\u003e\u003c/a\u003e\n### Linked List\n\n```.java\npublic class LinkedList\u003cT\u003e {\n    private Node\u003cT\u003e head;\n    private Integer size = 0;\n\n    public LinkedList() {}\n\n    public void add(T value) {\n        Node\u003cT\u003e newNode = new Node\u003c\u003e(value);\n\n        if (this.head == null)\n            this.head = newNode;\n\n        else {\n            Node\u003cT\u003e lastNode = this.head;\n            while (lastNode.next != null)\n                lastNode = lastNode.next;\n\n            lastNode.next = newNode;\n        }\n\n        this.size++;\n    }\n\n    public void add(int index, T value) {\n\n        if (index \u003c= 0)\n            this.addFirst(value);\n\n        else if (index \u003e= this.size) {\n            this.add(value);\n\n        } else {\n            Node\u003cT\u003e indexNode = new Node\u003c\u003e(value);\n\n            Node\u003cT\u003e n = this.head;\n            for (int i = 0; i \u003c index-1; i++) {\n                n = n.next;\n            }\n            indexNode.next = n.next;\n            n.next = indexNode;\n            this.size++;\n        }\n    }\n\n    public void addFirst(T value) {\n        Node\u003cT\u003e temp = this.head;\n        this.head = new Node\u003c\u003e(value);\n        this.head.next = temp;\n        this.size++;\n    }\n\n    public T get(int index) {\n        if (this.head == null)\n            return null;\n\n        Node\u003cT\u003e n = this.head;\n\n        if (index \u003c= 0)\n            return this.head.value;\n\n        else if (index \u003e= this.size) {\n            while (n.next != null) {\n                n = n.next;\n            }\n        } else {\n            for (int i = 0; i \u003c index; i++)\n                n = n.next;\n        }\n\n        return n.value;\n    }\n\n    public void remove() {\n        if (this.head == null)\n            return ;\n\n        Node\u003cT\u003e n = this.head;\n        while (n.next.next != null)\n            n = n.next;\n\n        n.next = null;\n\n        this.size--;\n    }\n\n    public void remove(int index) {\n\n        if (this.head == null)\n            return ;\n\n        if (index \u003c= 0)\n            this.removeFirst();\n\n        else if (index \u003e= size)\n            this.remove();\n\n        else {\n            Node\u003cT\u003e n = this.head;\n\n            for (int i = 0; i \u003c index-1; i++)\n                n = n.next;\n\n            n.next = n.next.next;\n\n            this.size--;\n        }\n    }\n\n    public void removeFirst() {\n\n        if (this.head == null)\n            return ;\n\n        this.head = this.head.next;\n\n        this.size--;\n    }\n\n    public void show() {\n        if (this.head == null) {\n            System.out.println(\"null\");\n            return ;\n        }\n\n        StringBuilder sb = new StringBuilder(\"[ \");\n\n        Node\u003cT\u003e n = this.head;\n        do {\n            sb.append(n.value).append(\" \");\n            n = n.next;\n        } while (n != null \u0026\u0026 n.next != null);\n\n        if (n != null)\n            sb.append(n.value).append(\" \");\n\n        sb.append(\"]\");\n        System.out.println(sb);\n    }\n\n    public void clear() {\n        this.head = null;\n        this.size = 0;\n    }\n\n    @Override\n    public String toString() {\n        if (this.head == null)\n            return null;\n\n        return this.head.toString();\n    }\n\n}\n```\n\nLinear structure where each element (node) contains a value and a reference to the next. Allows efficient insertions and deletions at any position in the list.\n\n\u003ca id=\"queue-en\"\u003e\u003c/a\u003e\n### Queue\n\n```.java\npublic class Queue\u003cT\u003e {\n    protected int end = 0;\n    protected int start = 0;\n    protected Object[] queue;\n    protected int currentSize = 0;\n    public static final int DEFAULT_SIZE = 5;\n\n    public Queue() {\n        this.queue = new Object[DEFAULT_SIZE];\n    }\n\n    public Queue(int size) {\n        this.queue = new Object[size];\n    }\n\n    public void enqueue(T t) {\n        if (currentSize +1 \u003e getQueueCapacity())\n            throw new ArrayIndexOutOfBoundsException(\"Capacity exceeded\\ncurrent size: \" + currentSize + \"\\ncapacity:\" + getQueueCapacity());\n\n\n        if (queue[end] == null)\n            queue[end] = t;\n\n        else\n            queue[start] = t;\n\n        start = (start+1) % getQueueCapacity();\n        currentSize++;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public T dequeue() {\n        if (currentSize -1 \u003c= -1)\n            throw new ArrayIndexOutOfBoundsException(\"index -1\");\n\n        T t = (T) queue[end];\n        queue[end] = null;\n\n        end = (end+1) % getQueueCapacity();\n        currentSize--;\n\n        return t;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public T peek() {\n        return (T) this.queue[end];\n    }\n\n    public void clear() {\n        this.end = 0;\n        this.currentSize = 0;\n\n        Arrays.fill(queue, null);\n    }\n\n    public void show() {\n        System.out.println(toList().toString());\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public List\u003cT\u003e toList() {\n        List\u003cT\u003e l = new ArrayList\u003c\u003e();\n\n        for (int i = 0; i \u003c currentSize; i++) {\n            l.add((T) queue[(end+i) % getQueueCapacity()]);\n        }\n\n        return l;\n    }\n\n    public int getCurrentSize() {\n        return this.currentSize;\n    }\n\n    public int getQueueCapacity() {\n        return this.queue.length;\n    }\n\n}\n```\n\nData structure that follows the FIFO (First In, First Out) principle. Elements are inserted at the end of the queue and removed from the front. Ideal for sequential processing.\n\n\u003ca id=\"binary-tree-en\"\u003e\u003c/a\u003e\n### Binary Tree\n\n```.java\npublic class BinaryTree\u003cT extends Comparable\u003cT\u003e\u003e {\n\n    private TreeNode\u003cT\u003e root;\n\n    public BinaryTree() {}\n\n    public void insert(T data) {\n        root = insertRec(root, data);\n    }\n\n    private TreeNode\u003cT\u003e insertRec(TreeNode\u003cT\u003e newRoot, T data) {\n\n        if (newRoot == null)\n            newRoot = new TreeNode\u003c\u003e(data);\n\n        else if (data.compareTo(newRoot.value) \u003c 0)\n            newRoot.left = insertRec(newRoot.left, data);\n\n        else\n            newRoot.right = insertRec(newRoot.right, data);\n\n        return newRoot;\n    }\n\n    public void inOrder() {\n        inOrderRec(root);\n        System.out.println();\n    }\n\n    private void inOrderRec(TreeNode\u003cT\u003e node) {\n\n        if (node != null) {\n            inOrderRec(node.left);\n            System.out.print(node.value + \" \");\n            inOrderRec(node.right);\n        }\n    }\n\n    public void preOrder() {\n        preOrderRec(root);\n        System.out.println();\n    }\n\n    private void preOrderRec(TreeNode\u003cT\u003e node) {\n\n        if (node != null) {\n            System.out.print(node.value + \" \");\n            preOrderRec(node.left);\n            preOrderRec(node.right);\n        }\n    }\n}\n```\n\nHierarchical structure where each node has up to two children. Used in various applications like search, sorting, and mathematical expressions. Allows variations like balanced trees, binary search trees, and more.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feduardob-programador%2Fdsa-learning","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feduardob-programador%2Fdsa-learning","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feduardob-programador%2Fdsa-learning/lists"}