\newpage
\subsubsection{Kruskal's algorithm}
\begin{definition}[]{Kruskal's Algorithm}
    Kruskal's Algorithm is a greedy algorithm for finding the Minimum Spanning Tree (MST) of a connected, weighted graph. It sorts all the edges by weight and adds them to the MST in order of increasing weight, provided they do not form a cycle with the edges already included.
\end{definition}

\begin{properties}[]{Characteristics and Performance}
    \begin{itemize}
        \item \textbf{Graph Type:} Works on undirected, weighted graphs.
        \item \textbf{Approach:} Greedy, edge-centric.
        \item \textbf{Time Complexity:} $\tco{|E| \log (|E|)}$ (for sort), $\tco{|V| \log(|V|)}$ (for union find data structure).\\
              \timecomplexity $\tco{|E| \log(|E|) + |V| \log(|V|)}$
        \item \textbf{Space Complexity:} Depends on the graph representation, typically $\tct{E + V}$.
        \item \textbf{Limitations:} Requires sorting of edges, which can dominate runtime.
    \end{itemize}
\end{properties}

\begin{algorithm}
    \caption{Kruskal's Algorithm}
    \begin{algorithmic}[1]
        \Procedure{Kruskal}{$G = (V, E)$}
            \State Sort all edges $E$ in non-decreasing order of weight.
            \State Initialize an empty MST $T$.
            \State Initialize a disjoint-set data structure for $V$.
            \For{each edge $(u, v)$ in $E$ (in sorted order)}
                \If{$u$ and $v$ belong to different components in the disjoint set}
                    \State Add $(u, v)$ to $T$.
                    \State Union the sets containing $u$ and $v$.
                \EndIf
            \EndFor
            \State \Return $T$.
        \EndProcedure
    \end{algorithmic}
\end{algorithm}

\begin{usage}[]{Kruskal's Algorithm}
    Kruskal's algorithm finds the Minimum Spanning Tree (MST) by sorting edges and adding them to the MST, provided they don't form a cycle.

    \begin{enumerate}
        \item \textbf{Sort Edges:}
              \begin{itemize}
                  \item Sort all edges in ascending order by their weights.
              \end{itemize}

        \item \textbf{Initialize Disjoint Sets (union find):}
              \begin{itemize}
                  \item Assign each vertex to its own disjoint set to track connected components.
              \end{itemize}

        \item \textbf{Iterate Over Edges:}
              \begin{itemize}
                  \item For each edge in the sorted list:
                        \begin{itemize}
                            \item Check if the edge connects vertices from different sets.
                            \item If it does, add the edge to the MST and merge the sets.
                        \end{itemize}
              \end{itemize}

        \item \textbf{Stop When Done:}
              \begin{itemize}
                  \item Stop when the MST contains \(n-1\) edges (for a graph with \(n\) vertices).
              \end{itemize}

        \item \textbf{End:}
              \begin{itemize}
                  \item The MST is complete, and all selected edges form a connected acyclic graph.
              \end{itemize}
    \end{enumerate}
\end{usage}


\newpage
\fhlc{Aquamarine}{Union-Find}
\begin{usage}[]{Union-Find Data Structure - Step-by-Step Execution}
    The Union-Find data structure efficiently supports two primary operations for disjoint sets:
    \begin{itemize}
        \item \textbf{Union:} Merge two sets into one.
        \item \textbf{Find:} Identify the representative (or root) of the set containing a given element.
    \end{itemize}

    \textbf{Steps for Using the Union-Find Data Structure:}

    \begin{enumerate}
        \item \textbf{Initialization:}
              \begin{itemize}
                  \item Create an array \(parent\), where \(parent[i] = i\), indicating that each element is its own parent (a singleton set).
                  \item Optionally, maintain a \(rank\) array to track the rank (or size) of each set for optimization.
              \end{itemize}

        \item \textbf{Find Operation:}
              \begin{itemize}
                  \item To find the representative (or root) of a set containing element \(x\):
                        \begin{enumerate}
                            \item Follow the \(parent\) array recursively until \(parent[x] = x\).
                            \item Apply \textbf{path compression} by updating \(parent[x]\) directly to the root to flatten the tree structure:
                                  \[
                                      parent[x] = \text{Find}(parent[x])
                                  \]
                        \end{enumerate}
              \end{itemize}

        \item \textbf{Union Operation:}
              \begin{itemize}
                  \item To merge the sets containing \(x\) and \(y\):
                        \begin{enumerate}
                            \item Find the roots of \(x\) and \(y\) using the Find operation.
                            \item Compare their ranks:
                                  \begin{itemize}
                                      \item Attach the smaller tree under the larger tree to keep the structure shallow.
                                      \item If ranks are equal, arbitrarily choose one as the root and increment its rank.
                                  \end{itemize}
                        \end{enumerate}
              \end{itemize}

        \item \textbf{Optimization Techniques:}
              \begin{itemize}
                  \item \textbf{Path Compression:} Flattens the tree during Find operations, reducing the time complexity.
                  \item \textbf{Union by Rank/Size:} Ensures smaller trees are always attached under larger trees, maintaining a logarithmic depth.
              \end{itemize}

        \item \textbf{End:}
              \begin{itemize}
                  \item After performing Find and Union operations, the Union-Find structure can determine connectivity between elements or group them into distinct sets efficiently.
              \end{itemize}
    \end{enumerate}
\end{usage}

\begin{properties}[]{Performance}
    \begin{itemize}
        \item \textsc{make}$(V)$: Initialize data structure $\tco{n}$
        \item \textsc{same}$(u, v)$: Check if two components belong to the same set $\tco{1}$ or $\tco{n}$, depending on if the representant is stored in an array or not
        \item \textsc{union}$(u, v)$: Combine two sets, $\tco{\log(n)}$, in Kruskal we call this $\tco{n}$ times, so total number (amortised) is $\tco{n \log(n)}$
    \end{itemize}
\end{properties}
