diff --git a/slides/images/search_algorithms_meme.png b/slides/images/search_algorithms_meme.png new file mode 100644 index 0000000..9181670 Binary files /dev/null and b/slides/images/search_algorithms_meme.png differ diff --git a/slides/slides-pt.typ b/slides/slides-pt.typ index 389e85f..738b1ce 100644 --- a/slides/slides-pt.typ +++ b/slides/slides-pt.typ @@ -62,7 +62,8 @@ Blank space can be filled with vertical spaces like #v(1fr). grid( columns: 2, gutter: 2mm, - image("images/turing.jpg", width: 60%), image("images/church.jpg", width: 60%), + image("images/turing.jpg", width: 60%), + image("images/church.jpg", width: 60%), ), caption: "Alan Turing e Alonzo Church", ) @@ -1693,3 +1694,346 @@ proposicional pode ser tornada verdadeira* por meio de uma atribuição adequada ] ] ] + += Algoritmos de Busca + +#align(horizon + center)[#image( + "images/search_algorithms_meme.png", + width: 100%, + )] + +== O que é um Algoritmo de Busca? + +#align(horizon)[ + Um *algoritmo de busca* é uma sequência de instruções que permite encontrar um + determinado elemento dentro de uma estrutura de dados. É fundamental em ciência da + computação, pois otimiza o acesso e a manipulação de dados. +] + +== Por que Estudar Algoritmos de Busca? + +#align(horizon)[ + - *Eficiência*: Algoritmos de busca eficientes economizam tempo e recursos. + - *Fundamentos*: São a base para algoritmos mais complexos e estruturas de dados. + - *Aplicações Práticas*: Usados em bancos de dados, sistemas operacionais, + inteligência artificial, entre outros. +] + +== Tipos de Algoritmos de Busca + +#align(horizon)[ + - *Busca Linear* (_Linear Search_) + - *Busca Binária* (_Binary Search_) + - *Busca em Grafos*: + - *Busca em Largura* (_Breadth-First Search - BFS_) + - *Busca em Profundidade* (_Depth-First Search - DFS_) +] + +== Busca Linear + +=== Conceito + +#align(horizon)[ + A *busca linear* é o algoritmo mais simples de busca. Ela percorre cada elemento + da estrutura de dados até encontrar o elemento desejado ou até o final da estrutura. +] + +#pagebreak() + +=== Características da Busca Linear + +#align(horizon)[ + - *Simples de Implementar* + - *_Não_ Requer Estrutura Ordenada* + - *Complexidade de Tempo*: $O(n)$, onde $n$ é o número de elementos. +] + +#pagebreak() + +=== Exemplo em C + +#align(horizon)[ + ```c + int busca_linear(int arr[], int n, int x) { + for (int i = 0; i < n; i++) { + if (arr[i] == x) + return i; // Elemento encontrado na posição i + } + return -1; // Elemento não encontrado + } + ``` +] + +#pagebreak() + +=== Análise da Complexidade + +#align(horizon)[ + - *Melhor Caso*: O elemento está na primeira posição; $O(1)$. + - *Pior Caso*: O elemento está na última posição ou não está presente; $O(n)$. + - *Caso Médio*: Em média, percorre metade dos elementos; $1/2 O(n) = O(n)$. +] + +== Busca Binária + +#align(horizon)[ + A *busca binária* é um algoritmo eficiente para encontrar um elemento em uma lista + ordenada, reduzindo o espaço de busca pela metade a cada iteração. +] + +#pagebreak() + +=== Características da Busca Binária + +#align(horizon)[ + - *Requer Estrutura Ordenada* + - *Complexidade de Tempo*: $O(log n)$ + - *Mais Eficiente que a Busca Linear em Grandes Conjuntos de Dados* +] + +#pagebreak() + +=== Exemplo em C + +#align(horizon)[ + #text(size: 12pt)[ + ```c + int busca_binaria(int arr[], int n, int x) { + int inicio = 0, fim = n - 1; + while (inicio <= fim) { + int meio = inicio + (fim - inicio) / 2; + if (arr[meio] == x) + // Elemento encontrado + return meio; + if (arr[meio] < x) + inicio = meio + 1; + else + fim = meio - 1; + } + // Elemento não encontrado + return -1; + } + ``` + ] +] + +#pagebreak() + +=== Análise da Complexidade + +#align(horizon)[ + - A cada iteração, o algoritmo reduz o espaço de busca pela metade. + - *Complexidade de Tempo*: $O(log n)$ + - *Eficiência*: Muito mais rápido que a busca linear em grandes conjuntos de dados. +] + +== Busca em Grafos + +#pagebreak() + +=== Tipos de Busca em Grafos + +#align(horizon)[ + - *Busca em Largura* (_Breadth-First Search - BFS_) + - *Busca em Profundidade* (_Depth-First Search - DFS_) +] + +#pagebreak() + +=== Aplicações + +#align(horizon)[ + - *Encontrar Caminhos*: Entre dois vértices em um grafo. + - *Verificar Conectividade*: Se todos os vértices são alcançáveis. + - *Detecção de Ciclos*: Em grafos direcionados e não direcionados. +] + +== Busca em Largura (BFS) + +#align(horizon)[ + Busca em Largura (_Breadth-First Search_) é um algoritmo de busca em grafos que explora todos os vértices +] + +#pagebreak() + +=== Conceito + +#align(horizon)[ + A *busca em largura* explora um grafo visitando todos os vértices na mesma camada + de distância da origem antes de passar para a próxima camada. +] + +#pagebreak() + +=== Características da BFS + +#align(horizon)[ + - *Usa Fila (_Queue_)* + - *Garante o Caminho Mais Curto em Grafos Não Ponderados* + - *Complexidade de Tempo*: $O(V + E)$, onde $V$ é o número de vértices e $E$ é o número de arestas. +] + +#pagebreak() + +=== Exemplo em C + +#align(horizon)[ + #text(size: 9pt)[ + ```c + void bfs(int grafo[][MAX], int inicio, int n) { + int visitado[MAX] = {0}; + int fila[MAX], frente = 0, traseira = 0; + + visitado[inicio] = 1; + fila[traseira++] = inicio; + + while (frente < traseira) { + int atual = fila[frente++]; + printf("%d ", atual); + + for (int i = 0; i < n; i++) { + if (grafo[atual][i] && !visitado[i]) { + visitado[i] = 1; + fila[traseira++] = i; + } + } + } + } + ``` + ] +] + +#pagebreak() + +=== Ilustração da BFS + +#align(horizon + center)[ + #figure( + raw-render( + ```dot + digraph BFS { + rankdir=TB; + node [shape=circle, style=filled, color=lightgrey]; + + // Definição dos nós e suas labels + A [label="1"]; + B [label="2"]; + C [label="3"]; + D [label="4"]; + E [label="5"]; + F [label="6"]; + G [label="7"]; + H [label="8"]; + + // Definição das arestas + A -> {B; C}; + B -> {D; E}; + C -> {F; G}; + E -> H; + } + ```, + width: 35%, + ), + caption: "Ilustração da BFS em um digrafo com os vértices numerados pela ordem de visitação", + ) +] + +== Busca em Profundidade (DFS) + +#align(horizon)[ + Busca em Profundidade (_Depth-First Search_) é um algoritmo de busca em grafos que explora todos os vértices +] + +#pagebreak() + +=== Conceito + +#align(horizon)[ + A *busca em profundidade* explora o grafo o mais profundo possível antes de retroceder. +] + +#pagebreak() + +=== Características da DFS + +#align(horizon)[ + - *Usa Pilha (_Stack_)* (pode ser implementada recursivamente) + - *Não Garante o Caminho Mais Curto* + - *Complexidade de Tempo*: $O(V + E)$ +] + +#pagebreak() + +=== Exemplo em C (Recursivo) + +#align(horizon)[ + #text(size: 13pt)[ + ```c + void dfs(int grafo[][MAX], int atual, int visitado[], int n) { + visitado[atual] = 1; + printf("%d ", atual); + + for (int i = 0; i < n; i++) { + if (grafo[atual][i] && !visitado[i]) { + dfs(grafo, i, visitado, n); + } + } + } + ``` + ] +] + +#pagebreak() + +=== Ilustração da DFS + +#align(horizon + center)[ + #figure( + raw-render( + ```dot + digraph DFS { + rankdir=TB; + node [shape=circle, style=filled, color=lightgrey]; + + // Definição dos nós e suas labels + A [label="1"]; + B [label="2"]; + C [label="6"]; + D [label="3"]; + E [label="4"]; + F [label="7"]; + G [label="8"]; + H [label="5"]; + + // Definição das arestas + A -> {B; C}; + B -> {D; E}; + C -> {F; G}; + E -> H; + } + ```, + width: 35%, + ), + caption: "Ilustração da DFS em um digrafo com os vértices numerados pela ordem de visitação", + ) +] + +== Comparação entre BFS e DFS + +#align(horizon)[ + #text(size: 12pt)[ + #table( + columns: 2, + align: left + horizon, + table.header([*Característica*], [*BFS*], [*DFS*]), + [*Estrutura de Dados*], [Fila (_Queue_)], + [Pilha (_Stack_)], [*Uso de Memória*], + [Maior (guarda todos os vizinhos)], [Menor (apenas caminho atual)], + [*Caminho Mais Curto*], [Sim (em grafos não ponderados)], + [Não necessariamente], [*Completo*], + [Sim], [Sim], + [*Aplicações*], [Caminho mais curto, nível dos nós], + [Detecção de ciclos, ordenação topológica], + ) + ] +] diff --git a/slides/slides.typ b/slides/slides.typ index 04930ba..5221866 100644 --- a/slides/slides.typ +++ b/slides/slides.typ @@ -62,7 +62,8 @@ Blank space can be filled with vertical spaces like #v(1fr). grid( columns: 2, gutter: 2mm, - image("images/turing.jpg", width: 60%), image("images/church.jpg", width: 60%), + image("images/turing.jpg", width: 60%), + image("images/church.jpg", width: 60%), ), caption: "Alan Turing and Alonzo Church", ) @@ -1687,3 +1688,332 @@ subtrees is at most 1. ] ] ] + += Search Algorithms + +#align(horizon + center)[#image( + "images/search_algorithms_meme.png", + width: 100%, + )] + +== What is a Search Algorithm? + +#align(horizon)[ + A *search algorithm* is a sequence of instructions that allows finding a specific element within a data structure. It is fundamental in computer science as it optimizes data access and manipulation. +] + +== Why Study Search Algorithms? + +#align(horizon)[ + - *Efficiency*: Efficient search algorithms save time and resources. + - *Foundations*: They are the basis for more complex algorithms and data structures. + - *Practical Applications*: Used in databases, operating systems, artificial intelligence, among others. +] + +== Types of Search Algorithms + +#align(horizon)[ + - *Linear Search* + - *Binary Search* + - *Graph Search Algorithms*: + - *Breadth-First Search (BFS)* + - *Depth-First Search (DFS)* +] + +== Linear Search + +=== Concept + +#align(horizon)[ + *Linear search* is the simplest search algorithm. It sequentially checks each element of the data structure until it finds the desired element or reaches the end of the structure. +] + +#pagebreak() + +=== Characteristics of Linear Search + +#align(horizon)[ + - *Simple to Implement* + - *Does Not Require Ordered Structure* + - *Time Complexity*: $O(n)$, where $n$ is the number of elements. +] + +#pagebreak() + +=== Example in C + +#align(horizon)[ + ```c + int linear_search(int arr[], int n, int x) { + for (int i = 0; i < n; i++) { + if (arr[i] == x) + return i; // Element found at position i + } + return -1; // Element not found + } + ``` +] + +#pagebreak() + +=== Complexity Analysis + +#align(horizon)[ + - *Best Case*: The element is at the first position; $O(1)$. + - *Worst Case*: The element is at the last position or not present; $O(n)$. + - *Average Case*: On average, it checks half of the elements; $O(n)$. +] + +== Binary Search + +#align(horizon)[ + *Binary search* is an efficient algorithm to find an element in an ordered list, reducing the search space by half with each iteration. +] + +#pagebreak() + +=== Characteristics of Binary Search + +#align(horizon)[ + - *Requires Ordered Structure* + - *Time Complexity*: $O(log n)$ + - *More Efficient than Linear Search in Large Data Sets* +] + +#pagebreak() + +=== Example in C + +#align(horizon)[ + #text(size: 14pt)[ + ```c + int binary_search(int arr[], int n, int x) { + int start = 0, end = n - 1; + while (start <= end) { + int mid = start + (end - start) / 2; + if (arr[mid] == x) + return mid; // Element found + if (arr[mid] < x) + start = mid + 1; + else + end = mid - 1; + } + return -1; // Element not found + } + ``` + ] +] + +#pagebreak() + +=== Complexity Analysis + +#align(horizon)[ + - With each iteration, the algorithm halves the search space. + - *Time Complexity*: $O(log n)$ + - *Efficiency*: Much faster than linear search in large data sets. +] + +== Graph Search Algorithms + +=== Types of Graph Search Algorithms + +#align(horizon)[ + - *Breadth-First Search (BFS)* + - *Depth-First Search (DFS)* +] + +#pagebreak() + +=== Applications + +#align(horizon)[ + - *Finding Paths*: Between two vertices in a graph. + - *Checking Connectivity*: Whether all vertices are reachable. + - *Cycle Detection*: In directed and undirected graphs. +] + +== Breadth-First Search (BFS) + +=== Concept + +#align(horizon)[ + *Breadth-first search* explores a graph by visiting all vertices at the same distance layer from the origin before moving to the next layer. +] + +#pagebreak() + +=== Characteristics of BFS + +#align(horizon)[ + - *Uses a Queue* + - *Guarantees the Shortest Path in Unweighted Graphs* + - *Time Complexity*: $O(V + E)$, where $V$ is the number of vertices and $E$ is the number of edges. +] + +#pagebreak() + +=== Example in C + +#align(horizon)[ + #text(size: 9pt)[ + ```c + void bfs(int graph[][MAX], int start, int n) { + int visited[MAX] = {0}; + int queue[MAX], front = 0, rear = 0; + + visited[start] = 1; + queue[rear++] = start; + + while (front < rear) { + int current = queue[front++]; + printf("%d ", current); + + for (int i = 0; i < n; i++) { + if (graph[current][i] && !visited[i]) { + visited[i] = 1; + queue[rear++] = i; + } + } + } + } + ``` + ] +] + +#pagebreak() + +=== Illustration of BFS + +#align(horizon + center)[ + #figure( + raw-render( + ```dot + digraph BFS { + rankdir=TB; + node [shape=circle, style=filled, color=lightgrey]; + + // Nodes with numbered labels + A [label="A\n(1)"]; + B [label="B\n(2)"]; + C [label="C\n(3)"]; + D [label="D\n(4)"]; + E [label="E\n(5)"]; + F [label="F\n(6)"]; + G [label="G\n(7)"]; + H [label="H\n(8)"]; + + // Edges + A -> B; + A -> C; + B -> D; + B -> E; + C -> F; + C -> G; + E -> H; + } + ```, + width: 37%, + ), + caption: "Illustration of BFS with vertices numbered by visitation order", + ) +] + +== Depth-First Search (DFS) + +=== Concept + +#align(horizon)[ + *Depth-first search* explores as far as possible along each branch before backtracking. +] + +#pagebreak() + +=== Characteristics of DFS + +#align(horizon)[ + - *Uses a Stack* (can be implemented recursively) + - *Does Not Guarantee the Shortest Path* + - *Time Complexity*: $O(V + E)$ +] + +#pagebreak() + +=== Example in C (Recursive) + +#align(horizon)[ + #text(size: 15pt)[ + ```c + void dfs(int graph[][MAX], int current, int visited[], int n) { + visited[current] = 1; + printf("%d ", current); + + for (int i = 0; i < n; i++) { + if (graph[current][i] && !visited[i]) { + dfs(graph, i, visited, n); + } + } + } + ``` + ] +] + +#pagebreak() + +=== Illustration of DFS + +#align(horizon + center)[ + #figure( + raw-render( + ```dot + digraph DFS { + rankdir=TB; + node [shape=circle, style=filled, color=lightgrey]; + + // Nodes with numbered labels + A [label="A\n(1)"]; + B [label="B\n(2)"]; + D [label="D\n(3)"]; + E [label="E\n(4)"]; + H [label="H\n(5)"]; + C [label="C\n(6)"]; + F [label="F\n(7)"]; + G [label="G\n(8)"]; + + // Edges + A -> B; + A -> C; + B -> D; + B -> E; + E -> H; + C -> F; + C -> G; + } + ```, + width: 37%, + ), + caption: "Illustration of DFS with vertices numbered by visitation order", + ) +] + +== Comparison between BFS and DFS + +#align(horizon)[ + #text(size: 12pt)[ + #table( + columns: 3, + align: left + horizon, + table.header([*Characteristic*], [*BFS*], [*DFS*]), + [*Data Structure*], [Queue], [Stack], + [*Memory Usage*], + [Higher (stores all neighbors)], + [Lower (stores only current path)], + + [*Shortest Path*], [Yes (in unweighted graphs)], [Not necessarily], + [*Completeness*], [Yes], [Yes], + [*Applications*], + [Shortest path, node levels], + [Cycle detection, topological sorting], + ) + ] +]