<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Gissandro Gama</title>
    <description>The latest articles on Forem by Gissandro Gama (@gissandrogama).</description>
    <link>https://forem.com/gissandrogama</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F876987%2Ff35989ed-46c3-4881-8c88-8377499824de.jpeg</url>
      <title>Forem: Gissandro Gama</title>
      <link>https://forem.com/gissandrogama</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/gissandrogama"/>
    <language>en</language>
    <item>
      <title>Desafio Final e o Segredo do O(N) (Dois Ponteiros)</title>
      <dc:creator>Gissandro Gama</dc:creator>
      <pubDate>Sun, 30 Nov 2025 00:39:13 +0000</pubDate>
      <link>https://forem.com/gissandrogama/desafio-final-e-o-segredo-do-on-dois-ponteiros-3g4</link>
      <guid>https://forem.com/gissandrogama/desafio-final-e-o-segredo-do-on-dois-ponteiros-3g4</guid>
      <description>&lt;h3&gt;
  
  
  Pensando Linear: Resolvendo Problemas Complexos em O(N) e o Segredo do O(1) de Elixir 🔑
&lt;/h3&gt;

&lt;p&gt;Chegamos ao final da nossa jornada pela Complexidade de Algoritmos! Vimos o poder do &lt;strong&gt;Merge Sort&lt;/strong&gt; O(N log N) e a velocidade da &lt;strong&gt;Busca Binária&lt;/strong&gt; O(log N).&lt;/p&gt;

&lt;p&gt;Neste post final, vamos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Aplicar o conhecimento de &lt;strong&gt;O(N)&lt;/strong&gt; em um desafio avançado (o "problema dos quadrados").&lt;/li&gt;
&lt;li&gt; Revelar o segredo técnico por trás da promessa de O(1) dos Mapas de Elixir.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Desafio O(N) Avançado: A Técnica dos Dois Ponteiros
&lt;/h3&gt;

&lt;p&gt;Revisite o problema: Dada uma &lt;em&gt;lista já ordenada&lt;/em&gt; &lt;code&gt;nums&lt;/code&gt;, retorne o lista dos quadrados dos números, também ordenado.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Entrada (&lt;code&gt;nums&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;Quadrados&lt;/th&gt;
&lt;th&gt;Resultado Ordenado&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[-4, -1, 0, 3, 10]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[16, 1, 0, 9, 100]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[0, 1, 9, 16, 100]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A solução ingênua seria elevar ao quadrado &lt;code&gt;O(N)&lt;/code&gt; e depois ordenar &lt;code&gt;O(N log N)&lt;/code&gt;, totalizando &lt;strong&gt;&lt;code&gt;O(N log N)&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O truque é usar a informação de que a entrada já está ordenada. Os &lt;strong&gt;maiores&lt;/strong&gt; quadrados estarão sempre nas &lt;strong&gt;pontas&lt;/strong&gt; do list de entrada, devido aos números negativos com alto valor absoluto.&lt;/p&gt;

&lt;p&gt;A solução &lt;strong&gt;O(N)&lt;/strong&gt; usa a técnica dos &lt;strong&gt;Dois Ponteiros&lt;/strong&gt; para construir o resultado &lt;em&gt;de trás para frente&lt;/em&gt; (do maior para o menor):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Um ponteiro (&lt;code&gt;l&lt;/code&gt;) no início (&lt;code&gt;-4&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; Um ponteiro (&lt;code&gt;r&lt;/code&gt;) no fim (&lt;code&gt;10&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; Comparamos os quadrados nas pontas. O maior quadrado é colocado na lista de resultados.&lt;/li&gt;
&lt;li&gt; O ponteiro correspondente se move para dentro.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Código Elixir: Solução &lt;code&gt;O(N)&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Em Elixir, usamos o &lt;strong&gt;&lt;code&gt;Enum.reduce&lt;/code&gt;&lt;/strong&gt; para simular o movimento dos ponteiros e o &lt;strong&gt;&lt;code&gt;[square | acc]&lt;/code&gt; (prepend)&lt;/strong&gt; para construir o resultado de trás para frente em &lt;code&gt;O(1)&lt;/code&gt; por passo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;SortedSquares&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nv"&gt;@doc&lt;/span&gt; &lt;span class="s2"&gt;"Solução O(N) com Dois Ponteiros, construindo o resultado em ordem inversa."&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;sorted_squares&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# l: ponteiro esquerdo (0), r: ponteiro direito (N-1)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result_reversed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;({[],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;left_square&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;right_square&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;left_square&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;right_square&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
          &lt;span class="c1"&gt;# Se o da esquerda for maior, movemos o ponteiro l&lt;/span&gt;
          &lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="n"&gt;left_square&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
          &lt;span class="c1"&gt;# Se o da direita for maior (ou igual), movemos o ponteiro r&lt;/span&gt;
          &lt;span class="p"&gt;{[&lt;/span&gt;&lt;span class="n"&gt;right_square&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;result_reversed&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Conclusão:&lt;/strong&gt; A técnica dos Dois Ponteiros garante que visitamos cada elemento exatamente uma vez &lt;code&gt;O(N)&lt;/code&gt;, evitando o &lt;code&gt;O(N log N)&lt;/code&gt; da ordenação final.&lt;/p&gt;




&lt;h3&gt;
  
  
  O Segredo Final: Por Que &lt;code&gt;O(1)&lt;/code&gt; não é mágica?
&lt;/h3&gt;

&lt;p&gt;Ao longo desta série, prometemos que a busca/inserção em &lt;strong&gt;&lt;code&gt;Map&lt;/code&gt;&lt;/strong&gt; e &lt;strong&gt;&lt;code&gt;MapSet&lt;/code&gt;&lt;/strong&gt; de Elixir é &lt;strong&gt;O(1)&lt;/strong&gt;. Por que é tão rápido e, mais importante, como o Elixir consegue fazer isso garantindo a &lt;strong&gt;imutabilidade&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;A resposta está na estrutura de dados que a Erlang/Elixir utiliza: as &lt;strong&gt;Hash Array Mapped Tries (HAMT)&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  HAMT: O Motor Imutável do &lt;code&gt;O(1)&lt;/code&gt;
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Hashing:&lt;/strong&gt; Quando você insere uma chave (ex: &lt;code&gt;:user&lt;/code&gt;), ela é transformada em um &lt;strong&gt;Hash Code&lt;/strong&gt; (um número).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Trie (Árvore Digital):&lt;/strong&gt; Esse hash code é usado como um caminho para navegar em uma &lt;strong&gt;árvore de alta ramificação&lt;/strong&gt; (a Trie). O HAMT só precisa descer alguns níveis da árvore para encontrar o endereço exato do valor.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Array Mapped:&lt;/strong&gt; Em cada nível, em vez de ter muitos ponteiros, há um pequeno &lt;em&gt;array&lt;/em&gt; (o "mapa") que é usado para buscar o próximo ramo.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Vantagem da Imutabilidade:&lt;/strong&gt; Quando você atualiza um MapSet em Elixir, o sistema não precisa copiar toda a estrutura. Ele &lt;strong&gt;reutiliza&lt;/strong&gt; os ramos antigos da árvore (nós) que não foram alterados e apenas cria novos nós para o caminho que foi modificado. Isso é conhecido como &lt;strong&gt;Compartilhamento Estrutural&lt;/strong&gt; (&lt;em&gt;Structural Sharing&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Graças ao HAMT, a promessa de &lt;strong&gt;O(1)&lt;/strong&gt; (tempo constante) para busca e inserção é mantida, e o código Elixir permanece rápido e seguro para concorrência na BEAM.&lt;/p&gt;




&lt;h3&gt;
  
  
  Parabéns! Fim da Série.
&lt;/h3&gt;

&lt;p&gt;Você agora tem uma compreensão sólida das classes de complexidade, sabe identificar os gargalos O(N^2) e possui as ferramentas de Elixir (Merge Sort, MapSet, e Reduções) para escrever código que não apenas funciona, mas que &lt;strong&gt;escala&lt;/strong&gt; de forma eficiente.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>computerscience</category>
      <category>performance</category>
      <category>elixir</category>
    </item>
    <item>
      <title>O Padrão Ouro da Ordenação: O(N log N)</title>
      <dc:creator>Gissandro Gama</dc:creator>
      <pubDate>Sun, 30 Nov 2025 00:37:04 +0000</pubDate>
      <link>https://forem.com/gissandrogama/post-4-o-padrao-ouro-da-ordenacao-on-log-n-46jp</link>
      <guid>https://forem.com/gissandrogama/post-4-o-padrao-ouro-da-ordenacao-on-log-n-46jp</guid>
      <description>&lt;h3&gt;
  
  
  O Melhor dos Dois Mundos: Entendendo a Complexidade O(N log N) do Merge Sort 🥇
&lt;/h3&gt;

&lt;p&gt;Nos posts anteriores, conquistamos a velocidade da &lt;a href="https://dev.to/gissandrogama/post-3-a-santa-graal-da-busca-olog-n-a6"&gt;&lt;strong&gt;Busca Binária&lt;/strong&gt; O(log N)&lt;/a&gt; e a eficiência &lt;strong&gt;Linear&lt;/strong&gt; O(N). Agora, vamos ao padrão-ouro para o &lt;strong&gt;Ordenação&lt;/strong&gt;: a complexidade &lt;strong&gt;O(N log N) (Linearithmic)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Todo algoritmo de ordenação que precisa escalar para grandes volumes de dados (como &lt;strong&gt;Merge Sort&lt;/strong&gt; ou &lt;strong&gt;Quick Sort&lt;/strong&gt;) mira nessa complexidade, pois ela combina o poder de dividir o problema &lt;strong&gt;log N&lt;/strong&gt; com a eficiência de processar os resultados de forma linear &lt;strong&gt;N&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  A Lógica do Merge Sort: Divisão e Mesclagem
&lt;/h3&gt;

&lt;p&gt;O &lt;strong&gt;Merge Sort&lt;/strong&gt; (Ordenação por Mesclagem) é um exemplo perfeito de &lt;em&gt;Divide and Conquer&lt;/em&gt; (Dividir para Conquistar). Ele funciona em duas fases, que correspondem diretamente à sua complexidade O(N log N):&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Fase de Divisão (log N) 🌳
&lt;/h4&gt;

&lt;p&gt;O algoritmo divide recursivamente a lista em metades, continuando a divisão até que restem apenas listas de um único elemento (que, por definição, estão ordenadas).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Se você tem 1.000.000 de itens, você só precisa de &lt;strong&gt;20 divisões&lt;/strong&gt; (log_2 1.000.000 ≈ 20) para chegar ao caso base.&lt;/li&gt;
&lt;li&gt;O log N é a &lt;strong&gt;altura&lt;/strong&gt; da árvore de recursão.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. Fase de Mesclagem N 🔗
&lt;/h4&gt;

&lt;p&gt;É aqui que o trabalho pesado é feito. Em cada nível da recursão (os log N níveis), o algoritmo mescla (combina) as listas ordenadas de volta em uma única lista maior e também ordenada.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Para mesclar duas listas que, juntas, somam N elementos, o algoritmo precisa fazer, no máximo, N comparações para garantir que a saída esteja em ordem.&lt;/li&gt;
&lt;li&gt;Esta operação de mesclagem é intrinsecamente &lt;strong&gt;O(N) (Linear)&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Como realizamos o trabalho O(N) em cada um dos &lt;code&gt;log N&lt;/code&gt; níveis, a complexidade final é &lt;strong&gt;O(N log N)&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  O Coração &lt;code&gt;O(N)&lt;/code&gt; em Elixir: A Função &lt;code&gt;merge&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A chave para um Merge Sort eficiente é garantir que a função de mesclagem seja rigorosamente O(N). Em Elixir, isso significa &lt;strong&gt;nunca&lt;/strong&gt; usar o operador de concatenação lenta (&lt;code&gt;++&lt;/code&gt;) e trabalhar apenas nas cabeças das listas.&lt;/p&gt;

&lt;p&gt;Nosso código de mesclagem faz exatamente isso, comparando as cabeças (&lt;code&gt;h_a&lt;/code&gt; e &lt;code&gt;h_b&lt;/code&gt;) e movendo o menor elemento para o resultado recursivamente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# --- O CORAÇÃO O(N) DA MESCLAGEM ---&lt;/span&gt;

&lt;span class="c1"&gt;# Casos base para quando uma das listas se esgota:&lt;/span&gt;
&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;([],&lt;/span&gt; &lt;span class="n"&gt;list_b&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;list_b&lt;/span&gt;
&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]),&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;list_a&lt;/span&gt;

&lt;span class="c1"&gt;# Cláusula Recursiva Principal&lt;/span&gt;
&lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;h_a&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;t_a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;list_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;h_b&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;t_b&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;list_b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;h_a&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;h_b&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# h_a é menor: Coloca na frente do resultado e continua a recursão&lt;/span&gt;
    &lt;span class="c1"&gt;# usando a CAUDA de A (t_a) e a LISTA B COMPLETA (list_b).&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;h_a&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;list_b&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="c1"&gt;# h_b é menor: Coloca na frente do resultado e continua a recursão&lt;/span&gt;
    &lt;span class="c1"&gt;# usando a LISTA A COMPLETA (list_a) e a CAUDA de B (t_b).&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;h_b&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t_b&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Código Final: O Merge Sort Completo
&lt;/h3&gt;

&lt;p&gt;Este código encapsula a filosofia O(N log N):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MergeSort&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nv"&gt;@doc&lt;/span&gt; &lt;span class="s2"&gt;"Implementação do Merge Sort em Elixir (O(N log N))."&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="c1"&gt;# Caso Base&lt;/span&gt;
      &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;# 1. DIVISÃO: Agora a função está definida.&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;low&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;split_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

        &lt;span class="c1"&gt;# 2. RECURSÃO&lt;/span&gt;
        &lt;span class="n"&gt;sorted_low&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;low&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sorted_high&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# 3. MESCLAGEM&lt;/span&gt;
        &lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sorted_low&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sorted_high&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;## 🛠️ FUNÇÃO AUXILIAR DE DIVISÃO (Adicionada para Corrigir o Erro)&lt;/span&gt;
  &lt;span class="c1"&gt;# O(N) para encontrar o comprimento e dividir a lista ligada.&lt;/span&gt;
  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;split_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# Encontrar o ponto médio da lista&lt;/span&gt;
    &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;split_point&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;trunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Enum.split faz a divisão no ponto (O(N) por varrer a lista)&lt;/span&gt;
    &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;split_point&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

 &lt;span class="c1"&gt;# Adicionar o código da acima&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Análise:&lt;/strong&gt; O &lt;code&gt;Merge Sort&lt;/code&gt; é o melhor que podemos fazer para ordenação genérica. Ele garante a performance O(N log N) em todos os casos (pior, médio e melhor), o que o torna incrivelmente estável e confiável.&lt;/p&gt;




&lt;h3&gt;
  
  
  Próxima Parada: O Desafio Final
&lt;/h3&gt;

&lt;p&gt;No próximo e último post da série, faremos uma aplicação avançada do &lt;strong&gt;O(N)&lt;/strong&gt;. Veremos como usar a técnica dos &lt;a href="https://dev.to/gissandrogama/desafio-final-e-o-segredo-do-on-dois-ponteiros-3g4"&gt;&lt;strong&gt;Dois Ponteiros&lt;/strong&gt;&lt;/a&gt; para resolver o problema &lt;strong&gt;Squares of a Sorted Array&lt;/strong&gt; (que já exploramos), transformando a necessidade de uma ordenação O(N log N) final em um único e elegante passo O(N)! Além disso, revelaremos o segredo do O(1) dos Mapas de Elixir (a estrutura HAMT).&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>performance</category>
      <category>algorithms</category>
      <category>programming</category>
    </item>
    <item>
      <title>A Santa Graal da Busca: O(log N)</title>
      <dc:creator>Gissandro Gama</dc:creator>
      <pubDate>Sat, 29 Nov 2025 23:47:20 +0000</pubDate>
      <link>https://forem.com/gissandrogama/post-3-a-santa-graal-da-busca-olog-n-a6</link>
      <guid>https://forem.com/gissandrogama/post-3-a-santa-graal-da-busca-olog-n-a6</guid>
      <description>&lt;h3&gt;
  
  
  Acelerando a Busca: Por que o O(log N) (Busca Binária) é mais rápido que a Luz? ✨
&lt;/h3&gt;

&lt;p&gt;Vimos nos posts anteriores &lt;a href="https://dev.to/gissandrogama/a-migracao-de-on2-para-on-o-poder-do-o1-3b84"&gt;como migrar de O(N^2) para O(N)&lt;/a&gt;. Mas e se pudéssemos ser ainda mais rápidos?&lt;/p&gt;

&lt;p&gt;A complexidade &lt;strong&gt;O(log N) (Logarítmica)&lt;/strong&gt; é o padrão-ouro para qualquer algoritmo de &lt;strong&gt;busca&lt;/strong&gt;. A grande diferença é a taxa de crescimento:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tamanho da Entrada (N)&lt;/th&gt;
&lt;th&gt;O(N) (Linear)&lt;/th&gt;
&lt;th&gt;O(log N) (Logarítmico)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1.000&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1.000 passos&lt;/td&gt;
&lt;td&gt;10 passos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1.000.000&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1.000.000 passos&lt;/td&gt;
&lt;td&gt;20 passos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1.000.000.000&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1 bilhão de passos&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;aproximadamente 30 passos&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;O tempo de execução é quase indiferente ao tamanho da entrada.&lt;/p&gt;




&lt;h3&gt;
  
  
  O Segredo: Dividir para Conquistar 🔪
&lt;/h3&gt;

&lt;p&gt;O algoritmo que atinge essa velocidade é a &lt;strong&gt;Busca Binária&lt;/strong&gt; (&lt;em&gt;Binary Search&lt;/em&gt;). A lógica é simples: em cada passo, você consegue &lt;strong&gt;descartar metade do espaço de busca&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Pré-requisito Obrigatório
&lt;/h4&gt;

&lt;p&gt;Para que a Busca Binária funcione, a estrutura de dados &lt;strong&gt;DEVE estar ordenada&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Você verifica o elemento &lt;strong&gt;central&lt;/strong&gt; (&lt;code&gt;mid&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt; Se o valor central for menor que seu alvo, você descarta toda a metade esquerda.&lt;/li&gt;
&lt;li&gt; Se for maior, descarta toda a metade direita.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Isso se repete recursivamente, dividindo o problema ao meio (log2) a cada iteração.&lt;/p&gt;




&lt;h3&gt;
  
  
  O Desafio O(N) em Elixir 💥
&lt;/h3&gt;

&lt;p&gt;Aqui está a pegadinha para quem programa em Elixir:&lt;/p&gt;

&lt;p&gt;Como a &lt;strong&gt;Lista Ligada&lt;/strong&gt; padrão só sabe onde a cabeça está, se você tentar acessar o elemento central (o índice N/2) em uma lista de Elixir, o sistema é forçado a percorrer os N/2 elementos, tornando essa operação &lt;strong&gt;O(N)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Se a cada passo da sua busca O(log N) você gasta O(N) para encontrar o meio, a complexidade final se torna O(N log N) no melhor dos casos, o que anula o ganho da Busca Binária!&lt;/p&gt;

&lt;h4&gt;
  
  
  A Solução em Elixir: Tuplas O(1)
&lt;/h4&gt;

&lt;p&gt;Para realizar a Busca Binária corretamente em O(log N), precisamos de uma estrutura que permita &lt;strong&gt;acesso por índice em O(1)&lt;/strong&gt;. No ecossistema Erlang/Elixir, usamos &lt;strong&gt;Tuplas&lt;/strong&gt; para essa finalidade.&lt;/p&gt;

&lt;p&gt;Com o acesso O(1) garantido, podemos implementar a lógica recursiva:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;BinarySearch&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nv"&gt;@doc&lt;/span&gt; &lt;span class="s2"&gt;"Inicia a Busca Binária O(log N)."&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# Conversão para Tupla para simular o acesso O(1) por índice&lt;/span&gt;
    &lt;span class="n"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Inicializa a recursão: low=0, high=N-1&lt;/span&gt;
    &lt;span class="n"&gt;binary_search_recursive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tuple_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# Condição de Falha: low cruzou high. Target não existe.&lt;/span&gt;
  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;binary_search_recursive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;low&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;when&lt;/span&gt; &lt;span class="n"&gt;low&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="ss"&gt;:not_found&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# Condição Recursiva Principal&lt;/span&gt;
  &lt;span class="k"&gt;defp&lt;/span&gt; &lt;span class="n"&gt;binary_search_recursive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;low&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# 1. Calcular o índice central (mid)&lt;/span&gt;
    &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;low&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 2. Obter o valor central (acesso O(1) na tupla)&lt;/span&gt;
    &lt;span class="c1"&gt;# Tuplas em Erlang são base 1, por isso o + 1&lt;/span&gt;
    &lt;span class="n"&gt;current_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:erlang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 

    &lt;span class="c1"&gt;# 3. Condição de Sucesso&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="c1"&gt;# Retorna o índice&lt;/span&gt;

    &lt;span class="c1"&gt;# 4. Alvo é MAIOR: Descartamos a esquerda, movemos low&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;binary_search_recursive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 5. Alvo é MENOR: Descartamos a direita, movemos high&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; 
      &lt;span class="n"&gt;binary_search_recursive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;low&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
   &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A beleza dessa função é que ela demonstra a complexidade &lt;strong&gt;O(log N)&lt;/strong&gt; de forma perfeita, pois as chamadas recursivas sempre reduzem o espaço de busca pela metade.&lt;/p&gt;




&lt;h3&gt;
  
  
  Próxima Parada: O Padrão Ouro
&lt;/h3&gt;

&lt;p&gt;Se O(log N) é o melhor para a busca, qual é o melhor para a &lt;strong&gt;Ordenação&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;No próximo post, exploraremos a complexidade &lt;a href="https://dev.to/gissandrogama/post-4-o-padrao-ouro-da-ordenacao-on-log-n-46jp"&gt;&lt;strong&gt;O(N log N)&lt;/strong&gt; (Linearithmic)&lt;/a&gt;, o padrão-ouro dos algoritmos de ordenação, e desvendaremos o &lt;strong&gt;Merge Sort&lt;/strong&gt;, que combina o poder logarítmico de dividir problemas com o trabalho linear de mesclá-los de volta.&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>performance</category>
      <category>programming</category>
      <category>erlang</category>
    </item>
    <item>
      <title>A Migração de O(N^2) para O(N): O Poder do O(1)</title>
      <dc:creator>Gissandro Gama</dc:creator>
      <pubDate>Sat, 29 Nov 2025 23:45:35 +0000</pubDate>
      <link>https://forem.com/gissandrogama/a-migracao-de-on2-para-on-o-poder-do-o1-3b84</link>
      <guid>https://forem.com/gissandrogama/a-migracao-de-on2-para-on-o-poder-do-o1-3b84</guid>
      <description>&lt;h3&gt;
  
  
  Domando o Crescimento: Como Transformar O(N^2) em O(N) com Estruturas de Dados Elixir
&lt;/h3&gt;

&lt;p&gt;No &lt;a href="https://dev.to/gissandrogama/o-que-e-big-o-e-o-vilao-on2-52ep"&gt;Post 1 - O que é Big O? e o Vilão O(N^2)&lt;/a&gt;, vimos que a complexidade &lt;strong&gt;O(N^2)&lt;/strong&gt; é causada por um laço aninhado que obriga o sistema a varrer a lista inteira (N) para cada elemento (N). Se um algoritmo tem que fazer N x N operações, ele não vai escalar.&lt;/p&gt;

&lt;p&gt;A chave para migrar de &lt;strong&gt;O(N^2)&lt;/strong&gt; para &lt;strong&gt;O(N) (Linear)&lt;/strong&gt; é garantir que cada elemento da entrada seja visitado um número &lt;strong&gt;constante&lt;/strong&gt; de vezes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Objetivo:&lt;/strong&gt; Transformar a operação de "procurar um elemento na lista" de O(N) para &lt;strong&gt;O(1)&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  O Segredo O(1): Mapas e Conjuntos
&lt;/h3&gt;

&lt;p&gt;Para obter uma busca ou inserção em tempo constante &lt;code&gt;O(1)&lt;/code&gt;, não podemos usar a lista padrão de Elixir. Precisamos de uma estrutura que responda "Este item já existe?" de forma instantânea, sem precisar iterar.&lt;/p&gt;

&lt;p&gt;Em Elixir, essa estrutura é o &lt;strong&gt;MapSet&lt;/strong&gt; (Conjunto) ou o &lt;strong&gt;Map&lt;/strong&gt; (Mapa). Eles utilizam uma técnica chamada &lt;strong&gt;Hashing&lt;/strong&gt; para transformar a chave em um endereço de memória previsível.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Estrutura&lt;/th&gt;
&lt;th&gt;Operação&lt;/th&gt;
&lt;th&gt;Complexidade&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lista&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Procurar um elemento&lt;/td&gt;
&lt;td&gt;O(N)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MapSet&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Procurar um elemento&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;O(1)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  A Solução O(N) em Elixir: Reduce e MapSet
&lt;/h3&gt;

&lt;p&gt;Para resolver o problema de duplicatas em tempo O(N), usaremos uma técnica de programação funcional chamada &lt;strong&gt;Acumulação&lt;/strong&gt;. Vamos percorrer a lista &lt;strong&gt;apenas uma vez&lt;/strong&gt; (&lt;code&gt;Enum.reduce_while&lt;/code&gt;), usando um &lt;code&gt;MapSet&lt;/code&gt; como nosso &lt;strong&gt;acumulador&lt;/strong&gt; para rastrear os elementos já vistos.&lt;/p&gt;

&lt;h4&gt;
  
  
  Código Elixir: Duplicata Rápida
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;OptimizedDuplicationCheck&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;contains_duplicate_fast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# 1. Acumulador: Iniciamos com um MapSet vazio.&lt;/span&gt;
    &lt;span class="n"&gt;initial_set&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MapSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="c1"&gt;# Usamos reduce_while para otimizar, parando assim que a duplicata for achada.&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reduce_while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initial_set&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seen_elements&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
      &lt;span class="c1"&gt;# Checagem O(1)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;MapSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;member?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seen_elements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="c1"&gt;# 🟢 Sucesso no Melhor Caso (O(1)): Encontrado! Paramos.&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:halt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; 
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="c1"&gt;# Atualização O(1): Adiciona o elemento e continua.&lt;/span&gt;
        &lt;span class="n"&gt;new_set&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MapSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seen_elements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:cont&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_set&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Trata o resultado: se foi halt, retorna true; se percorreu tudo, retorna false.&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;&amp;amp;1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
  &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📈 Análise de Complexidade
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operação&lt;/th&gt;
&lt;th&gt;Frequência&lt;/th&gt;
&lt;th&gt;Complexidade&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;Enum.reduce_while&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;N vezes&lt;/td&gt;
&lt;td&gt;O(N)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;MapSet.member?&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;N vezes (dentro do reduce)&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;MapSet.put&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;N vezes (dentro do reduce)&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Complexidade Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;N \times (O(1) + O(1))&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;O(N)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Ao trocar a busca interna de O(N) para O(1), eliminamos o fator N extra, garantindo que o algoritmo escale linearmente.&lt;/p&gt;

&lt;p&gt;Além disso, o uso de &lt;strong&gt;&lt;code&gt;Enum.reduce_while&lt;/code&gt;&lt;/strong&gt; nos dá uma otimização no &lt;strong&gt;Melhor Caso&lt;/strong&gt;: se a duplicata for o primeiro elemento, a execução é interrompida em &lt;strong&gt;O(1)&lt;/strong&gt;!&lt;/p&gt;




&lt;h3&gt;
  
  
  Próxima Parada: O O(log N)
&lt;/h3&gt;

&lt;p&gt;Se O(N) é excelente, imagine um algoritmo que requer apenas =~ 24 passos para encontrar um item em uma lista de 10 milhões de elementos.&lt;/p&gt;

&lt;p&gt;No próximo post, exploraremos a &lt;a href="https://dev.to/gissandrogama/post-3-a-santa-graal-da-busca-olog-n-a6"&gt;&lt;strong&gt;Busca Binária&lt;/strong&gt;&lt;/a&gt; e a complexidade &lt;strong&gt;O(log N) (Logarítmica)&lt;/strong&gt;, a verdadeira "Santa Graal" da velocidade de busca. Veremos por que a lista deve estar ordenada para que isso funcione e qual estrutura de dados de Elixir precisamos usar para implementá-la corretamente.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>performance</category>
      <category>programming</category>
      <category>elixir</category>
    </item>
    <item>
      <title>O que é Big O? e o Vilão O(N^2)</title>
      <dc:creator>Gissandro Gama</dc:creator>
      <pubDate>Sat, 29 Nov 2025 23:45:14 +0000</pubDate>
      <link>https://forem.com/gissandrogama/o-que-e-big-o-e-o-vilao-on2-52ep</link>
      <guid>https://forem.com/gissandrogama/o-que-e-big-o-e-o-vilao-on2-52ep</guid>
      <description>&lt;h3&gt;
  
  
  Complexidade de Algoritmos com Elixir: Entendendo o O(N^2) e Por que sua lista é tão lenta?
&lt;/h3&gt;

&lt;p&gt;Se você programa em Elixir ou qualquer outra linguagem e já viu seu código funcionar perfeitamente com 10 itens, mas travar com 10.000, você esbarrou na &lt;strong&gt;Complexidade de Algoritmos&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A Notação &lt;strong&gt;Big O&lt;/strong&gt; O(...) não mede o tempo em segundos, mas sim a &lt;strong&gt;regra de crescimento&lt;/strong&gt; do tempo de execução em relação ao tamanho da entrada (N). É a ferramenta mais importante para escrever código que escala.&lt;/p&gt;




&lt;h3&gt;
  
  
  Acelerando e Desacelerando: O(1) vs. O(N)
&lt;/h3&gt;

&lt;p&gt;Em Elixir, a estrutura de dados mais fundamental é a &lt;strong&gt;Lista Ligada Simples&lt;/strong&gt; (&lt;em&gt;Singly Linked List&lt;/em&gt;). Entender como ela funciona nos dá a base para o O(1) e o O(N).&lt;/p&gt;

&lt;h4&gt;
  
  
  🟢 O(1): Complexidade Constante
&lt;/h4&gt;

&lt;p&gt;O tempo de execução é sempre o mesmo, não importa se sua lista tem 10 elementos ou 1 milhão.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Exemplo Elixir:&lt;/strong&gt; Colocar um novo elemento no &lt;strong&gt;início&lt;/strong&gt; (prepend) da lista.&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# O(1): Cria um novo nó que aponta para a lista antiga.&lt;/span&gt;
&lt;span class="n"&gt;new_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;novo_item&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;lista_antiga&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# O(1): Acesso à Cabeça&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_list&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa é a operação mais comum em código funcional e a razão pela qual a criação de listas em Elixir é tão rápida.&lt;/p&gt;

&lt;h4&gt;
  
  
  🟡 O(N): Complexidade Linear
&lt;/h4&gt;

&lt;p&gt;O tempo de execução cresce proporcionalmente ao tamanho da entrada. Se a lista dobra de tamanho, o tempo dobra.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Exemplo Elixir:&lt;/strong&gt; Varrer a lista (map, reduce) ou &lt;strong&gt;anexar um item no final&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# O(N): Percorre CADA elemento da lista&lt;/span&gt;
&lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;&amp;amp;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;&amp;amp;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# O(N): Para anexar no final, o sistema deve percorrer a lista inteira.&lt;/span&gt;
&lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;item_no_fim&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🔥 O(N^2): O Vilão Quadrático
&lt;/h3&gt;

&lt;p&gt;A complexidade &lt;strong&gt;O(N^2)&lt;/strong&gt; é o seu pior inimigo para escalabilidade. Se a entrada (N) dobra de tamanho, o tempo de execução &lt;strong&gt;quadruplica&lt;/strong&gt; (2^2 = 4).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Causa:&lt;/strong&gt; A presença de &lt;strong&gt;laços de repetição aninhados&lt;/strong&gt; (um &lt;em&gt;loop&lt;/em&gt; dentro de outro &lt;em&gt;loop&lt;/em&gt;) onde o &lt;em&gt;loop&lt;/em&gt; interno depende do tamanho total da entrada.&lt;/p&gt;

&lt;h4&gt;
  
  
  Exemplo Prático: Checagem Ingênua de Duplicatas
&lt;/h4&gt;

&lt;p&gt;Imagine que queremos verificar se há duplicatas em uma lista. Se usarmos a abordagem ingênua, acabamos com O(N^2):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;check_duplicate_slow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# Enum.any? itera pela lista: N vezes&lt;/span&gt;
  &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;any?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;current_element&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;# Para cada current_element, essa linha varre a lista INTEIRA novamente: N vezes&lt;/span&gt;
    &lt;span class="n"&gt;list&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;&amp;amp;1&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;current_element&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Enum&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Análise:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; O &lt;code&gt;Enum.any?&lt;/code&gt; externo executa N vezes.&lt;/li&gt;
&lt;li&gt; Para cada execução, o &lt;code&gt;Enum.filter&lt;/code&gt; interno varre toda a lista (N elementos).&lt;/li&gt;
&lt;li&gt; Total de operações =~ N x N = O(N^2).&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Se N = 10.000, o algoritmo fará 100.000.000 de operações (cem milhões). Um crescimento insustentável!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Próxima Parada: O Salto para $O(N)$
&lt;/h3&gt;

&lt;p&gt;A solução O(N^2)$ é fácil de escrever, mas destrói a performance. Existe uma forma de resolver o problema de duplicatas visitando cada elemento apenas uma vez, transformando o algoritmo em um rápido &lt;strong&gt;O(N)&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;No próximo post, exploraremos a técnica que usa estruturas de dados &lt;strong&gt;O(1)&lt;/strong&gt; para eliminar o laço interno, transformando o código de lento e quadratico em rápido e linear. Não perca a &lt;a href="https://dev.to/gissandrogama/a-migracao-de-on2-para-on-o-poder-do-o1-3b84"&gt;&lt;strong&gt;Migração de O(N^2) para O(N) !&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>elixir</category>
      <category>algorithms</category>
      <category>webdev</category>
      <category>performance</category>
    </item>
    <item>
      <title>Desvendando os Superpoderes do Elixir: Concorrência e Tolerância a Falhas</title>
      <dc:creator>Gissandro Gama</dc:creator>
      <pubDate>Wed, 05 Nov 2025 23:38:26 +0000</pubDate>
      <link>https://forem.com/gissandrogama/desvendando-os-superpoderes-do-elixir-concorrencia-e-tolerancia-a-falhas-5f6e</link>
      <guid>https://forem.com/gissandrogama/desvendando-os-superpoderes-do-elixir-concorrencia-e-tolerancia-a-falhas-5f6e</guid>
      <description>&lt;p&gt;Se você já ouviu falar que o Elixir é ideal para sistemas &lt;strong&gt;escaláveis, distribuídos e tolerantes a falhas&lt;/strong&gt;, mas nunca entendeu exatamente &lt;strong&gt;o porquê&lt;/strong&gt;, este post é para você. Vamos mergulhar nos fundamentos que o Elixir herda da plataforma Erlang (BEAM) e que permitem a construção de aplicações robustas, capazes de lidar com milhões de conexões simultâneas.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. O Coração de Tudo: Processos Leves e o Modelo Ator
&lt;/h2&gt;

&lt;p&gt;A base da concorrência em Elixir não são &lt;em&gt;threads&lt;/em&gt; do sistema operacional, mas sim &lt;strong&gt;processos&lt;/strong&gt; extremamente leves gerenciados pela própria máquina virtual (BEAM).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Milhões de Processos:&lt;/strong&gt; É perfeitamente viável executar milhares ou até milhões desses processos concorrentemente na mesma máquina. Cada um deles é incrivelmente pequeno e eficiente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolamento Total:&lt;/strong&gt; Cada processo tem sua própria memória e seu próprio Garbage Collector. A falha de um processo não leva à falha de outros. O isolamento é crucial, pois simplifica o código (eliminando a necessidade de mecanismos complexos de sincronização como &lt;em&gt;locks&lt;/em&gt; ou &lt;em&gt;mutexes&lt;/em&gt;) e aumenta a estabilidade geral do sistema.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comunicação por Mensagens:&lt;/strong&gt; Os processos não compartilham memória. A única forma de se comunicarem é através da troca de mensagens. Enviar uma mensagem a outro processo resulta em uma &lt;strong&gt;cópia profunda&lt;/strong&gt; (&lt;em&gt;deep copy&lt;/em&gt;) do conteúdo, garantindo que a memória permaneça isolada.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cada processo funciona como um "ator" independente. Ele possui uma "caixa de correio" (mailbox) e processa uma mensagem por vez. Isso o torna um ponto de sincronização eficaz, garantindo a consistência de seu estado interno, mesmo que receba múltiplas requisições concorrentes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exemplo na Prática: Criando um Processo
&lt;/h2&gt;

&lt;p&gt;Vamos criar um processo simples que espera uma mensagem, imprime uma saudação e depois termina.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Defina um módulo com a função que o processo irá executar&lt;/span&gt;
&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;Greeter&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# A função receive espera por uma mensagem que corresponda a um dos padrões&lt;/span&gt;
    &lt;span class="k"&gt;receive&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:greet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Olá, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Não entendi a mensagem."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# Inicie uma sessão IEx (iex -S mix) para testar&lt;/span&gt;

&lt;span class="c1"&gt;# Crie um novo processo executando a função Greeter.start/0&lt;/span&gt;
&lt;span class="c1"&gt;# A função spawn retorna o PID (Process Identifier)&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Greeter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
&lt;span class="c1"&gt;#PID&amp;lt;0.150.0&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;# Envie uma mensagem para o processo usando seu PID&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:greet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Mundo"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;Ol&lt;/span&gt;&lt;span class="err"&gt;á&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Mundo&lt;/span&gt;&lt;span class="n"&gt;!&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:greet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Mundo"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste exemplo, &lt;code&gt;spawn&lt;/code&gt; criou um ator, e &lt;code&gt;send&lt;/code&gt; colocou uma mensagem em sua caixa de correio. O processo a consumiu, executou a ação e terminou, tudo isso sem interferir em mais nada no sistema.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. "Justiça para Todos": O Agendador Preemptivo (Scheduler)
&lt;/h2&gt;

&lt;p&gt;Como a BEAM gerencia milhões de processos sem que um deles "trave" todo o sistema? A resposta é o &lt;strong&gt;agendamento preemptivo&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Cada processo recebe uma pequena janela de tempo de execução (historicamente, cerca de 2.000 chamadas de função, ou "reduções"). Após esgotar essa fatia de tempo, o agendador pausa o processo e dá a vez para o próximo da fila.&lt;/p&gt;

&lt;p&gt;Isso impede que uma única tarefa de longa duração bloqueie todo o sistema, garantindo que a aplicação como um todo permaneça &lt;strong&gt;responsiva&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. A Filosofia "Let It Crash": Construindo Sistemas que se Curam
&lt;/h2&gt;

&lt;p&gt;Em vez de programar defensivamente com incontáveis blocos &lt;code&gt;try/catch&lt;/code&gt; para prever todos os erros possíveis, a filosofia em Elixir é "deixar falhar" (&lt;em&gt;let it crash&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;O modelo de concorrência do Erlang fornece as ferramentas para que os sistemas se &lt;strong&gt;autocurem&lt;/strong&gt; e recuperem de erros inesperados. A causa de erros imprevisíveis é frequentemente um estado corrompido, e ao falhar e ser reiniciado, o processo retorna a um &lt;strong&gt;estado inicial limpo e consistente&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Isso é possível graças a dois mecanismos principais: &lt;strong&gt;Links&lt;/strong&gt; e &lt;strong&gt;Monitores&lt;/strong&gt;, orquestrados por &lt;strong&gt;Supervisores&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Links: Falhando em Conjunto
&lt;/h3&gt;

&lt;p&gt;Quando dois processos são "linkados", eles formam um pacto: se um deles morrer de forma anormal, ele enviará um &lt;strong&gt;sinal de saída&lt;/strong&gt; (&lt;em&gt;exit signal&lt;/em&gt;) para o outro, que, por padrão, também morrerá.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplo na Prática:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Inicie uma sessão IEx&lt;/span&gt;

&lt;span class="c1"&gt;# Crie um processo que simplesmente falha e o linke ao processo do IEx&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;spawn_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"Oops, algo deu errado!"&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="no"&gt;Oops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;algo&lt;/span&gt; &lt;span class="n"&gt;deu&lt;/span&gt; &lt;span class="n"&gt;errado!&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stdlib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;erl_eval&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="ss"&gt;erl:&lt;/span&gt;&lt;span class="mi"&gt;680&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ss"&gt;:erl_eval&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;do_apply&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;

&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# O seu terminal IEx pode fechar ou mostrar um erro, pois ele estava linkado ao processo que falhou!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Monitores: Observando de Longe
&lt;/h3&gt;

&lt;p&gt;E se você quiser saber quando um processo morre, mas &lt;strong&gt;não&lt;/strong&gt; quer morrer junto com ele? Para isso, usamos monitores.&lt;/p&gt;

&lt;p&gt;O processo observador recebe uma mensagem &lt;code&gt;{:DOWN, ...}&lt;/code&gt; se o processo monitorado falhar, mas o observador não é derrubado. Monitores são a ferramenta ideal quando não se deseja que a falha se propague.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplo na Prática:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Inicie uma sessão IEx&lt;/span&gt;

&lt;span class="c1"&gt;# Crie um processo que falha, mas desta vez, apenas o monitore&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;_pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;monitor_ref&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;spawn_monitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"Falha controlada"&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="c1"&gt;#PID&amp;lt;0.154.0&amp;gt;, #Reference&amp;lt;...&amp;gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# O processo do IEx continua vivo. Vamos checar sua caixa de correio&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:DOWN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;#Reference&amp;lt;...&amp;gt;, :process, #PID&amp;lt;0.154.0&amp;gt;, {%RuntimeError{message: "Falha controlada"}, [...]}}&lt;/span&gt;
&lt;span class="ss"&gt;:ok&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A mensagem &lt;code&gt;:DOWN&lt;/code&gt; nos informa sobre a falha, permitindo que nosso processo tome uma ação (como tentar reiniciar o trabalhador) sem ser afetado.&lt;/p&gt;

&lt;h3&gt;
  
  
  Supervisores: A Rede de Segurança
&lt;/h3&gt;

&lt;p&gt;Supervisores são processos especiais cujo único trabalho é monitorar outros processos (seus "filhos") e reiniciá-los quando eles falham. Eles são a implementação prática da filosofia "let it crash".&lt;/p&gt;

&lt;p&gt;Eles formam uma &lt;strong&gt;árvore de supervisão&lt;/strong&gt;, o que permite a &lt;strong&gt;isolação de erros em grão fino&lt;/strong&gt;. Se um erro ocorre em um trabalhador, tenta-se resolvê-lo localmente (pelo supervisor imediato). Se o supervisor falhar, o erro se propaga para o supervisor pai, que tentará reiniciar uma parte maior do sistema. Isso garante que a falha seja contida na menor subestrutura possível.&lt;/p&gt;

&lt;h4&gt;
  
  
  Exemplo na Prática: Um Supervisor Simples
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;O Trabalhador (Worker):&lt;/strong&gt; Um &lt;code&gt;GenServer&lt;/code&gt; que mantém um estado.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Worker&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt;

  &lt;span class="c1"&gt;# API Pública&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initial_state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;crash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;GenServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:crash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;# Callbacks do GenServer&lt;/span&gt;
  &lt;span class="nv"&gt;@impl&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initial_state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Worker iniciado com estado: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initial_state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_state&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nv"&gt;@impl&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;handle_cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:crash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;IO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Recebi uma ordem para falhar! Adeus, estado: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"Falha intencional"&lt;/span&gt;
    &lt;span class="c1"&gt;# O GenServer irá travar aqui&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;O Supervisor:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Supervisor&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="no"&gt;Supervisor&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;init_arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="no"&gt;Supervisor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;init_arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="bp"&gt;__MODULE__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nv"&gt;@impl&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_init_arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;children&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="c1"&gt;# Define o nosso worker como um filho&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# O argumento `0` será passado para o start_link do Worker&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# A estratégia :one_for_one reinicia apenas o processo que falhou&lt;/span&gt;
    &lt;span class="no"&gt;Supervisor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;strategy:&lt;/span&gt; &lt;span class="ss"&gt;:one_for_one&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Testando no IEx:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Inicie o supervisor&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sup_pid&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Supervisor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_link&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;
&lt;span class="no"&gt;Worker&lt;/span&gt; &lt;span class="n"&gt;iniciado&lt;/span&gt; &lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="ss"&gt;estado:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;#PID&amp;lt;0.165.0&amp;gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Vamos forçar o worker a falhar&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;MyApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="no"&gt;Worker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;crash&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="no"&gt;Recebi&lt;/span&gt; &lt;span class="n"&gt;uma&lt;/span&gt; &lt;span class="n"&gt;ordem&lt;/span&gt; &lt;span class="n"&gt;para&lt;/span&gt; &lt;span class="n"&gt;falhar!&lt;/span&gt; &lt;span class="no"&gt;Adeus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;estado:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="ss"&gt;:ok&lt;/span&gt;

&lt;span class="c1"&gt;# O supervisor detecta a falha e reinicia o worker imediatamente!&lt;/span&gt;
&lt;span class="c1"&gt;# A saída abaixo aparece automaticamente no seu terminal:&lt;/span&gt;
&lt;span class="no"&gt;Worker&lt;/span&gt; &lt;span class="n"&gt;iniciado&lt;/span&gt; &lt;span class="n"&gt;com&lt;/span&gt; &lt;span class="ss"&gt;estado:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="c1"&gt;# O processo foi reiniciado com um estado limpo, como se nada tivesse acontecido.&lt;/span&gt;
&lt;span class="c1"&gt;# O sistema se curou sozinho!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  4. Bônus: Abstração de Dados com Structs e Módulos
&lt;/h2&gt;

&lt;p&gt;A filosofia de código limpo em Elixir também se beneficia da imutabilidade. Funções não modificam dados; elas retornam &lt;strong&gt;novas versões&lt;/strong&gt; dos dados.&lt;/p&gt;

&lt;p&gt;Isso é facilitado pelo uso de &lt;strong&gt;módulos&lt;/strong&gt; e &lt;strong&gt;structs&lt;/strong&gt;. Um módulo é uma coleção de funções que operam sobre um tipo de dado específico. &lt;code&gt;Structs&lt;/code&gt; fornecem campos nomeados e valores padrão, impondo contratos de dados mais rígidos que mapas genéricos.&lt;/p&gt;

&lt;p&gt;A convenção é que a estrutura de dados seja sempre o &lt;strong&gt;primeiro argumento&lt;/strong&gt; das funções, o que permite o uso elegante do operador &lt;em&gt;pipeline&lt;/em&gt; (&lt;code&gt;|&amp;gt;&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplo na Prática:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="k"&gt;defmodule&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# Define a estrutura de dados&lt;/span&gt;
  &lt;span class="k"&gt;defstruct&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;active:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="c1"&gt;# Funções que operam sobre a estrutura User&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;email:&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;activate&lt;/span&gt;&lt;span class="p"&gt;(%&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="ss"&gt;active:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# Retorna uma *nova* struct com o campo `active` alterado&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="n"&gt;change_email&lt;/span&gt;&lt;span class="p"&gt;(%&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="ss"&gt;email:&lt;/span&gt; &lt;span class="n"&gt;new_email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# Retorna uma *nova* struct&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# Testando no IEx&lt;/span&gt;
&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Gama"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"gama@example.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"Gama"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;email:&lt;/span&gt; &lt;span class="s2"&gt;"gama@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;active:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;activate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;change_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"elixir.dev@example.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;%&lt;/span&gt;&lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"Gama"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;email:&lt;/span&gt; &lt;span class="s2"&gt;"elixir.dev@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;active:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Os "superpoderes" do Elixir não são mágica. Eles são o resultado de um conjunto de princípios de design testados e aprovados ao longo de décadas com o Erlang:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Processos leves e isolados&lt;/strong&gt; para uma concorrência massiva.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Comunicação explícita por mensagens&lt;/strong&gt; para evitar o caos de memória compartilhada.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Supervisores&lt;/strong&gt; que constroem sistemas que se curam sozinhos.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Imutabilidade e abstração de dados&lt;/strong&gt; que tornam o código previsível e fácil de manter.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ao abraçar esses conceitos, você começa a pensar não apenas em escrever código que funciona, mas em construir sistemas que são projetados para &lt;strong&gt;continuar funcionando&lt;/strong&gt;, não importa o que aconteça.&lt;/p&gt;

</description>
      <category>functionalreactiveprogramming</category>
      <category>elixir</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
