<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ data structures - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ data structures - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 25 May 2026 22:37:54 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/data-structures/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Master Technical Interviews by Learning Data Structures and Algorithms ]]>
                </title>
                <description>
                    <![CDATA[ Learn how to master technical interviews for software engineering roles. We just posted a 49-hour course on the freeCodeCamp.org YouTube channel that will teach you everything you need to know about data structures and algorithms. Parth Vyas created ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/master-technical-interviews-by-learning-data-structures-and-algorithms/</link>
                <guid isPermaLink="false">68f7d7315429f082cb2c9593</guid>
                
                    <category>
                        <![CDATA[ data structures ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Tue, 21 Oct 2025 18:55:45 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1761072883079/51bad868-b848-41d9-8f01-15f56632d4ef.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Learn how to master technical interviews for software engineering roles.</p>
<p>We just posted a 49-hour course on the freeCodeCamp.org YouTube channel that will teach you everything you need to know about data structures and algorithms. Parth Vyas created this course.</p>
<p>Technical interviews often hinge on your ability to confidently solve problems using data structures and algorithms (DSA), which can feel challenging without the right foundation. In this comprehensive course, Parth will strip away the intimidation and equip you with the essential knowledge, starting with the core concepts of data structures, algorithms, and fundamental analysis like time and space complexity.</p>
<p>You'll learn how to judge an algorithm's efficiency using Big O notation and apply this important skill to code blocks. The course covers almost every major data structure and algorithm pattern, from Arrays, Linked Lists, Stacks, and Queues to advanced topics like Trees, Graphs, Dynamic Programming, and Backtracking.</p>
<p>Here are the sections in this course:</p>
<ul>
<li><p>Technical interviews 101</p>
</li>
<li><p>How to judge an algorithm</p>
</li>
<li><p>What is time complexity</p>
</li>
<li><p>What is Big O</p>
</li>
<li><p>Big O for code blocks</p>
</li>
<li><p>Space complexity example</p>
</li>
<li><p>How do you get good at solving DSA problems</p>
</li>
<li><p>Types of data structures</p>
</li>
<li><p>Quick recap</p>
</li>
<li><p>Arrays</p>
</li>
<li><p>Sliding window</p>
</li>
<li><p>Two pointers</p>
</li>
<li><p>Strings</p>
</li>
<li><p>Sorting &amp; searching</p>
</li>
<li><p>Linked list</p>
</li>
<li><p>Stack</p>
</li>
<li><p>Queue</p>
</li>
<li><p>Priority queue</p>
</li>
<li><p>Trees</p>
</li>
<li><p>Graph</p>
</li>
<li><p>Dynamic programming</p>
</li>
<li><p>Greedy</p>
</li>
<li><p>Interval</p>
</li>
<li><p>Backtracking</p>
</li>
<li><p>Math &amp; geometry</p>
</li>
<li><p>Matrix</p>
</li>
<li><p>Design</p>
</li>
<li><p>Bit manipulation</p>
</li>
</ul>
<p>Watch the full course on <a target="_blank" href="https://youtu.be/xwI5OBEnsZU">the freeCodeCamp.org YouTube channel</a> (49-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/xwI5OBEnsZU" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Arrays, Slices, and Maps in Go: a Quick Guide to Collection Types ]]>
                </title>
                <description>
                    <![CDATA[ Golang has a reputation for simplicity, and one reason is its small set of core data structures. Unlike some languages that offer lists, vectors, dictionaries, hashmaps, tuples, sets, and more, Go keeps things minimal. The three fundamental building ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/arrays-slices-and-maps-in-go-a-quick-guide-to-collection-types/</link>
                <guid isPermaLink="false">68bb12907f6ca0ada2df447f</guid>
                
                    <category>
                        <![CDATA[ Go Language ]]>
                    </category>
                
                    <category>
                        <![CDATA[ golang ]]>
                    </category>
                
                    <category>
                        <![CDATA[ data structures ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gabor Koos ]]>
                </dc:creator>
                <pubDate>Fri, 05 Sep 2025 16:40:48 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1757090426408/327ded41-5020-4f83-afa2-334f15569998.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Golang has a reputation for simplicity, and one reason is its small set of core data structures. Unlike some languages that offer lists, vectors, dictionaries, hashmaps, tuples, sets, and more, Go keeps things minimal.</p>
<p>The three fundamental building blocks you’ll use every day are:</p>
<ul>
<li><p><strong>Arrays</strong>: fixed-size sequences of elements.</p>
</li>
<li><p><strong>Slices</strong>: flexible, dynamic views of arrays.</p>
</li>
<li><p><strong>Maps</strong>: key–value stores implemented as hash tables.</p>
</li>
</ul>
<p>With these three, you can represent almost any collection of data you need.</p>
<p>In this tutorial, you'll learn how to use arrays, slices, and maps effectively. You'll also peek under the hood to see how Go represents them in memory. This will help you understand their performance characteristics and avoid common pitfalls.</p>
<p>By the end, you'll be able to:</p>
<ul>
<li><p>Choose the right data type for your problem.</p>
</li>
<li><p>Write idiomatic Go code for collections.</p>
</li>
<li><p>Understand how these types behave internally.</p>
</li>
<li><p>Build a small project combining arrays, slices, and maps.</p>
</li>
</ul>
<p>Let's dive in!</p>
<h3 id="heading-what-well-cover">What We’ll Cover:</h3>
<ol>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-arrays-in-go">Arrays in Go</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-initializing-with-values">Initializing with Values</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-array-length">Array Length</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-inner-representation-of-arrays">Inner Representation of Arrays</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-multi-dimensional-arrays">Multi-dimensional Arrays</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-limitations">Limitations</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-when-arrays-are-useful">When Arrays Are Useful</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-slices-in-go">Slices in Go</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-when-to-use-slices">When to use slices?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-declare-a-slice">How to Declare a Slice</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-allocate-with-make">Allocate (with make)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-append-elements">Append Elements</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-slice-slices">How to Slice Slices</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-inner-representation-of-slices">Inner Representation of Slices</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-copy-slices">How to Copy Slices</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-multi-dimensional-slices">Multi-dimensional Slices</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-slices-vs-arrays">Slices vs Arrays</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-maps-in-go">Maps in Go</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-to-declare-a-map">How to Declare a Map</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-access-values">How to Access Values</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-iterate-over-a-map">How to Iterate Over a Map</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-inner-representation-of-maps">Inner Representation of Maps</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-arrays-vs-slices-vs-maps">Arrays vs. Slices vs. Maps</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-mini-project-shopping-cart-totals">Mini Project: Shopping Cart Totals</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-practice-challenge">Practice Challenge</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-practice-challenge-solution">Practice Challenge Solution</a></li>
</ul>
</li>
</ol>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>This tutorial is designed for readers who already have some basic experience with Go. You don’t need to be an expert, but you should be comfortable with:</p>
<ul>
<li><p>Writing and running simple Go programs (<code>go run</code>, <code>go build</code>).</p>
</li>
<li><p>Declaring and using variables, functions, and basic types (for example, <code>int</code>, <code>string</code>, <code>bool</code>).</p>
</li>
<li><p>Understanding control structures like <code>if</code>, <code>for</code>, and <code>range</code>.</p>
</li>
<li><p>Using the Go toolchain and <code>go mod init</code> to set up a project.</p>
</li>
</ul>
<p>If you’ve completed the <a target="_blank" href="https://go.dev/tour">Tour of Go</a> or written a few small Go programs, you’ll be ready to follow along – we’ll cover the internals at a beginner-friendly level.</p>
<h2 id="heading-arrays-in-go">Arrays in Go</h2>
<p>An array is a numbered sequence of elements of the same type with a fixed length. Here’s an example in Go:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">var</span> nums [<span class="hljs-number">3</span>]<span class="hljs-keyword">int</span> <span class="hljs-comment">// array of 3 integers</span>
    fmt.Println(nums) <span class="hljs-comment">// [0 0 0]</span>
}
</code></pre>
<p>This code declares an array with space for exactly three <code>int</code> values. Go arrays are zero-indexed, meaning the first element is at index 0. The elements, like every Go variable, are initialized to the zero value of their type (0 for integers, ““ for strings, and so on).</p>
<p>Once the array is created, you can access its elements using their index like this:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">var</span> nums [<span class="hljs-number">3</span>]<span class="hljs-keyword">int</span> <span class="hljs-comment">// array of 3 integers</span>
    nums[<span class="hljs-number">1</span>] = <span class="hljs-number">2</span>
    fmt.Println(nums[<span class="hljs-number">1</span>]) <span class="hljs-comment">// 2</span>
    fmt.Println(nums) <span class="hljs-comment">// [0 2 0]</span>
}
</code></pre>
<h3 id="heading-initializing-with-values">Initializing with Values</h3>
<p>So far, we’ve seen that arrays are created with their elements set to the zero value of the element type. But often, you’ll want to give an array specific starting values right when you declare it. This process is called <strong>initialization</strong>: you provide the values in a list, and Go fills the array in order.</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    nums := [<span class="hljs-number">3</span>]<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>} <span class="hljs-comment">// array of 3 integers</span>
    fmt.Println(nums) <span class="hljs-comment">// [1 2 3]</span>
}
</code></pre>
<p>If you omit the size when initializing an array, Go will infer it from the number of elements you provide:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    nums := [...]<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>} <span class="hljs-comment">// array of 3 integers</span>
    fmt.Println(nums) <span class="hljs-comment">// [1 2 3]</span>
}
</code></pre>
<p>If you specify the size explicitly, the compiler will enforce that size:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    nums := [<span class="hljs-number">3</span>]<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>} <span class="hljs-comment">// array of 3 integers</span>
    fmt.Println(nums) <span class="hljs-comment">// [1 2 0]</span>
}
</code></pre>
<h3 id="heading-array-length">Array Length</h3>
<p>In Go, the length of an array is part of its type. <code>[3]int</code> and <code>[4]int</code> are considered completely different types, even though they both hold integers (you cannot assign a <code>[4]int</code> to a <code>[3]int</code>, or even compare them directly, because their lengths don’t match):</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">var</span> a [<span class="hljs-number">3</span>]<span class="hljs-keyword">int</span>
    <span class="hljs-keyword">var</span> b [<span class="hljs-number">4</span>]<span class="hljs-keyword">int</span>
    fmt.Println(a == b) <span class="hljs-comment">// compilation error</span>
}
</code></pre>
<p>When you use <code>[...]</code> in an array literal, Go counts how many elements you’ve provided and that will be the length. The length of an array is fixed and cannot be changed afterwards.</p>
<p>You can retrieve the length of an array using the built-in <code>len</code> function:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    nums := [<span class="hljs-number">3</span>]<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>}
    fmt.Println(<span class="hljs-built_in">len</span>(nums)) <span class="hljs-comment">// 3</span>
}
</code></pre>
<h3 id="heading-inner-representation-of-arrays">Inner Representation of Arrays</h3>
<p>In Go, arrays are represented as contiguous blocks of memory. This means that the elements of an array are stored one after the other in memory, making it easy to calculate the address of any element based on its index.</p>
<p>For example, consider the following array:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    nums := [<span class="hljs-number">3</span>]<span class="hljs-keyword">int32</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>} <span class="hljs-comment">// array of 3 32-bit integers</span>
    fmt.Println(&amp;nums[<span class="hljs-number">0</span>]) <span class="hljs-comment">// address of the first element</span>
    fmt.Println(&amp;nums[<span class="hljs-number">1</span>]) <span class="hljs-comment">// address of the second element</span>
    fmt.Println(&amp;nums[<span class="hljs-number">2</span>]) <span class="hljs-comment">// address of the third element</span>
}
</code></pre>
<p>It will give you something like this:</p>
<pre><code class="lang-plaintext">0xc00000a0f0
0xc00000a0f4
0xc00000a0f8
</code></pre>
<p>32 bits are 4 bytes, so the addresses of the elements differ by 4 bytes as well.</p>
<p>In the example above, we used <code>&amp;nums[0]</code> to get the address of the first element. You might wonder what happens if you take the address of the array itself, using <code>&amp;nums</code>:</p>
<pre><code class="lang-go">fmt.Println(&amp;nums)
</code></pre>
<p>At first glance, you might expect this to give you the same result as <code>&amp;nums[0]</code>, like in C where arrays often “decay” into pointers. But Go is different:</p>
<ul>
<li><p><code>&amp;nums</code> is a pointer to the <strong>entire array</strong> (type <code>*[3]int32</code>).</p>
</li>
<li><p><code>&amp;nums[0]</code> is a pointer to the <strong>first element</strong> (type <code>*int32</code>).</p>
</li>
</ul>
<p>When you print <code>&amp;nums</code>, the <code>fmt</code> package recognizes it as a pointer to an array and shows the array’s contents (<code>&amp;[1 2 3]</code>) rather than a raw memory address.</p>
<p>In Go, arrays and pointers to arrays are distinct types, and <code>&amp;nums</code> is of type <code>*[3]int32</code>, not <code>*int32</code>. When you print <code>&amp;nums</code>, <code>fmt</code> recognizes it as a pointer to an array and displays the array's contents, not the address. If you want the address of the first element, you use <code>&amp;nums[0]</code>, which is of type <code>*int32</code>.</p>
<p>If you try to access an out-of-bounds index, your program will panic at runtime with an error:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    nums := [<span class="hljs-number">3</span>]<span class="hljs-keyword">int32</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>}
        i := <span class="hljs-number">4</span>
    fmt.Println(&amp;nums[i])
}
</code></pre>
<pre><code class="lang-plaintext">panic: runtime error: index out of range [4] with length 3

goroutine 1 [running]:
main.main()
        C:/projects/Articles/Go Context/main.go:8 +0x3d
exit status 2
</code></pre>
<p>This behavior is called <strong>bounds checking</strong>: before Go reads or writes an array element, it ensures the index is within the valid range (<code>0</code> up to <code>len(array)-1</code>). If it’s not, the program immediately panics instead of letting you access memory that doesn’t belong to the array.</p>
<p>Bounds checking is important because it:</p>
<ul>
<li><p>Prevents memory corruption: in languages like C, out-of-bounds access can overwrite unrelated memory and cause hard-to-find bugs or security issues.</p>
</li>
<li><p>Makes programs safer by default: Go will stop execution right away rather than let invalid memory access continue silently.</p>
</li>
<li><p>Helps debugging: the panic message clearly shows the invalid index and the array’s length, so you can quickly track down the bug.</p>
</li>
<li><p>It trades a small runtime cost for much greater safety and reliability.</p>
</li>
</ul>
<p>Like every other data structure in Go, arrays are passed by value, meaning that when you pass an array to a function, a copy is made. This can lead to performance issues, so for large arrays, it's often better to pass a pointer to the array instead.</p>
<h3 id="heading-multi-dimensional-arrays">Multi-dimensional Arrays</h3>
<p>Multi-dimensional arrays let you model data that naturally fits into rows and columns (or higher dimensions). Some common uses include:</p>
<ul>
<li><p>Matrices and grids</p>
</li>
<li><p>Images and pixel data in 2D or 3D</p>
</li>
<li><p>Static lookup tables</p>
</li>
</ul>
<p>Go supports multi-dimensional arrays, which are essentially arrays of arrays. Here's an example:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    <span class="hljs-keyword">var</span> matrix [<span class="hljs-number">2</span>][<span class="hljs-number">3</span>]<span class="hljs-keyword">int</span> <span class="hljs-comment">// 2x3 matrix</span>
    matrix[<span class="hljs-number">0</span>][<span class="hljs-number">0</span>] = <span class="hljs-number">1</span>
    matrix[<span class="hljs-number">0</span>][<span class="hljs-number">1</span>] = <span class="hljs-number">2</span>
    matrix[<span class="hljs-number">0</span>][<span class="hljs-number">2</span>] = <span class="hljs-number">3</span>
    matrix[<span class="hljs-number">1</span>][<span class="hljs-number">0</span>] = <span class="hljs-number">4</span>
    matrix[<span class="hljs-number">1</span>][<span class="hljs-number">1</span>] = <span class="hljs-number">5</span>
    matrix[<span class="hljs-number">1</span>][<span class="hljs-number">2</span>] = <span class="hljs-number">6</span>
    fmt.Println(matrix)
}
</code></pre>
<p>In this example, we create a 2x3 matrix (2 rows and 3 columns) and initialize its elements. You can access elements using two indices: the first for the row and the second for the column. This can be extended to more dimensions too, but the size of each dimension must be known at compile time.</p>
<h3 id="heading-limitations">Limitations</h3>
<p>The greatest limitation of arrays in Golang is that their size must be known at compile time. Once it’s declared, the size can’t be changed. Because of this rigidity, arrays are rarely used directly.</p>
<h3 id="heading-when-arrays-are-useful">When Arrays Are Useful</h3>
<p>Despite their rigidity, arrays have a few niche but important use cases in Go:</p>
<ul>
<li><p>Fixed-size data like IP addresses</p>
</li>
<li><p>Low-level data structures</p>
</li>
<li><p>Interop with C or system calls</p>
</li>
</ul>
<h2 id="heading-slices-in-go">Slices in Go</h2>
<p>Because arrays are fixed-size, Go introduced <strong>slices</strong>: flexible, dynamic sequences built on top of arrays. Think of slices as views into arrays. A slice keeps three things:</p>
<ol>
<li><p><strong>Pointer</strong>: A reference to the underlying array.</p>
</li>
<li><p><strong>Length</strong>: The number of elements in the slice.</p>
</li>
<li><p><strong>Capacity</strong>: The maximum number of elements the slice can hold (which is always greater than or equal to the length).</p>
</li>
</ol>
<p>Unlike arrays, a slice's length and capacity can change dynamically as you add or remove elements.</p>
<h3 id="heading-when-to-use-slices">When to Use Slices</h3>
<p>In practice, slices are the default way to work with collections in Go. You’ll use them when:</p>
<ul>
<li><p>You don’t know the size of the collection in advance.</p>
</li>
<li><p>You need to grow or shrink the collection over time.</p>
</li>
<li><p>You want to pass around subsections of an array without copying data.</p>
</li>
<li><p>You want idiomatic Go code (most Go APIs accept and return slices, not arrays).</p>
</li>
</ul>
<p>Arrays are mainly useful when you need a fixed size known at compile time (like a 16-byte UUID). For almost everything else, slices are the go-to choice.</p>
<h3 id="heading-how-to-declare-a-slice">How to Declare a Slice</h3>
<pre><code class="lang-go"><span class="hljs-keyword">var</span> s []<span class="hljs-keyword">int</span>           <span class="hljs-comment">// slice of integers</span>
fmt.Println(s)        <span class="hljs-comment">// []</span>
fmt.Println(<span class="hljs-built_in">len</span>(s))   <span class="hljs-comment">// length: 0</span>
fmt.Println(<span class="hljs-built_in">cap</span>(s))   <span class="hljs-comment">// capacity: 0</span>
</code></pre>
<p>With <code>var s []int</code> you are <strong>declaring a slice</strong>. That means you’ve introduced a variable <code>s</code> of type “slice of int” (<code>[]int</code>), but you haven’t yet given it any backing array. At this point, <code>s</code> is <code>nil</code> – it doesn’t point to any actual storage. That’s why its length and capacity are both zero, until you allocate or append to it.</p>
<p>Note that you can also declare a slice using <code>var s[]int{}</code> which initializes the slice with zero elements, but you can’t create an empty array using this syntax: <code>var s[...]int{}</code>. The latter is invalid in Go: you can’t use <code>[...]</code> with <code>var</code> and an empty initialiser!</p>
<h3 id="heading-allocate-with-make">Allocate (with <code>make</code>)</h3>
<pre><code class="lang-go">s := <span class="hljs-built_in">make</span>([]<span class="hljs-keyword">int</span>, <span class="hljs-number">3</span>) <span class="hljs-comment">// length 3, capacity 3</span>
fmt.Println(s)      <span class="hljs-comment">// [0 0 0]</span>
</code></pre>
<p>Here, Go creates an underlying array of size 3 and makes <code>s</code> point to it. Now <code>s</code> has length 3 and capacity 3.</p>
<p>You can also specify a larger capacity:</p>
<pre><code class="lang-go">s := <span class="hljs-built_in">make</span>([]<span class="hljs-keyword">int</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>) <span class="hljs-comment">// length 3, capacity 5</span>
fmt.Println(s)         <span class="hljs-comment">// [0 0 0]</span>
fmt.Println(<span class="hljs-built_in">len</span>(s))    <span class="hljs-comment">// length: 3</span>
fmt.Println(<span class="hljs-built_in">cap</span>(s))    <span class="hljs-comment">// capacity: 5</span>
</code></pre>
<p>The built-in <code>make</code> function is Go’s way of allocating and initializing certain composite types: slices, maps, and channels. Unlike <code>new</code>, which gives you a pointer to a zeroed value, <code>make</code> sets up the internal data structures those types need to work.</p>
<p>For slices, <code>make</code> does three things under the hood:</p>
<ol>
<li><p>Allocates an array of the given size (either the length you specify, or the capacity if you provide both).</p>
</li>
<li><p>Creates a slice header (pointer, length, capacity) that points to that array.</p>
</li>
<li><p>Returns the slice header, ready to use.</p>
</li>
</ol>
<h3 id="heading-append-elements">Append Elements</h3>
<p>One of the main reasons slices are so useful compared to arrays is that they can grow dynamically. In practice, you’ll often start with a slice of a certain length and then need to add more elements later. Again, this is something arrays don’t allow.</p>
<p>Go provides the built-in <code>append</code> function for this. <code>append</code> takes an existing slice and one or more new elements, and returns a new slice with those elements added:</p>
<pre><code class="lang-go">s := <span class="hljs-built_in">make</span>([]<span class="hljs-keyword">int</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>)  <span class="hljs-comment">// create [0 0 0]</span>
s = <span class="hljs-built_in">append</span>(s, <span class="hljs-number">1</span>)
s = <span class="hljs-built_in">append</span>(s, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>)
fmt.Println(s)          <span class="hljs-comment">// [0 0 0 1 2 3]</span>
fmt.Println(<span class="hljs-built_in">len</span>(s))     <span class="hljs-comment">// length: 6</span>
fmt.Println(<span class="hljs-built_in">cap</span>(s))     <span class="hljs-comment">// capacity: 10 - may be different, depending on the Go version and implementation, but generally it will double when exceeded</span>
</code></pre>
<p>If there’s enough capacity, <code>append</code> just writes into the existing array. If not, Go automatically allocates a new larger array, copies the old elements over, and adds the new value. That’s why a slice can grow even though arrays themselves are fixed-size. On one hand, this provides flexibility, but it can also lead to performance overhead due to the need for memory allocation and copying.</p>
<p>To mitigate this, it's a good practice to preallocate slices with an appropriate capacity when you know the size in advance.</p>
<h3 id="heading-how-to-slice-slices">How to Slice Slices</h3>
<p>In Golang, you can create a new slice by slicing an existing one. You can do this using the <code>[:]</code> operator. The syntax is <code>slice[low:high]</code>, where <code>low</code> is the starting index (inclusive) and <code>high</code> is the ending index (exclusive). If <code>low</code> is omitted, it defaults to 0. If <code>high</code> is omitted, it defaults to the length of the slice:</p>
<pre><code class="lang-go">s := []<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>}
s1 := s[<span class="hljs-number">1</span>:<span class="hljs-number">4</span>] <span class="hljs-comment">// [2 3 4]</span>
s2 := s[:<span class="hljs-number">3</span>]  <span class="hljs-comment">// [1 2 3]</span>
s3 := s[<span class="hljs-number">2</span>:]  <span class="hljs-comment">// [3 4 5]</span>
fmt.Println(s1, s2, s3)
</code></pre>
<p>If two slices share the same underlying array, changes to the elements of one slice will be reflected in the other. This is because both slices point to the same data in memory. For example:</p>
<pre><code class="lang-go">s := []<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>}
s1 := s[<span class="hljs-number">1</span>:<span class="hljs-number">4</span>] <span class="hljs-comment">// [2 3 4]</span>
s2 := s[<span class="hljs-number">2</span>:]  <span class="hljs-comment">// [3 4 5]</span>
s1[<span class="hljs-number">0</span>] = <span class="hljs-number">10</span>
fmt.Println(s)  <span class="hljs-comment">// [1 10 3 4 5]</span>
fmt.Println(s2)  <span class="hljs-comment">// [10 3 4 5]</span>
</code></pre>
<h3 id="heading-inner-representation-of-slices">Inner Representation of Slices</h3>
<p>Internally, a slice is represented by a struct that contains a pointer to the underlying array, the length of the slice, and its capacity:</p>
<pre><code class="lang-go"><span class="hljs-keyword">type</span> slice <span class="hljs-keyword">struct</span> {
    ptr *ElementType  <span class="hljs-comment">// pointer to underlying array</span>
    <span class="hljs-built_in">len</span> <span class="hljs-keyword">int</span>
    <span class="hljs-built_in">cap</span> <span class="hljs-keyword">int</span>
}
</code></pre>
<p>This allows slices to be lightweight and efficient, as they don't require copying the entire array when being passed around, just the pointer to the array (and length and capacity). This is often a source of confusion: passing a slice to a function <em>feels</em> like passing by reference, as the values are not copied – but the slice struct itself is still passed by value:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">modify</span><span class="hljs-params">(s1 [3]<span class="hljs-keyword">int</span>, s2 []<span class="hljs-keyword">int</span>)</span></span> {
    s1[<span class="hljs-number">0</span>] = <span class="hljs-number">99</span>
    s2[<span class="hljs-number">0</span>] = <span class="hljs-number">99</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    nums_array := [...]<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>} <span class="hljs-comment">// array of 3 integers</span>
    nums_slice := []<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>}    <span class="hljs-comment">// slice of 3 integers</span>
    modify(nums_array, nums_slice)
    fmt.Println(nums_array)         <span class="hljs-comment">// Output: [1 2 3] - only modified the copy</span>
    fmt.Println(nums_slice)         <span class="hljs-comment">// Output: [99 2 3] - modified the value in the original slice</span>
}
</code></pre>
<h3 id="heading-how-to-copy-slices">How to Copy Slices</h3>
<p>Copying a slice creates a new slice with the same elements. You can do this using the built-in <code>copy</code> function:</p>
<pre><code class="lang-go">s1 := []<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>}
s2 := <span class="hljs-built_in">make</span>([]<span class="hljs-keyword">int</span>, <span class="hljs-built_in">len</span>(s1))
<span class="hljs-built_in">copy</span>(s2, s1)      <span class="hljs-comment">// copies elements from s1 to s2</span>
fmt.Println(s2)   <span class="hljs-comment">// [1 2 3]</span>
</code></pre>
<p>Common pitfalls when copying slices:</p>
<ul>
<li><p><strong>Capacity</strong>: When copying a slice, the capacity of the destination slice is not automatically adjusted. If the destination slice has a smaller capacity than the source slice, it will only copy up to the capacity of the destination slice.</p>
</li>
<li><p><strong>Nil Slices</strong>: If the source slice is nil, the <code>copy</code> function will not panic, but the destination slice will remain unchanged.</p>
</li>
<li><p><strong>Overlapping Slices</strong>: If the source and destination slices overlap, the behavior is undefined. To avoid this, make sure to copy to a separate slice.</p>
</li>
</ul>
<h3 id="heading-multi-dimensional-slices">Multi-dimensional Slices</h3>
<p>Just like multi-dimensional arrays, you can create multi-dimensional slices, which are essentially slices of slices:</p>
<pre><code class="lang-go">matrix := [][]<span class="hljs-keyword">int</span>{
    {<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>},
    {<span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>},
    {<span class="hljs-number">7</span>, <span class="hljs-number">8</span>, <span class="hljs-number">9</span>},
}
fmt.Println(matrix)
</code></pre>
<p>Or:</p>
<pre><code class="lang-go">rows := <span class="hljs-number">3</span>
cols := <span class="hljs-number">4</span>
matrix := <span class="hljs-built_in">make</span>([][]<span class="hljs-keyword">int</span>, rows)
<span class="hljs-keyword">for</span> i := <span class="hljs-keyword">range</span> matrix {
    matrix[i] = <span class="hljs-built_in">make</span>([]<span class="hljs-keyword">int</span>, cols)
}
</code></pre>
<p>Multi-dimensional slices are useful when you need flexible, dynamic grids of data. Common use cases include:</p>
<ul>
<li><p>Representing game boards (for example, Tic-Tac-Toe, Minesweeper). This could be done with an array, too.</p>
</li>
<li><p>Mathematical matrices where the size isn’t fixed.</p>
</li>
<li><p>Jagged arrays, where each row can have a different length.</p>
</li>
</ul>
<p>Because slices can grow and shrink, they’re generally preferred over multi-dimensional arrays unless you need a fixed size known at compile time.</p>
<h3 id="heading-slices-vs-arrays">Slices vs Arrays</h3>
<p>Let’s recap the key differences between slices and arrays in Go:</p>
<ol>
<li><p><strong>Size</strong>: Arrays have a fixed size, while slices can grow and shrink dynamically.</p>
</li>
<li><p><strong>Memory</strong>: Arrays are value types and are copied when passed to functions, while slices are reference types and only the slice header is copied.</p>
</li>
<li><p><strong>Flexibility</strong>: Slices provide more flexibility and are generally preferred over arrays for most use cases.</p>
</li>
</ol>
<h2 id="heading-maps-in-go">Maps in Go</h2>
<p>A <strong>map</strong> is Go's built-in associative data type (hash table). It stores key-value pairs with fast average-time lookups.</p>
<p>Unlike arrays and slices, which are indexed only by integers, maps let you use more meaningful keys such as names, IDs, or other comparable values. This makes them ideal when you need to look up, group, or count data quickly, for example, storing user ages by username, counting word frequencies in text, or mapping product IDs to their prices.</p>
<h3 id="heading-how-to-declare-a-map">How to Declare a Map</h3>
<pre><code class="lang-go">m := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">int</span>)  <span class="hljs-comment">// a map with string keys and int values</span>
m[<span class="hljs-string">"alice"</span>] = <span class="hljs-number">23</span>
m[<span class="hljs-string">"bob"</span>] = <span class="hljs-number">30</span>
fmt.Println(m)             <span class="hljs-comment">// map[alice:23 bob:30]</span>
</code></pre>
<p>Here, we create a map with string keys and int values. We can add key-value pairs to the map using the syntax <code>m[key] = value</code>. The <code>make</code> function is used to initialize the map. When we print the map, we see the key-value pairs in the output.</p>
<p>Keys can be of any type that is comparable (for example, strings, integers, structs). But they can’t be slices, maps, or functions.</p>
<p>A key in a map must be unique. If you assign a value to an existing key, it will overwrite the previous value.</p>
<h3 id="heading-how-to-access-values">How to Access Values</h3>
<p>Once you have a map, you can retrieve a value using its key with the syntax <code>map[key]</code>:</p>
<pre><code class="lang-go">age := m[<span class="hljs-string">"alice"</span>]
fmt.Println(age) <span class="hljs-comment">// 23</span>
</code></pre>
<p>If the key doesn't exist, you get the zero value:</p>
<pre><code class="lang-go">age := m[<span class="hljs-string">"charlie"</span>]
fmt.Println(age) <span class="hljs-comment">// 0</span>
</code></pre>
<p>Here’s what happens under the hood:</p>
<ol>
<li><p>Go computes the hash of the key (<code>"alice"</code>) to find which bucket in the hash table to look in. A <strong>bucket</strong> is a small container within the hash table that holds one or more key-value pairs. When multiple keys hash to the same bucket, they are stored together inside it.</p>
</li>
<li><p>It searches the bucket for the key.</p>
</li>
<li><p>If the key exists, Go returns the associated value (<code>23</code> in this case).</p>
</li>
<li><p>If the key doesn’t exist, Go returns the zero value of the map’s value type (<code>0</code> for <code>int</code>, <code>""</code> for <code>string</code>, <code>nil</code> for a pointer or slice, and so on).</p>
</li>
</ol>
<p>To distinguish between a <strong>key that doesn’t exist</strong> and a key whose value happens to be the zero value of the map’s value type, Go provides a second return value when you access a map. Normally, <code>m[key]</code> just returns the value. But if you write:</p>
<pre><code class="lang-go">value, ok := m[key]
</code></pre>
<ul>
<li><p><code>value</code> is the map value for that key (or the zero value if the key is missing).</p>
</li>
<li><p><code>ok</code> is a boolean that is <code>true</code> if the key exists in the map, and <code>false</code> if it does not.</p>
</li>
</ul>
<p>You need this because some types have a zero value that is valid in your application. For example, consider a map of usernames to ages:</p>
<pre><code class="lang-go">m := <span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">int</span>{
    <span class="hljs-string">"alice"</span>: <span class="hljs-number">23</span>,
    <span class="hljs-string">"bob"</span>:   <span class="hljs-number">0</span>,
}
</code></pre>
<p>If you try to access <code>"bob"</code> or <code>"charlie"</code> without the second return value:</p>
<pre><code class="lang-go">fmt.Println(m[<span class="hljs-string">"bob"</span>])     <span class="hljs-comment">// 0</span>
fmt.Println(m[<span class="hljs-string">"charlie"</span>]) <span class="hljs-comment">// 0</span>
</code></pre>
<p>Both print <code>0</code>, so you can’t tell whether <code>"charlie"</code> is missing or <code>"bob"</code> actually has age <code>0</code>. Using the second return value solves this:</p>
<pre><code class="lang-go">age, ok := m[<span class="hljs-string">"charlie"</span>]
<span class="hljs-keyword">if</span> !ok {
    fmt.Println(<span class="hljs-string">"Key not found"</span>)
}
</code></pre>
<p>Here, <code>ok</code> is <code>false</code> for <code>"charlie"</code> but would be <code>true</code> for <code>"bob"</code>. This is a common pattern in Go to safely handle map lookups.</p>
<h3 id="heading-how-to-iterate-over-a-map">How to Iterate Over a Map</h3>
<p>Iterating over a map means going through all key-value pairs in the map, one at a time. You do this with a <code>for</code> loop and the <code>range</code> keyword:</p>
<pre><code class="lang-go"><span class="hljs-keyword">for</span> key, value := <span class="hljs-keyword">range</span> m {
    fmt.Printf(<span class="hljs-string">"%s: %d\n"</span>, key, value)
}
</code></pre>
<p>What’s happening here:</p>
<ul>
<li><p><code>range m</code> produces each key in the map, one by one.</p>
</li>
<li><p>The loop assigns the current key to <code>key</code> and the corresponding value to <code>value</code>.</p>
</li>
<li><p>Inside the loop, you can use <code>key</code> and <code>value</code> to process, print, or modify data.</p>
</li>
</ul>
<p>Iterating over a map is useful whenever you need to:</p>
<ul>
<li><p>Process all entries in the map (for example, compute a total, filter items, or apply a transformation).</p>
</li>
<li><p>Print or display data in key-value format (like logging user ages or product prices).</p>
</li>
<li><p>Perform aggregate operations, such as counting, summing, or finding the maximum/minimum value.</p>
</li>
</ul>
<p><strong>Important note:</strong> Map iteration order in Go is randomized: each loop may produce keys in a different order. This prevents you from relying on insertion order. If you need a deterministic order, you can collect the keys into a slice, sort them, and iterate over the sorted keys.</p>
<h3 id="heading-inner-representation-of-maps">Inner Representation of Maps</h3>
<p>Go maps are implemented as hash tables with buckets:</p>
<ul>
<li><p>Keys are hashed to decide which bucket they go into.</p>
</li>
<li><p>Each bucket holds multiple key-value pairs.</p>
</li>
<li><p>When a bucket gets too full, Go splits it into two (similar to dynamic resizing).</p>
</li>
<li><p>That's why map operations are usually O(1), but not guaranteed constant time.</p>
</li>
</ul>
<p>Just keep in mind that maps are not safe for concurrent writes. If multiple goroutines write to a map at the same time, you’ll get a runtime panic. Use <code>sync.Mutex</code> or <code>sync.RWMutex</code> to protect map access in concurrent scenarios.</p>
<p>If you're interested in how different hash map implementations work under the hood, check out my <a target="_blank" href="https://blog.gaborkoos.com/posts/2025-08-03-Hash-Map-Deep-Dive/">article on hash maps</a>.</p>
<h3 id="heading-arrays-vs-slices-vs-maps">Arrays vs. Slices vs. Maps</h3>
<p>Here’s a quick comparison of the feature set of collection types in Go:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Feature</td><td>Arrays</td><td>Slices</td><td>Maps</td></tr>
</thead>
<tbody>
<tr>
<td>Size</td><td>Fixed</td><td>Dynamic</td><td>Dynamic</td></tr>
<tr>
<td>Type</td><td>Value type</td><td>Reference type</td><td>Reference type</td></tr>
<tr>
<td>Zero value</td><td>Array of zero values</td><td>Nil slice</td><td>Nil map</td></tr>
<tr>
<td>Length</td><td>Known at compile time</td><td>Known at runtime</td><td>N/A</td></tr>
<tr>
<td>Indexing</td><td>By integer</td><td>By integer</td><td>By key</td></tr>
<tr>
<td>Internal rep</td><td>Contiguous memory block</td><td>Header (ptr, len, cap) + array</td><td>Hash table with buckets</td></tr>
<tr>
<td>Use cases</td><td>Low-level, fixed-size data</td><td>Most lists, sequences</td><td>Lookups, dictionaries</td></tr>
</tbody>
</table>
</div><h2 id="heading-mini-project-shopping-cart-totals">Mini Project: Shopping Cart Totals</h2>
<p>Let's combine slices and maps into a practical program: given a list of items and their prices, compute the total cost of all items.</p>
<p>The list of items is represented as a slice of strings, and the prices are stored in a map. The key is the item name, and the value is the price:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    items := []<span class="hljs-keyword">string</span>{<span class="hljs-string">"apple"</span>, <span class="hljs-string">"banana"</span>, <span class="hljs-string">"orange"</span>}
    prices := <span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>]<span class="hljs-keyword">float64</span>{
        <span class="hljs-string">"apple"</span>:  <span class="hljs-number">0.99</span>,
        <span class="hljs-string">"banana"</span>: <span class="hljs-number">0.59</span>,
        <span class="hljs-string">"orange"</span>: <span class="hljs-number">0.79</span>,
    }

    <span class="hljs-keyword">var</span> total <span class="hljs-keyword">float64</span>
    <span class="hljs-keyword">for</span> _, item := <span class="hljs-keyword">range</span> items {
        total += prices[item]
    }
    fmt.Printf(<span class="hljs-string">"Total cost: $%.2f\n"</span>, total)
}
</code></pre>
<pre><code class="lang-plaintext">Total cost: $2.37
</code></pre>
<p>This short example shows the synergy between slices (to hold the item names) and maps (to look up prices).</p>
<h2 id="heading-practice-challenge">Practice Challenge</h2>
<p>Write a function that takes a slice of integers and returns a new slice with duplicates removed. (Solution below.)</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Go keeps things simple: with arrays, slices, and maps, you can model almost all everyday data problems.</p>
<ul>
<li><p><strong>Arrays</strong>: fixed size, contiguous memory, rarely used directly.</p>
</li>
<li><p><strong>Slices</strong>: flexible, built on top of arrays, your go-to for ordered collections.</p>
</li>
<li><p><strong>Maps</strong>: hash tables for key–value lookups.</p>
</li>
</ul>
<p>You now have the tools to confidently handle collections in Go. The next step? Try writing a small project where you read data from a file, store it in slices, and process it into maps for quick lookups. That's how Go developers handle real-world data.</p>
<h3 id="heading-practice-challenge-solution">Practice Challenge Solution</h3>
<p>To remove duplicates from a slice, we can keep track of the values we’ve seen in a map and build a new slice containing only the first occurrence of each element:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> <span class="hljs-string">"fmt"</span>

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">removeDuplicates</span><span class="hljs-params">(intSlice []<span class="hljs-keyword">int</span>)</span> []<span class="hljs-title">int</span></span> {
    seen := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">map</span>[<span class="hljs-keyword">int</span>]<span class="hljs-keyword">bool</span>) <span class="hljs-comment">// to track seen integers</span>
    result := []<span class="hljs-keyword">int</span>{}
    <span class="hljs-keyword">for</span> _, v := <span class="hljs-keyword">range</span> intSlice {
        <span class="hljs-keyword">if</span> !seen[v] { <span class="hljs-comment">// if we haven't seen this integer yet, set it to seen and add it to the result</span>
            seen[v] = <span class="hljs-literal">true</span>
            result = <span class="hljs-built_in">append</span>(result, v)
        }
    }
    <span class="hljs-keyword">return</span> result
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    s := []<span class="hljs-keyword">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>}
    s = removeDuplicates(s)
    fmt.Println(s) <span class="hljs-comment">// [1 2 3 4 5]</span>
}
</code></pre>
<p>How it works:</p>
<ul>
<li><p><code>seen</code> keeps track of numbers that have already been added.</p>
</li>
<li><p><code>result</code> collects unique numbers as we iterate.</p>
</li>
<li><p>For each element in the input slice, if it hasn’t been seen, we mark it and append it to <code>result</code>.</p>
</li>
<li><p>Finally, <code>result</code> contains only unique values.</p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Data Structure and Algorithm Patterns for LeetCode Interviews ]]>
                </title>
                <description>
                    <![CDATA[ To get the best tech jobs, it can be helpful to understand how to apply data structures and algorithms to coding challenges. We just published a comprehensive course on the freeCodeCamp.org channel about data structures and algorithms. This course wi... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/data-structure-and-algorithm-patterns-for-leetcode-interviews/</link>
                <guid isPermaLink="false">687fa4c693f63bc290c6ada1</guid>
                
                    <category>
                        <![CDATA[ data structures ]]>
                    </category>
                
                    <category>
                        <![CDATA[ algorithms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Tue, 22 Jul 2025 14:48:38 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1753195703148/03e55da6-8391-4f8a-9493-036abd0518d9.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>To get the best tech jobs, it can be helpful to understand how to apply data structures and algorithms to coding challenges.</p>
<p>We just published a comprehensive course on the freeCodeCamp.org channel about data structures and algorithms. This course will help you prepare for coding interviews and strengthen your foundational programming skills. Sheldon Chi developed this course.</p>
<p>Sheldon will break down the most essential data structures and algorithmic patterns. This course will help you build your intuition for efficiency and help you recognize which patterns to apply and how to avoid brute force solutions. And each concept is taught step by step, with practical code walkthroughs and tips for common pitfalls.</p>
<p>Here is the full list of sections in this course:</p>
<ul>
<li><p>Array</p>
</li>
<li><p>String</p>
</li>
<li><p>Set</p>
</li>
<li><p>Control Flow &amp; Looping</p>
</li>
<li><p>Big O Notation</p>
</li>
<li><p>Hashmap</p>
</li>
<li><p>Hashmap practice problems</p>
</li>
<li><p>Two Pointers</p>
</li>
<li><p>Two Pointers practice problems</p>
</li>
<li><p>Sliding Window</p>
</li>
<li><p>Sliding Window practice problems</p>
</li>
<li><p>Binary Search</p>
</li>
<li><p>Binary Search practice problems</p>
</li>
<li><p>Breadth-First Search (BFS) on Trees</p>
</li>
<li><p>BFS on Graphs</p>
</li>
<li><p>BFS practice problems</p>
</li>
<li><p>Depth-First Search (DFS)</p>
</li>
<li><p>DFS on Graphs</p>
</li>
<li><p>DFS practice problems</p>
</li>
<li><p>Backtracking</p>
</li>
<li><p>Backtracking practice problems</p>
</li>
<li><p>Priority Queue/heap</p>
</li>
<li><p>Priority Queue/heap practice problems</p>
</li>
</ul>
<p>Watch the full course <a target="_blank" href="https://youtu.be/Z_c4byLrNBU">on the freeCodeCamp.org YouTube channel</a> (1-hour course).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/Z_c4byLrNBU" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Word Search Game Using HTML, CSS, and JavaScript ]]>
                </title>
                <description>
                    <![CDATA[ The Wordle phenomenon from a few years back inspired developers worldwide to create their own word games. It inspired me to conceive and build a game, too. ‘Word Zearch’ combines elements of Boggle and word search puzzles into a web-based game where ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-word-search-game-using-html-css-and-javascript/</link>
                <guid isPermaLink="false">687543a2e9820caf95eae4f3</guid>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ data structures ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Mark Mahoney ]]>
                </dc:creator>
                <pubDate>Mon, 14 Jul 2025 17:51:30 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1752511862075/76f0131a-336f-4670-a571-ad023e3906bb.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The <a target="_blank" href="https://www.nytimes.com/games/wordle/index.html">Wordle</a> phenomenon from a few years back inspired developers worldwide to create their own word games. It inspired me to conceive and build a game, too. ‘<a target="_blank" href="https://markm208.github.io/wordZearch/">Word Zearch</a>’ combines elements of <a target="_blank" href="https://en.wikipedia.org/wiki/Boggle">Boggle</a> and word search puzzles into a web-based game where players find words on a board.</p>
<p>This tutorial will teach you how to build a complete game from scratch. You'll implement advanced data structures (Trie), optimize search algorithms (recursion), and create a polished user interface (HTML/CSS). By the end, you will build a fully playable game and learn techniques that you can apply to any web project.</p>
<p>This tutorial covers:</p>
<ul>
<li><p>Implementing a Trie data structure for lightning-fast word search including partial word validation</p>
</li>
<li><p>Using recursion to efficiently explore millions of possible paths through a game board</p>
</li>
<li><p>Analyzing 20,000+ dictionary words to create balanced gameplay</p>
</li>
<li><p>Creating a build system that pre-processes data for better performance</p>
</li>
<li><p>Building a responsive UI that handles complex user interactions</p>
</li>
</ul>
<h2 id="heading-the-inspiration"><strong>The Inspiration</strong></h2>
<p>When playing Boggle with my family, I have designated myself as the 'checker' of other peoples' words when we are tabulating scores. All of the other players will list the words that they found while I point them out on the board to make sure that they are valid. Once you know that a word is on the board, finding it feels a whole lot easier than searching for it blindly.</p>
<p>I enjoy this process almost as much as playing the game. So, I built a game that focuses on that experience.</p>
<p>The rules are simple. The game presents 49 random letter groupings in a 7x7 grid. Starting with the longest words that can be found, players are presented with words and are asked to find them. Players click on adjacent letter groupings (horizontally, vertically, or diagonally) to form words. Each letter group can be used once per game. The challenge is to find as many valid words as possible in the shortest amount of time.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1752511838114/d205d825-ff26-4f6b-b375-aeb7215b922e.png" alt="Image of the game" class="image--center mx-auto" width="1728" height="1764" loading="lazy"></p>
<p><strong>You can play the finished game here:</strong> <a target="_blank" href="https://markm208.github.io/wordZearch/"><strong>https://markm208.github.io/wordZearch/</strong></a><strong>.</strong></p>
<h2 id="heading-an-interactive-tutorial-on-building-word-zearch"><strong>An Interactive Tutorial on Building Word Zearch</strong></h2>
<p>To share how I built Word Zearch, I created "<a target="_blank" href="https://playbackpress.com/books/wordzearchbook">How I Built It: Word Zearch</a>". It is a collection of annotated code playbacks that walk through the entire development process. These playbacks show every line of code I wrote, from implementing the core data structures to polishing the user interface.</p>
<p>To view a code playback, click on the comments in the left panel. Each comment updates the code in the editor and highlights the change. Read the explanation, study the code, and use the built-in AI assistant if you have questions. For more information about code playbacks, you can watch a short demo here.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/uYbHqCNjVDM" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<p>You should have some programming experience to follow along. I use object-oriented programming, recursion, and DOM manipulation throughout the tutorial.</p>
<p>If you're new to web development, this offers a complete start-to-finish project that will help put all of the pieces together. If this tutorial moves too fast for you, consider starting with my introductory web development 'book' first: <a target="_blank" href="https://playbackpress.com/books/webdevbook">An Introduction to Web Development from Back to Front</a></p>
<h2 id="heading-what-youll-learn"><strong>What You'll Learn</strong></h2>
<h3 id="heading-1-building-a-trie-data-structure"><strong>1. Building a Trie Data Structure</strong></h3>
<p><a target="_blank" href="https://playbackpress.com/books/wordzearchbook/chapter/1/1">https://playbackpress.com/books/wordzearchbook/chapter/1/1</a></p>
<p>Learn how to implement a <a target="_blank" href="https://www.freecodecamp.org/news/how-to-validate-user-input-with-automated-trie-visualization/">Trie (prefix tree)</a> for fast word validation. This data structure is the foundation of the game's performance.</p>
<p>Starting with a dictionary file, I parse 20,000+ words into a nested object structure. Each level represents a letter position. The implementation includes a search method that returns three values: <code>FOUND</code>, <code>NOT FOUND</code>, or <code>PARTIAL</code>.</p>
<p>This <code>PARTIAL</code> value is crucial. It indicates when the beginning of a dictionary word is found but it is not a complete word. Later on when searching for words on the board, it tells the algorithm when to stop searching, preventing millions of unnecessary operations during gameplay.</p>
<h3 id="heading-2-modeling-letter-frequencies"><strong>2. Modeling Letter Frequencies</strong></h3>
<p><a target="_blank" href="https://playbackpress.com/books/wordzearchbook/chapter/1/2">https://playbackpress.com/books/wordzearchbook/chapter/1/2</a></p>
<p>Here, I analyze letter frequencies from the words in the dictionary to create weighted distributions for generating game boards randomly. I start by tracking how often single letters, two-letter combinations, and three-letter combinations appear across all dictionary words. This approach will work for words in any language as long as you have a dictionary file filled with words.</p>
<p>For each word, I extract all possible letter groupings of each size and count their occurrences. After processing the entire dictionary, I sort these groupings by frequency and select the most common ones. To ensure interesting game boards, I create proportional arrays where more frequent letter groups appear multiple times relative to their frequency. I'll use this data to create a balanced game board that reflects real language usage by picking the most used groups of letters at random.</p>
<h3 id="heading-3-a-simple-web-app"><strong>3. A Simple Web App</strong></h3>
<p><a target="_blank" href="https://playbackpress.com/books/wordzearchbook/chapter/1/3">https://playbackpress.com/books/wordzearchbook/chapter/1/3</a></p>
<p>In this playback, I set up the foundation for the web application and create an efficient build process. Rather than rebuilding the <code>Trie</code> and calculating letter frequencies every time someone plays the game, I develop a build system that pre-generates these data structures.</p>
<p>Then I reorganize the project by creating a build folder and a template file. The <code>BuildTrie</code> class will read the dictionary, construct the word map and letter frequencies, and inject this data into a template file to generate a static <code>Trie.js</code> file. This approach significantly improves performance since the computationally expensive dictionary processing happens once during the build phase rather than on every page load.</p>
<h3 id="heading-4-building-the-game-board"><strong>4. Building the Game Board</strong></h3>
<p><a target="_blank" href="https://playbackpress.com/books/wordzearchbook/chapter/1/4">https://playbackpress.com/books/wordzearchbook/chapter/1/4</a></p>
<p>Next, I implement the <code>WordBoard</code> class, which manages the 7x7 game board and contains the core algorithm for finding valid words. The board is configured to hold 49 letter groups with customizable distributions of single, double, and triple letter combinations.</p>
<p>The heart of the implementation is a recursive search algorithm in the <code>solve</code> method that explores all possible word paths. Starting from each position on the board, the algorithm moves in eight directions (horizontally, vertically, and diagonally), building up potential words by concatenating adjacent letter groups. To prevent infinite loops and ensure game rules are followed, I track visited positions so each letter group can only be used once per word.</p>
<p>The <code>Trie</code> integration provides a crucial optimization. When a letter sequence isn't found in the <code>Trie</code>, the algorithm stops exploring that path, preventing unnecessary searching. Found words are organized by length in a results array, with each result storing the complete path through the board. The playback concludes with testing the <code>WordBoard</code>, demonstrating how it successfully identifies all valid words that can be formed from the randomly generated letter groups.</p>
<h3 id="heading-5-the-front-end"><strong>5. The Front End</strong></h3>
<p><a target="_blank" href="https://playbackpress.com/books/wordzearchbook/chapter/1/5">https://playbackpress.com/books/wordzearchbook/chapter/1/5</a></p>
<p>In this final playback, I build the complete user interface for Word Zearch. I start by creating a 7x7 HTML table where each cell displays a letter group from the <code>WordBoard</code>.</p>
<p>I implement click handling that allows players to select adjacent letter groups, visually highlighting them as they build words. The core gameplay logic compares the player's selected path against the pre-calculated valid word paths from the <code>WordBoard</code>'s <code>solve</code> method.</p>
<p>When a match is found, I add visual feedback including directional arrows showing the word's path, color coding for completed words, and preventing reuse of letter groups by marking them as solved. Found words are displayed in a results list with timestamps and links to their definitions. The interface also includes hover effects to highlight previously found words on the board and handles game completion by showing total time and offering a replay option.</p>
<p>The result is a fully interactive word search game with intuitive visual feedback and smooth gameplay.</p>
<h2 id="heading-start-building"><strong>Start Building</strong></h2>
<p>Word games make excellent programming projects. They combine interesting computer science concepts with practical web development skills.</p>
<p><a target="_blank" href="https://markm208.github.io/wordZearch/">Try playing the game first to understand what I'm building</a>. Then dive into the code playbacks to see how it all comes together. If you get stuck, use the AI assistant like a tutor to help explain what is happening in the code. Afterwards, if you are feeling adventurous, try modifying the code, optimizing it, adding new features, or building your own word game!</p>
<p>Questions and feedback are always welcome here: <a target="_blank" href="mailto:mark@playbackpress.com">mark@playbackpress.com</a></p>
<p>If you'd like to support my work and help keep Playback Press free for all, consider donating using <a target="_blank" href="https://github.com/sponsors/markm208">GitHub Sponsors</a>. I use all of the donations for hosting costs. Your support helps me continue creating educational content like this. Thank you!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Work with Queues in TypeScript ]]>
                </title>
                <description>
                    <![CDATA[ A queue is a collection of items arranged in a First-In-First-Out (FIFO) order. This means that the first item added is the first to be removed, much like a supermarket line where customers are served in the order they arrive. In this hands-on tutor... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-work-with-queues-in-typescript/</link>
                <guid isPermaLink="false">6850919d88713cbf971283b0</guid>
                
                    <category>
                        <![CDATA[ TypeScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ algorithms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ data structures ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Yazdun ]]>
                </dc:creator>
                <pubDate>Mon, 16 Jun 2025 21:50:21 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1750082265731/de8b778c-935d-4a38-a5ef-748896475327.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>A queue is a collection of items arranged in a First-In-First-Out (FIFO) order. This means that the first item added is the first to be removed, much like a supermarket line where customers are served in the order they arrive.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749741091206/42a62a3c-cf1b-4e7a-b8ce-4209e13f70d3.png" alt="Diagram illustrating a queue. Items are added to the back through &quot;enqueue&quot; and removed from the front through &quot;dequeue.&quot; Arrows show the flow into and out of a rectangular box representing the queue." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>In this hands-on tutorial, you will learn how to implement queues in TypeScript using linked lists.</p>
<h2 id="heading-heres-what-well-cover">Here’s what we’ll cover</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-getting-started">Getting started</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-are-queues">What are Queues?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-are-linked-lists">What are Linked Lists?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-a-simple-queue">What is a Simple Queue?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-a-circular-queue">What is a Circular Queue?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-a-double-ended-queue">What is a Double Ended Queue?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-a-priority-queue">What is a Priority Queue?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-when-to-use-queues-and-when-to-avoid-them">When to Use Queues (and When to Avoid Them)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ol>
<li><p><strong>TypeScript:</strong> You need to know <a target="_blank" href="https://www.freecodecamp.org/news/learn-typescript-with-react-handbook/">TypeScript basics</a>, such as interfaces, types, and classes.</p>
</li>
<li><p><strong>Algorithm fundamentals:</strong> You need a basic understanding of data structures and algorithms. For example, you should be comfortable analyzing time and space complexity using <a target="_blank" href="https://www.freecodecamp.org/news/big-o-cheat-sheet-time-complexity-chart/">Big-O notation.</a></p>
</li>
<li><p><strong>Linked Lists Data Structure:</strong> It's important to have a solid understanding of linked lists before starting this tutorial. I wrote a detailed <a target="_blank" href="https://www.freecodecamp.org/news/how-to-code-linked-lists-with-typescript-handbook">linked list tutorial</a> that you can use to learn about this data structure.</p>
</li>
</ol>
<h2 id="heading-getting-started">Getting Started</h2>
<p>To get started with this tutorial, you’ll use a playground project that’s designed to help you implement queues and follow each step hands-on.</p>
<p>Clone the project from the <a target="_blank" href="https://github.com/Yazdun/fcc-queues">GitHub repository and code along</a> with the tutorial.</p>
<p>The project structure is as follows:</p>
<pre><code class="lang-plaintext">.
├── index.ts
├── examples
│   ├── 01-linked-list.ts
│   ├── 02-simple-queue.ts
│   ├── 03-circular-queue.ts
│   ├── 04-double-ended-queue.ts
│   └── 05-priority-queue.ts
└── playground
    ├── 01-linked-list.ts
    ├── 02-simple-queue.ts
    ├── 03-circular-queue.ts
    ├── 04-double-ended-queue.ts
    └── 05-priority-queue.ts
</code></pre>
<p>Throughout the tutorial, you will use the <code>playground</code> directory to implement and test your code.</p>
<p>The <code>examples</code> directory contains the final version of each implementation. If you get stuck, you can look at these solutions as a last resort!</p>
<h2 id="heading-what-are-queues">What Are Queues?</h2>
<p>A queue is a data structure that manages items in a first-in, first-out (FIFO) order, where the first item added is the first removed.</p>
<p>For example, imagine a printer handling jobs. If you send three documents to print, the printer processes them in the order they arrive. The first document prints first, then the second, and finally the third.</p>
<p>In programming, queues help manage tasks that need to happen in order, such as:</p>
<ul>
<li><p>A web server queues incoming requests to process them one by one.</p>
</li>
<li><p>A chat app queues messages to send them in the order they’re typed.</p>
</li>
<li><p>A navigation app queues locations to explore a map level by level. (Breadth-First Search)</p>
</li>
</ul>
<p>There are four types of queues in a data structure:</p>
<ul>
<li><p><strong>Simple Queue</strong>: Adds items to the back and removes them from the front in first-in, first-out (FIFO) order.</p>
</li>
<li><p><strong>Circular Queue</strong>: It is similar to a simple queue, except the last element is connected to the first.</p>
</li>
<li><p><strong>Double-Ended Queue (Deque)</strong>: Allows adding or removing items from both front and back, like a bus stop line where people join or leave either end.</p>
</li>
<li><p><strong>Priority Queue</strong>: Processes items based on priority, not arrival order. Like a delivery app processes VIP orders before regular ones.</p>
</li>
</ul>
<p>Each of these queues has a set of operations for managing their items. In this tutorial, you will learn about the following common and widely used operations:</p>
<ul>
<li><p><strong>enqueue</strong>: Adds an item to the back of the queue, like a new customer joining the end of a ticket line.</p>
</li>
<li><p><strong>dequeue</strong>: Removes and returns the item at the front of the queue.</p>
</li>
<li><p><strong>getFront</strong>: Looks at the item at the front without removing it, like checking who’s first in line.</p>
</li>
<li><p><strong>getRear</strong>: Looks at the item at the back without removing it, like seeing who’s last in line.</p>
</li>
<li><p><strong>isEmpty</strong>: Checks if the queue has no items.</p>
</li>
<li><p><strong>isFull</strong>: Checks if the queue has reached its maximum size.</p>
</li>
<li><p><strong>peek</strong>: Same as <code>getFront</code>, views the front item without removing it, like a quick glance at the first task.</p>
</li>
<li><p><strong>size</strong>: Returns the number of items in the queue, like counting how many people are in line.</p>
</li>
</ul>
<p>Now that you know about queues and their main operations, let's get into the actual implementation and see how it looks in code.</p>
<p>There are a few different ways to implement queues, but in this tutorial, you will learn about <strong>linked list-based queues</strong>, which use a linked list to create the queues.</p>
<p>First, let's briefly learn about the linked list data structure and then move on to the queue implementation.</p>
<h2 id="heading-what-are-linked-lists">What Are Linked Lists?</h2>
<p>A linked list is a method of storing a collection of items where each item, known as a "node," contains two parts: the actual data and a reference (or pointer) to the next item in the list.</p>
<p>Unlike arrays, where all items are stored next to each other in memory, linked lists connect nodes using these references, like a chain.</p>
<p>Linked lists are used to implement queues because they allow efficient <strong>insertion at the end</strong> and <strong>removal from the front</strong>, which are the two main operations of a queue.</p>
<p>In a linked list-based queue, you can add a new node at the tail and remove one from the head in constant time (<code>O(1)</code>) without needing to shift elements, as you would in an array.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749741385495/1bfab581-481d-4108-9f48-bf93d9dcf4f1.png" alt="Diagram of a linked list with four nodes connected sequentially. Node 1 is labeled as the head and Node 4 as the tail." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>In this tutorial, you are going to use a specific type of linked list called <strong>Circular Doubly Linked List</strong>.</p>
<p>A circular doubly linked list is a type of linked list where each node connects to both the next and previous nodes, and the last node loops back to the first one to form a circle.</p>
<p>This means you can move through the list in both directions and never hit a dead end. This makes it easy to go forward or backward through nodes and helps avoid special cases like handling <code>null</code> at the ends.</p>
<p>In a circular doubly linked list, everything is connected in a loop, which simplifies certain queue operations and keeps things efficient.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749741872784/d01a9c89-945e-4b4a-acff-56b7e528ea7e.png" alt="Diagram showing a circular doubly linked list with five nodes labeled from Node 1 (head) to Node 5 (tail), connected in a loop." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>You can learn more about circular linked lists in my <a target="_blank" href="https://www.freecodecamp.org/news/how-to-code-linked-lists-with-typescript-handbook/#heading-what-is-a-circular-linked-list">Linked Lists Handbook</a>.</p>
<p>For this tutorial, I’ve already added a circular doubly linked list in <code>src/playground/01-linked-list.ts</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// 📁 src/playground/01-linked-list.ts</span>

<span class="hljs-comment">/**
 * Node for doubly linked list
 */</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> NodeItem&lt;T&gt; {
  value: T;
  next: NodeItem&lt;T&gt; | <span class="hljs-literal">null</span> = <span class="hljs-literal">null</span>;
  prev: NodeItem&lt;T&gt; | <span class="hljs-literal">null</span> = <span class="hljs-literal">null</span>;

  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">value: T</span>) {
    <span class="hljs-built_in">this</span>.value = value;
  }
}

<span class="hljs-comment">/**
 * Circular Doubly Linked List
 */</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> LinkedList&lt;T&gt; {
  <span class="hljs-keyword">private</span> head: NodeItem&lt;T&gt; | <span class="hljs-literal">null</span> = <span class="hljs-literal">null</span>;
  <span class="hljs-keyword">private</span> tail: NodeItem&lt;T&gt; | <span class="hljs-literal">null</span> = <span class="hljs-literal">null</span>;
  <span class="hljs-keyword">private</span> currentSize: <span class="hljs-built_in">number</span> = <span class="hljs-number">0</span>;

  <span class="hljs-comment">/**
   * Add a new node to the front of the list
   * @param value The value to add
   */</span>
  prepend(value: T): <span class="hljs-built_in">void</span> {
    <span class="hljs-keyword">const</span> newNode = <span class="hljs-keyword">new</span> NodeItem(value);
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.isEmpty()) {
      <span class="hljs-built_in">this</span>.head = newNode;
      <span class="hljs-built_in">this</span>.tail = newNode;
      newNode.next = newNode;
      newNode.prev = newNode;
    } <span class="hljs-keyword">else</span> {
      newNode.next = <span class="hljs-built_in">this</span>.head;
      newNode.prev = <span class="hljs-built_in">this</span>.tail;
      <span class="hljs-built_in">this</span>.head!.prev = newNode;
      <span class="hljs-built_in">this</span>.tail!.next = newNode;
      <span class="hljs-built_in">this</span>.head = newNode;
    }
    <span class="hljs-built_in">this</span>.currentSize++;
  }

  <span class="hljs-comment">/**
   * Add a new node to the back of the list
   * @param value The value to add
   */</span>
  append(value: T): <span class="hljs-built_in">void</span> {
    <span class="hljs-keyword">const</span> newNode = <span class="hljs-keyword">new</span> NodeItem(value);
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.isEmpty()) {
      <span class="hljs-built_in">this</span>.head = newNode;
      <span class="hljs-built_in">this</span>.tail = newNode;
      newNode.next = newNode;
      newNode.prev = newNode;
    } <span class="hljs-keyword">else</span> {
      newNode.next = <span class="hljs-built_in">this</span>.head;
      newNode.prev = <span class="hljs-built_in">this</span>.tail;
      <span class="hljs-built_in">this</span>.tail!.next = newNode;
      <span class="hljs-built_in">this</span>.head!.prev = newNode;
      <span class="hljs-built_in">this</span>.tail = newNode;
    }
    <span class="hljs-built_in">this</span>.currentSize++;
  }

  <span class="hljs-comment">/**
   * Remove and return the value from the front of the list
   * @returns The value at the head or undefined if empty
   */</span>
  deleteHead(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.isEmpty()) {
      <span class="hljs-keyword">return</span> <span class="hljs-literal">undefined</span>;
    }
    <span class="hljs-keyword">const</span> value = <span class="hljs-built_in">this</span>.head!.value;
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.currentSize === <span class="hljs-number">1</span>) {
      <span class="hljs-built_in">this</span>.head = <span class="hljs-literal">null</span>;
      <span class="hljs-built_in">this</span>.tail = <span class="hljs-literal">null</span>;
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">this</span>.head = <span class="hljs-built_in">this</span>.head!.next;
      <span class="hljs-built_in">this</span>.head!.prev = <span class="hljs-built_in">this</span>.tail;
      <span class="hljs-built_in">this</span>.tail!.next = <span class="hljs-built_in">this</span>.head;
    }
    <span class="hljs-built_in">this</span>.currentSize--;
    <span class="hljs-keyword">return</span> value;
  }

  <span class="hljs-comment">/**
   * Remove and return the value from the back of the list
   * @returns The value at the tail or undefined if empty
   */</span>
  deleteTail(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.isEmpty()) {
      <span class="hljs-keyword">return</span> <span class="hljs-literal">undefined</span>;
    }
    <span class="hljs-keyword">const</span> value = <span class="hljs-built_in">this</span>.tail!.value;
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.currentSize === <span class="hljs-number">1</span>) {
      <span class="hljs-built_in">this</span>.head = <span class="hljs-literal">null</span>;
      <span class="hljs-built_in">this</span>.tail = <span class="hljs-literal">null</span>;
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">this</span>.tail = <span class="hljs-built_in">this</span>.tail!.prev;
      <span class="hljs-built_in">this</span>.tail!.next = <span class="hljs-built_in">this</span>.head;
      <span class="hljs-built_in">this</span>.head!.prev = <span class="hljs-built_in">this</span>.tail;
    }
    <span class="hljs-built_in">this</span>.currentSize--;
    <span class="hljs-keyword">return</span> value;
  }

  <span class="hljs-comment">/**
   * Get the value at the front without removing it
   * @returns The value at the head or undefined if empty
   */</span>
  getHead(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.head?.value;
  }

  <span class="hljs-comment">/**
   * Get the value at the back without removing it
   * @returns The value at the tail or undefined if empty
   */</span>
  getTail(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.tail?.value;
  }

  <span class="hljs-comment">/**
   * Check if the list is empty
   * @returns True if the list is empty, false otherwise
   */</span>
  isEmpty(): <span class="hljs-built_in">boolean</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.currentSize === <span class="hljs-number">0</span>;
  }

  <span class="hljs-comment">/**
   * Get the current size of the list
   * @returns The number of nodes in the list
   */</span>
  size(): <span class="hljs-built_in">number</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.currentSize;
  }
}
</code></pre>
<p>In this module, you have a circular doubly linked list with 8 different methods that will make it easier to build queues later in the tutorial:</p>
<ul>
<li><p><code>prepend</code>: Adds a new value to the <strong>front</strong> of the list.</p>
</li>
<li><p><code>append</code>: Adds a new value to the <strong>end</strong> of the list.</p>
</li>
<li><p><code>deleteHead</code>: Removes and returns the value at the <strong>front</strong>.</p>
</li>
<li><p><code>deleteTail</code>: Removes and returns the value at the <strong>end</strong>.</p>
</li>
<li><p><code>getHead</code>: Returns the front value <strong>without removing it</strong>.</p>
</li>
<li><p><code>getTail</code>: Returns the end value <strong>without removing it</strong>.</p>
</li>
<li><p><code>isEmpty</code>: Checks whether the list has <strong>no items</strong>.</p>
</li>
<li><p><code>size</code>: Returns the <strong>number of items</strong> currently in the list.</p>
</li>
</ul>
<p>Now that your linked list is ready, let's begin creating your first queue!</p>
<h2 id="heading-what-is-a-simple-queue">What is a Simple Queue?</h2>
<p>A Simple Queue follows the basic FIFO rule: you’ll to add items to the back and remove them from the front.</p>
<p>It’s like a line of customers at a ticket counter, where the first person in line buys a ticket first.</p>
<p>To get started, open <code>src/playground/02-simple-queue.ts</code>, where you will find the placeholder for the Simple Queue with its methods:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// 📁 src/playground/02-simple-queue.ts</span>

<span class="hljs-keyword">import</span> { LinkedList } <span class="hljs-keyword">from</span> <span class="hljs-string">"./01-linked-list"</span>;

<span class="hljs-comment">/**
 * Simple Queue implemented with a circular doubly linked list
 */</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> SimpleQueue&lt;T&gt; {
  <span class="hljs-keyword">private</span> list: LinkedList&lt;T&gt;;
  <span class="hljs-keyword">private</span> maxSize?: <span class="hljs-built_in">number</span>;

  <span class="hljs-comment">/**
   * @param maxSize Optional maximum size of the queue
   */</span>
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">maxSize?: <span class="hljs-built_in">number</span></span>) {
    <span class="hljs-built_in">this</span>.list = <span class="hljs-keyword">new</span> LinkedList&lt;T&gt;();
    <span class="hljs-built_in">this</span>.maxSize = maxSize;
  }

  ...methods
}
</code></pre>
<p>At the core of this <code>SimpleQueue</code> class, you're using a circular doubly linked list to store the items, and optionally allowing a maximum size limit to control how big the queue can grow.</p>
<ul>
<li><p><code>private list: LinkedList&lt;T&gt;</code> is where the queue's data is stored. Instead of a simple array, you're using a custom linked list, which makes it efficient to add or remove items from either end. The linked list manages the data structure and allows you to focus on how the queue works.</p>
</li>
<li><p><code>private maxSize</code> is an optional limit for how many items the queue can hold. If not provided, the queue can grow as large as needed.</p>
</li>
<li><p>Then, the <code>constructor</code> method that runs when you create a new queue. It creates a new, empty linked list to hold the queue items.</p>
</li>
</ul>
<p>Now, let's implement the queue methods.</p>
<p>Open your code editor and update <code>src/playground/02-simple-queue.ts</code> with the following code:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// 📁 src/playground/02-simple-queue.ts</span>

<span class="hljs-keyword">import</span> { LinkedList } <span class="hljs-keyword">from</span> <span class="hljs-string">"./01-linked-list"</span>;

<span class="hljs-comment">/**
 * Simple Queue implemented with a circular doubly linked list
 */</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> SimpleQueue&lt;T&gt; {
  <span class="hljs-keyword">private</span> list: LinkedList&lt;T&gt;;
  <span class="hljs-keyword">private</span> maxSize?: <span class="hljs-built_in">number</span>;

  <span class="hljs-comment">/**
   * @param maxSize Optional maximum size of the queue
   */</span>
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">maxSize?: <span class="hljs-built_in">number</span></span>) {
    <span class="hljs-built_in">this</span>.list = <span class="hljs-keyword">new</span> LinkedList&lt;T&gt;();
    <span class="hljs-built_in">this</span>.maxSize = maxSize;
  }

  <span class="hljs-comment">/**
   * Add an element to the rear of the queue
   * @param item The element to add
   */</span>
  enqueue(item: T): <span class="hljs-built_in">void</span> {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.isFull()) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Queue is full"</span>);
    }
    <span class="hljs-built_in">this</span>.list.append(item);
  }

  <span class="hljs-comment">/**
   * Remove and return the element from the front of the queue
   * @returns The element at the front or undefined if empty
   */</span>
  dequeue(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.deleteHead();
  }

  <span class="hljs-comment">/**
   * Get the element at the front without removing it
   * @returns The element at the front or undefined if empty
   */</span>
  getFront(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.getHead();
  }

  <span class="hljs-comment">/**
   * Get the element at the rear without removing it
   * @returns The element at the rear or undefined if empty
   */</span>
  getRear(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.getTail();
  }

  <span class="hljs-comment">/**
   * Check if the queue is empty
   * @returns True if the queue is empty, false otherwise
   */</span>
  isEmpty(): <span class="hljs-built_in">boolean</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.isEmpty();
  }

  <span class="hljs-comment">/**
   * Check if the queue is full
   * @returns True if the queue is full, false otherwise
   */</span>
  isFull(): <span class="hljs-built_in">boolean</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.maxSize !== <span class="hljs-literal">undefined</span> &amp;&amp; <span class="hljs-built_in">this</span>.list.size() &gt;= <span class="hljs-built_in">this</span>.maxSize;
  }

  <span class="hljs-comment">/**
   * Peek at the front element without removing it
   * @returns The element at the front or undefined if empty
   */</span>
  peek(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.getFront();
  }

  <span class="hljs-comment">/**
   * Get the current size of the queue
   * @returns The number of elements in the queue
   */</span>
  size(): <span class="hljs-built_in">number</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.size();
  }
}
</code></pre>
<p>As you can see, the linked list greatly simplifies your queue implementation because it acts as the engine behind your queue.</p>
<p>Here's how your Simple Queue works:</p>
<ul>
<li><p><strong>isEmpty()</strong>: This method checks whether the queue contains any items. It calls the <code>isEmpty()</code> method on the linked list, which internally checks if the current size of the list is zero. If the list has no nodes, it returns <code>true</code>, indicating that the queue is empty. This is a basic utility method often used before attempting to dequeue or inspect the queue.</p>
</li>
<li><p><strong>isFull()</strong>: This method determines whether the queue has reached its capacity. It compares the current size of the linked list (via the <code>size()</code> method) to the optional <code>maxSize</code> value. If <code>maxSize</code> is defined and the size is equal to or greater than that limit, it returns <code>true</code>, indicating that no more items can be added. This is useful to prevent overflow in bounded queues.</p>
</li>
<li><p><strong>size()</strong>: This method returns the number of items currently stored in the queue. It directly calls the <code>size()</code> method of the linked list, which tracks how many nodes are present. This allows you to monitor queue usage and remaining capacity.</p>
</li>
<li><p><strong>enqueue()</strong>: This method adds a new item to the end (rear) of the queue. It first checks whether the queue is full by calling the <code>isFull()</code> method. If it is, the method throws an error. Otherwise, it appends the new item to the internal linked list using the <code>append()</code> method, which adds the new node to the tail of the circular doubly linked list.</p>
</li>
<li><p><strong>dequeue()</strong>: This method removes and returns the item at the front of the queue. It calls the <code>deleteHead()</code> method of the linked list, which removes the head node and updates the links of the surrounding nodes to maintain the circular structure. If the queue is empty, it returns <code>undefined</code>.</p>
</li>
<li><p><strong>getFront()</strong>: This method returns the value at the front of the queue without removing it. It uses the <code>getHead()</code> method of the linked list to retrieve the value of the head node. This operation does not modify the queue and is useful for previewing the next item to be dequeued.</p>
</li>
<li><p><strong>getRear()</strong>: This method returns the value at the rear of the queue without removing it. It uses the <code>getTail()</code> method of the linked list, which returns the value of the tail node. This helps you inspect the most recently added item without altering the queue.</p>
</li>
<li><p><strong>peek()</strong>: This method is an alias for <code>getFront()</code>. It returns the item at the front of the queue without removing it. Internally, it calls <code>getFront()</code> to get the head value. This is often used in queue APIs to check the next item in line.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749742108067/3f5aab62-8314-4889-925a-cb9d52d9a277.png" alt="Flowchart illustrating queue operations. The process starts with either an enqueue or dequeue operation. Enqueue checks if the queue is full: if yes, triggers an error; if no, it adds an element, updates the rear pointer, and ends. Dequeue checks if the queue is empty: if yes, triggers an error; if no, removes an element, updates the front pointer, and ends." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>You’ve just implemented your first queue in TypeScript. To make sure that your implementation works correctly, run the following command in your terminal at the root of the project:</p>
<pre><code class="lang-bash">npm run <span class="hljs-built_in">test</span>:file 02
</code></pre>
<p>If any of the tests fail, use the final example from <code>src/examples/02-simple-queue.ts</code> to debug the issue, and then run the tests again.</p>
<p>If all tests pass, you can proceed to the next section, where you'll implement a Circular Queue.</p>
<h2 id="heading-what-is-a-circular-queue">What is a Circular Queue?</h2>
<p>A <code>CircularQueue</code> is a fixed-size queue where the last position connects back to the first. This allows you to reuse space after removing items.</p>
<p>Imagine a buffet line with a limited number of plates: when someone takes a plate from the front, a new one is added at the back, using the same space again.</p>
<p>The <code>CircularQueue</code> is quite similar to the <code>SimpleQueue</code>, but it has a few unique differences.</p>
<p>Let’s modify <code>src/playground/03-circular-queue.ts</code> and add the following code:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// 📁 src/playground/03-circular-queue.ts</span>

<span class="hljs-keyword">import</span> { LinkedList } <span class="hljs-keyword">from</span> <span class="hljs-string">"./01-linked-list"</span>;

<span class="hljs-comment">/**
 * Circular Queue implemented with a circular doubly linked list
 */</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CircularQueue&lt;T&gt; {
  <span class="hljs-keyword">private</span> list: LinkedList&lt;T&gt;;
  <span class="hljs-keyword">private</span> maxSize: <span class="hljs-built_in">number</span>;

  <span class="hljs-comment">/**
   * @param maxSize Required maximum size of the circular queue
   */</span>
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">maxSize: <span class="hljs-built_in">number</span></span>) {
    <span class="hljs-built_in">this</span>.list = <span class="hljs-keyword">new</span> LinkedList&lt;T&gt;();
    <span class="hljs-built_in">this</span>.maxSize = maxSize;
  }

  <span class="hljs-comment">/**
   * Add an element to the rear of the queue
   * @param item The element to add
   */</span>
  enqueue(item: T): <span class="hljs-built_in">void</span> {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.isFull()) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Circular queue is full"</span>);
    }
    <span class="hljs-built_in">this</span>.list.append(item);
  }

  <span class="hljs-comment">/**
   * Remove and return the element from the front of the queue
   * @returns The element at the front or undefined if empty
   */</span>
  dequeue(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.deleteHead();
  }

  <span class="hljs-comment">/**
   * Get the element at the front without removing it
   * @returns The element at the front or undefined if empty
   */</span>
  getFront(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.getHead();
  }

  <span class="hljs-comment">/**
   * Get the element at the rear without removing it
   * @returns The element at the rear or undefined if empty
   */</span>
  getRear(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.getTail();
  }

  <span class="hljs-comment">/**
   * Check if the queue is empty
   * @returns True if the queue is empty, false otherwise
   */</span>
  isEmpty(): <span class="hljs-built_in">boolean</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.isEmpty();
  }

  <span class="hljs-comment">/**
   * Check if the queue is full
   * @returns True if the queue is full, false otherwise
   */</span>
  isFull(): <span class="hljs-built_in">boolean</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.size() &gt;= <span class="hljs-built_in">this</span>.maxSize;
  }

  <span class="hljs-comment">/**
   * Peek at the front element without removing it
   * @returns The element at the front or undefined if empty
   */</span>
  peek(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.getFront();
  }

  <span class="hljs-comment">/**
   * Get the current size of the queue
   * @returns The number of elements in the queue
   */</span>
  size(): <span class="hljs-built_in">number</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.size();
  }
}
</code></pre>
<p>This may look very similar to a <code>SimpleQueue</code>, but there are a few key differences:</p>
<ul>
<li><p><strong>Constructor Difference</strong>: Unlike the <code>SimpleQueue</code>, the <code>CircularQueue</code> <strong>requires</strong> a <code>maxSize</code> parameter during instantiation. This enforces a strict upper limit on how many elements can be in the queue at once.</p>
<p>  In contrast, <code>SimpleQueue</code> treats <code>maxSize</code> as optional and allows unbounded queues. By making the size mandatory, <code>CircularQueue</code> is better suited for fixed-size buffer scenarios where memory or resource control is important (for example, in real-time systems or caching).</p>
</li>
<li><p><strong>enqueue()</strong>: This method is almost identical to the one in <code>SimpleQueue</code>, but the key difference lies in the design intent. In <code>CircularQueue</code>, throwing an error when the queue is full is part of the contract and it assumes that you’re managing a fixed buffer.</p>
<p>  The circular nature comes into play conceptually: once full, no more data can enter unless older entries are removed, which mimics a circular overwrite mechanism (though this specific implementation doesn’t auto-overwrite).</p>
</li>
<li><p><strong>isFull()</strong>: This method behaves the same as in <code>SimpleQueue</code> when a <code>maxSize</code> is set, but in <code>CircularQueue</code>, it’s always applicable because <code>maxSize</code> is required. The consistent presence of a size limit makes the queue predictable and ideal for bounded use cases like streaming data and rate-limited processing.</p>
</li>
</ul>
<p>Now, let's test the implementation to see if it works:</p>
<pre><code class="lang-bash">npm run <span class="hljs-built_in">test</span>:file 03
</code></pre>
<p>If any of the tests fail, use the final <code>/examples</code> directory to debug the issue.</p>
<p>If the tests pass, you'll be ready to move on to the next section, where you will learn about double-ended queues.</p>
<h2 id="heading-what-is-a-double-ended-queue">What is a Double Ended Queue?</h2>
<p>A double-ended queue (deque) lets you add or remove items from both the front and the back.</p>
<p>It’s like a line at a bus stop where people can join or leave from either end.</p>
<p>Let’s modify <code>src/playground/04-double-ended-queue.ts</code> and add the following code:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// 📁 src/playground/04-double-ended-queue.ts</span>

<span class="hljs-keyword">import</span> { LinkedList } <span class="hljs-keyword">from</span> <span class="hljs-string">"./01-linked-list"</span>;

<span class="hljs-comment">/**
 * Double-Ended Queue (Deque) implemented with a circular doubly linked list
 */</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> Deque&lt;T&gt; {
  <span class="hljs-keyword">private</span> list: LinkedList&lt;T&gt;;
  <span class="hljs-keyword">private</span> maxSize?: <span class="hljs-built_in">number</span>;

  <span class="hljs-comment">/**
   * @param maxSize Optional maximum size of the deque
   */</span>
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">maxSize?: <span class="hljs-built_in">number</span></span>) {
    <span class="hljs-built_in">this</span>.list = <span class="hljs-keyword">new</span> LinkedList&lt;T&gt;();
    <span class="hljs-built_in">this</span>.maxSize = maxSize;
  }

  <span class="hljs-comment">/**
   * Add an element to the front of the deque
   * @param item The element to add
   */</span>
  enqueueFront(item: T): <span class="hljs-built_in">void</span> {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.isFull()) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Deque is full"</span>);
    }
    <span class="hljs-built_in">this</span>.list.prepend(item);
  }

  <span class="hljs-comment">/**
   * Add an element to the rear of the deque
   * @param item The element to add
   */</span>
  enqueueRear(item: T): <span class="hljs-built_in">void</span> {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.isFull()) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Deque is full"</span>);
    }
    <span class="hljs-built_in">this</span>.list.append(item);
  }

  <span class="hljs-comment">/**
   * Remove and return the element from the front of the deque
   * @returns The element at the front or undefined if empty
   */</span>
  dequeueFront(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.deleteHead();
  }

  <span class="hljs-comment">/**
   * Remove and return the element from the rear of the deque
   * @returns The element at the rear or undefined if empty
   */</span>
  dequeueRear(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.deleteTail();
  }

  <span class="hljs-comment">/**
   * Get the element at the front without removing it
   * @returns The element at the front or undefined if empty
   */</span>
  getFront(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.getHead();
  }

  <span class="hljs-comment">/**
   * Get the element at the rear without removing it
   * @returns The element at the rear or undefined if empty
   */</span>
  getRear(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.getTail();
  }

  <span class="hljs-comment">/**
   * Check if the deque is empty
   * @returns True if the deque is empty, false otherwise
   */</span>
  isEmpty(): <span class="hljs-built_in">boolean</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.isEmpty();
  }

  <span class="hljs-comment">/**
   * Check if the deque is full
   * @returns True if the deque is full, false otherwise
   */</span>
  isFull(): <span class="hljs-built_in">boolean</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.maxSize !== <span class="hljs-literal">undefined</span> &amp;&amp; <span class="hljs-built_in">this</span>.list.size() &gt;= <span class="hljs-built_in">this</span>.maxSize;
  }

  <span class="hljs-comment">/**
   * Peek at the front element without removing it
   * @returns The element at the front or undefined if empty
   */</span>
  peek(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.getFront();
  }

  <span class="hljs-comment">/**
   * Get the current size of the deque
   * @returns The number of elements in the deque
   */</span>
  size(): <span class="hljs-built_in">number</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.size();
  }
}
</code></pre>
<p>Now, let's go through the methods:</p>
<ul>
<li><p><strong>enqueueFront()</strong>: This method allows adding an element to the <strong>front</strong> of the deque, unlike in <code>SimpleQueue</code> or <code>CircularQueue</code> which only support adding to the rear. Internally, it uses <code>list.prepend(item)</code> to insert the item at the head.</p>
<p>  This operation makes the deque suitable for use cases where elements need to be pushed and popped from both ends, like in undo/redo systems or task schedulers.</p>
</li>
<li><p><strong>enqueueRear()</strong>: This behaves similarly to <code>SimpleQueue</code>’s <code>enqueue</code>, adding elements to the <strong>rear</strong> using <code>list.append(item)</code>.</p>
<p>  The distinction in <code>Deque</code> is that this is just one of two symmetric operations and it gives you full double-ended control.</p>
</li>
<li><p><strong>dequeueFront()</strong>: This removes and returns the element from the <strong>front</strong> of the deque using <code>list.deleteHead()</code>.</p>
<p>  While similar to the <code>dequeue</code> method in queues, the naming here is explicit to clarify that it's operating on the front and can be paired with a rear counterpart.</p>
</li>
<li><p><strong>dequeueRear()</strong>: This is a unique feature to deques, it removes and returns the element at the <strong>rear</strong> using <code>list.deleteTail()</code>. This complements <code>dequeueFront()</code> and enables LIFO (stack-like) behavior if needed.</p>
</li>
<li><p><strong>Constructor Difference</strong>: Like <code>SimpleQueue</code>, the <code>Deque</code> accepts an optional <code>maxSize</code>. This allows for flexible configurations.</p>
<p>  You can have unbounded deques when <code>maxSize</code> is not provided, or fixed-size deques when constraints are important. This is in contrast to <code>CircularQueue</code>, which requires a max size.</p>
</li>
</ul>
<p>Once you have completed the implementation, run the following command to test the module:</p>
<pre><code class="lang-bash">npm run <span class="hljs-built_in">test</span>:file 04
</code></pre>
<p>Now, you're ready to move on to the last section of the tutorial, where you'll learn about the Priority Queue.</p>
<h2 id="heading-what-is-a-priority-queue">What is a Priority Queue?</h2>
<p>A priority queue processes items based on their priority, not their order of arrival.</p>
<p>Higher-priority items are removed first, like an emergency room where patients with severe conditions are treated before others.</p>
<p>Let’s modify <code>src/playground/05-priority-queue.ts</code>:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// 📁 src/playground/05-priority-queue.ts</span>

<span class="hljs-keyword">import</span> { LinkedList, NodeItem } <span class="hljs-keyword">from</span> <span class="hljs-string">"./01-linked-list"</span>;

<span class="hljs-comment">/**
 * Interface for an element with priority
 */</span>
<span class="hljs-keyword">interface</span> PriorityItem&lt;T&gt; {
  value: T;
  priority: <span class="hljs-built_in">number</span>;
}

<span class="hljs-comment">/**
 * Priority Queue implemented with a circular doubly linked list
 */</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> PriorityQueue&lt;T&gt; {
  <span class="hljs-keyword">private</span> list: LinkedList&lt;PriorityItem&lt;T&gt;&gt;;
  <span class="hljs-keyword">private</span> maxSize?: <span class="hljs-built_in">number</span>;

  <span class="hljs-comment">/**
   * @param maxSize Optional maximum size of the priority queue
   */</span>
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">maxSize?: <span class="hljs-built_in">number</span></span>) {
    <span class="hljs-built_in">this</span>.list = <span class="hljs-keyword">new</span> LinkedList&lt;PriorityItem&lt;T&gt;&gt;();
    <span class="hljs-built_in">this</span>.maxSize = maxSize;
  }

  <span class="hljs-comment">/**
   * Add an element to the queue based on its priority
   * Higher priority numbers are dequeued first
   * @param value The value to add
   * @param priority The priority of the value (higher number = higher priority)
   */</span>
  enqueue(value: T, priority: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">void</span> {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.isFull()) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Error</span>(<span class="hljs-string">"Priority queue is full"</span>);
    }

    <span class="hljs-keyword">const</span> newItem: PriorityItem&lt;T&gt; = { value, priority };
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">this</span>.isEmpty()) {
      <span class="hljs-built_in">this</span>.list.prepend(newItem);
      <span class="hljs-keyword">return</span>;
    }

    <span class="hljs-keyword">let</span> current = <span class="hljs-built_in">this</span>.list[<span class="hljs-string">"head"</span>];
    <span class="hljs-keyword">let</span> count = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">while</span> (
      current &amp;&amp;
      current.value.priority &gt;= priority &amp;&amp;
      count &lt; <span class="hljs-built_in">this</span>.size()
    ) {
      current = current.next;
      count++;
    }

    <span class="hljs-keyword">if</span> (count === <span class="hljs-built_in">this</span>.size()) {
      <span class="hljs-built_in">this</span>.list.append(newItem);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-keyword">const</span> newNode = <span class="hljs-keyword">new</span> NodeItem(newItem);
      newNode.next = current;
      newNode.prev = current!.prev;
      <span class="hljs-keyword">if</span> (current!.prev) {
        current!.prev.next = newNode;
      } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">this</span>.list[<span class="hljs-string">"head"</span>] = newNode;
      }
      current!.prev = newNode;
      <span class="hljs-keyword">if</span> (current === <span class="hljs-built_in">this</span>.list[<span class="hljs-string">"head"</span>]) {
        <span class="hljs-built_in">this</span>.list[<span class="hljs-string">"head"</span>] = newNode;
      }
      <span class="hljs-built_in">this</span>.list[<span class="hljs-string">"tail"</span>]!.next = <span class="hljs-built_in">this</span>.list[<span class="hljs-string">"head"</span>];
      <span class="hljs-built_in">this</span>.list[<span class="hljs-string">"head"</span>]!.prev = <span class="hljs-built_in">this</span>.list[<span class="hljs-string">"tail"</span>];
      <span class="hljs-built_in">this</span>.list[<span class="hljs-string">"currentSize"</span>]++;
    }
  }

  <span class="hljs-comment">/**
   * Remove and return the element with the highest priority from the queue
   * @returns The value with the highest priority or undefined if empty
   */</span>
  dequeue(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.deleteHead()?.value;
  }

  <span class="hljs-comment">/**
   * Get the element with the highest priority without removing it
   * @returns The value at the front or undefined if empty
   */</span>
  getFront(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.getHead()?.value;
  }

  <span class="hljs-comment">/**
   * Get the element with the lowest priority without removing it
   * @returns The value at the rear or undefined if empty
   */</span>
  getRear(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.getTail()?.value;
  }

  <span class="hljs-comment">/**
   * Check if the queue is empty
   * @returns True if the queue is empty, false otherwise
   */</span>
  isEmpty(): <span class="hljs-built_in">boolean</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.isEmpty();
  }

  <span class="hljs-comment">/**
   * Check if the queue is full
   * @returns True if the queue is full, false otherwise
   */</span>
  isFull(): <span class="hljs-built_in">boolean</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.maxSize !== <span class="hljs-literal">undefined</span> &amp;&amp; <span class="hljs-built_in">this</span>.list.size() &gt;= <span class="hljs-built_in">this</span>.maxSize;
  }

  <span class="hljs-comment">/**
   * Peek at the element with the highest priority without removing it
   * @returns The value at the front or undefined if empty
   */</span>
  peek(): T | <span class="hljs-literal">undefined</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.getFront();
  }

  <span class="hljs-comment">/**
   * Get the current size of the queue
   * @returns The number of elements in the queue
   */</span>
  size(): <span class="hljs-built_in">number</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.list.size();
  }
}
</code></pre>
<p>Let's understand how the methods work within a Priority Queue:</p>
<ul>
<li><p><strong>enqueue()</strong>: This method inserts a new element into the queue based on its <code>priority</code>. Unlike other queue types where order is based on insertion time, <code>PriorityQueue</code> uses a sorting mechanism where elements with higher <code>priority</code> values are placed closer to the front.</p>
<p>  The method traverses the linked list from the head, searching for the correct position where the new item should be inserted so that the list remains sorted in descending priority order.</p>
<p>  It manually adjusts the <code>prev</code> and <code>next</code> pointers to keep the circular doubly linked list intact. This sorting during insertion ensures quick access to the highest priority element later.</p>
</li>
<li><p><strong>dequeue()</strong>: This method removes and returns the element with the highest priority, which is always positioned at the front of the list.</p>
<p>  Internally, it calls <code>deleteHead()</code> and then returns the <code>value</code> from the <code>PriorityItem&lt;T&gt;</code> node. Because items are sorted during insertion, this operation is always efficient and retrieves the correct item.</p>
</li>
<li><p><strong>getFront()</strong>: This retrieves the value at the front of the queue without removing it. Since the list is sorted in descending priority, this value always represents the highest priority item.</p>
</li>
<li><p><strong>getRear()</strong>: This returns the value at the rear of the queue, which is the item with the <strong>lowest</strong> priority. It accesses the last element in the list using <code>getTail()</code> and extracts the <code>value</code>.</p>
</li>
<li><p><strong>isEmpty()</strong>: This checks whether the queue contains any elements by delegating to the linked list’s <code>isEmpty()</code> method.</p>
</li>
<li><p><strong>isFull()</strong>: This checks whether the queue has reached its maximum allowed size. It compares the current size with <code>maxSize</code> if it's defined.</p>
</li>
<li><p><strong>peek()</strong>: This is functionally equivalent to <code>getFront()</code>. It provides a clearer semantic name when users want to examine the highest-priority element without removing it.</p>
</li>
<li><p><strong>size()</strong>: This returns the total number of items currently in the priority queue. It's useful for monitoring capacity or debugging.</p>
</li>
<li><p><strong>Key Differences</strong>: The priority queue differs from other queue types by enforcing order during insertion based on a numeric priority.</p>
<p>  This enables <strong>constant-time access to the highest priority element</strong> but introduces <strong>linear-time insertion</strong> complexity due to the need to find the correct place for each new element.</p>
<p>  It supports advanced scheduling and load balancing use cases where task urgency or importance matters more than arrival time.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749743948626/78505f93-d7fd-4c63-b59a-5db1edcdae6c.png" alt="Flowchart illustrating the process of inserting an element into a priority queue. It begins by checking if the queue is empty, then assesses priority, updates the queue, traverses it if necessary, and continually checks for the correct position to insert." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Once you’re done with the implementation, run the following command to test your code:</p>
<pre><code class="lang-bash">npm run <span class="hljs-built_in">test</span>:file 05
</code></pre>
<p>That’s it, congratulations!</p>
<p>You have successfully completed the tutorial and learned about queues and their different variations. Great job!</p>
<p>Before reaching conclusions, let’s briefly learn about where to use queues and where to avoid them. We’ll also discuss the bottlenecks and issues that queues may create if not used correctly and in the right place.</p>
<h2 id="heading-when-to-use-queues-and-when-to-avoid-them"><strong>When to Use Queues (and When to Avoid Them)</strong></h2>
<p>Queues are ideal in scenarios where tasks or data must be processed in the exact order they arrive, such as in job scheduling and event handling systems.</p>
<p>For example, when multiple print jobs are sent to a printer, a queue can make sure each document is printed in the order it was submitted.</p>
<p>Similarly, queues are used in operating systems for managing tasks in thread pools or CPU scheduling (for example, Round Robin), where order is crucial.</p>
<p>Queues are also heavily used in asynchronous communication systems such as message brokers like RabbitMQ and Kafka.</p>
<p>In these systems, producers and consumers operate independently: a producer pushes messages into the queue, and a consumer processes them later.</p>
<p>This pattern is extremely useful in microservices architecture or serverless environments, where different parts of a system need to remain loosely coupled and highly scalable.</p>
<p>Similarly, in real-time systems like video streaming or sensor data ingestion, queues help buffer incoming data to avoid data loss and allow for smooth downstream processing.</p>
<h3 id="heading-when-to-avoid-queues">When to Avoid Queues</h3>
<p>Queues are not well-suited for problems that require random access to elements, complex search operations, or sorting.</p>
<p>Since queues typically allow insertion at one end and removal from the other, they’re inefficient for use cases where you frequently need to access elements in the middle or search through all items.</p>
<p>An array, tree, or hash map would serve better in such cases.</p>
<p>Using queues inappropriately can introduce unnecessary complexity and hidden bottlenecks.</p>
<p>For instance, blindly placing a queue between every microservice might decouple components but also make debugging and failure handling more difficult.</p>
<p>Over-queuing can also lead to backpressure problems where queues grow uncontrollably under high load which will increase latency or even crashing the system if not managed properly.</p>
<p>So you should use queues deliberately: when order, buffering, or async processing is required.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Queues are a basic data structure that work well when you need order and async processing.</p>
<p>Queues are useful for handling tasks, streaming data, or coordinating services, and making sure things run smoothly and efficiently.</p>
<p>But they aren't suitable for every problem. It's important to understand their pros and cons to use them correctly and avoid unnecessary complexity.</p>
<p>Thanks for following along with this tutorial. You can follow me on <a target="_blank" href="https://x.com/Yazdun">X</a>, where I share more useful tips on data structures and web development.</p>
<p>Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ A Beginner’s Guide to Graphs — From Google Maps to Chessboards ]]>
                </title>
                <description>
                    <![CDATA[ Most of us use Google Maps without thinking twice. You open the app, check which route has the least traffic, and hit start. Then somewhere along the way – maybe you miss a turn (I do that often) – and Maps calmly recalculates your route, showing you... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/a-beginners-guide-to-graphs/</link>
                <guid isPermaLink="false">683dc829f7d4772789f06d02</guid>
                
                    <category>
                        <![CDATA[ Graph ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ data structures ]]>
                    </category>
                
                    <category>
                        <![CDATA[ DFS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ BFS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tilda Udufo ]]>
                </dc:creator>
                <pubDate>Mon, 02 Jun 2025 15:50:01 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1748879365710/23d7601e-cde0-489b-a843-97190e58e5c9.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Most of us use Google Maps without thinking twice. You open the app, check which route has the least traffic, and hit start. Then somewhere along the way – maybe you miss a turn (I do that often) – and Maps calmly recalculates your route, showing you a new path that still gets you to your destination.</p>
<p>Behind that seamless rerouting is a graph – not a chart, but a structure of <strong>nodes</strong> (places) and <strong>edges</strong> (roads) that allows Google Maps to calculate the shortest, fastest, or least congested path from point A to point B.</p>
<p>Once you start noticing them, you’ll realize graphs are everywhere. If you’ve ever used:</p>
<ul>
<li><p><strong>Google Maps</strong> to get from one city to another,</p>
</li>
<li><p><strong>LinkedIn</strong> to see how you’re connected to someone,</p>
</li>
<li><p>or <strong>Git</strong> to visualize branches and merges…</p>
</li>
</ul>
<p>…you’ve interacted with a graph.</p>
<p>Graphs are everywhere, in how we plan routes, recommend friends, manage project dependencies, and even predict the possible moves of a knight on a chessboard. But to use them well, we first need to understand how they’re structured and why they’re so useful.</p>
<p>In this article, you’ll learn:</p>
<ul>
<li><p>What a graph is and how it’s used in real-world systems</p>
</li>
<li><p>The different types of graphs and how they’re represented in code</p>
</li>
<li><p>How to traverse graphs using search algorithms</p>
</li>
<li><p>And finally, how a knight’s movement in chess can be modeled using graphs, and solved using traversal techniques</p>
</li>
</ul>
<p>Let’s start by breaking down what graphs are made of and why they show up in so many things you already use.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-a-graph">What is a Graph?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-types-of-graphs">Types of Graphs</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-graphs-are-represented">How Graphs Are Represented</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-graph-traversal">Graph Traversal</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-knights-travails-a-real-world-graph-problem">Knight's Travails: A Real-World Graph Problem</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></p>
</li>
</ul>
<h3 id="heading-prerequisites"><strong>Prerequisites</strong></h3>
<p>This article is beginner-friendly, and no prior knowledge of graphs is required. To follow along with the code examples, it helps to have:</p>
<ul>
<li><p>Some familiarity with data structures like stacks and queues.</p>
</li>
<li><p>I use Python for the code snippets, but if you’ve worked with another language, you should be able to follow along easily.</p>
</li>
</ul>
<h2 id="heading-what-is-a-graph">What is a Graph?</h2>
<p>At its core, a graph is a collection of <strong>nodes</strong> (also called vertices) and <strong>edges</strong> – connections that link those nodes together.</p>
<p>If it sounds simple, that’s because it is. The power of graphs isn’t in their complexity, it’s in their flexibility. You can use them to represent almost anything: people, cities, web pages, tasks, game moves, and the relationships between them.</p>
<p>Let’s break it down:</p>
<h3 id="heading-nodes-vertices">Nodes (Vertices)</h3>
<p>Each node is a point in the graph. It might represent:</p>
<ul>
<li><p>A location (like a city on a map)</p>
</li>
<li><p>A person (in a social network)</p>
</li>
<li><p>A page (for example, on the web)</p>
</li>
<li><p>A square (like one on a chessboard)</p>
</li>
</ul>
<h3 id="heading-edges">Edges</h3>
<p>An edge is a connection between two nodes. It could represent:</p>
<ul>
<li><p>A road between two cities</p>
</li>
<li><p>A friendship between two users</p>
</li>
<li><p>A hyperlink between two web pages</p>
</li>
<li><p>A legal knight move between two squares</p>
</li>
</ul>
<p>Edges can have direction (one-way or two-way), weight (like distance or cost), or be simple and unweighted.</p>
<h3 id="heading-graph-visualizer">Graph Visualizer</h3>
<p>Here’s a simple graph:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748363812251/59a945ea-eae0-4792-98bb-3f1d8477dde9.png" alt="Graph with 7 circular nodes labeled 0 through 6. Lines connect various pairs of nodes, forming a network-like structure. Each node is connected to one or more others." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>In this image:</p>
<ul>
<li><p>The circles represent nodes (also called vertices)</p>
</li>
<li><p>The lines connecting them are edges, which show that two nodes are related or connected in some way</p>
</li>
</ul>
<p>Each node is connected to one or more other nodes, forming a network of relationships<strong>.</strong></p>
<h2 id="heading-types-of-graphs">Types of Graphs</h2>
<p>Now that we’ve seen what a graph looks like, let’s talk about the different ways graphs can behave.</p>
<p>Graphs can vary in <strong>direction</strong>, <strong>weight</strong>, and <strong>structure</strong>. Understanding these types helps us choose the right graph model for the problem we’re trying to solve.</p>
<h3 id="heading-directed-graphs">Directed Graphs</h3>
<p>In a directed graph (also known as a <strong>digraph</strong>), connections between nodes move in a specific direction. Think of it like a one-way street – if you can drive from Point A to Point B, that doesn't necessarily mean you can drive back the same way.</p>
<p>A good example of this is X (Twitter). If you follow someone on X, it doesn’t automatically mean they follow you back. Your “follow” is a one-way connection, a directed edge from you to them.</p>
<p>This kind of graph is especially useful in situations where relationships are not mutual. On the internet, links between web pages behave the same way. Page A might link to Page B, but Page B might not link back. Similarly, in workflow systems or task pipelines, each step flows into the next in a specific order, and you generally don’t loop back – Step 1 leads to Step 2, and so on.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748365204873/4926ff56-af90-438d-8281-8423ffa1bfad.png" alt="An directed graph with six blue nodes (0–5) and edges connecting them." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-undirected-graphs">Undirected Graphs</h3>
<p>An undirected graph represents relationships that go both ways. If there’s a connection between node A and node B, you can travel in either direction.</p>
<p>A common example is a friendship on Facebook. If you’re friends with someone, the connection is mutual by default. It wouldn’t make sense to be “half-friends”.</p>
<p>Undirected graphs are useful when the relationship itself is mutual and symmetrical, like shared devices on a network or road systems where travel is allowed both ways.</p>
<p>The key difference here is that edges are just lines, not arrows – they don’t imply flow or hierarchy, just connection.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748365067259/af75d2bc-91ee-459a-8277-d0b53a039bd3.png" alt="An undirected graph with six red nodes (0–5) and edges connecting them symmetrically, showing bidirectional relationships with no arrows." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-weighted-graphs">Weighted Graphs</h3>
<p>A weighted graph is one where each connection (edge) carries extra information, usually a number representing distance, cost, time, or importance.</p>
<p>Consider how you use Google Maps to get from one location to another. The app doesn’t just look for any route, it looks for the one that takes the <strong>least time</strong>, travels the <strong>shortest distance</strong>, or uses the <strong>least fuel</strong>. All of those are weights.</p>
<p>In a graph like this, two cities might be connected, but one road might take 5 minutes while another takes 20, so the edge between those cities isn’t just a line – it’s a line with a value.</p>
<p>This structure lets us make smarter decisions. We can ask questions like:</p>
<ul>
<li><p>What’s the cheapest way to reach a destination?</p>
</li>
<li><p>Which route avoids the most traffic?</p>
</li>
<li><p>What’s the fastest route from node A to node Z?</p>
</li>
</ul>
<p>If undirected and directed graphs describe who is connected to whom, weighted graphs help us understand how strong, far, or costly those connections are<strong>.</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748365667877/bfa51c1c-e17d-4db9-aaf9-5d25d1825af0.png" alt="A weighted undirected graph with nine purple nodes (0–8) and labeled edges showing weights. Edge values vary (e.g., 3, 5, 10), modeling a weighted graph." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-unweighted-graphs">Unweighted Graphs</h3>
<p>In an unweighted graph, all edges are treated equally. A connection either exists, or it doesn’t – there’s no extra value or cost attached.</p>
<p>Think of a group of friends where you only care about whether two people know each other. You’re not trying to measure how close they are or how often they talk, you just want to map the presence or absence of a relationship.</p>
<p>Unweighted graphs are useful for modeling systems where the existence of a connection is more important than any nuance of how strong it is. These are great for representing basic relationships, board game states, or decision trees where each path is considered equally likely or valuable.</p>
<p>In short, unweighted graphs are all about the “yes/no,” not the “how much.”</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748365816756/761186c7-befb-4dc9-8059-787aac271e05.png" alt="An unweighted graph with orange nodes (0–8). The nodes are connected without arrows, forming a loosely circular layout." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-cyclic-graphs">Cyclic Graphs</h3>
<p>A cyclic graph is one where it’s possible to loop back to where you started. You can travel through a series of connections and eventually end up at the same node.</p>
<p>If you’ve ever looked at a city map or used a public transit system with circular routes, you’ve seen a cycle in action. You might start at a station, ride the train through several stops, and eventually return to where you began, without ever retracing your exact steps.</p>
<p>Cyclic graphs are especially useful in simulations, games, or real-world systems where loops are part of the design, like control circuits or repeated workflows. They’re a natural fit for any scenario where repetition or return paths matter.</p>
<p>But they can also introduce complexity, especially in algorithms that aren’t meant to handle cycles. Recognizing whether your graph has cycles is often an important first step in choosing the right traversal method.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748366079943/bf3b7675-cee8-442a-a680-e52e9ee85612.png" alt="A green-node cyclic graph with eight nodes (0–7)." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-acyclic-graphs">Acyclic Graphs</h3>
<p>An acyclic graph is the opposite of a cyclic one – there are no loops. Once you start moving through the graph, you can’t return to a node you’ve already visited by following the direction of the edges. They can either be directed or undirected graphs.</p>
<p>Think of task management systems where some tasks depend on others. You can't complete Task C until you’ve finished Task B, and you can't start B until A is done. There’s a natural order, and no looping back<strong>.</strong></p>
<p>Acyclic graphs are common in:</p>
<ul>
<li><p>Scheduling systems</p>
</li>
<li><p>Organizational charts</p>
</li>
<li><p>Tutorial progression systems (like one chapter unlocking the next)</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748366703312/412cece1-85f2-4251-a422-776d56f115e7.png" alt="A red-node acyclic graph with eight nodes (0–7)." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-directed-acyclic-graphs">Directed Acyclic Graphs</h3>
<p>A Directed Acyclic Graph or DAG is a type of acyclic graph where every edge has a direction, and you can’t form any cycles. It’s like a roadmap where all roads point forward and never loop.</p>
<p>This structure is incredibly common in computing, especially when you need to track progress<strong>,</strong> dependencies<strong>,</strong> or history<strong>.</strong></p>
<p>In Git, for example, every commit points to one or more parent commits, forming a directed graph of changes. But since commits can’t “revisit” an earlier state, the structure remains acyclic.</p>
<p>In package managers, a library might depend on others, but you can't have a loop. Say library A depends on B, which depends on C, which depends on A again – that would break everything. A DAG ensures that dependencies move forward<strong>,</strong> not in circles<strong>.</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748366537100/1110ebc4-33eb-4036-9ead-4a6178e02474.png" alt="A blue-node directed acyclic graph (DAG) with eight nodes (0–7). " class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-graphs-are-represented">How Graphs Are Represented</h2>
<p>So far, we’ve explored graphs as concepts and visuals with various types and behaviors. But when it’s time to work with graphs in code, we need a way to represent those connections in a structured format.</p>
<p>There are two common ways to represent a graph:</p>
<ul>
<li><p><strong>Adjacency List</strong></p>
</li>
<li><p><strong>Adjacency Matrix</strong></p>
</li>
</ul>
<p>Each has its strengths, and which one you use depends on the type of graph and what operations you need to perform.</p>
<h3 id="heading-adjacency-list">Adjacency List</h3>
<p>An adjacency list stores a graph as a collection of nodes, where each node maps to a list of its neighbors (nodes it’s connected to). An adjacency list is one of the most intuitive ways to represent a graph. But how you write this list depends on the type of graph you’re working with.</p>
<p><strong>For an undirected graph</strong>, the connection goes both ways, so each edge is written twice – once for each node.</p>
<p><strong>For a directed graph</strong>, each connection only flows one way, so you only write it once, in the direction it points.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748375989397/6589e103-8589-4529-9ede-98d298567c39.png" alt="An undirected graph diagram with six nodes labeled A through F, shown alongside its adjacency list representation. In the graph: nodes are connected with straight lines representing undirected edges. The adjacency list shows each node and its neighbors: A connects to E, F, and C. B connects to E and F. C connects to A, D, and E. D connects to C. E connects to A, B, C, and F. F connects to A, B, and E" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p><strong>Benefits:</strong></p>
<ul>
<li><p>Memory-efficient for sparse graphs (that is, not all nodes are connected)</p>
</li>
<li><p>Easy to add or remove nodes and edges</p>
</li>
<li><p>Fast to get a node’s neighbors – just read its list</p>
</li>
</ul>
<p><strong>Downsides:</strong></p>
<ul>
<li><p>Slower edge lookup: To check if two nodes are connected, you have to scan a list</p>
</li>
<li><p>Can be inefficient for dense graphs where most nodes connect to many others</p>
</li>
<li><p>Sorting neighbors or accessing them by index is less convenient</p>
</li>
</ul>
<h3 id="heading-adjacency-matrix">Adjacency Matrix</h3>
<p>An adjacency matrix uses a 2D array (or grid) to represent connections between nodes. Each row and column corresponds to a node, and the cell at the intersection tells you whether there’s a connection.</p>
<ul>
<li><p>A value of <code>1</code> means there <strong>is</strong> an edge between the two nodes.</p>
</li>
<li><p>A value of <code>0</code> means an edge doesn’t exist between two nodes.</p>
</li>
</ul>
<p><strong>For an undirected graph</strong>, an edge between <code>i</code> and <code>j</code> means the connection works both ways. So if <code>(i, j)</code> is <code>1</code>, <code>(j, i)</code> is also <code>1</code>. This makes the matrix symmetric, that is, <code>(i, j) == (j, i)</code>.</p>
<p><strong>For a directed graph</strong>, an edge from node <code>i</code> to node <code>j</code> is at position <code>(i, j)</code>. But this doesn’t imply that there's an edge from <code>j</code> to <code>i</code>. So in general, <code>(i, j) ≠ (j, i)</code>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748378013560/6ecd11fc-bede-4dda-b01e-6f6d65f3bcb6.png" alt="A diagram showing a directed graph and its corresponding adjacency matrix. The adjacency matrix is a 6×6 table labeled with nodes A through F. A cell with a value of 1 indicates a directed edge from the row node to the column node.  Node A has outgoing edges to C, E, and F; Node B points to E and F; Node C connects to D and E; Node E connects to F. Nodes D and F have no outgoing edges." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p><strong>Benefits:</strong></p>
<ul>
<li><p>Instant edge lookup between any two nodes in <code>O(1)</code> time.</p>
</li>
<li><p>Simple to implement and often used in low-node-count, dense graphs.</p>
</li>
</ul>
<p><strong>Downsides:</strong></p>
<ul>
<li><p>High space complexity – even if the graph has few edges, the matrix still takes up <code>O(V²)</code> space.</p>
</li>
<li><p>Inefficient for sparse graphs, where many cells are unused.</p>
</li>
<li><p>Finding neighbors requires scanning an entire row, which takes <code>O(V)</code> time.</p>
</li>
</ul>
<h2 id="heading-graph-traversal">Graph Traversal</h2>
<p>Once you’ve built a graph using adjacency lists or matrices, the next question is: how do you explore it?</p>
<p>Graph traversal is the process of visiting each node (and its neighbors) in a graph in a specific order. It’s a foundational technique in computer science, used in everything from web crawling to friend suggestions on social media.</p>
<p>Traversal is used when:</p>
<ul>
<li><p>You want to search for a specific value or node.</p>
</li>
<li><p>You want to visit all nodes, for example, to analyze connectivity.</p>
</li>
<li><p>You want to solve puzzles, like mazes or routing problems.</p>
</li>
</ul>
<p>There are two primary ways to traverse a graph: <strong>Depth-First Search (DFS)</strong> and <strong>Breadth-First Search (BFS)</strong>. Let’s traverse through this graph using both methods:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748378930021/c8c46f1e-493d-4790-a48b-5059359bd3a4.png" alt="An undirected graph with labeled nodes (A–E)" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-breadth-first-search-bfs">Breadth-First Search (BFS)</h3>
<p>BFS starts from a node and explores all of its immediate neighbors before moving on to the neighbors of those neighbors.</p>
<p>It’s commonly used in:</p>
<ul>
<li><p>Finding the shortest path (in unweighted graphs)</p>
</li>
<li><p>Level-order traversal</p>
</li>
<li><p>Network broadcast simulations</p>
</li>
</ul>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> collections <span class="hljs-keyword">import</span> deque

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">bfs</span>(<span class="hljs-params">graph, start</span>):</span>
    visited = set()
    queue = deque([start])

    <span class="hljs-keyword">while</span> queue:
        node = queue.popleft()
        <span class="hljs-comment"># node has not been visited</span>
        <span class="hljs-keyword">if</span> node <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> visited:
            print(node)  <span class="hljs-comment"># Visit the node</span>
            visited.add(node)
            <span class="hljs-keyword">for</span> neighbor <span class="hljs-keyword">in</span> graph[node]:  <span class="hljs-comment"># Look at each neighbor of the current node</span>
                <span class="hljs-keyword">if</span> neighbor <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> visited:     
                    queue.append(neighbor)  

<span class="hljs-comment"># Undirected graph</span>
graph = {
    <span class="hljs-string">'A'</span>: [<span class="hljs-string">'B'</span>, <span class="hljs-string">'C'</span>],
    <span class="hljs-string">'B'</span>: [<span class="hljs-string">'A'</span>, <span class="hljs-string">'D'</span>],
    <span class="hljs-string">'C'</span>: [<span class="hljs-string">'A'</span>, <span class="hljs-string">'D'</span>],
    <span class="hljs-string">'D'</span>: [<span class="hljs-string">'B'</span>, <span class="hljs-string">'E'</span>],
    <span class="hljs-string">'E'</span>: [<span class="hljs-string">'D'</span>]
}

bfs(graph, <span class="hljs-string">'A'</span>)
</code></pre>
<p>Here’s the output of the code above:</p>
<pre><code class="lang-bash">A
B
C
D
E
</code></pre>
<h4 id="heading-what-this-code-does">What This Code Does:</h4>
<p><strong>Step 1: Choose a Starting Point</strong><br>Pick the node where you want to begin the traversal. Add it to a queue.</p>
<p><strong>Step 2: Visit the Node at the Front of the Queue</strong><br>Take the first node from the queue (this is your current node) and mark it as visited. Do something with it, like printing its value.</p>
<p><strong>Step 3: Add Its Neighbors to the Queue</strong><br>Look at all the nodes directly connected to the current node (its neighbors). For each neighbor, if it hasn't been visited yet, add it to the end of the queue.</p>
<p><strong>Step 4: Repeat Until the Queue Is Empty</strong><br>Go back to Step 2. Keep visiting the node at the front of the queue and enqueue its unvisited neighbors until no more nodes are left in the queue.</p>
<h3 id="heading-depth-first-search-dfs">Depth-First Search (DFS)</h3>
<p>DFS dives deep into one path of the graph before backtracking and exploring other branches.</p>
<p>It’s useful for:</p>
<ul>
<li><p>Cycle detection</p>
</li>
<li><p>Topological sorting</p>
</li>
<li><p>Solving puzzles like mazes (where the shortest path doesn’t matter)</p>
</li>
</ul>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">dfs</span>(<span class="hljs-params">graph, start</span>):</span>
    visited = set()
    stack = [start]

    <span class="hljs-keyword">while</span> stack:
        node = stack.pop()
        <span class="hljs-keyword">if</span> node <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> visited:
            print(node)  <span class="hljs-comment"># Visit the node</span>
            visited.add(node)
            <span class="hljs-keyword">for</span> neighbor <span class="hljs-keyword">in</span> graph[node]:
                <span class="hljs-keyword">if</span> neighbor <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> visited:
                    stack.append(neighbor)


<span class="hljs-comment"># Example graph (same as before)</span>
graph = {
    <span class="hljs-string">'A'</span>: [<span class="hljs-string">'B'</span>, <span class="hljs-string">'C'</span>],
    <span class="hljs-string">'B'</span>: [<span class="hljs-string">'A'</span>, <span class="hljs-string">'D'</span>],
    <span class="hljs-string">'C'</span>: [<span class="hljs-string">'A'</span>, <span class="hljs-string">'D'</span>],
    <span class="hljs-string">'D'</span>: [<span class="hljs-string">'B'</span>, <span class="hljs-string">'E'</span>],
    <span class="hljs-string">'E'</span>: [<span class="hljs-string">'D'</span>]
}

dfs(graph, <span class="hljs-string">'A'</span>)
</code></pre>
<p>Here’s the output of the code above:</p>
<pre><code class="lang-bash">A
C
D
E
B
</code></pre>
<h4 id="heading-just-like-bfs-we">Just like BFS, we:</h4>
<ul>
<li><p>Track visited nodes with a set</p>
</li>
<li><p>Use a loop to process each node</p>
</li>
<li><p>Visit neighbors one by one</p>
</li>
</ul>
<p><strong>But here’s the important difference</strong>: DFS uses a <strong>stack</strong>, so it goes <em>deep</em> into one path until it can’t go further, then it backtracks and explores the next path. This makes it great for tasks like solving mazes or exploring all possibilities in a decision tree.</p>
<h3 id="heading-wrapping-up-graph-traversal"><strong>Wrapping Up Graph Traversal</strong></h3>
<p>Understanding how to traverse a graph is foundational to solving many real-world problems, from mapping routes to analyzing social networks. Whether you're using BFS to find the shortest path or DFS to explore deep relationships, choosing the right traversal method depends on the problem you're trying to solve.</p>
<h2 id="heading-knights-travails-a-real-world-graph-problem">Knight's Travails: A Real-World Graph Problem</h2>
<p>To bring graphs to life, let’s start with a simple example.</p>
<p>Imagine you're playing chess, and your knight is stuck in one corner of the board. Let’s say you want to move it to a specific square to defend your queen. What’s the fewest number of moves it’ll take to get there?</p>
<p>This is a classic graph problem.</p>
<p>Each square on the chessboard can be represented as a node. If a knight can legally move from one square to another, there's an edge between them. The knight’s movement rules – those L-shaped hops – define the graph’s edges. So if you think about it, you're navigating a graph, trying to find the shortest path from one node (start square) to another (target square).</p>
<p>Let’s break it down.</p>
<h3 id="heading-modeling-the-board-as-a-graph">Modeling the Board as a Graph</h3>
<ul>
<li><p>The chessboard is an 8x8 grid.</p>
</li>
<li><p>Each square is a node, identified by its coordinates <code>(x, y)</code> where <code>0 ≤ x &lt; 8</code> and <code>0 ≤ y &lt; 8</code>.</p>
</li>
<li><p>A knight has a maximum of <strong>8 possible moves</strong> from any position (some may be out of bounds).</p>
</li>
<li><p>The goal is to build a graph where each node connects to all valid knight moves from that square.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748383043887/83609e20-d41d-47d1-ba19-25887a96abcc.jpeg" alt="A chessboard labeled with coordinate pairs along the bottom and left edges. A knight is positioned at (4, 0). The x-axis runs from (0, 0) to (0, 7) across the bottom, and the y-axis runs from (0, 0) to (7, 0) up the left side. The board visually shows how squares are represented as coordinate pairs in a grid." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<h3 id="heading-bfs-or-dfs-choosing-the-right-tool">BFS or DFS? Choosing the Right Tool</h3>
<p>There are two traversal methods we discussed earlier, Breadth-First Search (BFS) and Depth-First Search (DFS). So, which one should we use to solve the Knight’s Travails problem?</p>
<p>Let’s think about what would happen if we used DFS.</p>
<p>DFS goes as deep as it can along one path before backtracking. So, if you use DFS to move the knight, it might follow a long, winding sequence of valid moves that eventually leads to the destination, say, in 7 moves.</p>
<p>But that doesn’t mean it’s the shortest path. The optimal path could have reached the target in just 3 or 4 moves, but DFS wouldn’t find that unless it happens to explore that exact path first.</p>
<p>Even worse, DFS doesn’t guarantee you’ll find the shortest path unless you exhaustively search every possibility and compare them, which is slow and inefficient for this kind of problem.</p>
<p>Now, here’s why BFS is a better fit.</p>
<p>BFS explores all positions the knight can reach in 1 move, then all positions reachable in 2 moves, then 3 moves, and so on. As soon as it finds the destination square, you can be sure it got there using the fewest possible steps, because it explores all shorter paths before any longer ones.</p>
<p>In short:</p>
<ul>
<li><p>DFS might reach the destination eventually, but not efficiently, and not necessarily via the shortest path.</p>
</li>
<li><p>BFS guarantees that the path it returns is the shortest in terms of the number of moves.</p>
</li>
</ul>
<p>That’s why, for problems like this, where minimum steps are the goal, BFS is the go-to approach.</p>
<h3 id="heading-implementing-knights-travails-with-bfs">Implementing Knight’s Travails with BFS</h3>
<p>To model the knight’s traversal across the board, we’ll use a class called <code>Square</code>. This class will help us track:</p>
<ul>
<li><p>The knight’s current position on the board (<code>x_coord</code>, <code>y_coord</code>)</p>
</li>
<li><p>A reference to its parent square, so we can reconstruct the shortest path once the destination is reached</p>
</li>
<li><p>Keep track of all valid next moves (its <code>children</code>), which represent the squares the knight can legally move to from the current position</p>
</li>
</ul>
<p>Here’s the initial class:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> collections <span class="hljs-keyword">import</span> deque

<span class="hljs-comment"># Class to represent a square on the chessboard</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Square</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, x_coord, y_coord, parent=None</span>):</span>
        self.x_coord = x_coord
        self.y_coord = y_coord
        self.parent = parent
        self.children = []
</code></pre>
<p>This setup is useful because we’re building a path tree: each move creates a child node, and we can trace our way back to the starting point using the <code>parent</code>.</p>
<h4 id="heading-how-does-a-knight-move">How Does a Knight Move?</h4>
<p>A knight in chess moves in an “<strong>L</strong>” shape, two steps in one direction and one step perpendicular to it. If the knight is at the center of an 8x8 chessboard, it can make up to 8 legal moves. These moves can be visualized as edges connecting one square (node) to others.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1748425100670/fbccffb8-4cc0-46eb-b67d-b206bd528bd6.jpeg" alt="A chessboard with a knight placed on e5. Dashed lines and red dots indicate the eight possible L-shaped moves the knight can make from that position. Each red dot marks a valid destination square according to the knight's movement pattern." class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Here’s how we can represent and generate those moves:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> collections <span class="hljs-keyword">import</span> deque

<span class="hljs-comment"># Class to represent a square on the chessboard</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Square</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, x_coord, y_coord, parent=None</span>):</span>
        self.x_coord = x_coord
        self.y_coord = y_coord
        self.parent = parent
        self.children = []

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">generate_legal_moves</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-comment"># All 8 possible knight moves (in L-shape)</span>
        row_moves = [<span class="hljs-number">-2</span>, <span class="hljs-number">-1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">-1</span>, <span class="hljs-number">-2</span>]
        col_moves = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">-1</span>, <span class="hljs-number">-2</span>, <span class="hljs-number">-2</span>, <span class="hljs-number">-1</span>]

        <span class="hljs-keyword">for</span> dx, dy <span class="hljs-keyword">in</span> zip(row_moves, col_moves):
            nx, ny = self.x_coord + dx, self.y_coord + dy

            <span class="hljs-comment"># Only add valid board positions (0–7 for an 8x8 board)</span>
            <span class="hljs-keyword">if</span> <span class="hljs-number">0</span> &lt;= nx &lt; <span class="hljs-number">8</span> <span class="hljs-keyword">and</span> <span class="hljs-number">0</span> &lt;= ny &lt; <span class="hljs-number">8</span>:
                self.children.append(Square(nx, ny, self))
</code></pre>
<h4 id="heading-finding-the-shortest-path">Finding the Shortest Path</h4>
<p>Now that we have the <code>Square</code> class and the knight’s possible moves, we should implement BFS to find the shortest path from a starting square to a destination.</p>
<pre><code class="lang-python"><span class="hljs-comment"># BFS function to find the shortest path from start to end square</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">knight_travails</span>(<span class="hljs-params">start_coords, end_coords</span>):</span>
    <span class="hljs-comment"># Initialize the BFS queue with the starting square</span>
    start_x, start_y = start_coords
    queue = deque([Square(start_x, start_y)])
    <span class="hljs-comment"># Set to track visited positions and prevent revisiting</span>
    visited = set()
    end_coords = tuple(end_coords)

    <span class="hljs-keyword">while</span> queue:
        current = queue.popleft()
        coords = (current.x_coord, current.y_coord)

        <span class="hljs-comment"># If this square is the target, we've found the shortest path</span>
        <span class="hljs-keyword">if</span> coords == end_coords:
            <span class="hljs-keyword">return</span> current

        <span class="hljs-comment"># Skip, if this position has already been visited</span>
        <span class="hljs-keyword">if</span> coords <span class="hljs-keyword">in</span> visited:
            <span class="hljs-keyword">continue</span>

        visited.add(coords)

        <span class="hljs-comment"># Generate all legal knight moves from the current square</span>
        current.generate_legal_moves()
        <span class="hljs-comment"># Append children to queue</span>
        queue.extend(current.children)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">construct_path</span>(<span class="hljs-params">start, end</span>):</span>
    <span class="hljs-comment"># Run BFS to get the final square</span>
    end_square = knight_travails(start, end)
    path = []

    <span class="hljs-comment"># Trace back from the end square to the start using the parent links</span>
    <span class="hljs-keyword">while</span> end_square:
        path.append((end_square.x_coord, end_square.y_coord))
        end_square = end_square.parent

    <span class="hljs-comment"># Reverse the path to show it from start to end</span>
    <span class="hljs-keyword">return</span> path[::<span class="hljs-number">-1</span>]
</code></pre>
<p>Once you’ve implemented the functions above, you can print the output like this:</p>
<pre><code class="lang-python">print(construct_path([<span class="hljs-number">3</span>, <span class="hljs-number">4</span>], [<span class="hljs-number">0</span>, <span class="hljs-number">1</span>]))
</code></pre>
<p>This returns the shortest sequence of moves the knight must take to travel from <code>[3, 4]</code> to <code>[0, 1]</code>. Sample output:</p>
<pre><code class="lang-python">[(<span class="hljs-number">3</span>, <span class="hljs-number">4</span>), (<span class="hljs-number">2</span>, <span class="hljs-number">2</span>), (<span class="hljs-number">0</span>, <span class="hljs-number">1</span>)]
</code></pre>
<p>Each tuple represents a square on the chessboard that the knight visits. This is the shortest possible path the knight can take (from start to end square) – and thanks to how BFS works, we know for sure that no shorter path exists. That guarantee of optimality is what makes Breadth-First Search a perfect fit here.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>From chessboards to road maps and airline routes, graphs are everywhere. They silently power much of the technology we rely on daily. Whether you're booking a flight, navigating a city, or getting a recommendation on your favorite app, graphs are often at work behind the scenes.</p>
<p>They allow you to model and solve complex real-world problems by connecting entities and exploring their relationships. So next time your Google Maps reroutes you, remember: graphs are the mechanism behind that magic. Once you start recognizing graphs, you start seeing the hidden structure behind apps, systems, and even games you use every day.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Binary Exponentiation Algorithm – Explained with Practical Examples ]]>
                </title>
                <description>
                    <![CDATA[ Binary exponentiation, also known as exponentiation by squaring, is a powerful algorithm used to efficiently calculate large powers of numbers. This technique is particularly useful in various fields of computer science, including cryptography, compe... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/binary-exponentiation-algorithm-explained-with-examples/</link>
                <guid isPermaLink="false">670d739fdb0a005601d5afdc</guid>
                
                    <category>
                        <![CDATA[ algorithms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ data structures ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Competitive programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MathJax ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sahil ]]>
                </dc:creator>
                <pubDate>Mon, 14 Oct 2024 19:40:15 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1728672475917/5eeec863-5481-42d8-8b1f-9c92915f570f.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Binary exponentiation, also known as exponentiation by squaring, is a powerful algorithm used to efficiently calculate large powers of numbers. This technique is particularly useful in various fields of computer science, including cryptography, competitive programming, and computer graphics.</p>
<p>In this article, we'll explore the concept of binary exponentiation, understand how it works, and implement it in code.</p>
<h2 id="heading-what-is-binary-exponentiation">What is Binary Exponentiation?</h2>
<p>Binary exponentiation is a method to compute \(a^n\) (a raised to the power of n) using only multiplications, instead of the naïve \(O(n)\) multiplications.</p>
<p>This significant improvement in efficiency makes it possible to calculate extremely large powers quickly, even when dealing with modular arithmetic.</p>
<h2 id="heading-how-binary-exponentiation-works">How Binary Exponentiation Works</h2>
<p>The key idea behind binary exponentiation is to break down the exponent into its binary representation and use the properties of exponents to simplify the calculation.</p>
<p>Let's break it down step by step:</p>
<ol>
<li><p>Convert the exponent <code>n</code> to its binary representation.</p>
</li>
<li><p>Initialize the result as 1 and the base as <code>a</code>.</p>
</li>
<li><p>Iterate through each bit of the binary representation of <code>n</code> from right to left: (a). If the current bit is 1, multiply the result by the current base. (b). Square the base (multiply it by itself).</p>
</li>
<li><p>Return the final result.</p>
</li>
</ol>
<p>For example, let's calculate \(3^{13}\):</p>
<ol>
<li><p>Convert 13 to binary: \(13_{10} = 1101_2\)</p>
</li>
<li><p>Initialize result = 1, base = 3</p>
</li>
<li><p>Iterate through the bits:</p>
<ul>
<li><p>Bit 1: result = \(1 *3 = 3\)<em>, base =</em> \(3 *3 = 9\)</p>
</li>
<li><p>Bit 0: result = 3, base = \(9 * 9 = 81\)</p>
</li>
<li><p>Bit 1: result = \(3 *81 = 243\)<em>, base =</em> \(81 *81 = 6561\)</p>
</li>
<li><p>Bit 1: result = \(243 * 6561 = 1,594,323\)</p>
</li>
</ul>
</li>
</ol>
<p>Thus, \(3^{13}=1,594,323.\)</p>
<h2 id="heading-why-binary-exponentiation-is-efficient">Why Binary Exponentiation is Efficient</h2>
<p>The efficiency of binary exponentiation comes from two main factors:</p>
<ol>
<li><p><strong>Reduced number of multiplications</strong>: Instead of performing <code>n-1</code> multiplications as in the naïve approach, we only perform \(O(log n)\) multiplications. This is because we're essentially breaking down the problem into smaller subproblems based on the binary representation of the exponent.</p>
</li>
<li><p><strong>Reuse of previous calculations</strong>: By squaring the base at each step, we're reusing the results of previous calculations, which significantly reduces the overall number of operations needed.</p>
</li>
</ol>
<p>To illustrate this efficiency, consider calculating \(a^{1000000}\). The naïve approach would require 999,999 multiplications, while binary exponentiation would only require about 20 multiplications (as \(\log_2(1000000) \approx 20\)).</p>
<h2 id="heading-algorithm-implementation">Algorithm Implementation</h2>
<p>Let's implement the binary exponentiation algorithm in Python:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">binary_exponentiation</span>(<span class="hljs-params">base, exponent</span>):</span>
    result = <span class="hljs-number">1</span>
    <span class="hljs-keyword">while</span> exponent &gt; <span class="hljs-number">0</span>:
        <span class="hljs-comment"># If the current bit is 1, multiply the result by the current base</span>
        <span class="hljs-keyword">if</span> exponent &amp; <span class="hljs-number">1</span>:
            result *= base
        <span class="hljs-comment"># Square the base</span>
        base *= base
        <span class="hljs-comment"># Move to the next bit</span>
        exponent &gt;&gt;= <span class="hljs-number">1</span>
    <span class="hljs-keyword">return</span> result

<span class="hljs-comment"># Example usage</span>
print(binary_exponentiation(<span class="hljs-number">3</span>, <span class="hljs-number">13</span>))  <span class="hljs-comment"># Output: 1594323</span>
</code></pre>
<p>Let's break down the algorithm:</p>
<ol>
<li><p>We initialize <code>result</code> to 1, which is the identity for multiplication.</p>
</li>
<li><p>We use a while loop to iterate until the exponent becomes 0.</p>
</li>
<li><p>We check if the least significant bit of the exponent is 1 using the bitwise AND operator <code>&amp;</code>. If it is, we multiply the result by the current base.</p>
</li>
<li><p>We square the base by multiplying it by itself.</p>
</li>
<li><p>We use the right shift operator <code>&gt;&gt;=</code> to move to the next bit of the exponent.</p>
</li>
<li><p>Finally, we return the result.</p>
</li>
</ol>
<h3 id="heading-time-complexity-analysis">Time Complexity Analysis</h3>
<p>The time complexity of binary exponentiation is \(O(log n)\), where <code>n</code> is the exponent. This is because:</p>
<ol>
<li><p>The number of bits in the binary representation of <code>n</code> is \(\lfloor \log_2 n\rfloor + 1\).</p>
</li>
<li><p>We perform at most two multiplications per bit (one for squaring the base, and potentially one for updating the result).</p>
</li>
</ol>
<p>Therefore, the total number of multiplications is at most \(2(\lfloor \log_2 n \rfloor + 1)\), which simplifies to \(O(\log n)\).</p>
<h2 id="heading-example-problems-and-solutions">Example Problems and Solutions</h2>
<p>Let's look at some algorithmic problems that you can solve efficiently using binary exponentiation, along with detailed explanations of the solutions and how we arrived at using binary exponentiation.</p>
<h3 id="heading-problem-1-modular-exponentiation">Problem 1: Modular Exponentiation</h3>
<p><strong>Problem</strong>: Calculate \(3^{1000000} \bmod 1000000007\).</p>
<p><strong>Approach</strong>:</p>
<ol>
<li><p>We recognize that this problem involves a very large exponent (1000000), which would be impractical to compute using naïve exponentiation.</p>
</li>
<li><p>We also notice that we need to find the result modulo a large prime number (1000000007).</p>
</li>
<li><p>This combination of a large exponent and modular arithmetic is a clear indicator that we should use modular binary exponentiation.</p>
</li>
</ol>
<p><strong>Solution</strong>: We'll modify our binary exponentiation function to include modular arithmetic:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">mod_binary_exponentiation</span>(<span class="hljs-params">base, exponent, mod</span>):</span>
    result = <span class="hljs-number">1</span>
    base %= mod
    <span class="hljs-keyword">while</span> exponent &gt; <span class="hljs-number">0</span>:
        <span class="hljs-keyword">if</span> exponent &amp; <span class="hljs-number">1</span>:
            result = (result * base) % mod
        base = (base * base) % mod
        exponent &gt;&gt;= <span class="hljs-number">1</span>
    <span class="hljs-keyword">return</span> result

print(mod_binary_exponentiation(<span class="hljs-number">3</span>, <span class="hljs-number">1000000</span>, <span class="hljs-number">1000000007</span>))  <span class="hljs-comment"># Output: 624098969</span>
</code></pre>
<p><strong>Explanation</strong>:</p>
<ol>
<li><p>We initialize <code>result</code> to 1 and set <code>base</code> to <code>base % mod</code> to handle cases where the initial base is larger than the modulus.</p>
</li>
<li><p>The main loop works similarly to the original binary exponentiation algorithm, but with two key differences:</p>
<p> a. When updating <code>result</code>, we perform <code>(result * base) % mod</code>. This ensures that <code>result</code> never exceeds <code>mod</code>, preventing integer overflow and maintaining the correct modular result.</p>
<p> b. When squaring <code>base</code>, we perform <code>(base * base) % mod</code> for the same reason.</p>
</li>
<li><p>The bitwise operations (<code>exponent &amp; 1</code> and <code>exponent &gt;&gt;= 1</code>) work exactly as in the original algorithm, allowing us to process the binary representation of the exponent efficiently.</p>
</li>
<li><p>By applying the modulo operation at each step, we ensure that all intermediate results remain within the range [0, mod-1]. This is possible because of the properties of modular arithmetic:</p>
<p> $$(a⋅b)modm=((amodm)⋅(bmodm))modm$$</p>
</li>
</ol>
<p>This problem would be impossible to solve with naïve exponentiation due to the huge result, but modular binary exponentiation makes it tractable by keeping all intermediate results manageable.</p>
<h3 id="heading-problem-2-matrix-exponentiation">Problem 2: Matrix Exponentiation</h3>
<p><strong>Problem</strong>: Given a 2x2 matrix A, calculate An where n = 1000000.</p>
<p><strong>Approach</strong>:</p>
<ol>
<li><p>We observe that we need to raise a matrix to a very large power (1000000).</p>
</li>
<li><p>Matrix multiplication is associative, which allows us to use the same principle as binary exponentiation for numbers.</p>
</li>
<li><p>We recognize that this is a perfect scenario for applying binary exponentiation to matrices.</p>
</li>
</ol>
<p><strong>Solution</strong>: We can use binary exponentiation on matrices. Here's a Python implementation with explanations:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">matrix_multiply</span>(<span class="hljs-params">A, B, mod</span>):</span>
    <span class="hljs-keyword">return</span> np.array([[(A[<span class="hljs-number">0</span>][<span class="hljs-number">0</span>]*B[<span class="hljs-number">0</span>][<span class="hljs-number">0</span>] + A[<span class="hljs-number">0</span>][<span class="hljs-number">1</span>]*B[<span class="hljs-number">1</span>][<span class="hljs-number">0</span>]) % mod, (A[<span class="hljs-number">0</span>][<span class="hljs-number">0</span>]*B[<span class="hljs-number">0</span>][<span class="hljs-number">1</span>] + A[<span class="hljs-number">0</span>][<span class="hljs-number">1</span>]*B[<span class="hljs-number">1</span>][<span class="hljs-number">1</span>]) % mod],
                     [(A[<span class="hljs-number">1</span>][<span class="hljs-number">0</span>]*B[<span class="hljs-number">0</span>][<span class="hljs-number">0</span>] + A[<span class="hljs-number">1</span>][<span class="hljs-number">1</span>]*B[<span class="hljs-number">1</span>][<span class="hljs-number">0</span>]) % mod, (A[<span class="hljs-number">1</span>][<span class="hljs-number">0</span>]*B[<span class="hljs-number">0</span>][<span class="hljs-number">1</span>] + A[<span class="hljs-number">1</span>][<span class="hljs-number">1</span>]*B[<span class="hljs-number">1</span>][<span class="hljs-number">1</span>]) % mod]])

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">matrix_power</span>(<span class="hljs-params">A, n, mod</span>):</span>
    result = np.eye(<span class="hljs-number">2</span>, dtype=int)
    <span class="hljs-keyword">while</span> n &gt; <span class="hljs-number">0</span>:
        <span class="hljs-keyword">if</span> n &amp; <span class="hljs-number">1</span>:
            result = matrix_multiply(result, A, mod)
        A = matrix_multiply(A, A, mod)
        n &gt;&gt;= <span class="hljs-number">1</span>
    <span class="hljs-keyword">return</span> result

A = np.array([[<span class="hljs-number">1</span>, <span class="hljs-number">1</span>], [<span class="hljs-number">1</span>, <span class="hljs-number">0</span>]])
n = <span class="hljs-number">1000000</span>
mod = <span class="hljs-number">1000000007</span>

result = matrix_power(A, n, mod)
print(result)  <span class="hljs-comment"># Output: [[690749268 297612485]</span>
                <span class="hljs-comment">#         [297612485 393136783]]</span>
</code></pre>
<p><strong>Explanation</strong>:</p>
<ol>
<li><p><code>matrix_multiply(A, B, mod)</code>:</p>
<ul>
<li><p>This function performs matrix multiplication of two 2x2 matrices, A and B.</p>
</li>
<li><p>Each element of the resulting matrix is computed using the standard matrix multiplication formula, followed by a modulo operation to keep the values manageable.</p>
</li>
</ul>
</li>
<li><p><code>matrix_power(A, n, mod)</code>:</p>
<ul>
<li><p>This function implements binary exponentiation for matrices.</p>
</li>
<li><p>We start with <code>result</code> as the 2x2 identity matrix (created using <code>np.eye(2, dtype=int)</code>).</p>
</li>
<li><p>The main loop follows the same pattern as scalar binary exponentiation: a. If the current bit of n is 1, we multiply <code>result</code> by the current <code>A</code>. b. We square <code>A</code> (by multiplying it with itself). c. We right-shift n to move to the next bit.</p>
</li>
<li><p>All matrix multiplications are done using our <code>matrix_multiply</code> function, which incorporates modular arithmetic.</p>
</li>
</ul>
</li>
</ol>
<p>This matrix exponentiation technique is particularly powerful for solving linear recurrence relations in logarithmic time, as demonstrated here with the Fibonacci sequence.</p>
<h2 id="heading-practice-problems">Practice Problems</h2>
<p>Here are some problems for you to solve using binary exponentiation:</p>
<ol>
<li><p><strong>Modular Exponentiation</strong>: Calculate \(7^{1234567} \bmod 1000000009\). (Hint: Use the <code>mod_binary_exponentiation</code> function from Problem 1 in the examples.)</p>
</li>
<li><p><strong>Last Digit</strong>: Find the last digit of . (Hint: Observe the pattern of last digits of powers of 2 and use binary exponentiation with modulo 10.)</p>
</li>
<li><p><strong>Power Tower</strong>: Calculate the last 3 digits of \(2^{2^{20}}\). (Hint: Use the property of modular arithmetic that \(a^b \bmod m = a^{b \bmod \phi(m)} \bmod m\) where \(\phi\) is Euler's totient function. You'll need to calculate \(2^{20} \bmod \phi(1000)\) first.)</p>
</li>
<li><p><strong>Matrix Chains</strong>: Given a 2x2 matrix A = [[1, 2], [3, 4]], calculate the last two digits of the sum of all elements in \(A^{1000000}\). (Hint: Use matrix exponentiation as in Problem 2 from the examples, but only keep track of the last two digits of each element. You'll need to sum the elements after the final exponentiation.)</p>
</li>
<li><p><strong>Fibonacci Sequence</strong>: Find the 1000000th Fibonacci number modulo 1000000007. (Hint: Use the matrix form of the Fibonacci sequence ([[1, 1], [1, 0]]) and apply matrix exponentiation as shown in Problem 2 of the examples.)</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Binary exponentiation is a powerful technique that can be applied to a wide range of problems involving large exponents. As we've seen in the example and practice problems, it's particularly useful in modular arithmetic, matrix operations, and solving recurrence relations.</p>
<p>By practicing these problems, you'll gain a deeper understanding of how to apply binary exponentiation in various scenarios. Remember, the key is to recognize when a problem involves raising something to a large power, whether it's a number, a matrix, or even a more complex structure.</p>
<p>If you found this explanation of Binary Exponentiation algorithm helpful, you might also enjoy more in-depth programming tutorials and concepts I cover on my <a target="_blank" href="https://blog.theenthusiast.dev">blog</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Intro to Stacks – Data Structure and Algorithm Tutorial ]]>
                </title>
                <description>
                    <![CDATA[ Understanding the stack data structure is important for anyone interested in computer science. It is a key data structure used in many programs and also coding challenges. Understanding stacks can help you in technical interviews. We just posted a co... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/intro-to-stacks-data-structure-and-algorithm-tutorial/</link>
                <guid isPermaLink="false">66b203a9eea9870582e16c71</guid>
                
                    <category>
                        <![CDATA[ data structures ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Tue, 19 Mar 2024 15:08:15 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/03/stacks.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Understanding the stack data structure is important for anyone interested in computer science. It is a key data structure used in many programs and also coding challenges. Understanding stacks can help you in technical interviews.</p>
<p>We just posted a course on the freeCodeCamp.org YouTube channel that will help you master the stack data structure. The course is a deep dive into one of the most fundamental and powerful data structures in computer science. Parth from Destination FAANG developed this course.</p>
<p>Stacks are dynamic data structures that follow the Last In, First Out (LIFO) principle, where the last element added to the stack is the first one to be removed. This course, enriched with diagrams and code examples, will provide you with a solid understanding of stacks and prepare you to ace those crucial interview questions.</p>
<p>Here are the sections in the coruse:</p>
<h3 id="heading-introduction-to-stacks"><strong>Introduction to Stacks</strong></h3>
<p>The course begins with an introduction to the stack data structure, explaining its LIFO nature and its analogy to a stack of plates. You'll learn about the basic operations of push (adding an item to the top), pop (removing the top item), and peek (viewing the top item without removing it), illustrated with Java examples:</p>
<pre><code class="lang-java">Stack&lt;Integer&gt; stack = <span class="hljs-keyword">new</span> Stack&lt;&gt;();
stack.push(<span class="hljs-number">10</span>); <span class="hljs-comment">// Pushes 10 on the stack</span>
stack.push(<span class="hljs-number">20</span>); <span class="hljs-comment">// Pushes 20 on the stack</span>
stack.pop();    <span class="hljs-comment">// Removes the top item (20)</span>
<span class="hljs-keyword">int</span> top = stack.peek(); <span class="hljs-comment">// Returns 10 without removing it</span>
</code></pre>
<h3 id="heading-implementation-operations-and-use-cases">Implementation, Operations, and Use Cases</h3>
<p>This section covers the internal workings of stacks, showcasing how to implement a stack in Java using arrays or linked lists. You'll explore advanced stack operations and delve into practical use cases, such as undo mechanisms in text editors, parsing expressions, and backtracking algorithms.</p>
<h3 id="heading-when-to-use-stacks">When to Use Stacks</h3>
<p>Understanding when and where to apply stacks is crucial. This part of the course will guide you through scenarios where stacks shine, including function call management, syntax parsing, and maintaining histories in applications.</p>
<h3 id="heading-ace-your-interviews-with-these-stack-questions">Ace Your Interviews with These Stack Questions</h3>
<p>The course includes a dedicated section to prepare you for interviews, focusing on the 10 most popular stack-related questions. Each problem is broken down, explained, and solved with Java code to enhance your problem-solving skills and stack understanding.</p>
<ol>
<li><strong>Daily Temperatures</strong>: Learn how to use a stack to find the number of days until a warmer temperature.</li>
<li><strong>Evaluate Reverse Polish Notation</strong>: Decode and evaluate expressions in Reverse Polish Notation using stacks.</li>
<li><strong>Valid Parentheses</strong>: Use a stack to check for the validity of parentheses in a string.</li>
<li><strong>Min Stack</strong>: Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.</li>
<li><strong>Generate Parentheses</strong>: Discover how to generate all combinations of well-formed parentheses with stacks.</li>
<li><strong>Car Fleet</strong>: Understand how to apply stacks to solve complex problems like the car fleet challenge.</li>
<li><strong>Minimum Remove to Make Valid Parentheses</strong>: Use stacks to balance parentheses in a string efficiently.</li>
<li><strong>Largest Rectangle in Histogram</strong>: Tackle this classic problem with a stack-based approach to find the largest rectangular area.</li>
<li><strong>Longest Valid Parentheses</strong>: Learn to use stacks to find the length of the longest valid parentheses substring.</li>
<li><strong>Max Stack</strong>: Design a max stack that supports all regular stack operations along with retrieving the stack's maximum element.</li>
</ol>
<h3 id="heading-your-path-to-stack-mastery">Your Path to Stack Mastery</h3>
<p>By the end of this course, you'll have a deep understanding of stacks, equipped with the knowledge to implement and utilize them effectively in various scenarios. Whether you're preparing for an interview or looking to solidify your understanding of data structures, this course offers a comprehensive guide to mastering stacks with real-world applications and interview-ready questions.</p>
<p>Watch the full course on the <a target="_blank" href="https://www.youtube.com/watch?v=k1IaYPGel3s">freeCodeCamp.org YouTube channel</a> (3-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/k1IaYPGel3s" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is a Linked list? Types of Linked List with Code Examples ]]>
                </title>
                <description>
                    <![CDATA[ A linked list is a linear data structure consisting of a sequence of nodes. Unlike arrays, linked lists do not require contiguous memory allocation. Instead, each node is dynamically allocated its own memory space.  Nodes are connected through refere... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-a-linked-list-types-and-examples/</link>
                <guid isPermaLink="false">66ba2fe64d935175898a7086</guid>
                
                    <category>
                        <![CDATA[ data structures ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ PHP ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sule-Balogun Olanrewaju ]]>
                </dc:creator>
                <pubDate>Mon, 18 Mar 2024 15:25:17 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/03/john-petter-fagerhaug-nlT3NvhGKt8-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>A linked list is a linear data structure consisting of a sequence of nodes. Unlike arrays, linked lists do not require contiguous memory allocation. Instead, each node is dynamically allocated its own memory space. </p>
<p>Nodes are connected through references, forming the linked structure. One advantage of linked lists is that insertion and deletion of elements at the beginning of the list can be done in constant time, denoted as O(1). </p>
<p>This efficiency stems from the ability to directly manipulate references without needing to shift elements as required in arrays. Data types in a linked list can be any of the available data types supported by a programming language.</p>
<p>In this tutorial, you'll learn the following:</p>
<ul>
  <li><a href="#understanding-linked-list">Understanding Linked list</a></li>
  <li><a href="#types-of-linked-list">Types of Linked List</a></li>
    <li><a href="#summary-of-operations">Summary of operations with their respective time and space complexities in tabular format.</a></li>
  <li><a href="#differentiate-between-array-and-linked-list">Differences Between Array and Linked list.</a></li>
  <li><a href="#how-to-solve-the-remove-duplicates-from-sorted-list-problem">Algorithm: Solve the Remove Duplicates from Sorted list in PHP and JavaScript.</a></li>
</ul>

<h2 id="understanding-linked-list"> Understanding Linked list </h2>

<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/Untitled-2024-01-31-1554.png" alt="Untitled-2024-01-31-1554" width="600" height="400" loading="lazy"></p>
<p>head =&gt; Points to the first box in the list<br>tail =&gt; Points to the last box in the list</p>
<p>To access the data in the first box</p>
<p>head.data =&gt; 6</p>
<p>To access the data in the second box, we first need to set the pointer (arrow) to point to the box. Hence we need the (next)<br>head.next =&gt; This points to the next item on the list<br>head.next.data =&gt; 4</p>
<p>To access the data in the third box, we first need to set the pointer (arrow) to point to the box. Hence we need the (next.next)<br>head.next.next =&gt; This points to the next &gt; next item on the list<br>head.next.next.data =&gt; 5</p>
<h3 id="heading-what-is-a-node">What is a node ?</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/node.png" alt="node" width="600" height="400" loading="lazy"></p>
<p>A node in a linked list is an example of a self-referential structure in programming. This structure is comprised of elements called nodes, where each node contains both data and a reference to another node of the same type. This reference, often termed a 'pointer,' facilitates the creation of a chain-like structure, where nodes are interconnected, forming the linked list.</p>
<p>The self-referential nature of nodes allows for efficient traversal and manipulation of data within the linked list. The structure can be implemented using classes or arrays</p>
<h3 id="heading-how-to-implement-a-linked-list-using-classes">How to Implement a Linked List Using classes</h3>
<pre><code class="lang-php"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Node</span> </span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params">
        <span class="hljs-keyword">public</span> $data,
        <span class="hljs-keyword">public</span> ?Node $next = <span class="hljs-literal">null</span>
    </span>) </span>{}
}

<span class="hljs-comment">// Creating nodes</span>

$node1 = <span class="hljs-keyword">new</span> Node(<span class="hljs-number">10</span>);
$node2 = <span class="hljs-keyword">new</span> Node(<span class="hljs-number">20</span>);
$node3 = <span class="hljs-keyword">new</span> Node(<span class="hljs-number">30</span>);

<span class="hljs-comment">// Linking nodes</span>

$node1-&gt;next = $node2;
$node2-&gt;next = $node3;

<span class="hljs-comment">// Traversing linked list</span>

$current = $node1;
<span class="hljs-keyword">while</span> ($current != <span class="hljs-literal">null</span>) {
    <span class="hljs-keyword">echo</span> $current-&gt;data . <span class="hljs-string">" "</span>;
    $current = $current-&gt;next;
}
</code></pre>
<h3 id="heading-how-to-implement-a-linked-list-using-using-arrays">How to Implement a Linked List Using Using arrays</h3>
<pre><code class="lang-php"><span class="hljs-comment">// creating nodes as an associative array</span>

$node1 = [<span class="hljs-string">'data'</span> =&gt; <span class="hljs-number">10</span>, <span class="hljs-string">'next'</span> =&gt; <span class="hljs-literal">null</span>];
$node2 = [<span class="hljs-string">'data'</span> =&gt; <span class="hljs-number">20</span>, <span class="hljs-string">'next'</span> =&gt; <span class="hljs-literal">null</span>];
$node3 = [<span class="hljs-string">'data'</span> =&gt; <span class="hljs-number">30</span>, <span class="hljs-string">'next'</span> =&gt; <span class="hljs-literal">null</span>];

<span class="hljs-comment">// linking nodes</span>

$node1[<span class="hljs-string">'next'</span>] = &amp;$node2;
$node2[<span class="hljs-string">'next'</span>] = &amp;$node3;

<span class="hljs-comment">// Traversing linked list</span>

$current = $node1;
<span class="hljs-keyword">while</span> ($current != <span class="hljs-literal">null</span>) {
  <span class="hljs-keyword">echo</span> $current[<span class="hljs-string">"data"</span>] . <span class="hljs-string">" "</span>;
  $current = &amp;$current[<span class="hljs-string">"next"</span>];
}
</code></pre>
<p>In both cases, we create a structure where each element (node) contains data and a reference (next) to another element of the same type. This creates a self-referential structure. We then link these elements together to form a data structure like a linked list. Finally, we traverse the structure to access and manipulate its elements.</p>
<p>Unlike an array, a linked list doesn't provide constant time access to a particular index within the list. This means that if you'd like to find the nth element in the list, you'll need to traverse through to the nth element. </p>
<p>Traversing a linked list means iterating through each node of the list until the end node is reached.</p>
<h2 id="types-of-linked-list"> Types of Linked list</h2>

<p>We'll discuss the types under the Traversal, Memory and Complexity categories.</p>
<h2 id="heading-singly-linked-list">Singly Linked List</h2>
<p>Each node has data and a reference to the next node. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/singly-2.png" alt="singly linked list" width="600" height="400" loading="lazy"></p>
<h3 id="heading-non-code-explanation">Non-code explanation</h3>
<p>Imagine taking a journey by train, where each train represents a part of your trip, and each station represents a point where you need to make a change.</p>
<ul>
<li>Train A represents the first part of your journey, taking you from Station A to Station B. When you arrive at Station B, there's a sign directing you to switch trains to continue your journey.</li>
<li>Train B represents the second part of your journey, taking you from Station B to Station C. Again, when you arrive at Station C, there's no sign for another train because you've reached your final destination.</li>
</ul>
<p>In this analogy:</p>
<ul>
<li>Each train segment (Train A, Train B, and Train C) represent a node in the singly linked list.</li>
<li>The task of each train is analogous to the data stored in each node, representing a segment of your journey.</li>
<li>The transition between trains at each station is analogous to the "next" pointer in a linked list, indicating the next segment of your journey.</li>
<li>At the final destination (Station C), there's no need for a pointer or sign to another train because it's the end of your journey.</li>
</ul>
<p>In simpler terms, a singly linked list is like a train journey with different segments, where each train (node) has the task of taking you from one station to the next until you reach your final destination. The transitions between trains are like pointers, guiding you through each segment of your journey.</p>
<h3 id="heading-performance-characteristics-of-singly-linked-list">Performance Characteristics of Singly Linked List</h3>
<ol>
<li><strong>Traversal:</strong> Traversal is allowed only in one direction (that is, forward only). You can move forward through the list, but you cannot easily move backward. </li>
<li><strong>Memory Efficiency:</strong> Singly linked list is generally more memory-efficient because it requires only one reference per node. </li>
<li><strong>Complexity:</strong> Insertion and Deletion operation is easier as you only need to update references in one direction.</li>
</ol>
<h3 id="heading-time-and-space-complexity">Time and Space Complexity</h3>
<p>I wrote about constant and linear time complexity <a target="_blank" href="https://www.freecodecamp.org/news/what-is-a-hash-map/">here</a>, and we'll be using that to discuss the general time and space complexities for some common operations:</p>
<h4 id="heading-traversal">Traversal</h4>
<p>Time complexity O(n), where n is the number of nodes in the list. Space complexity O(1), it doesn't require additional space proportional to the input size.</p>
<h4 id="heading-insertion-at-the-beginning">Insertion at the Beginning</h4>
<p>Time complexity O(1), it involves updating references at the head. Space complexity O(1), it doesn't require additional space proportional to the input size.</p>
<h4 id="heading-insertion-at-the-end">Insertion at the End</h4>
<p>Time complexity O(n), it may require traversing the entire list to reach the end. Space complexity O(1), it doesn't require additional space proportional to the input size.</p>
<h4 id="heading-deletion-at-the-beginning">Deletion at the Beginning</h4>
<p>Time complexity O(1), it involves updating references at the head. Space complexity O(1), constant.</p>
<h4 id="heading-deletion-at-the-end">Deletion at the End</h4>
<p>Time complexity O(n), it may require traversing the entire list to reach the end. Space complexity O(1), constant.</p>
<h2 id="heading-doubly-linked-list">Doubly Linked List</h2>
<p>In a doubly linked list, the <code>head</code> node typically does not have a <code>prev</code> reference because it is the first node and therefore has no previous node. </p>
<p>However, the <code>head</code> node does have a <code>next</code> reference pointing to the next node in the list. Each node has data and references to both the next and previous nodes.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/doubly-1.png" alt="doubly-1inked-list" width="600" height="400" loading="lazy"></p>
<h3 id="heading-non-code-explanation-1">Non-code explanation</h3>
<p>Imagine that you have a book where each page represents a task you need to complete, just like items on your to-do list.</p>
<p>Each page does not only contain information about the task written on it but also has connections to the pages before and after it in the book.</p>
<ul>
<li>Page 1 (Task A) represents the first task in the book. It contains information about Task A and has an arrow pointing forward to Page 2 (Task B), indicating that Task B comes after Task A in the book. However, Page 1 does not have a backward arrow because it is the first page of the book and doesn't have a previous page.</li>
<li>Page 2 (Task B) contains information about Task B and has arrows pointing both forward to Page 3 (Task C) and backward to Page 1 (Task A), indicating that Task C comes after Task B and Task A comes before Task B in the book.</li>
<li>Page 3 (Task C) represents the last task in the book. It contains information about Task C and has an arrow pointing backward to Page 2 (Task B), indicating that Task B comes before Task C in the book.</li>
</ul>
<p>With this in mind, you can think of a doubly linked list as a book where each page not only contains information about a task but also provides easy navigation to the tasks before and after it. The first page, similar to the head of a doubly linked list, does not have a previous reference, while the last page, similar to the tail of a doubly linked list, does not have a next reference</p>
<h3 id="heading-performance-characteristics-of-doubly-linked-lists">Performance Characteristics of Doubly Linked Lists</h3>
<ol>
<li><strong>Traversal:</strong> Doubly linked lists allow traversal in both directions — forward and backward. This bidirectional traversal enables more flexible navigation through the list, allowing operations such as iterating in reverse order.</li>
<li><strong>Memory Efficiency</strong>: Doubly linked lists typically require more memory compared to singly linked lists because each node contains two references (pointers) — one for the next node and one for the previous node. This additional memory overhead per node can impact the overall memory efficiency, especially for large lists.</li>
<li><strong>Complexity</strong>: Doubly linked lists offer bidirectional traversal and flexibility. Insertion and deletion operations may require updating references in both directions (forward and backward), which can increase the complexity and potentially impact performance.</li>
</ol>
<h3 id="heading-time-and-space-complexity-1">Time and Space Complexity</h3>
<h4 id="heading-traversal-1">Traversal</h4>
<p>The time and space complexity for this operation is the same with the singly linked list.</p>
<h4 id="heading-insertion-at-the-beginning-1">Insertion at the Beginning</h4>
<p>The time and space complexity for this operation is the same with the singly linked list.</p>
<h4 id="heading-insertion-at-the-end-1">Insertion at the End</h4>
<p>Time complexity for this operation takes O(1) time. This is because you have direct access to the tail node, so you can update the references without needing to traverse the entire list. Space complexity O(1), it doesn't require additional space proportional to the input size.</p>
<h4 id="heading-deletion-at-the-beginning-1">Deletion at the Beginning</h4>
<p>The time and space complexity for this operation is the same with the singly linked list.</p>
<h4 id="heading-deletion-at-the-end-1">Deletion at the End</h4>
<p>Time complexity for this operation takes O(1) time. This is because you have direct access to the tail node, so you can update the references without needing to traverse the entire list. Space complexity O(1), it doesn't require additional space proportional to the input size.</p>
<h2 id="heading-circular-linked-list">Circular Linked List</h2>
<p>A circular linked list is a type of linked list where the last node of the list points back to the first node, forming a circle or loop. This characteristic distinguishes it from a traditional linked list, where the last node typically points to null, indicating the end of the list. In a circular linked list, there is no null pointer at the end; instead, the last node points back to the first node, creating a loop structure. This looping behavior allows for continuous traversal through the list. The below image shows how a singly circular linked list works.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/circular-linked-list-1.png" alt="circular-linked-list-1" width="600" height="400" loading="lazy"></p>
<h3 id="heading-non-code-explanation-2">Non-code explanation</h3>
<p>Imagine a train line that forms a loop, with passengers boarding and exiting at various stations along the way. This loop represents a circular linked list, where each station is a node and the train continuously travels around the loop, picking up and dropping off passengers. </p>
<p>Just like in a circular linked list, the loop ensures continuous traversal without an end point, and passengers (data) can be added or removed at any station (node).  </p>
<p>The circular linked list offers advantages in certain applications but requires careful handling of pointers and memory management to maintain its circular structure and prevent issues such as infinite loops.</p>
<h3 id="heading-performance-characteristics-of-circular-linked-lists">Performance Characteristics of Circular Linked Lists</h3>
<ol>
<li><strong>Traversal:</strong> Circular linked lists enable traversal in a loop, allowing seamless navigation from one node to another regardless of the direction. This circular structure facilitates efficient traversal without needing to iterate back to the beginning when reaching the end, enhancing traversal performance.</li>
<li><strong>Memory Efficiency</strong>: Singly circular linked lists typically offer similar memory efficiency to singly linked lists, as they require only one pointer per node to connect to the next node in the sequence. This single-pointer structure results in lower memory overhead per node compared to doubly linked lists, potentially improving memory efficiency for large lists.</li>
<li><strong>Complexity:</strong> In singly circular linked lists, insertion and deletion operations require updating references to maintain the circular structure, introducing moderate complexity compared to linear linked lists.</li>
</ol>
<h3 id="heading-time-and-space-complexity-2">Time and Space Complexity</h3>
<h4 id="heading-traversal-2">Traversal</h4>
<p>Time Complexity: O(n) – Since you have to traverse through all the nodes in the list to reach the end. </p>
<p>Space Complexity: O(1) – Only a constant amount of extra space is required for a temporary variable to traverse the list.</p>
<h4 id="heading-insertion-at-the-beginning-2">Insertion at the Beginning</h4>
<p>Time Complexity: O(1) – Insertion at the beginning simply involves updating the references at the head. </p>
<p>Space Complexity: O(1) – No additional space is required.</p>
<h4 id="heading-insertion-at-the-end-2">Insertion at the End</h4>
<p>Time Complexity: O(n) – It may require traversing the entire list to reach the end where insertion needs to take place.</p>
<p>Space Complexity: O(1) – No additional space is required.</p>
<h4 id="heading-deletion-at-the-beginning-2">Deletion at the Beginning</h4>
<p>Time complexity O(1), it involves updating references at the head. </p>
<p>Space complexity O(1), constant.</p>
<h4 id="heading-deletion-at-the-end-2">Deletion at the End</h4>
<p>Time complexity O(n), it may require traversing the entire list to reach the end.</p>
<p>Space complexity O(1), constant.</p>
<h2 id="summary-of-operations"> Summary of Operations for the Time Complexity </h2>

<table>
<thead>
<tr>
<th>Operation</th>
<th>Singly Linked List</th>
<th>Doubly Linked List</th>
<th>Circular Linked List</th>
</tr>
</thead>
<tbody>
<tr>
<td>Traversal</td>
<td>O(n)</td>
<td>O(n)</td>
<td>O(n)</td>
</tr>
<tr>
<td>Insertion at Beginning</td>
<td>O(1)</td>
<td>O(1)</td>
<td>O(1)</td>
</tr>
<tr>
<td>Insertion at End</td>
<td>O(n)</td>
<td>O(1)</td>
<td>O(n)</td>
</tr>
<tr>
<td>Deletion at Beginning</td>
<td>O(1)</td>
<td>O(1)</td>
<td>O(1)</td>
</tr>
<tr>
<td>Deletion at End</td>
<td>O(n)</td>
<td>O(1)</td>
<td>O(n)</td>
</tr>
</tbody>
</table>


<h2 id="summary-of-operations"> Summary of Operations for the Space Complexity </h2>

<table>
<thead>
<tr>
<th>Operation</th>
<th>Singly Linked List</th>
<th>Doubly Linked List</th>
<th>Circular Linked List</th>
</tr>
</thead>
<tbody>
<tr>
<td>Traversal</td>
<td>O(1)</td>
<td>O(1)</td>
<td>O(1)</td>
</tr>
<tr>
<td>Insertion at Beginning</td>
<td>O(1)</td>
<td>O(1)</td>
<td>O(1)</td>
</tr>
<tr>
<td>Insertion at End</td>
<td>O(1)</td>
<td>O(1)</td>
<td>O(1)</td>
</tr>
<tr>
<td>Deletion at Beginning</td>
<td>O(1)</td>
<td>O(1)</td>
<td>O(1)</td>
</tr>
<tr>
<td>Deletion at End</td>
<td>O(1)</td>
<td>O(1)</td>
<td>O(1)</td>
</tr>
</tbody>
</table>

<h2 id="differentiate-between-array-and-linked-list"> Differences Between Array and Linked list </h2>

<p>A linked list is a dynamic way to represent a list, where adding and removing items from the beginning of the list typically involves changing only a few pointers. This operation can be performed in constant time, denoted as O(1), regardless of the list's size.</p>
<p>On the other hand, arrays are a sequential representation of a list. Adding or removing items from the beginning of the list requires shifting all subsequent elements to accommodate the change. This operation has a time complexity of O(n), where n is the number of elements in the array. Therefore, for large arrays, adding or removing items from the beginning can be relatively slow compared to linked lists.</p>
<h2 id="how-to-solve-the-remove-duplicates-from-sorted-list-problem"> How to Solve the Remove Duplicates from Sorted List Problem </h2>

<p>Explanation of the problem: Given the <code>head</code> of a sorted linked list, <em>delete all duplicates such that each element appears only once</em>. Return <em>the linked list <strong>sorted</strong></em> as well.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/algo-sample-3.png" alt="algo-sample-3" width="600" height="400" loading="lazy"></p>
<h3 id="heading-solution-in-php">Solution in PHP</h3>
<pre><code class="lang-php"><span class="hljs-comment">/**
 * Definition for a singly-linked list.
 * class ListNode {
 *     public $val = 0;
 *     public $next = null;
 *     function __construct($val = 0, $next = null) {
 *         $this-&gt;val = $val;
 *         $this-&gt;next = $next;
 *     }
 * }
 */</span>


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Solution</span> </span>{

    <span class="hljs-comment">/**
     * <span class="hljs-doctag">@param</span> ListNode $head
     * <span class="hljs-doctag">@return</span> ListNode
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">deleteDuplicates</span>(<span class="hljs-params">$head</span>) </span>{
        $node = $head;

        <span class="hljs-keyword">while</span>($node !== <span class="hljs-literal">null</span> &amp;&amp; $node-&gt;next !== <span class="hljs-literal">null</span>) {

            <span class="hljs-keyword">if</span> ($node-&gt;val == $node-&gt;next-&gt;val) {
                $node-&gt;next = $node-&gt;next-&gt;next;
            }<span class="hljs-keyword">else</span> {
                $node = $node-&gt;next;
            }   
        }

        <span class="hljs-keyword">return</span> $head;
    }
}
</code></pre>
<h3 id="heading-solution-in-javascript">Solution in JavaScript</h3>
<pre><code class="lang-javascript"><span class="hljs-comment">/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */</span>
<span class="hljs-comment">/**
 * <span class="hljs-doctag">@param <span class="hljs-type">{ListNode}</span> <span class="hljs-variable">head</span></span>
 * <span class="hljs-doctag">@return <span class="hljs-type">{ListNode}</span></span>
 */</span>


<span class="hljs-keyword">var</span> deleteDuplicates = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">head</span>) </span>{
    <span class="hljs-keyword">let</span> node = head;

    <span class="hljs-keyword">while</span>(node?.next) {

        <span class="hljs-keyword">if</span> (node.val === node.next.val) {
            node.next = node.next.next
        } <span class="hljs-keyword">else</span> {
            node = node.next
        }
    }

    <span class="hljs-keyword">return</span> head
};
</code></pre>
<p><strong>Code explanation</strong></p>
<p>Given the <code>deleteDuplicates</code> method:</p>
<ul>
<li><code>node</code> is initialized to the head of the linked list.</li>
<li>A while loop iterates through the linked list until the end or until the current node's <code>next</code> property is <code>null</code>.</li>
<li>Inside the loop, it checks if the current node's value is equal to the next node's value. If they are equal, it skips the next node by setting the current node's <code>next</code> property to the next node's <code>next</code> property.</li>
<li>If the values are not equal, it moves to the next node by updating the value of <code>node</code> to <code>node-&gt;next</code>.</li>
<li>Finally, the method returns the head of the modified linked list.</li>
</ul>
<p>The null safe operator (<code>?.</code>) used in the JS code solution is also available from PHP 8.0. </p>
<p>This code efficiently removes duplicates from a singly-linked list by adjusting pointers and has a time complexity of <code>_O_(_n_)</code> and a space complexity of <code>_O_(1)</code>, where <em><code>n</code></em> is the number of nodes in the linked list.</p>
<h2 id="heading-reference">Reference</h2>
<ul>
<li><a target="_blank" href="https://www.freecodecamp.org/news/how-linked-lists-work/">How does a linked list work</a></li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you learned about linked list, types of linked list and a real world problem that involves solving the removal of duplicates from sorted list.</p>
<p>Keep learning, and Happy Coding!</p>
<p>You can find me on <a target="_blank" href="https://www.linkedin.com/in/suleolanrewaju/">LinkedIn</a> and <a target="_blank" href="https://twitter.com/bigdevlarry">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Learn Data Structures and Algorithms in 48 Hours ]]>
                </title>
                <description>
                    <![CDATA[ In the realm of software development, mastering Data Structures and Algorithms could be a critical step towards securing your dream job. We just posted a course on the freeCodeCamp.org YouTube channel that will equip you with the knowledge to excel i... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/learn-data-structures-and-algorithms-2/</link>
                <guid isPermaLink="false">66b2042882069b4c678c98f3</guid>
                
                    <category>
                        <![CDATA[ data structures ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Tue, 20 Feb 2024 18:20:57 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/dsa.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In the realm of software development, mastering Data Structures and Algorithms could be a critical step towards securing your dream job.</p>
<p>We just posted a course on the freeCodeCamp.org YouTube channel that will equip you with the knowledge to excel in coding interviews and problem-solving. You will learn the important data structures and algorithms you need to know to develop efficient code.</p>
<h4 id="heading-course-overview">Course Overview</h4>
<p>The course is designed to cover the breadth and depth of topics necessary for placement preparations, coding interviews, and enhancing logical thinking capabilities. With a focus on real-world applications, the course ensures learners are not just memorizing code but truly understanding the principles behind the solutions. It walks you through various Java algorithms and data structure problems, accompanied by step-by-step visualizations to foster genuine learning.</p>
<p>Java, known for its versatility and widespread use, is the primary language used in this course. However, students with backgrounds in other programming languages like Javascript, Python, C#, C++, or C can also easily grasp the concepts taught. The course uniquely utilizes animated slides to demonstrate the implementation of various algorithms and data structures, making complex topics accessible and engaging.</p>
<h4 id="heading-what-you-will-learn">What You Will Learn</h4>
<p>This comprehensive course covers a wide array of topics to prepare you for technical interviews and software development challenges, including:</p>
<ul>
<li><p><strong>Algorithm Analysis</strong>: Understanding the efficiency and scalability of algorithms.</p>
</li>
<li><p><strong>Data Structures</strong>: Diving into arrays, matrices, linked lists (singly, doubly, and circular), stacks, queues, binary trees, binary search trees, graphs, priority queues, heaps, and the Trie data structure.</p>
</li>
<li><p><strong>Core Concepts</strong>: Exploring recursion, searching, sorting, strings, and dynamic programming.</p>
</li>
</ul>
<p>Each section is crafted to address common interview questions and scenarios, ensuring learners are well-prepared for the questions they might face in an actual interview setting.</p>
<h4 id="heading-why-choose-this-course">Why Choose This Course?</h4>
<ul>
<li><p><strong>Real-World Problem Solving</strong>: Learn how to approach and solve complex problems with optimal solutions.</p>
</li>
<li><p><strong>Visual Learning</strong>: Animated slides and step-by-step visualizations make learning interactive and effective.</p>
</li>
<li><p><strong>Comprehensive Coverage</strong>: From basic to advanced topics, this course has everything covered.</p>
</li>
<li><p><strong>Language Versatility</strong>: While Java is used, concepts are applicable across various programming languages.</p>
</li>
<li><p><strong>Interview Preparation</strong>: Specifically designed to tackle the most common interview challenges in the IT industry.</p>
</li>
</ul>
<h4 id="heading-conclusion">Conclusion</h4>
<p>Whether you're aiming to land a software engineering job or simply wish to deepen your understanding of data structures and algorithms, this course is for you. Watch the full course <a target="_blank" href="https://youtu.be/xwI5OBEnsZU">on the freeCodeCamp.org YouTube channel</a> (48-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/xwI5OBEnsZU" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is a Hash Map? Time Complexity and Two Sum Example ]]>
                </title>
                <description>
                    <![CDATA[ A hash table or hash map, is a data structure that helps with mapping keys to values for highly efficient operations like the lookup, insertion and deletion operations. In this tutorial, you'll learn the following: Constant and linear time complexit... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-a-hash-map/</link>
                <guid isPermaLink="false">66ba2fd8de9370f66eeb0aa1</guid>
                
                    <category>
                        <![CDATA[ algorithms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ data structures ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Hash tables ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Mapping ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sule-Balogun Olanrewaju ]]>
                </dc:creator>
                <pubDate>Thu, 25 Jan 2024 17:02:13 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/joan-gamell-ZS67i1HLllo-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>A hash table or hash map, is a data structure that helps with mapping keys to values for highly efficient operations like the lookup, insertion and deletion operations.</p>
<p>In this tutorial, you'll learn the following:</p>
<ul>
<li>Constant and linear time complexity.</li>
<li>Why use a hash map?</li>
<li>Things to consider when writing hash functions.</li>
<li>How to solve the Two Sum problem in PHP and JavaScript.</li>
</ul>
<h2 id="heading-what-is-constant-time-complexity-o1">What is Constant Time Complexity - O(1)?</h2>
<p>O(1) indicates that the running time of an algorithm is constant, regardless of the input size. </p>
<p>This implies that the algorithm's performance isn't dependent on the size of the input. An example is accessing an index of an array.</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">constantTimeAlgorithm</span>(<span class="hljs-params">$arr</span>) 
</span>{

    <span class="hljs-keyword">echo</span> $arr[<span class="hljs-number">0</span>] . PHP_EOL;
}
</code></pre>
<p>Here is a non-code example to illustrate the concept of constant time complexity:</p>
<p>Imagine sending a file through an airline to your friend, and the airline has a policy where they charge based on the weight of the package.</p>
<p>Now, whether your file weighs 2 grams or 20 kilograms, the airline's processing time remains constant. This means that the time it takes for the airline to handle your package doesn't depend on the weight of the file – it's always the same. </p>
<p>In other words, the processing time is constant irrespective of the size of the file.</p>
<h2 id="heading-what-is-linear-time-complexity-on">What is Linear Time Complexity - O(n)?</h2>
<p>O(n) indicates that the running time of an algorithm grows linearly with the size of the input. </p>
<p>The performance of the algorithm is directly proportional to the input size. An example is traversing a <code>for</code> loop and printing elements.</p>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">linearTimeAlgorithm</span>(<span class="hljs-params">$arr</span>) 
</span>{
    <span class="hljs-keyword">foreach</span> ($arr <span class="hljs-keyword">as</span> $element) {
        <span class="hljs-keyword">echo</span> $element . PHP_EOL;
    }
}
</code></pre>
<p>Here's a non-code example to illustrate the concept of linear time complexity:</p>
<p>Consider using an electronic transfer service to send a file to your friend. In this scenario, the time it takes to transfer the file increases linearly with the size of the file. </p>
<p>For instance, if it takes 1 minutes to transfer a 100 MB file, it would take approximately 100 minutes to transfer a 10 GB file using the same service. </p>
<p>This linear relationship between the size of the file and the time it takes to transfer it reflects linear time complexity. The time taken to transfer the file increases proportionally or linearly with the size of the input or file.</p>
<h2 id="heading-why-use-a-hash-map">Why use a Hash Map?</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/image-108.png" alt="Image" width="600" height="400" loading="lazy">
<em>Illustration of how a hash map works</em></p>
<p>A hash map is a concrete implementation of the abstract data type known as an associative array. </p>
<p>In a hash map, keys are hashed to determine the index where the corresponding values will be stored, allowing for efficient retrieval and storage of key-value pairs. </p>
<p>This implementation typically provides fast access times for operations like insertion, deletion, and lookup of values based on their associated keys. </p>
<p>In languages like PHP or JavaScript, when you use an associative array, you are essentially using a hash map. Their associative arrays are implemented using hash tables behind the scenes. </p>
<p>You can use strings, integers, or other data types as keys, and the language's internal hashing mechanism efficiently maps these keys to their corresponding values. Additionally, JavaScript provides the <code>Map</code> object for more advanced hash map functionalities.</p>
<h3 id="heading-time-and-space-complexity-for-hash-map">Time and Space Complexity for Hash Map</h3>
<p>The time and space complexity for a hash map (or hash table) is not necessarily O(n) for all operations. The typical and desired time complexity for basic operations like insertion, lookup, and deletion in a well-designed hash map is O(1) on average. </p>
<p>Here's a breakdown of time and space complexity for a hash map:</p>
<h4 id="heading-time-complexity">Time Complexity:</h4>
<p>Average Case:</p>
<ul>
<li>Insertion (average): O(1)</li>
<li>Lookup (average): O(1)</li>
<li>Deletion (average): O(1)</li>
</ul>
<p>Worst Case:</p>
<ul>
<li>Insertion (worst): O(n), where n is the size of the hash map. This occurs when there are many hash collisions, leading to linear probing or other collision resolution strategies that may involve traversing the entire hash map.</li>
<li>Lookup and Deletion (worst): O(n), for the same reason as insertion.</li>
</ul>
<h4 id="heading-space-complexity">Space Complexity:</h4>
<ul>
<li>The space complexity is typically O(n). Where n is the number of key-value pairs stored in the hash map. Each key-value pair occupies constant space, and the space required grows linearly with the number of elements.</li>
</ul>
<p>In algorithm analysis, the notation O(1) and O(n) represent the upper bounds on the time complexity of an algorithm, where n is the size of the input.</p>
<h4 id="heading-operations">Operations</h4>
<ol>
<li><strong>Insertion:</strong> The key-value pair is hashed, and the resulting index is used to store the value in the corresponding slot. If a collision occurs, the collision resolution strategy is applied.</li>
<li><strong>Deletion:</strong> The key is hashed to find the index, and the item at that index is removed. Collision resolution may be necessary.</li>
<li><strong>Lookup:</strong> The key is hashed to find the index, and the value at that index is returned. Collision resolution may be applied if needed.</li>
</ol>
<h2 id="heading-things-to-consider-when-creating-hash-tables">Things to consider When Creating Hash Tables</h2>
<p>When creating hash tables, there are several important considerations to ensure efficiency, including fast computation of hash codes and effective collision resolution strategies.</p>
<h3 id="heading-fast-computation">Fast Computation</h3>
<p>Hash codes should be computed quickly to ensure efficient insertion, lookup, and deletion operations. A good hash function contributes to the speed of hash code computation.</p>
<h3 id="heading-avoid-collision">Avoid collision</h3>
<p>A collision happens when two or more keys produce the same hash code. In other words, multiple keys map to the same array index.</p>
<h2 id="heading-how-to-handle-collisions">How to Handle Collisions</h2>
<p>Hash maps use collision resolution techniques to deal with collisions. Common strategies include:</p>
<h4 id="heading-chaining">Chaining</h4>
<p>To manage several values with the same hash code, chaining involves storing a linked list or other data structure at each array index.  If a collision occurs, the new key-value pair is appended to the linked list at the relevant index.</p>
<h4 id="heading-open-addressing">Open addressing</h4>
<p>When a collision happens in a hash table, a technique called open addressing is employed to resolve it by searching for the next open space. </p>
<p>All it does is search the array for the next empty slot where the key-value combination can be placed. Methods including double hashing, quadratic probing, and linear probing are applied.</p>
<p><strong>Linear Probing:</strong> In linear probing, the algorithm moves linearly to the next index in the array in order to find the next open slot when a collision occurs.</p>
<p><strong>Quadratic Probing:</strong> In this method, an algorithm employs a quadratic function to find the next slot that becomes available.</p>
<p><strong>Double Hashing:</strong> In double hashing, the algorithm calculates the step size between probes using a secondary hash function.</p>
<p>In order to reduce the possibility of collisions, a good hash function should generate distinct hash codes for various inputs. By making sure the hash codes are evenly distributed throughout the range of potential values, collisions can be prevented.</p>
<h2 id="heading-how-to-solve-the-two-sum-problem">How to Solve the Two Sum Problem</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/image-117.png" alt="Image" width="600" height="400" loading="lazy">
<em>Two sum problem</em></p>
<p>The Two Sum problem involves finding all pairs of elements in an array that sum up to a specific target value. Now let's look at the problem statement.</p>
<h3 id="heading-problem-statement">Problem statement</h3>
<p>Given an array of integers <code>nums</code> and an integer <code>target</code>, return the indices of the two numbers such that they add up to the <code>target</code>.</p>
<p><em>Example 1:</em></p>
<p><strong>Input:</strong> nums = [3,2,4, 8], target = 12</p>
<p><strong>Output:</strong> [2, 3]</p>
<p><em>Example 2:</em></p>
<p><strong>Input:</strong> nums = [5,5], target = 10 </p>
<p><strong>Output:</strong> [0,1]</p>
<h3 id="heading-solution">Solution</h3>
<p>To solve the Two Sum problem, we can use a hash table. The idea is to traverse the <code>nums</code> array and, for each element, check if the complement (the difference between the target and the current element) is already in the hash table. If it is, we have found a pair of indices whose elements add up to the target.</p>
<p>Here are the steps to follow:</p>
<ol>
<li>To hold the elements and their respective indices, create an empty hash table upon initialization.</li>
<li>Go over the array of <code>nums</code>.</li>
<li>Do the complement calculation (target - current element) for each element.</li>
<li>Verify if the complement has already been added to the hash table.  If yes, return the current index and the index stored in the hash table for the complement.</li>
<li>If the complement is not in the hash table, store the current element and its index in the hash table.</li>
<li>If no such pair is found during the traversal, it implies that there is no solution.</li>
</ol>
<h5 id="heading-php-code-solution">PHP Code Solution</h5>
<pre><code class="lang-php"><span class="hljs-meta">&lt;?php</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">twoSum</span>(<span class="hljs-params">$nums, $target</span>) </span>{
    $hashTable = [];

    <span class="hljs-keyword">foreach</span> ($nums <span class="hljs-keyword">as</span> $i =&gt; $num) {
        $complement = $target - $num;

        <span class="hljs-keyword">if</span> (array_key_exists($complement, $hashTable)) {

            <span class="hljs-comment">// Found the pair, return the indices</span>
            <span class="hljs-keyword">return</span> [$hashTable[$complement], $i];
        }

        <span class="hljs-comment">// Store the current element in the hash table</span>
        $hashTable[$num] = $i;
    }

    <span class="hljs-comment">// No solution found</span>
    <span class="hljs-keyword">return</span> [];
}

<span class="hljs-comment">// Example usage:</span>
$nums = [<span class="hljs-number">2</span>, <span class="hljs-number">7</span>, <span class="hljs-number">11</span>, <span class="hljs-number">5</span>, <span class="hljs-number">15</span>, <span class="hljs-number">30</span>];
$target = <span class="hljs-number">12</span>;
$result = twoSum($nums, $target);

<span class="hljs-keyword">echo</span> <span class="hljs-string">"Indices of the two numbers: ["</span> . implode(<span class="hljs-string">", "</span>, $result) . <span class="hljs-string">"]"</span>;
</code></pre>
<h5 id="heading-javascript-code-solution-using-map-function">JavaScript Code Solution using <code>map</code> Function</h5>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">twoSum</span>(<span class="hljs-params">nums, target</span>) </span>{
    <span class="hljs-keyword">const</span> hashTable = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Map</span>();

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> [index, num] <span class="hljs-keyword">of</span> nums.entries()) {
        <span class="hljs-keyword">const</span> complement = target - num;

        <span class="hljs-comment">// Check if the complement is in the Map</span>
        <span class="hljs-keyword">if</span> (hashTable.has(complement)) {

            <span class="hljs-comment">// Found the pair, return the indices</span>
            <span class="hljs-keyword">return</span> [hashTable.get(complement), index];
        }

        <span class="hljs-comment">// Store the current number and its index in the Map</span>
        hashTable.set(num, index);
    }

    <span class="hljs-comment">// No solution found</span>
    <span class="hljs-keyword">return</span> [];
}

<span class="hljs-comment">// Example usage:</span>
<span class="hljs-keyword">const</span> nums = [<span class="hljs-number">2</span>, <span class="hljs-number">7</span>, <span class="hljs-number">11</span>, <span class="hljs-number">5</span>, <span class="hljs-number">15</span>, <span class="hljs-number">30</span>];
<span class="hljs-keyword">const</span> target = <span class="hljs-number">12</span>;
<span class="hljs-keyword">const</span> result = twoSum(nums, target);

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Indices of the two numbers that add up to <span class="hljs-subst">${target}</span>: [<span class="hljs-subst">${result.join(<span class="hljs-string">', '</span>)}</span>]`</span>);
</code></pre>
<p>This approach has a time complexity of O(n) because we iterate through the array once. The space complexity is also O(n) due to the storage of elements in the hash map.</p>
<h2 id="heading-resources">Resources</h2>
<ol>
<li><a target="_blank" href="https://en.wikipedia.org/wiki/Hash_table">Hash table From Wikipedia</a></li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=RcZsTI5h0kg">Hash maps in Python</a></li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you learned about hash maps, things to consider when writing hash functions and a real world problem that involves solving the Two Sum problem.</p>
<p>Keep learning, and Happy Coding!</p>
<p>You can find me on <a target="_blank" href="https://www.linkedin.com/in/suleolanrewaju/">LinkedIn</a> and <a target="_blank" href="https://twitter.com/bigdevlarry">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use the Sliding Window Technique – Algorithm Example and Solution ]]>
                </title>
                <description>
                    <![CDATA[ Recently, I was practicing coding problems that focused on Data Structures and Algorithms in preparation for a job change.  During this process, I came across the Sliding Window technique. I found this algorithm to be very interesting, so I wanted to... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/sliding-window-technique/</link>
                <guid isPermaLink="false">66ba10f3da6e5d90e89ee191</guid>
                
                    <category>
                        <![CDATA[ algorithms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ data structures ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Arunachalam B ]]>
                </dc:creator>
                <pubDate>Thu, 11 Jan 2024 15:11:48 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/Sliding-Window-Technique---Banner.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Recently, I was practicing coding problems that focused on Data Structures and Algorithms in preparation for a job change. </p>
<p>During this process, I came across the Sliding Window technique. I found this algorithm to be very interesting, so I wanted to share my learnings with the community. </p>
<p>This tutorial will be useful for you if you're preparing for competitive programming interviews. So, let's get started. </p>
<h2 id="heading-what-is-the-sliding-window-technique">What is the Sliding Window Technique?</h2>
<p>The sliding window technique is an algorithmic approach used in computer science and signal processing. It involves selecting a fixed-size subset, or "window," from a larger dataset and moving this window through the dataset in a step-wise fashion. </p>
<p>The window slides over the data, typically one element at a time, and performs some operation on the elements within the window at each step. </p>
<p>Are you confused? Let me elaborate on this technique with an example. </p>
<h3 id="heading-sliding-window-example">Sliding Window example</h3>
<p>Assume you're practicing for competitive programming and you encounter the following problem:</p>
<p>"Find the maximum sum of sub-array of size k with the time complexity of O(N).</p>
<p>Array = [1, 2, 6, 2, 4, 1], k = 3"</p>
<p>If you're not familiar with the concept of time complexity, here's a quick definition:</p>
<blockquote>
<p>In theoretical computer science, the time complexity is the computational complexity that describes the amount of computer time it takes to run an algorithm.</p>
</blockquote>
<p>And <a target="_blank" href="https://www.freecodecamp.org/news/learn-big-o-notation/">here's a course</a> if you'd like to learn more.</p>
<p>Back to our problem. Basically, we have to find the sub-array of size 3, whose sum is the maximum (largest number). Here's a pictorial view of how we can go about solving this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/image-27.png" alt="Image" width="600" height="400" loading="lazy">
<em>Find sum of sub-array of size k</em></p>
<h4 id="heading-manual-solution">Manual solution</h4>
<p>Let's solve it manually. From the above image, let's find the sum of each of the sub-arrays of size 3. </p>
<ul>
<li>Sum of 1st sub-array = 1 + 2 + 6 = 9</li>
<li>Sum of 2nd sub-array = 2 + 6 + 2 = 10</li>
<li>Sum of 3rd sub-array = 6 + 2 + 4 = 12</li>
<li>Sum of 4th sub-array = 2 + 4 + 1 = 7</li>
</ul>
<p>The maximum (biggest) number among 9, 10, 12, and 7 is 12 – or the 3rd sub-array. That is our solution. </p>
<h4 id="heading-code-solution">Code solution</h4>
<p>Alright, let's wear our programming shoes and try to solve this using code. </p>
<p>Here's my solution to the problem:</p>


<p>Here's a quick walk through of the above code. </p>
<p>I'm defining the input array and window size at the bottom, and calling the method <code>findMaxSumOfSequence</code> with these parameters. </p>
<p>Initially I'm doing a validation if the input array size is more than the window size, else the calculation is not possible, so return null. </p>
<p>I'm assuming the maximum sum to be negative infinity. </p>
<p>I iterate over the array, and for each item in the array, I iterate for next <code>k</code> items, find their sum, and assign the current window sum to maximum sum variable if the current window sum is more than existing maximum sum. Finally, return the maximum sum. </p>
<p>Let's try to run the code. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/image-26.png" alt="Image" width="600" height="400" loading="lazy">
<em>Find maximum sum of a sub-array of size k</em></p>
<p>Here we go. We got the right answer. </p>
<p>But, the problem does not stop here. If you look at the problem carefully, we have to find the solution in O(N) time complexity. </p>
<p>So, you might wonder what's the time complexity of the above solution. Well, the time complexity of the above solution is O(N*k). This means, we're iterating <code>k</code> times for each item in the array (nested for-loop). </p>
<p>O(N) time complexity basically describes that you have to find the maximum value by iterating over the given array only once. </p>
<h4 id="heading-using-the-sliding-window-technique">Using the Sliding Window technique</h4>
<p>How do we solve this with one iteration? Here's where sliding window technique comes into play. Let's take a look at the pictorial representation of our solution once again:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/image-27.png" alt="Image" width="600" height="400" loading="lazy">
<em>Sliding window technique</em></p>
<p>Here, you may notice that the window slides over the array. It's initially covering the indices 0, 1, and 2 in the 1st sub-array. For the next sub-array, it slides one-position to the right, eliminating 0th index to the left and adding the 3rd index to the right. So, now it covers the 1, 2, and 3 in the 2nd sub-array...and so on. </p>
<p>The calculation goes this way for the sub-arrays:</p>
<ul>
<li>1st sub-array = 1 + 2 + 6 = 9</li>
<li>2nd sub-array = 9 (sum of 1st sub-array) - 1 + 2 = 10</li>
</ul>
<p>Let's take a look at this carefully. We find the sum of 1st sub-array to be 9. To calculate the sum of 2nd sub-array, we subtract the number that's going out (1 at 0th index) and add the number that's coming in (2 at 3rd index). </p>
<ul>
<li>3rd sub-array = 10 (sum of 2nd sub-array) - 2 + 4 = 12</li>
<li>4th sub-array = 12 (sum of 3rd sub-array) - 6 + 1 = 7</li>
</ul>
<p>This is the sliding window technique. Following this technique, we'll able to find the sum of maximum sub-array in a single iteration. </p>
<h4 id="heading-how-to-implement-sliding-window-in-code">How to implement Sliding Window in code</h4>
<p>Alright, let's put on our coding shoes again and try to implement this. </p>


<p>Let's try to understand the above code. I made some changes to the <code>findMaxSumOfSequence</code> method. I introduced <code>start</code> and <code>end</code> variables which describe the window block. </p>
<p>In this implementation, we have 2 loops but they're not nested. This is because, in the first loop, we have to find the sum of the 1st window. The second loop will subtract and add items from the result of the first loop. </p>
<p>From the above example, the first loop will iterate over the first k items (3) which are 1, 2, and 6. I calculate the sum and store them in the <code>maxSum</code> and <code>windowSum</code> variables. </p>
<p>In the next loop, I'm iterating over each item in the array. For each item, I'm subtracting the previous number and adding the next number, and updating the result in the <code>windowSum</code> variable. I compare the <code>windowSum</code> and <code>maxSum</code> variables and update the <code>maxSum</code> variable if the <code>windowSum</code> is larger. Then I move the window to the next sub-array by incrementing the <code>start</code> and <code>end</code> variables. Finally, I return the maximum sum. </p>
<p>Here's the output of the above code:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/image-32.png" alt="Image" width="600" height="400" loading="lazy">
<em>Find maximum sum of a sub-array of size k using sliding window technique</em></p>
<p>With this implementation, we have satisfied the problem's requirement by iterating over the array only once and finding the maximum sum of a sub-array (with O(N) time complexity). </p>
<h2 id="heading-applications-of-the-sliding-window-technique">Applications of the Sliding Window Technique</h2>
<p>The Sliding Window Technique is versatile and finds applications in various domains. </p>
<p><strong>Array and String Manipulation</strong>: In array or string processing, a sliding window can be used to efficiently perform operations such as finding subarrays or substrings that satisfy certain conditions.</p>
<p><strong>Data Compression</strong>: Sliding window compression algorithms, like LZ77 and its variants, use a window to find repeated patterns in the input data and replace them with references to previous occurrences.</p>
<p><strong>Image Processing</strong>: In image processing, a sliding window can be employed for tasks such as feature extraction, object detection, or image segmentation.</p>
<p><strong>Signal Processing</strong>: Time-series data can be analyzed using a sliding window to capture local patterns, trends, or anomalies.</p>
<p><strong>Network Protocols</strong>: Sliding window protocols are used in computer networks for reliable and efficient data transmission. The sender and receiver maintain a window of allowable sequence numbers to manage the flow of data. </p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Hope you now have a clear idea of how the Sliding Window Technique works after seeing these examples. I would recommend that you try to solve some other problems with this technique to get familiar with it. Trying to find the minimum sum of the sub-array of size k on your own using this technique would be a helpful exercise.</p>
<p>As I mentioned earlier, I'm actively looking to switch my job. If you have a good position available in your organization, please refer <a target="_blank" href="https://arunachalam-b.github.io/">me</a>. </p>
<p>Hope you enjoyed reading this article. If you wish to learn more about techniques to crack competitive programming interviews, subscribe to my newsletter by visiting my <a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_sliding_window_technique">site</a> which also has a consolidated list of all my blogs. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Data Structures Handbook – The Key to Scalable Software ]]>
                </title>
                <description>
                    <![CDATA[ If you're regularly confronted by the complexity of modern data, you’re not alone. In our data-centric world, understanding data structures isn’t optional — it’s essential.  Whether you’re a novice coder or an experienced developer, this handbook is ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/data-structures-the-key-to-scalable-software/</link>
                <guid isPermaLink="false">66b99af117d9592471979c50</guid>
                
                    <category>
                        <![CDATA[ Computer Science ]]>
                    </category>
                
                    <category>
                        <![CDATA[ data structures ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Vahe Aslanyan ]]>
                </dc:creator>
                <pubDate>Wed, 22 Nov 2023 20:44:53 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/11/The-Data-Structures-Handbook-Cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you're regularly confronted by the complexity of modern data, you’re not alone. In our data-centric world, understanding data structures isn’t optional — it’s essential. </p>
<p>Whether you’re a novice coder or an experienced developer, this handbook is your concise guide to the critical skill of data management through data structures.</p>
<p>Data today isn’t just vast – it’s also complex. Organizing, retrieving, and manipulating this data efficiently is key. Enter data structures — the backbone of effective data management. </p>
<p>This guide cuts through the complexity of arrays, linked lists, stacks, queues, trees, and graphs. You’ll gain insights into each type’s strengths, limitations, and practical applications, backed by real-world examples.</p>
<p>Even the big brains at places like MIT and Stanford say knowing your data structures is super important for making great software. And here, I'll share real-life case studies showing you how these data structures are used in everyday situations. </p>
<p>Ready to dive in? We're going to explore the world of data structures together. You'll find out how to make your data work smarter, not harder, and give yourself an edge in the tech world.</p>
<p>Here’s the awesome journey you’re about to embark on:</p>
<ol>
<li><strong>Land Your Dream Tech Job:</strong> Imagine walking into big names like Google or Apple with confidence. Your new skills in data structures could be your golden ticket to these tech havens, where knowing your stuff really matters.</li>
<li><strong>Make Shopping Online a Breeze:</strong> Ever wonder how Amazon makes shopping so smooth? With your skills, you could be the wizard behind faster, smarter shopping experiences.</li>
<li><strong>Be a Financial Whiz:</strong> Banks and finance companies love quick, error-free data handling. Your know-how could make you a star in places like Visa or PayPal, keeping money moving swiftly and safely.</li>
<li><strong>Revolutionize Healthcare:</strong> In the world of health, like at Mayo Clinic or Pfizer, your ability to manage data could speed up lifesaving decisions. You could be part of a team that’s changing lives every day.</li>
<li><strong>Level Up Gaming Experiences:</strong> Got a passion for gaming? Companies like Nintendo or Riot Games are always on the lookout for talent that can make games even more thrilling. That could be you.</li>
<li><strong>Transform Shipping and Travel:</strong> Imagine helping FedEx or Delta Airlines move things faster and smarter around the globe.</li>
<li><strong>Shape the Future with AI:</strong> Dream of working with Generative AI? Your understanding of data structures is crucial. You could be part of groundbreaking work at places like OpenAI, Google, Netflix, Tesla or SpaceX, making the stuff of science fiction real.</li>
</ol>
<p>Upon completing this journey, your grasp of data structures will extend far beyond mere understanding. You'll be equipped to apply them effectively. </p>
<p>Imagine enhancing app performance, devising solutions for business challenges, or even playing a role in pioneering tech advancements. Your newfound skills will open doors to diverse opportunities, positioning you as a go-to problem solver. </p>
<h2 id="heading-table-of-contents">Table Of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-1-the-importance-of-data-structures">The Importance of Data Structures</a></li>
<li><a class="post-section-overview" href="#heading-2-types-of-data-structures">Types of Data Structures</a></li>
<li><a class="post-section-overview" href="#heading-3-array-data-structure">Array Data Structure</a></li>
<li><a class="post-section-overview" href="#heading-4-singly-linked-list-data-structure">Single-linked List Data Structure</a></li>
<li><a class="post-section-overview" href="#heading-5-double-linked-list-data-structure">Double-linked List Data Structure</a></li>
<li><a class="post-section-overview" href="#heading-6-stack-data-structure">Stack Data Structure</a></li>
<li><a class="post-section-overview" href="#heading-7-queue-data-structure">Queue Data Structure</a></li>
<li><a class="post-section-overview" href="#heading-8-tree-data-structure">Tree Data Structure</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/p/ad4edb43-532a-430e-82b2-1fb2558b7f73/9-graph-data-structure">Graph Data Structure</a></li>
<li><a class="post-section-overview" href="#heading-10-hash-table-data-structure">Hash Table Data Structure</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/p/ad4edb43-532a-430e-82b2-1fb2558b7f73/11-how-to-unleash-the-power-of-data-structures-in-programming">How to Unleash the Power of Data Structures in Programming</a></li>
<li><a class="post-section-overview" href="#heading-12-how-to-choose-the-right-data-structure-for-your-application">How to Choose the Right Data Structure for Your Application</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/p/ad4edb43-532a-430e-82b2-1fb2558b7f73/13-how-to-efficiently-implement-data-structures">How to Efficiently Implement Data Structures</a></li>
<li><a class="post-section-overview" href="#heading-14-how-to-optimize-for-performance-understanding-time-complexities-in-data-structures">Common Data Structure Operations and Their Time Complexities</a></li>
<li><a target="_blank" href="https://www.freecodecamp.org/news/p/ad4edb43-532a-430e-82b2-1fb2558b7f73/15-real-world-examples-of-data-structures-in-action">Real-World Examples of Data Structures in Action</a></li>
<li><a class="post-section-overview" href="#heading-16-essential-toolkit-for-learning-data-structures">Resources and Tools for Learning Data Structures</a></li>
<li><a class="post-section-overview" href="#heading-17-conclusion-and-actionable-steps-forward">Conclusion and Next Steps</a></li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/image-56.png" alt="Image" width="600" height="400" loading="lazy">
<em>Abstract digital cityscape with interconnected cubic structures and glowing lines symbolizing complex data structures - Source: <a target="_blank" href="lunartech.ai">lunartech.ai</a></em></p>
<h2 id="heading-1-the-importance-of-data-structures">1. The Importance of Data Structures</h2>
<p>Learning about data structures can really help you power-up your software engineering skills. These critical components are key to ensuring your applications operate flawlessly, which is a must-have ability for every software engineer.</p>
<h3 id="heading-they-enhance-efficiency-and-performance">They Enhance Efficiency and Performance</h3>
<p>Data structures are the turbochargers of your code. They do more than just store data – they enable swift and efficient access. Think of a hash table as your instant-access tool for speedy data retrieval or the linked list as your dynamic, adaptable strategy for evolving data needs.</p>
<h3 id="heading-they-optimize-memory-use-and-management">They Optimize Memory Use and Management</h3>
<p>These structures are really good at optimizing memory. They fine-tune your program’s memory consumption, ensuring robustness under heavy data loads and helping you avoid common issues like memory leaks.</p>
<h3 id="heading-they-boost-problem-solving-and-algorithm-design">They Boost Problem-Solving and Algorithm Design</h3>
<p>Data structures elevate your code from functional to exceptional. They efficiently organize data and operations, enhancing your code’s effectiveness, reusability, and scalability. This leads to better maintainability and adaptability of your software.</p>
<h3 id="heading-theyre-essential-for-professional-advancement">They're Essential for Professional Advancement</h3>
<p>Grasping data structures is crucial for any aspiring software engineer. Not only do they provide efficient ways to handle data and bolster performance, but they are also instrumental in solving complex problems and designing algorithms. </p>
<p>These skills are vital for career growth, particularly for those aiming to move into senior technical roles. Tech giants like Google, Amazon, and Microsoft value this expertise highly.</p>
<h3 id="heading-key-take-aways">Key take-aways</h3>
<p>Thoroughly learning data structures can help you stand out in technical interviews and attract leading employers. You'll also use them every day as a developer.</p>
<p>Data Structures are essential for building scalable systems and tackling intricate coding problems, and they're key to maintaining a competitive edge in the evolving tech sector. </p>
<p>This guide focuses on crucial data structures, empowering you to create efficient, advanced software solutions. Begin your journey to enhance your technical capabilities for future industry challenges.</p>
<h2 id="heading-2-types-of-data-structures">2. Types of Data Structures</h2>
<p>Data structures are essential tools in software development that enable efficient storage, organization, and manipulation of data. Understanding the different types of data structures is crucial for aspiring software engineers, as it helps them choose the most appropriate structure for their specific needs. </p>
<p>Let’s dive into some of the most commonly used types of data structures:</p>
<h3 id="heading-arrays-the-backbone-of-efficient-data-management"><strong>Arrays: The Backbone of Efficient Data Management</strong></h3>
<p>Arrays, a cornerstone of data structures, epitomize efficiency by storing elements of the same type in contiguous memory slots. Their power lies in their ability to offer direct, lightning-fast access to any element, simply by knowing its index. </p>
<p>This feature, according to a Stanford University study, makes arrays up to 30% faster for random access compared to other structures. </p>
<p>But arrays have their limitations: their size is fixed, and altering their length, particularly for large arrays, can be a resource-intensive task.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/image-58.png" alt="Image" width="600" height="400" loading="lazy">
<em>Illustration of an array. Source: <a target="_blank" href="lunartech.ai">lunartech.ai</a></em></p>
<p><strong>Practical Insight:</strong> Consider using <strong><code>int[] numbers = {1, 2, 3, 4, 5};</code></strong> for scenarios where quick, random access is paramount and size modifications are minimal.</p>
<h3 id="heading-linked-lists-flexibility-at-its-finest"><strong>Linked Lists: Flexibility at its Finest</strong></h3>
<p>Linked lists excel in scenarios requiring dynamic memory allocation. Unlike arrays, they don't mandate contiguous memory, making them more flexible if you need to change their size. This makes them ideal for applications where the volume of data can fluctuate significantly. </p>
<p>But their flexibility comes at a cost: traversing a linked list, as per the findings of the MIT Computer Science and Artificial Intelligence Laboratory, can be up to 20% slower than accessing elements in an array due because of sequential access.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/Untitled-design--2-.png" alt="Image" width="600" height="400" loading="lazy">
<em>Illustration of a linked list. Source: <a target="_blank" href="lunartech.ai">lunartech.ai</a></em></p>
<p><strong>Practical Insight:</strong> Use <strong><code>1 -&gt; 2 -&gt; 3 -&gt; 4 -&gt; 5</code></strong> for data that requires frequent insertions and deletions.</p>
<h3 id="heading-stacks-simplifying-last-in-first-out-operations"><strong>Stacks: Simplifying Last-In-First-Out Operations</strong></h3>
<p>Stacks adhere to the Last-In-First-Out (LIFO) principle. This singular access point at the top simplifies adding and removing elements, making them an excellent choice for applications like function call stacks, undo mechanisms, and expression evaluation. </p>
<p>Harvard's CS50 course suggest that stacks are up to 50% more efficient in managing certain types of sequential data processing tasks.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/Untitled-design--1-.png" alt="Image" width="600" height="400" loading="lazy">
<em>Illustration of a stack. Source: <a target="_blank" href="lunartech.ai">lunartech.ai</a></em></p>
<p><strong>Practical Insight:</strong> Implement stacks <strong><code>[5, 4, 3, 2, 1] (Top: 5)</code></strong> for reversing data sequences or parsing expressions.</p>
<h3 id="heading-queues-mastering-sequential-processing"><strong>Queues: Mastering Sequential Processing</strong></h3>
<p>Operating on the First-In-First-Out (FIFO) principle, queues ensure that the first element in is always the first one out. With distinct front and rear access points, queues offer streamlined operations, making them indispensable in task scheduling, resource management, and breadth-first search algorithms. </p>
<p>Research indicates that queues can improve process management efficiency by up to 40% in computational systems.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/Untitled-design.png" alt="Image" width="600" height="400" loading="lazy">
<em>Illustration of a queue. Source: <a target="_blank" href="lunartech.ai">lunartech.ai</a></em></p>
<p><strong>Practical Insight:</strong> Opt for queues <strong><code>[1, 2, 3, 4, 5] (Front: 1, Rear: 5)</code></strong> in scenarios demanding sequential processing, like task scheduling.</p>
<h3 id="heading-trees-the-hierarchical-data-maestros"><strong>Trees: The Hierarchical Data Maestros</strong></h3>
<p>Trees, a hierarchical structure of nodes linked by edges, are unparalleled in representing layered data. The root node forms the foundation, with subsequent layers branching out. Their non-linear nature allows for efficient organization and retrieval of data, particularly in databases and file systems. </p>
<p>According to the IEEE, trees can enhance data retrieval efficiency by over 60% in hierarchical systems.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/image-61.png" alt="Image" width="600" height="400" loading="lazy">
<em>Illustration of a tree. Source: <a target="_blank" href="lunartech.ai">lunartech.ai</a></em></p>
<p><strong>Practical Insight:</strong> Trees are best utilized in scenarios requiring structured, hierarchical data organization, such as in database indexing or file system structuring.</p>
<h3 id="heading-graphs-interconnected-data-mapping"><strong>Graphs: Interconnected Data Mapping</strong></h3>
<p>Graphs are adept at illustrating relationships between various data points through nodes (vertices) and edges (connections). They shine in applications involving network topology, social network analysis, and route optimization. </p>
<p>Graphs bring a level of interconnectedness and flexibility that linear data structures can't match. As per a recent ACM journal, graph algorithms have been pivotal in optimizing network designs, improving efficiency by up to 70%.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/image-60.png" alt="Image" width="600" height="400" loading="lazy">
<em>Illustration of a graph. Source: <a target="_blank" href="lunartech.ai">lunartech.ai</a></em></p>
<p><strong>Practical Insight:</strong> Implement graphs for complex data sets where relationships and interconnectivity are key factors.</p>
<h3 id="heading-hash-tables-the-speedsters-of-data-retrieval"><strong>Hash Tables: The Speedsters of Data Retrieval</strong></h3>
<p>Hash tables stand out as a pinnacle of efficient data management, leveraging key-value pairs for swift data retrieval. Renowned for their speed, especially in search operations, hash tables, as highlighted by a report from the IEEE, can significantly reduce data access time, often achieving constant-time complexity. </p>
<p>This efficiency stems from their unique mechanism of using hash functions to map keys to specific slots, allowing for immediate access. They dynamically adapt to varying data sizes, a feature that has led to their widespread use in applications like database indexing and caching. </p>
<p>But you'll have to navigate the occasional challenge of 'collisions', where different keys hash to the same index. Still, with well-designed hash functions, as recommended by experts in computational algorithms, hash tables remain unparalleled in balancing speed and flexibility.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/image-59.png" alt="Image" width="600" height="400" loading="lazy">
<em>Illustration of a hashtable. Source: <a target="_blank" href="lunartech.ai">lunartech.ai</a></em></p>
<p><strong>Practical Insight:</strong> Consider using <strong><code>HashMap&lt;String, Integer&gt; userAges = new HashMap&lt;&gt;(); userAges.put("Alice", 30); userAges.put("Bob", 25);</code></strong> in scenarios demanding rapid and frequent data retrieval.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/image-68.png" alt="Image" width="600" height="400" loading="lazy">
<em>Digital rendering of a vast, organized grid of illuminated skyscrapers, representing array data structures, with glowing lines crisscrossing between them to signify structured data connections and indexing.- Source: <a target="_blank" href="lunartech.ai">lunartech.ai</a></em></p>
<h2 id="heading-3-array-data-structure">3. Array Data Structure</h2>
<p>Arrays are like a row of sequentially numbered lockers, each holding specific items. They represent a structured grouping of data, where each item is stored in contiguous memory locations. This setup allows for efficient and direct access to each data element using a numerical index. </p>
<p>Arrays are fundamental in programming, serving as a cornerstone for data organization and manipulation. Their linear structure simplifies the concept of data storage, making it intuitive and accessible. </p>
<p>Arrays are crucial in various computational tasks, from basic to complex. They offer a blend of simplicity and efficiency, making them ideal for numerous applications.</p>
<h3 id="heading-what-does-an-array-do"><strong>What Does an Array Do?</strong></h3>
<p>Arrays primarily store data elements of a single type in a sequential order. They are essential for managing multiple items collectively and systematically. Arrays facilitate efficient indexing, which is pivotal in handling large datasets. </p>
<p>This data structure is crucial for algorithms that require quick access to elements. Arrays streamline tasks such as sorting, searching, and storing homogeneous data. Their importance in data management cannot be overstated, especially in fields like database management and software development. </p>
<p>Arrays, by virtue of their structure, offer a predictable and easy-to-understand format for data storage.</p>
<h3 id="heading-how-do-arrays-work"><strong>How Do Arrays Work?</strong></h3>
<p>Arrays store data in adjacent memory locations, ensuring continuity and fast access. Each element in an array is like a compartment in a row of storage units, each marked with an index. This indexing starts from zero, enabling a direct and predictable access path to each element. </p>
<p>Arrays can efficiently utilize memory, as they store elements of the same type contiguously. The linear memory allocation of arrays makes them a go-to choice for straightforward data storage needs. Accessing an array element is akin to selecting a book from a numbered shelf. This simple yet effective mechanism is what makes arrays so widely used.</p>
<h3 id="heading-key-array-operations"><strong>Key Array Operations</strong></h3>
<p>The fundamental operations performed on arrays are accessing elements, inserting elements, deleting elements, transversing the array, searching the array, and updating the array.</p>
<p><strong>Explanation of Each Operation:</strong></p>
<ul>
<li><strong>Accessing elements</strong> involves identifying and retrieving an element from a specific index.</li>
<li><strong>Inserting elements</strong> is the process of adding a new element at a desired index within the array.</li>
<li><strong>Deleting elements</strong> refers to the removal of an element, followed by the adjustment of the remaining elements.</li>
<li><strong>Traversing an array</strong> means systematically going through each element, typically for inspection or modification.</li>
<li><strong>Searching an array</strong> aims to locate a specific element within the array.</li>
<li><strong>Updating an array</strong> is the act of modifying the value of an existing element at a given index.</li>
</ul>
<h3 id="heading-array-code-example-in-java"><strong>Array Code Example in Java</strong></h3>
<p>Let's look at an example of how you can work with an array in Java:</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArrayOperations</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        <span class="hljs-keyword">int</span>[] array = {<span class="hljs-number">10</span>, <span class="hljs-number">20</span>, <span class="hljs-number">30</span>, <span class="hljs-number">40</span>, <span class="hljs-number">50</span>};

        <span class="hljs-comment">// Access Operation</span>
        <span class="hljs-keyword">int</span> firstElement = array[<span class="hljs-number">0</span>];
        System.out.println(<span class="hljs-string">"Access Operation: First element = "</span> + firstElement);
        <span class="hljs-comment">// Expected Output: "Access Operation: First element = 10"</span>

        <span class="hljs-comment">// Insertion Operation (For simplicity, replacing an element)</span>
        array[<span class="hljs-number">2</span>] = <span class="hljs-number">35</span>; <span class="hljs-comment">// Replacing the third element (index 2)</span>
        System.out.println(<span class="hljs-string">"Insertion Operation: Element at index 2 = "</span> + array[<span class="hljs-number">2</span>]);
        <span class="hljs-comment">// Expected Output: "Insertion Operation: Element at index 2 = 35"</span>

        <span class="hljs-comment">// Deletion Operation (For simplicity, setting an element to 0)</span>
        array[<span class="hljs-number">3</span>] = <span class="hljs-number">0</span>; <span class="hljs-comment">// Deleting the fourth element (index 3)</span>
        System.out.println(<span class="hljs-string">"Deletion Operation: Element at index 3 after deletion = "</span> + array[<span class="hljs-number">3</span>]);
        <span class="hljs-comment">// Expected Output: "Deletion Operation: Element at index 3 after deletion = 0"</span>

        <span class="hljs-comment">// Traversal Operation</span>
        System.out.println(<span class="hljs-string">"Traversal Operation:"</span>);
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; array.length; i++) {
            System.out.println(<span class="hljs-string">"Element at index "</span> + i + <span class="hljs-string">" = "</span> + array[i]);
        }
        <span class="hljs-comment">// Expected Output for Traversal:</span>
        <span class="hljs-comment">// "Element at index 0 = 10"</span>
        <span class="hljs-comment">// "Element at index 1 = 20"</span>
        <span class="hljs-comment">// "Element at index 2 = 35"</span>
        <span class="hljs-comment">// "Element at index 3 = 0"</span>
        <span class="hljs-comment">// "Element at index 4 = 50"</span>

        <span class="hljs-comment">// Searching Operation for value 35</span>
        System.out.println(<span class="hljs-string">"Searching Operation: Search for value 35"</span>);
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; array.length; i++) {
            <span class="hljs-keyword">if</span> (array[i] == <span class="hljs-number">35</span>) {
                System.out.println(<span class="hljs-string">"Value 35 found at index "</span> + i);
                <span class="hljs-keyword">break</span>;
            }
        }
        <span class="hljs-comment">// Expected Output: "Value 35 found at index 2"</span>

        <span class="hljs-comment">// Updating Operation</span>
        array[<span class="hljs-number">1</span>] = <span class="hljs-number">25</span>; <span class="hljs-comment">// Updating second element (index 1)</span>
        System.out.println(<span class="hljs-string">"Updating Operation: Element at index 1 after update = "</span> + array[<span class="hljs-number">1</span>]);
        <span class="hljs-comment">// Expected Output: "Updating Operation: Element at index 1 after update = 25"</span>

        <span class="hljs-comment">// Final Array State after all operations</span>
        System.out.println(<span class="hljs-string">"Final Array State:"</span>);
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> value : array) {
            System.out.println(value);
        }
        <span class="hljs-comment">// Expected Output for Final State:</span>
        <span class="hljs-comment">// "10"</span>
        <span class="hljs-comment">// "25"</span>
        <span class="hljs-comment">// "35"</span>
        <span class="hljs-comment">// "0"</span>
        <span class="hljs-comment">// "50"</span>
    }
}
</code></pre>
<h3 id="heading-when-should-you-use-arrays"><strong>When Should You Use Arrays?</strong></h3>
<p>Arrays are useful in various scenarios where organized data storage is required. They are perfect for handling lists of items like names, numbers, or identifiers. </p>
<p>Arrays are extensively used in software applications like spreadsheets and database systems. Their predictable structure makes them ideal for situations requiring quick access to data. They're also commonly used in sorting and searching algorithms. </p>
<p>Arrays can be particularly useful in applications where you know the size of the data set in advance. Arrays form the basis of more complex data structures, so it's essential that you understand them as a developer.</p>
<h3 id="heading-advantages-and-limitations-of-arrays"><strong>Advantages and Limitations of Arrays</strong></h3>
<p>Arrays offer fast access to elements, a result of their contiguous memory allocation. Their simplicity and ease of use make them a popular choice in programming. Arrays also provide a predictable pattern of memory usage, enhancing efficiency.</p>
<p>But arrays have a fixed size, which limits their flexibility. This fixed size can lead to wasted space or insufficient capacity issues. Inserting and deleting elements from arrays can be inefficient, as they often require shifting elements. </p>
<p>Despite these limitations, arrays are a fundamental tool in a programmer's toolkit, balancing simplicity and functionality.</p>
<h3 id="heading-key-takeaways">Key Takeaways</h3>
<p>Arrays are a primary data structure for organized, sequential data storage. Their ability to store and manage collections of data efficiently is unmatched in many scenarios. </p>
<p>Arrays are fundamental in programming, forming the basis for more complex structures and algorithms. Understanding arrays is essential for anyone venturing into software development or data processing. </p>
<p>Mastering arrays equips programmers with a vital tool for efficient data management. Arrays, in essence, are the building blocks for many sophisticated programming solutions.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/image-69.png" alt="Image" width="600" height="400" loading="lazy">
<em>Futuristic visualization of a Singly Linked List Data Structure, with illuminated nodes connected in a linear sequence by directed glowing paths, highlighting the one-way navigational flow of data. - Source: <a target="_blank" href="lunartech.ai">lunartech.ai</a>`</em></p>
<h2 id="heading-4-singly-linked-list-data-structure">4. Singly Linked List Data Structure</h2>
<p>Envision a single linked list as a sequence of train carriages connected in a line, where each carriage is an individual data element. </p>
<p>A linked list is a sequential, dynamic collection of elements termed as nodes. Each node points to its successor, establishing a chain-like, navigable structure. This configuration allows for a linear but adaptable organization of data.</p>
<h3 id="heading-what-does-a-linked-list-do"><strong>What Does a Linked List Do?</strong></h3>
<p>The core functionality of a linked list is its sequential data arrangement. Each node, containing data and a reference to the next node, streamlines operations like insertions and deletions, offering a highly efficient data management system. </p>
<p>In the diverse world of data structures, linked lists stand out for their adaptability. They are particularly valuable in scenarios where the data volume varies dynamically, making them a flexible solution for modern computing needs.</p>
<h3 id="heading-how-do-linked-lists-work"><strong>How Do Linked Lists Work?</strong></h3>
<p>The structure of a linked list is built upon nodes. Every node consists of two parts: the data itself and a pointer to the next node. </p>
<p>Imagine a treasure trail. Each clue (node) guides you not only to a piece of treasure (data) but also to the next clue (next node).</p>
<h3 id="heading-key-linked-list-operations"><strong>Key Linked List Operations</strong></h3>
<p>The fundamental operations in a linked list include adding nodes, removing nodes, finding nodes, iterating through the list, and updating the list.</p>
<ul>
<li><strong>Adding nodes</strong> involves inserting a new node into the list.</li>
<li><strong>Removing nodes</strong> focuses on efficiently removing a node from the list.</li>
<li><strong>Finding nodes</strong> aims to locate a specific node by traversing the list.</li>
<li><strong>Iterating through a list</strong> involves moving sequentially through each node in the list.</li>
<li><strong>Updating a list</strong> allows for modifying the data within an existing node.</li>
</ul>
<h3 id="heading-when-are-linked-lists-used"><strong>When are Linked Lists Used?</strong></h3>
<p>Linked lists excel in environments where data is frequently inserted or removed. Their versatility extends from powering undo functionalities in software to enabling dynamic memory management in operating systems.</p>
<h3 id="heading-advantages-and-limitations-of-linked-lists"><strong>Advantages and Limitations of Linked Lists</strong></h3>
<p>The primary advantage of linked lists lies in their size flexibility and the efficiency of insertions and deletions.</p>
<p>But they incur increased memory usage due to the storage of references and lack direct element access, depending on sequential traversal.</p>
<h3 id="heading-linked-list-code-demonstration"><strong>Linked List Code Demonstration</strong></h3>
<p>Let's look at an example problem that uses a linked list: managing a dynamic task list.</p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> java.util.LinkedList;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LinkedListOperations</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        LinkedList&lt;String&gt; list = <span class="hljs-keyword">new</span> LinkedList&lt;&gt;();

        <span class="hljs-comment">// Add Operation</span>
        list.add(<span class="hljs-string">"Node1"</span>);
        System.out.println(<span class="hljs-string">"After adding Node1: "</span> + list); <span class="hljs-comment">// Expected Output: [Node1]</span>
        list.add(<span class="hljs-string">"Node2"</span>);
        System.out.println(<span class="hljs-string">"After adding Node2: "</span> + list); <span class="hljs-comment">// Expected Output: [Node1, Node2]</span>
        list.add(<span class="hljs-string">"Node3"</span>);
        System.out.println(<span class="hljs-string">"After adding Node3: "</span> + list); <span class="hljs-comment">// Expected Output: [Node1, Node2, Node3]</span>

        <span class="hljs-comment">// Remove Operation</span>
        list.remove(<span class="hljs-string">"Node2"</span>);
        System.out.println(<span class="hljs-string">"After removing Node2: "</span> + list); <span class="hljs-comment">// Expected Output: [Node1, Node3]</span>

        <span class="hljs-comment">// Find Operation</span>
        <span class="hljs-keyword">boolean</span> found = list.contains(<span class="hljs-string">"Node3"</span>);
        System.out.println(<span class="hljs-string">"Find Operation - Is Node3 in the list? "</span> + found); <span class="hljs-comment">// Expected Output: true</span>

        <span class="hljs-comment">// Iterate Operation</span>
        System.out.print(<span class="hljs-string">"Iterate Operation: "</span>);
        <span class="hljs-keyword">for</span>(String node : list) {
            System.out.print(node + <span class="hljs-string">" "</span>); <span class="hljs-comment">// Expected Output: Node1 Node3 </span>
        }
        System.out.println();

        <span class="hljs-comment">// Update Operation</span>
        list.set(<span class="hljs-number">0</span>, <span class="hljs-string">"NewNode1"</span>);
        System.out.println(<span class="hljs-string">"After updating Node1 to NewNode1: "</span> + list); <span class="hljs-comment">// Expected Output: [NewNode1, Node3]</span>

        <span class="hljs-comment">// Final State of the List</span>
        System.out.println(<span class="hljs-string">"Final State of the List: "</span> + list); <span class="hljs-comment">// Expected Output: [NewNode1, Node3]</span>
    }
}
</code></pre>
<h3 id="heading-key-takeaways-1"><strong>Key takeaways</strong></h3>
<p>Linked lists are an essential dynamic data structure that are pivotal for effective and adaptable data management. Mastering linked lists is vital for all developers, offering a unique blend of simplicity, flexibility, and functional depth.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/image-70.png" alt="Image" width="600" height="400" loading="lazy">
<em>Illuminated visualization of a Double Linked List Data Structure with nodes featuring bidirectional connections, showcasing the forward and backward traversal capabilities within the structure.- Source: <a target="_blank" href="lunartech.ai">lunartech.ai</a></em></p>
<h2 id="heading-5-double-linked-list-data-structure">5. Double Linked List Data Structure</h2>
<p>The Double Linked List is an evolution in data structures. It's like a two-way street where each node serves as a house with doors leading to the next and previous houses. </p>
<p>Unlike its single-linked cousin, this structure gives nodes the luxury of knowing both their predecessor and successor, a feature that fundamentally changes how data can be traversed and manipulated. </p>
<p>Double linked lists stand as a more nuanced and versatile way to handle data, reflecting the complexity and interconnectedness of real-world scenarios.</p>
<h3 id="heading-what-does-a-double-linked-list-do"><strong>What Does a Double Linked List Do?</strong></h3>
<p>Double linked lists are the multitaskers of the data structure world, adept at forward and backward data navigation. They excel in applications where flexibility in movement through data is paramount. </p>
<p>This structure enables users to step back and forth through elements with ease, a feature particularly invaluable in complex data sequences where both past and future elements may need quick referencing.</p>
<h3 id="heading-how-do-double-linked-lists-work"><strong>How Do Double Linked Lists Work?</strong></h3>
<p>Each node in a double linked list is a self-contained unit with three key components: the data it holds, a pointer to the next node, and a pointer to the previous node. </p>
<p>This setup is somewhat like a playlist where each song (node) knows both the song before and after it, allowing for a fluid transition in either direction. The list thus forms a bidirectional pathway through its elements, making it inherently more flexible than a single linked list.</p>
<h3 id="heading-key-double-linked-list-operations"><strong>Key Double Linked List Operations</strong></h3>
<p>Key operations in a double linked list include adding, removing, finding, iterating (both forward and backward), and updating nodes. </p>
<ul>
<li><strong>Adding</strong> involves inserting new elements at precise positions. </li>
<li><strong>Removing</strong> means unlinking and eliminating a node from the list. </li>
<li><strong>Finding</strong> nodes is more efficient as one can start from either end. </li>
<li><strong>Iteration</strong> is especially versatile, allowing traversal in both directions.</li>
<li><strong>Updating</strong> nodes involves modifying existing data, akin to revising entries in a logbook.</li>
</ul>
<h3 id="heading-when-are-double-linked-lists-used"><strong>When are Double Linked Lists Used?</strong></h3>
<p>Double linked lists find their utility in systems where two-way navigation is beneficial. </p>
<p>They are used in browser histories, allowing users to move back and forth through previously visited sites. In applications like music players or document viewers, they enable users to jump between items smoothly and intuitively. Their ability to insert and delete items efficiently also makes them suitable for dynamic data manipulation tasks.</p>
<h3 id="heading-advantages-and-limitations-of-double-linked-lists"><strong>Advantages and Limitations of Double Linked Lists</strong></h3>
<p>The double linked list excels in its ability to traverse back and forth, offering a level of element manipulation that single linked lists cannot match. This unique capability allows for traversing data both forwards and backwards with equal efficiency, significantly enhancing algorithmic possibilities in complex data structures. </p>
<p>But this advanced functionality demands a trade-off: each node requires two pointers (to the previous and next nodes), leading to increased memory consumption. </p>
<p>Additionally, double linked lists are more complex to implement compared to single linked lists. This can pose challenges in terms of code maintenance and understanding for beginners. </p>
<p>Despite these considerations, the double linked list remains a robust choice for dynamic data scenarios where the benefits of its flexible structure outweigh the cost of additional memory and complexity.</p>
<h3 id="heading-double-linked-list-code-example">Double Linked List Code Example</h3>
<pre><code class="lang-jsx"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Node</span> </span>{
    <span class="hljs-built_in">String</span> data;
    Node next;
    Node prev;

    Node(<span class="hljs-built_in">String</span> data) {
        <span class="hljs-built_in">this</span>.data = data;
    }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DoubleLinkedList</span> </span>{
    Node head;
    Node tail;

    <span class="hljs-comment">// Method to add a node to the end of the list</span>
    <span class="hljs-keyword">void</span> add(<span class="hljs-built_in">String</span> data) {
        Node newNode = <span class="hljs-keyword">new</span> Node(data);
        <span class="hljs-keyword">if</span> (head == <span class="hljs-literal">null</span>) {
            head = newNode;
            tail = newNode;
        } <span class="hljs-keyword">else</span> {
            tail.next = newNode;
            newNode.prev = tail;
            tail = newNode;
        }
    }

    <span class="hljs-comment">// Method to remove a specific node</span>
    boolean remove(<span class="hljs-built_in">String</span> data) {
        Node current = head;
        <span class="hljs-keyword">while</span> (current != <span class="hljs-literal">null</span>) {
            <span class="hljs-keyword">if</span> (current.data.equals(data)) {
                <span class="hljs-keyword">if</span> (current.prev != <span class="hljs-literal">null</span>) {
                    current.prev.next = current.next;
                } <span class="hljs-keyword">else</span> {
                    head = current.next;
                }
                <span class="hljs-keyword">if</span> (current.next != <span class="hljs-literal">null</span>) {
                    current.next.prev = current.prev;
                } <span class="hljs-keyword">else</span> {
                    tail = current.prev;
                }
                <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
            }
            current = current.next;
        }
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }

    <span class="hljs-comment">// Method to find a node</span>
    boolean contains(<span class="hljs-built_in">String</span> data) {
        Node current = head;
        <span class="hljs-keyword">while</span> (current != <span class="hljs-literal">null</span>) {
            <span class="hljs-keyword">if</span> (current.data.equals(data)) {
                <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
            }
            current = current.next;
        }
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }

    <span class="hljs-comment">// Method to print the list from head to tail</span>
    <span class="hljs-keyword">void</span> printForward() {
        Node current = head;
        <span class="hljs-keyword">while</span> (current != <span class="hljs-literal">null</span>) {
            System.out.print(current.data + <span class="hljs-string">" "</span>);
            current = current.next;
        }
        System.out.println();
    }

    <span class="hljs-comment">// Method to print the list from tail to head</span>
    <span class="hljs-keyword">void</span> printBackward() {
        Node current = tail;
        <span class="hljs-keyword">while</span> (current != <span class="hljs-literal">null</span>) {
            System.out.print(current.data + <span class="hljs-string">" "</span>);
            current = current.prev;
        }
        System.out.println();
    }

    <span class="hljs-comment">// Method to update a node's data</span>
    boolean update(<span class="hljs-built_in">String</span> oldData, <span class="hljs-built_in">String</span> newData) {
        Node current = head;
        <span class="hljs-keyword">while</span> (current != <span class="hljs-literal">null</span>) {
            <span class="hljs-keyword">if</span> (current.data.equals(oldData)) {
                current.data = newData;
                <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
            }
            current = current.next;
        }
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }
}

public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DoubleLinkedListOperations</span> </span>{
    public <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> main(<span class="hljs-built_in">String</span>[] args) {
        DoubleLinkedList list = <span class="hljs-keyword">new</span> DoubleLinkedList();

        <span class="hljs-comment">// Add Operation</span>
        list.add(<span class="hljs-string">"Node1"</span>);
        list.add(<span class="hljs-string">"Node2"</span>);
        list.add(<span class="hljs-string">"Node3"</span>);
        System.out.println(<span class="hljs-string">"After Add Operations:"</span>);
        list.printForward(); <span class="hljs-comment">// Expected Output: Node1 Node2 Node3 </span>

        <span class="hljs-comment">// Remove Operation</span>
        list.remove(<span class="hljs-string">"Node2"</span>);
        System.out.println(<span class="hljs-string">"After Remove Operation:"</span>);
        list.printForward(); <span class="hljs-comment">// Expected Output: Node1 Node3</span>

        <span class="hljs-comment">// Find Operation</span>
        boolean foundNode1 = list.contains(<span class="hljs-string">"Node1"</span>);
        boolean foundNode3 = list.contains(<span class="hljs-string">"Node3"</span>);
        System.out.println(<span class="hljs-string">"Find Operation - Is Node1 in the list? "</span> + foundNode1); <span class="hljs-comment">// Expected Output: true</span>
        System.out.println(<span class="hljs-string">"Find Operation - Is Node3 in the list? "</span> + foundNode3); <span class="hljs-comment">// Expected Output: true</span>

        <span class="hljs-comment">// Forward Iterate Operation</span>
        System.out.print(<span class="hljs-string">"Forward Iterate Operation: "</span>);
        list.printForward(); <span class="hljs-comment">// Expected Output: Node1 Node3</span>

        <span class="hljs-comment">// Backward Iterate Operation</span>
        System.out.print(<span class="hljs-string">"Backward Iterate Operation: "</span>);
        list.printBackward(); <span class="hljs-comment">// Expected Output: Node3 Node1</span>

        <span class="hljs-comment">// Update Operation</span>
        list.update(<span class="hljs-string">"Node1"</span>, <span class="hljs-string">"UpdatedNode1"</span>);
        System.out.println(<span class="hljs-string">"After Update Operation:"</span>);
        list.printForward(); <span class="hljs-comment">// Expected Output: UpdatedNode1 Node3</span>

        <span class="hljs-comment">// Final State of the List</span>
        System.out.println(<span class="hljs-string">"Final State of the List:"</span>);
        list.printForward(); <span class="hljs-comment">// Expected Output: UpdatedNode1 Node3</span>
    }
}
</code></pre>
<h3 id="heading-real-world-applications-of-double-linked-lists"><strong>Real-World Applications of Double Linked Lists</strong></h3>
<p>Double linked lists are particularly useful in applications that require frequent and efficient insertion and deletion of elements from both ends of the list. </p>
<p>They are widely used in advanced computing systems like gaming applications, where players' actions might dictate immediate changes to the game state, or in navigation systems within complex software, allowing users to traverse through historical states or settings. </p>
<p>Another key application is in multimedia software, like photo or video editing tools, where a user might need to move back and forth through a sequence of edits. </p>
<p>Their bidirectional traversal capability also makes them ideal for implementing advanced algorithms in cache eviction policies used in database management systems, where the order of elements needs to be modified frequently and efficiently.</p>
<h3 id="heading-performance-aspects-of-double-linked-lists"><strong>Performance Aspects of Double Linked Lists</strong></h3>
<p>In terms of performance, double linked lists offer significant advantages as well as some trade-offs compared to other data structures. </p>
<p>The time complexity for insertion and deletion operations at both ends of the list is O(1), making these operations extremely efficient. But searching for an element in a double linked list has a time complexity of O(n), as it may require traversal through the list. This is less efficient compared to data structures like hash tables. </p>
<p>Also, the added memory overhead for storing two pointers for each node is something to consider in memory-sensitive applications. This contrasts with arrays and single linked lists, where memory usage is typically lower. </p>
<p>Still, for applications where quick insertion and deletion are critical, and the dataset size isn't overwhelmingly large, double linked lists offer a balanced mix of efficiency and flexibility.</p>
<h3 id="heading-key-takeaways-2"><strong>Key Takeaways</strong></h3>
<p>In essence, double linked lists represent a sophisticated approach to data management, offering enhanced flexibility and efficiency. And you'll want to understand them as you venture into more advanced data structure implementations. </p>
<p>Double linked lists serve as a bridge between basic data management and more complex data handling needs. This makes them a vital component in a programmer's toolkit for sophisticated data solutions.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/image-71.png" alt="Image" width="600" height="400" loading="lazy">
<em>A vertical, layered structure glowing with golden light beams, depicting the LIFO (Last In, First Out) concept of a Stack Data Structure, with the topmost layer brightly illuminated to signify the top of the stack.- Source: <a target="_blank" href="lunartech.ai">lunartech.ai</a></em></p>
<h2 id="heading-6-stack-data-structure">6. Stack Data Structure</h2>
<p>Picture a stack as a cafeteria's tower of plates, where the only way to interact with them is by adding or removing a plate from the top.  </p>
<p>A stack, in the world of data structures, is a linear and ordered collection of elements that strictly adheres to the Last In, First Out (LIFO) principle. This means that the last element added is the first one to be removed. While this might sound simplistic, its implications for data management are profound and far-reaching.</p>
<p>Stacks serve as a foundational concept in computer science, forming the basis for many complex algorithms and functionalities. In this section, we'll explore stacks in-depth, uncovering their applications, operations, and significance in modern computing.</p>
<h3 id="heading-what-does-a-stack-do"><strong>What Does a Stack Do?</strong></h3>
<p>The fundamental purpose of a stack is to store elements in an ordered and reversible manner. The primary operations are addition (push) and removal (pop) from the top of the stack. This seemingly simple structure holds immense importance in scenarios where immediate access to the most recently added data is critical.</p>
<p>Let's consider some scenarios in which stacks are indispensable. In software development, undo mechanisms in text editors rely on stacks to store the history of changes. When you hit "Undo Typing," you are essentially popping elements from the top of the stack, reverting to previous states. </p>
<p>Similarly, navigating through your web browser's history—clicking "Back" or "Forward"—utilizes a stack-based structure to manage the pages you've visited.</p>
<h3 id="heading-how-do-stacks-work"><strong>How Do Stacks Work?</strong></h3>
<p>To understand how stacks function, let's use a practical analogy: imagine a stack of books. In this stack, you can only interact with the books at the top. You can add a new book to the stack, which becomes the new topmost book, or you can remove the top book. This results in a sequential order of books that mirrors the LIFO principle.</p>
<p>If you want to access a book from the middle or bottom of the stack, you must first remove all the books above it. This core characteristic simplifies data management in various applications, ensuring that the most recently added item is always the next to be processed.</p>
<h3 id="heading-key-stack-operations"><strong>Key Stack Operations</strong></h3>
<p>The key operations in a stack are the building blocks of its functionality. Let's explore each operation in detail:</p>
<ul>
<li><strong>Push</strong> adds an element to the top of the stack. It's akin to placing a new plate on the top of the pile in our cafeteria analogy.</li>
<li><strong>Pop</strong> removes and returns the top element of the stack. It's like taking the topmost plate from the stack.</li>
<li><strong>Peek</strong> allows you to view the top element without removing it. You can think of it as glancing at the top plate without actually taking it off.</li>
<li><strong>IsEmpty</strong> checks if the stack is empty. It's essential to verify whether there are any plates left in our cafeteria stack.</li>
<li><strong>Search</strong> helps you find the position of a specific element within the stack. It tells you how far down the stack an item is located.</li>
</ul>
<p>These operations are the tools developers use to manipulate data within a stack, ensuring that it remains well-ordered and efficient.</p>
<h3 id="heading-when-are-stacks-used"><strong>When are Stacks Used?</strong></h3>
<p>Stacks find application in a wide array of scenarios. Some common use cases include:</p>
<ul>
<li><strong>Undo Features:</strong> In text editors and other software, stacks are employed to implement undo and redo functionalities, allowing users to revert to previous states.</li>
<li><strong>Browser History:</strong> When you navigate backward or forward in your web browser, you're essentially traversing a stack of visited pages.</li>
<li><strong>Backtracking Algorithms:</strong> In fields like artificial intelligence and graph traversal, stacks play a pivotal role in backtracking algorithms, enabling efficient exploration of potential paths.</li>
<li><strong>Function Call Management:</strong> When you call a function in a program, a stack frame is added to the call stack, facilitating the tracking of function calls and their return values.</li>
</ul>
<p>These examples emphasize the ubiquity of stacks in modern computing, making them a fundamental concept for software developers.</p>
<h3 id="heading-advantages-and-limitations-of-stacks"><strong>Advantages and Limitations of Stacks</strong></h3>
<p>Stacks come with their own set of strengths and limitations.</p>
<p><strong>Strengths:</strong></p>
<ul>
<li><strong>Simplicity:</strong> Stacks are straightforward to implement and use.</li>
<li><strong>Efficiency:</strong> They provide an efficient way to handle data in LIFO order.</li>
<li><strong>Predictability:</strong> The strict LIFO order simplifies data management and ensures a clear sequence of operations.</li>
</ul>
<p><strong>Weaknesses:</strong></p>
<ul>
<li><strong>Limited Access:</strong> Stacks offer limited access, as you can only interact with the top element. This restricts their use in scenarios requiring access to elements deeper within the stack.</li>
<li><strong>Memory Constraints:</strong> Stacks can run out of memory if pushed to their limits, leading to an OutOfMemoryError. This is a practical concern in software development.</li>
</ul>
<p>Despite their limitations, stacks remain an essential tool in the programmer's toolbox due to their efficiency and predictability.</p>
<h3 id="heading-stack-code-example">Stack Code Example</h3>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> java.util.Stack;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AdvancedStackOperations</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        <span class="hljs-comment">// Create a stack to store integers</span>
        Stack&lt;Integer&gt; stack = <span class="hljs-keyword">new</span> Stack&lt;&gt;();

        <span class="hljs-comment">// Check if the stack is empty</span>
        <span class="hljs-keyword">boolean</span> isEmpty = stack.isEmpty();
        System.out.println(<span class="hljs-string">"Is the stack empty? "</span> + isEmpty); <span class="hljs-comment">// Output: Is the stack empty? true</span>

        <span class="hljs-comment">// Push integers onto the stack</span>
        stack.push(<span class="hljs-number">10</span>);
        stack.push(<span class="hljs-number">20</span>);
        stack.push(<span class="hljs-number">30</span>);
        stack.push(<span class="hljs-number">40</span>);
        stack.push(<span class="hljs-number">50</span>);

        <span class="hljs-comment">// Display the stack after pushing integers</span>
        System.out.println(<span class="hljs-string">"Stack after pushing integers: "</span> + stack);
        <span class="hljs-comment">// Output: Stack after pushing integers: [10, 20, 30, 40, 50]</span>

        <span class="hljs-comment">// Check if the stack is empty again</span>
        isEmpty = stack.isEmpty();
        System.out.println(<span class="hljs-string">"Is the stack empty? "</span> + isEmpty); <span class="hljs-comment">// Output: Is the stack empty? false</span>

        <span class="hljs-comment">// Peek at the top integer without removing it</span>
        <span class="hljs-keyword">int</span> topElement = stack.peek();
        System.out.println(<span class="hljs-string">"Peek at the top integer: "</span> + topElement); <span class="hljs-comment">// Output: Peek at the top integer: 50</span>

        <span class="hljs-comment">// Pop the top integer from the stack</span>
        <span class="hljs-keyword">int</span> poppedElement = stack.pop();
        System.out.println(<span class="hljs-string">"Popped integer: "</span> + poppedElement); <span class="hljs-comment">// Output: Popped integer: 50</span>

        <span class="hljs-comment">// Display the stack after popping an integer</span>
        System.out.println(<span class="hljs-string">"Stack after popping an integer: "</span> + stack);
        <span class="hljs-comment">// Output: Stack after popping an integer: [10, 20, 30, 40]</span>

        <span class="hljs-comment">// Search for an integer in the stack</span>
        <span class="hljs-keyword">int</span> searchElement = <span class="hljs-number">30</span>;
        <span class="hljs-keyword">int</span> position = stack.search(searchElement);
        <span class="hljs-keyword">if</span> (position != -<span class="hljs-number">1</span>) {
            System.out.println(<span class="hljs-string">"Position of "</span> + searchElement + <span class="hljs-string">" in the stack (1-based index): "</span> + position);
        } <span class="hljs-keyword">else</span> {
            System.out.println(searchElement + <span class="hljs-string">" not found in the stack."</span>);
        }
        <span class="hljs-comment">// Output: Position of 30 in the stack (1-based index): 3</span>
    }
}
</code></pre>
<h3 id="heading-real-world-applications-of-stacks">Real World Applications of Stacks</h3>
<p>Stack data structures have widespread real-world applications, particularly in computer science and software development. </p>
<p>They are commonly used for implementing undo and redo features in text editors and design software, allowing users to reverse or redo actions efficiently. </p>
<p>In web browsers, stacks enable seamless navigation through browsing history when users click back or forward buttons. </p>
<p>Operating systems rely on stacks for managing function calls and execution contexts. Backtracking algorithms in AI, gaming, and optimization problems benefit from stacks to keep track of choices and backtrack effectively. </p>
<p>Stack-based architectures are also employed in parsing and evaluating mathematical expressions, enabling complex calculations.</p>
<h3 id="heading-performance-considerations-for-stacks">Performance Considerations for Stacks</h3>
<p>Stacks are known for their efficiency, with key operations like push, pop, peek, and isEmpty having a constant time complexity of O(1), ensuring quick access to the top element. </p>
<p>But stacks have limitations, offering limited access to elements beyond the top one. This makes them less suitable for deeper element retrieval. </p>
<p>Stacks can also consume significant memory in deeply recursive applications, necessitating careful memory management. Tail recursion optimization and iterative approaches are strategies to mitigate stack memory concerns. </p>
<p>In summary, stack data structures provide efficient solutions for real-world applications in software development but require an understanding of their limitations and prudent memory usage for optimal performance.</p>
<h3 id="heading-key-takeaways-3"><strong>Key Takeaways</strong></h3>
<p>Stacks are an essential data structure in programming, offering a straightforward yet effective way to manage data following the Last In, First Out (LIFO) principle. Understanding how stacks work and how to utilize their key operations is vital for developers, given their widespread application in various computer science and programming scenarios. </p>
<p>Whether you're implementing an undo feature in a text editor or navigating web browser history, stacks are the behind-the-scenes heroes that make it all possible. Mastering them is a fundamental step toward becoming a proficient software developer.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/image-72.png" alt="Image" width="600" height="400" loading="lazy">
<em>A line of silhouetted figures with a glowing path weaving through them, representing a Queue Data Structure, with the illumination highlighting the FIFO (First In, First Out) sequence from one end to the other. - Source: <a target="_blank" href="lunartech.ai">lunartech.ai</a></em></p>
<h2 id="heading-7-queue-data-structure">7. Queue Data Structure</h2>
<p>Think of Queues like a digital equivalent of a line of people waiting patiently for their turn. Just like in real life, a queue data structure follows the "first come, first served" (FIFO) principle. This means that the first item to be added to the queue is the first to be processed. </p>
<p>In essence, a queue is a linear data structure designed for holding elements in a specific order, ensuring that the order of processing remains fair and predictable.</p>
<h3 id="heading-what-does-a-queue-do">What Does a Queue Do?</h3>
<p>The primary function of a queue is to manage elements based on the FIFO principle we just discussed. It serves as an orderly collection where the element that has been waiting the longest gets its turn first. </p>
<p>Now, you might wonder why a queue is so crucial in the world of computer science. The answer lies in its significance in ensuring that tasks are processed in a specific order. </p>
<p>Imagine scenarios where processing order matters, such as print jobs in a queue or keyboard input buffering. A queue ensures that these tasks are executed with precision, avoiding chaos and ensuring fairness.</p>
<h3 id="heading-how-do-queues-work">How Do Queues Work?</h3>
<p>To understand the inner workings of a queue, let's break it down into its basic mechanics using a real-world example.</p>
<p>In a queue, elements are added to the tail (end) and removed from the head (front) of the queue. This straightforward operation ensures that the element that has been waiting the longest is the next in line to be processed.</p>
<h3 id="heading-simple-example-the-cashier-ticket-selling-scenario">Simple Example: The Cashier Ticket-Selling Scenario</h3>
<p>Picture yourself as a cashier selling tickets to a concert. Your queue is formed by customers who approach your register. </p>
<p>Following the FIFO principle, the customer who arrived first is at the head of the queue, and the one who arrived last is at the tail. As you serve customers in order, they move up the queue until they are helped and then exit.</p>
<h3 id="heading-key-queue-operations">Key Queue Operations</h3>
<p>Queues come with a set of key operations that make them function seamlessly.</p>
<ul>
<li><strong>Enqueue</strong>: Think of enqueuing as customers joining the line. The new element is placed at the end of the queue, patiently waiting for its turn to be served.</li>
<li><strong>Dequeue</strong>: Dequeueing is akin to serving the customer at the front of the line. The element at the head of the queue is removed, signifying that it has been processed and can now exit the queue.</li>
</ul>
<p>While these operations might sound straightforward, they form the backbone of a queue's functionality.</p>
<h3 id="heading-when-are-queues-used">When are Queues Used?</h3>
<p>Now that you understand how a queue works, let's explore some use cases:</p>
<ul>
<li><strong>Keyboard Buffers</strong>: When you type rapidly on your keyboard, the computer uses a queue to ensure that the characters appear on the screen in the order you pressed the keys.</li>
<li><strong>Printer Queues</strong>: In printing, queues are used to manage print jobs, ensuring that they are completed in the order they were initiated.</li>
</ul>
<h3 id="heading-real-world-applications">Real-World Applications</h3>
<p>Think of online services where users submit requests or tasks, such as downloading files from a website or processing orders in an e-commerce platform. These requests are typically handled on a 'first come, first served' basis, just like a digital queue. </p>
<p>Similarly, in a multiplayer online game, players often join a game server's queue before entering the game, ensuring that they are served in the order they joined. </p>
<p>In these digital scenarios, queues are pivotal in managing and processing data or requests efficiently</p>
<h3 id="heading-queue-example-code">Queue Example Code</h3>
<p>To truly grasp the power of queues, let's dive into a practical example problem.</p>
<p>Imagine you're tasked with implementing a system to process customer service requests in a call center. Each request is assigned a priority level, and you need to ensure that high-priority requests are processed before lower-priority ones.</p>
<p>To tackle this problem, you can use a combination of queues. Create separate queues for each priority level, and process requests in the order of their priority. Here's a simplified code snippet in Java to illustrate this concept:</p>
<pre><code class="lang-java">Queue&lt;CustomerRequest&gt; highPriorityQueue = <span class="hljs-keyword">new</span> LinkedList&lt;&gt;();
Queue&lt;CustomerRequest&gt; mediumPriorityQueue = <span class="hljs-keyword">new</span> LinkedList&lt;&gt;();
Queue&lt;CustomerRequest&gt; lowPriorityQueue = <span class="hljs-keyword">new</span> LinkedList&lt;&gt;();

<span class="hljs-comment">// Enqueue requests based on their priority</span>
highPriorityQueue.offer(highPriorityRequest);
mediumPriorityQueue.offer(mediumPriorityRequest);
lowPriorityQueue.offer(lowPriorityRequest);

<span class="hljs-comment">// Process requests in priority order</span>
processRequests(highPriorityQueue);
processRequests(mediumPriorityQueue);
processRequests(lowPriorityQueue);
</code></pre>
<p>This code ensures that high-priority requests are processed before medium and low-priority ones, maintaining fairness while addressing different levels of urgency.</p>
<p>Let's look at another example of using queues in code:</p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> java.util.LinkedList;
<span class="hljs-keyword">import</span> java.util.Queue;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">QueueOperationsExample</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        <span class="hljs-comment">// Create a queue using LinkedList</span>
        Queue&lt;String&gt; queue = <span class="hljs-keyword">new</span> LinkedList&lt;&gt;();

        <span class="hljs-comment">// Enqueue: Adding elements to the queue</span>
        queue.offer(<span class="hljs-string">"Customer 1"</span>);
        queue.offer(<span class="hljs-string">"Customer 2"</span>);
        queue.offer(<span class="hljs-string">"Customer 3"</span>);

        <span class="hljs-comment">// Display the queue after enqueuing</span>
        System.out.println(<span class="hljs-string">"Queue after enqueuing: "</span> + queue);
        <span class="hljs-comment">// Expected output: Queue after enqueuing: [Customer 1, Customer 2, Customer 3]</span>

        <span class="hljs-comment">// Dequeue: Removing the element at the head of the queue</span>
        String servedCustomer = queue.poll();

        <span class="hljs-comment">// Display the served customer and the updated queue</span>
        System.out.println(<span class="hljs-string">"Served customer: "</span> + servedCustomer);
        <span class="hljs-comment">// Expected output: Served customer: Customer 1</span>
        System.out.println(<span class="hljs-string">"Queue after dequeuing: "</span> + queue);
        <span class="hljs-comment">// Expected output: Queue after dequeuing: [Customer 2, Customer 3]</span>

        <span class="hljs-comment">// Enqueue more customers</span>
        queue.offer(<span class="hljs-string">"Customer 4"</span>);
        queue.offer(<span class="hljs-string">"Customer 5"</span>);

        <span class="hljs-comment">// Display the queue after enqueuing more customers</span>
        System.out.println(<span class="hljs-string">"Queue after enqueuing more customers: "</span> + queue);
        <span class="hljs-comment">// Expected output: Queue after enqueuing more customers: [Customer 2, Customer 3, Customer 4, Customer 5]</span>

        <span class="hljs-comment">// Dequeue another customer</span>
        String servedCustomer2 = queue.poll();

        <span class="hljs-comment">// Display the served customer and the updated queue</span>
        System.out.println(<span class="hljs-string">"Served customer: "</span> + servedCustomer2);
        <span class="hljs-comment">// Expected output: Served customer: Customer 2</span>
        System.out.println(<span class="hljs-string">"Queue after dequeuing: "</span> + queue);
        <span class="hljs-comment">// Expected output: Queue after dequeuing: [Customer 3, Customer 4, Customer 5]</span>
    }
}
</code></pre>
<h3 id="heading-advantages-and-limitations-of-queues">Advantages and Limitations of Queues</h3>
<p>Every data structure comes with its own set of strengths and weaknesses, and queues are no exception.</p>
<p>One of the key strengths of a queue is its ability to maintain order. It ensures fairness and predictability in processing elements. When order matters, a queue is the go-to data structure.</p>
<p>But queues also have limitations. They lack the ability to prioritize elements based on any criteria other than their arrival time. If you need to handle elements with different priorities, you'll likely need to complement queues with other data structures or algorithms.</p>
<h3 id="heading-key-takeaways-4">Key Takeaways</h3>
<p>The Queue Data Structure, based on the "first come, first served" (FIFO) principle, is vital for maintaining order. It involves adding to the tail (enqueuing) and removing from the head (dequeuing). </p>
<p>Real-world applications include keyboard buffers and printer queues. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/image-73.png" alt="Image" width="600" height="400" loading="lazy">
<em>A radiant, tree-like structure with branching nodes, symbolizing a Tree Data Structure, where each glowing connection represents a parent-child relationship, converging towards the luminous root at the base. - Source: <a target="_blank" href="lunartech.ai">lunartech.ai</a></em></p>
<h2 id="heading-8-tree-data-structure">8. Tree Data Structure</h2>
<p>Imagine a tree – not just any tree, but a meticulously structured hierarchy that can revolutionize how you store and access data. This isn't just a theoretical concept – it's a powerful tool used extensively in computer science and various industries.</p>
<h3 id="heading-what-does-a-tree-do">What Does a Tree Do?</h3>
<p>The Tree Data Structure's primary function is to arrange data hierarchically, creating a structure that mirrors real-world hierarchies. </p>
<p>Why is this important, you ask? Consider this: it's the backbone of file systems, ensures efficient hierarchical data representation, and excels in optimizing search operations. If you want to efficiently manage data with a hierarchical structure, the Tree Data Structure is your go-to choice.</p>
<h3 id="heading-how-do-trees-work">How Do Trees Work?</h3>
<p>The mechanics behind trees are elegantly simple yet incredibly versatile. Imagine a family tree, where each individual is a node connected to their parents. </p>
<p>Nodes in a tree are linked through parent-child relationships, with a single root node at the top. Just as in a real family tree, information flows from the root to the leaves, creating a structured hierarchy. </p>
<p>Whether it's organizing files in your computer or representing the structure of a company, trees provide a clear and efficient way to handle hierarchical data.</p>
<h3 id="heading-key-tree-operations">Key Tree Operations</h3>
<p>Understanding the key operations of a tree is essential for practical use. These operations encompass adding nodes, removing nodes, and traversing the tree. Let's delve into each of these operations to grasp their significance:</p>
<h4 id="heading-adding-nodes">Adding Nodes</h4>
<p>Adding nodes to a tree is akin to expanding its hierarchy. This operation allows you to incorporate new data points seamlessly. </p>
<p>When you add a node, you establish a connection between an existing node (the parent) and the new node (the child). This relationship signifies the hierarchical structure of the data. </p>
<p>Practical scenarios for adding nodes include inserting new files into a file system or adding new employees to an organizational chart.</p>
<h4 id="heading-removing-nodes">Removing Nodes</h4>
<p>Removing nodes is a crucial operation for maintaining the integrity of the tree. It enables you to prune unnecessary branches or data points. </p>
<p>When you remove a node, you sever its connection with the tree, effectively eliminating it and its substructure. This operation is essential for tasks such as deleting files from a file system or handling employee departures in an organizational hierarchy.</p>
<h4 id="heading-traversing-the-tree">Traversing the Tree</h4>
<p>Traversing the tree is like navigating through its branches to access specific data points. Tree traversal is vital for retrieving information efficiently. </p>
<p>There are various traversal techniques, each with its own use cases:</p>
<ul>
<li><strong>In-Order Traversal</strong> visits nodes in ascending order, and is commonly used in binary search trees to retrieve data in sorted order.</li>
<li><strong>Pre-Order Traversal</strong> processes the current node before its children, and is suitable for copying a tree structure.</li>
<li><strong>Post-Order Traversal</strong> processes the current node after its children, and is useful for deleting a tree or evaluating mathematical expressions.</li>
</ul>
<p>Tree traversal operations provide practical means to explore and work with hierarchical data, making it accessible and usable in various applications.</p>
<p>By mastering these key operations, you can effectively manage hierarchical data structures, making trees a valuable tool in computer science and software engineering. </p>
<p>Whether you need to organize files, represent family relationships, or optimize data retrieval, a solid understanding of these operations empowers you to harness the full potential of tree structures.</p>
<h3 id="heading-performance-aspects-of-trees">Performance Aspects of Trees</h3>
<p>Now, let's dive into the practical world of performance, a critical aspect of the Tree Data Structure. </p>
<p>Performance is all about efficiency—how quickly can you execute operations on a tree when you're faced with real-world data? </p>
<p>Let's break it down by examining the time and space complexities of common tree operations, including insertion, deletion, and traversal.</p>
<h4 id="heading-time-and-space-complexities-of-common-operations">Time and Space Complexities of Common Operations</h4>
<p><strong>Insertion</strong>: When you add new data to a tree, how fast can you do it? The time complexity of insertion varies depending on the type of tree. </p>
<p>For example, in a balanced binary search tree, like AVL or Red-Black trees, insertion has a time complexity of O(log n), where n is the number of nodes in the tree. </p>
<p>But in an unbalanced binary tree, it can be as bad as O(n) in the worst case. The space complexity of insertion is typically O(1) as it involves adding a single node.</p>
<p><strong>Deletion</strong>: Removing data from a tree should be a smooth process. Similar to insertion, the time complexity of deletion depends on the type of tree. </p>
<p>In balanced binary search trees, deletion also has a time complexity of O(log n). But in an unbalanced tree, it can be O(n). The space complexity of deletion is O(1).</p>
<p><strong>Traversal</strong>: Traversing the tree, whether it's for searching, retrieving data, or processing it in a specific order, is a fundamental operation. The time complexity of traversal methods can vary:</p>
<ul>
<li>In-order, pre-order, and post-order traversals have a time complexity of O(n) as they visit each node exactly once.</li>
<li>Level-order traversal, using a queue, also has a time complexity of O(n). The space complexity of traversal methods typically depends on the data structures used during traversal. For example, level-order traversal with a queue has a space complexity of O(w), where w is the maximum width (number of nodes in the widest level) of the tree.</li>
</ul>
<h4 id="heading-space-complexity-and-memory-usage">Space Complexity and Memory Usage</h4>
<p>While time complexity deals with speed, space complexity tackles memory usage. Trees can impact how much memory your application consumes, which is crucial in resource-conscious environments. </p>
<p>The space complexity of the entire tree structure depends on its type and balance:</p>
<ul>
<li>In balanced binary search trees (like AVL, Red-Black), the space complexity is O(n), where n is the number of nodes.</li>
<li>In B-trees, which are used in databases and file systems, space complexity can be higher but is designed to efficiently store large amounts of data.</li>
<li>In unbalanced trees, space complexity can also be O(n), making them less memory-efficient.</li>
</ul>
<p>By delving into the practical aspects of time and space complexities, you'll be equipped to make informed decisions about using trees in your projects. </p>
<p>Whether you're optimizing data storage, speeding up searches, or ensuring efficient data management, these insights will guide you in implementing tree structures effectively.</p>
<h3 id="heading-tree-code-example">Tree Code Example</h3>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> java.util.LinkedList;
<span class="hljs-keyword">import</span> java.util.Queue;

<span class="hljs-comment">// Class representing a single node in the tree</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TreeNode</span> </span>{
    <span class="hljs-keyword">int</span> value; <span class="hljs-comment">// Value of the node</span>
    TreeNode left; <span class="hljs-comment">// Pointer to the left child</span>
    TreeNode right; <span class="hljs-comment">// Pointer to the right child</span>

    <span class="hljs-comment">// Constructor to create a new node with a given value</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">TreeNode</span><span class="hljs-params">(<span class="hljs-keyword">int</span> value)</span> </span>{
        <span class="hljs-keyword">this</span>.value = value;
        <span class="hljs-keyword">this</span>.left = <span class="hljs-keyword">null</span>; <span class="hljs-comment">// Initialize left child as null</span>
        <span class="hljs-keyword">this</span>.right = <span class="hljs-keyword">null</span>; <span class="hljs-comment">// Initialize right child as null</span>
    }
}

<span class="hljs-comment">// Class representing a Binary Search Tree</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BinarySearchTree</span> </span>{
    TreeNode root; <span class="hljs-comment">// Root of the BST</span>

    <span class="hljs-comment">// Constructor to create an empty BST</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">BinarySearchTree</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">this</span>.root = <span class="hljs-keyword">null</span>; <span class="hljs-comment">// Initialize root as null</span>
    }

    <span class="hljs-comment">// Public method to insert a value into the BST</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">insert</span><span class="hljs-params">(<span class="hljs-keyword">int</span> value)</span> </span>{
        <span class="hljs-comment">// Call the private recursive method to insert the value</span>
        root = insertRecursive(root, value);
    }

    <span class="hljs-comment">// Private recursive method to insert a value starting from a given node</span>
    <span class="hljs-function"><span class="hljs-keyword">private</span> TreeNode <span class="hljs-title">insertRecursive</span><span class="hljs-params">(TreeNode current, <span class="hljs-keyword">int</span> value)</span> </span>{
        <span class="hljs-keyword">if</span> (current == <span class="hljs-keyword">null</span>) {
            <span class="hljs-comment">// If the current node is null, create a new node with the value</span>
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> TreeNode(value);
        }

        <span class="hljs-comment">// Decide whether to insert in the left or right subtree</span>
        <span class="hljs-keyword">if</span> (value &lt; current.value) {
            <span class="hljs-comment">// Insert in the left subtree</span>
            current.left = insertRecursive(current.left, value);
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (value &gt; current.value) {
            <span class="hljs-comment">// Insert in the right subtree</span>
            current.right = insertRecursive(current.right, value);
        }

        <span class="hljs-comment">// Return the current node</span>
        <span class="hljs-keyword">return</span> current;
    }

    <span class="hljs-comment">// Public method for in-order traversal of the BST</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">inOrderTraversal</span><span class="hljs-params">()</span> </span>{
        System.out.println(<span class="hljs-string">"In-Order Traversal:"</span>);
        <span class="hljs-comment">// Start recursive in-order traversal from the root</span>
        inOrderRecursive(root);
        System.out.println();
        <span class="hljs-comment">// Expected output: "20 30 40 50 60 70 80"</span>
    }

    <span class="hljs-comment">// Private recursive method for in-order traversal</span>
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">inOrderRecursive</span><span class="hljs-params">(TreeNode node)</span> </span>{
        <span class="hljs-keyword">if</span> (node != <span class="hljs-keyword">null</span>) {
            <span class="hljs-comment">// Traverse the left subtree, visit the node, then traverse the right subtree</span>
            inOrderRecursive(node.left);
            System.out.print(node.value + <span class="hljs-string">" "</span>);
            inOrderRecursive(node.right);
        }
    }

    <span class="hljs-comment">// Public method for pre-order traversal of the BST</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">preOrderTraversal</span><span class="hljs-params">()</span> </span>{
        System.out.println(<span class="hljs-string">"Pre-Order Traversal:"</span>);
        <span class="hljs-comment">// Start recursive pre-order traversal from the root</span>
        preOrderRecursive(root);
        System.out.println();
        <span class="hljs-comment">// Expected output: "50 30 20 40 70 60 80"</span>
    }

    <span class="hljs-comment">// Private recursive method for pre-order traversal</span>
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">preOrderRecursive</span><span class="hljs-params">(TreeNode node)</span> </span>{
        <span class="hljs-keyword">if</span> (node != <span class="hljs-keyword">null</span>) {
            <span class="hljs-comment">// Visit the node, then traverse the left and right subtrees</span>
            System.out.print(node.value + <span class="hljs-string">" "</span>);
            preOrderRecursive(node.left);
            preOrderRecursive(node.right);
        }
    }

    <span class="hljs-comment">// Public method for post-order traversal of the BST</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">postOrderTraversal</span><span class="hljs-params">()</span> </span>{
        System.out.println(<span class="hljs-string">"Post-Order Traversal:"</span>);
        <span class="hljs-comment">// Start recursive post-order traversal from the root</span>
        postOrderRecursive(root);
        System.out.println();
        <span class="hljs-comment">// Expected output: "20 40 30 60 80 70 50"</span>
    }

    <span class="hljs-comment">// Private recursive method for post-order traversal</span>
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">postOrderRecursive</span><span class="hljs-params">(TreeNode node)</span> </span>{
        <span class="hljs-keyword">if</span> (node != <span class="hljs-keyword">null</span>) {
            <span class="hljs-comment">// Traverse the left and right subtrees, then visit the node</span>
            postOrderRecursive(node.left);
            postOrderRecursive(node.right);
            System.out.print(node.value + <span class="hljs-string">" "</span>);
        }
    }

    <span class="hljs-comment">// Public method for level-order traversal of the BST</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">levelOrderTraversal</span><span class="hljs-params">()</span> </span>{
        System.out.println(<span class="hljs-string">"Level-Order Traversal:"</span>);
        Queue&lt;TreeNode&gt; queue = <span class="hljs-keyword">new</span> LinkedList&lt;&gt;(); <span class="hljs-comment">// Queue to assist with level-order traversal</span>
        <span class="hljs-keyword">if</span> (root != <span class="hljs-keyword">null</span>) {
            <span class="hljs-comment">// Start from the root</span>
            queue.add(root);
        }

        <span class="hljs-comment">// Continue until the queue is empty</span>
        <span class="hljs-keyword">while</span> (!queue.isEmpty()) {
            <span class="hljs-comment">// Remove the front node from the queue and print its value</span>
            TreeNode node = queue.poll();
            System.out.print(node.value + <span class="hljs-string">" "</span>);
            <span class="hljs-comment">// Expected output: "50 30 70 20 40 60 80"</span>

            <span class="hljs-comment">// Add the left and right children to the queue if they exist</span>
            <span class="hljs-keyword">if</span> (node.left != <span class="hljs-keyword">null</span>) {
                queue.add(node.left);
            }
            <span class="hljs-keyword">if</span> (node.right != <span class="hljs-keyword">null</span>) {
                queue.add(node.right);
            }
        }
        System.out.println();
    }
}

<span class="hljs-comment">// Main class</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Main</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        BinarySearchTree bst = <span class="hljs-keyword">new</span> BinarySearchTree(); <span class="hljs-comment">// Create a new BST</span>
        <span class="hljs-keyword">int</span>[] values = {<span class="hljs-number">50</span>, <span class="hljs-number">30</span>, <span class="hljs-number">70</span>, <span class="hljs-number">20</span>, <span class="hljs-number">40</span>, <span class="hljs-number">60</span>, <span class="hljs-number">80</span>}; <span class="hljs-comment">// Array of values to be inserted</span>

        <span class="hljs-comment">// Loop to insert each value into the BST</span>
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> value : values) {
            bst.insert(value);
        }

        <span class="hljs-comment">// Perform different tree traversals</span>
        bst.inOrderTraversal(); <span class="hljs-comment">// In-order traversal: Expected output: 20 30 40 50 60 70 80</span>
        bst.preOrderTraversal(); <span class="hljs-comment">// Pre-order traversal: Expected output: 50 30 20 40 70 60 80</span>
        bst.postOrderTraversal(); <span class="hljs-comment">// Post-order traversal: Expected output: 20 40 30 60 80 70 50</span>
        bst.levelOrderTraversal(); <span class="hljs-comment">// Level-order traversal: Expected output: 50 30 70 20 40 60 80</span>

    }
}
</code></pre>
<h3 id="heading-advantages-and-limitations-of-trees">Advantages and Limitations of Trees</h3>
<p>Understanding the strengths and weaknesses of trees is vital. There are various advantages, such as efficient hierarchical data retrieval. But there are also situations where trees may not be the best choice, such as unstructured data. </p>
<p>It's essential to make informed decisions about when and where to employ this powerful data structure.</p>
<h3 id="heading-key-takeaways-5">Key Takeaways</h3>
<p>Trees are practical tools that can revolutionize how you organize and access hierarchical data. </p>
<p>Whether you're building a file system or optimizing search algorithms, the Tree Data Structure is your trusted ally in the world of data structures.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/image-74.png" alt="Image" width="600" height="400" loading="lazy">
<em>A complex network of interconnected glowing points, illustrating a Graph Data Structure with no clear beginning or end, highlighting the multiple pathways and vertices in a non-linear, web-like formation.- Source: <a target="_blank" href="lunartech.ai">lunartech.ai</a></em></p>
<h2 id="heading-9-graph-data-structure">9. Graph Data Structure</h2>
<p>The Graph Data Structure stands as a pivotal concept in computer science, likened to a network of interconnected nodes and edges. </p>
<p>At its core, a graph represents a collection of nodes (or vertices) connected by edges – each node potentially holding a piece of data, and each edge signifying a relationship or connection. </p>
<p>Now, we'll delve into the essence of graph data structures, their functionality, and their real-world applications.</p>
<h3 id="heading-what-does-a-graph-data-structure-do">What Does a Graph Data Structure Do?</h3>
<p>Graphs primarily model intricate relationships and connections among various entities. They have diverse applications such as social networks, road maps, and data networks. </p>
<p>By understanding graphs, you can grasp the underlying structure of many complex systems in our digital and physical worlds.</p>
<h3 id="heading-how-do-graphs-work">How Do Graphs Work?</h3>
<p>Graphs function through nodes connected by edges. Consider a non-technical example: a city's road map, or a social network. These represent graphs where connections (edges) between points (nodes) create a network. </p>
<h3 id="heading-key-operations-in-graph-data-structures">Key Operations in Graph Data Structures</h3>
<p>In graph data structures, there are a few key operations you'll need to know for building, analyzing, and modifying the network. These operations include the addition and removal of nodes and edges, as well as the analysis of connections and relationships within the graph.</p>
<ul>
<li><strong>Adding a Node (Vertex)</strong> involves inserting a new node into the graph, serving as the initial step in constructing the graph's structure. It's essential for expanding the network.</li>
<li><strong>Removing a Node (Vertex)</strong> entails deleting a node and its associated edges, thereby altering the graph's configuration. It's a crucial step for modifying the graph's layout and connections.</li>
<li><strong>Adding an Edge</strong> or establishing a connection between two nodes is fundamental in graph construction. In undirected graphs, this connection is bidirectional, while in directed graphs, the edge is a one-way link from one node to another.</li>
<li><strong>Removing an Edge</strong> between two nodes is vital for changing the relationships and pathways within the graph.</li>
<li><strong>Checking for Adjacency</strong> or determining whether a direct edge exists between two nodes is critical for understanding their adjacency, revealing direct connections within the graph.</li>
<li><strong>Finding Neighbors</strong> or identifying all nodes directly linked to a specific node is key for exploring and comprehending the graph's structure, as it reveals the immediate connections of any given node.</li>
<li><strong>Graph Traversal</strong> utilizing systematic methods such as Depth-First Search (DFS) and Breadth-First Search (BFS) enables the comprehensive exploration of all nodes in the graph.</li>
<li><strong>Search Operations</strong> include locating specific nodes or determining paths between nodes, often employing traversal techniques to navigate through the graph.</li>
</ul>
<h3 id="heading-code-example-for-graph-operations">Code Example for Graph Operations</h3>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> java.util.*;

public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Graph</span> </span>{
    <span class="hljs-comment">// Adjacency list to store graph edges</span>
    private <span class="hljs-built_in">Map</span>&lt;Integer, List&lt;Integer&gt;&gt; adjList;
    <span class="hljs-comment">// Boolean to check if graph is directed</span>
    private boolean directed;

    <span class="hljs-comment">// Constructor to initialize graph with directed/undirected flag</span>
    public Graph(boolean directed) {
        <span class="hljs-built_in">this</span>.directed = directed;
        adjList = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();
    }

    <span class="hljs-comment">// Method to add a new node to the graph</span>
    public <span class="hljs-keyword">void</span> addNode(int node) {
        <span class="hljs-comment">// Puts the node in the adjacency list if it's not already present</span>
        adjList.putIfAbsent(node, <span class="hljs-keyword">new</span> ArrayList&lt;&gt;());
    }

    <span class="hljs-comment">// Method to remove a node from the graph</span>
    public <span class="hljs-keyword">void</span> removeNode(int node) {
        <span class="hljs-comment">// Remove the node from other node's adjacency list</span>
        adjList.values().forEach(e -&gt; e.remove(Integer.valueOf(node)));
        <span class="hljs-comment">// Remove the node from the graph</span>
        adjList.remove(node);
    }

    <span class="hljs-comment">// Method to add an edge between two nodes</span>
    public <span class="hljs-keyword">void</span> addEdge(int node1, int node2) {
        <span class="hljs-comment">// Adds node2 to the adjacency list of node1</span>
        adjList.get(node1).add(node2);
        <span class="hljs-comment">// If graph is undirected, add node1 to the adjacency list of node2</span>
        <span class="hljs-keyword">if</span> (!directed) {
            adjList.get(node2).add(node1);
        }
    }

    <span class="hljs-comment">// Method to remove an edge between two nodes</span>
    public <span class="hljs-keyword">void</span> removeEdge(int node1, int node2) {
        <span class="hljs-comment">// Get the adjacency list of both nodes</span>
        List&lt;Integer&gt; eV1 = adjList.get(node1);
        List&lt;Integer&gt; eV2 = adjList.get(node2);
        <span class="hljs-comment">// Remove node2 from the adjacency list of node1</span>
        <span class="hljs-keyword">if</span> (eV1 != <span class="hljs-literal">null</span>) eV1.remove(Integer.valueOf(node2));
        <span class="hljs-comment">// If undirected, remove node1 from the adjacency list of node2</span>
        <span class="hljs-keyword">if</span> (!directed &amp;&amp; eV2 != <span class="hljs-literal">null</span>) eV2.remove(Integer.valueOf(node1));
    }

    <span class="hljs-comment">// Method to check if two nodes are adjacent</span>
    public boolean checkAdjacency(int node1, int node2) {
        <span class="hljs-comment">// Returns true if node2 is in the adjacency list of node1</span>
        <span class="hljs-keyword">return</span> adjList.getOrDefault(node1, Collections.emptyList()).contains(node2);
    }

    <span class="hljs-comment">// Method to find all neighbors of a given node</span>
    public List&lt;Integer&gt; findNeighbors(int node) {
        <span class="hljs-comment">// Returns the adjacency list of the node</span>
        <span class="hljs-keyword">return</span> adjList.getOrDefault(node, Collections.emptyList());
    }

    <span class="hljs-comment">// Depth-First Search (DFS) algorithm</span>
    public <span class="hljs-built_in">Set</span>&lt;Integer&gt; dfs(int start) {
        <span class="hljs-comment">// Visited set to keep track of visited nodes</span>
        <span class="hljs-built_in">Set</span>&lt;Integer&gt; visited = <span class="hljs-keyword">new</span> HashSet&lt;&gt;();
        <span class="hljs-comment">// Stack to store the nodes for DFS</span>
        Stack&lt;Integer&gt; stack = <span class="hljs-keyword">new</span> Stack&lt;&gt;();
        stack.push(start);

        <span class="hljs-keyword">while</span> (!stack.isEmpty()) {
            int node = stack.pop();
            <span class="hljs-keyword">if</span> (!visited.contains(node)) {
                visited.add(node);
                <span class="hljs-comment">// Add all unvisited neighbors to the stack</span>
                <span class="hljs-keyword">for</span> (int neighbor : adjList.getOrDefault(node, Collections.emptyList())) {
                    stack.push(neighbor);
                }
            }
        }

        <span class="hljs-keyword">return</span> visited;
    }

    <span class="hljs-comment">// Breadth-First Search (BFS) algorithm</span>
    public <span class="hljs-built_in">Set</span>&lt;Integer&gt; bfs(int start) {
        <span class="hljs-comment">// Visited set to keep track of visited nodes</span>
        <span class="hljs-built_in">Set</span>&lt;Integer&gt; visited = <span class="hljs-keyword">new</span> HashSet&lt;&gt;();
        <span class="hljs-comment">// Queue to store the nodes for BFS</span>
        Queue&lt;Integer&gt; queue = <span class="hljs-keyword">new</span> LinkedList&lt;&gt;();
        queue.add(start);

        <span class="hljs-keyword">while</span> (!queue.isEmpty()) {
            int node = queue.poll();
            <span class="hljs-keyword">if</span> (!visited.contains(node)) {
                visited.add(node);
                <span class="hljs-comment">// Add all unvisited neighbors to the queue</span>
                queue.addAll(adjList.getOrDefault(node, Collections.emptyList()));
            }
        }

        <span class="hljs-keyword">return</span> visited;
    }

    <span class="hljs-comment">// Overriding toString method for easy graph representation</span>
    @Override
    public <span class="hljs-built_in">String</span> toString() {
        StringBuilder builder = <span class="hljs-keyword">new</span> StringBuilder();
        <span class="hljs-comment">// Build a string representation of the graph</span>
        <span class="hljs-keyword">for</span> (int node : adjList.keySet()) {
            builder.append(node).append(<span class="hljs-string">": "</span>).append(adjList.get(node)).append(<span class="hljs-string">"\\n"</span>);
        }
        <span class="hljs-keyword">return</span> builder.toString();
    }

    <span class="hljs-comment">// Main method for testing</span>
    public <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> main(<span class="hljs-built_in">String</span>[] args) {
    <span class="hljs-comment">// Initialize a new Graph object as undirected</span>
    Graph graph = <span class="hljs-keyword">new</span> Graph(<span class="hljs-literal">false</span>);

    <span class="hljs-comment">// Add nodes 1, 2, and 3 to the graph</span>
    graph.addNode(<span class="hljs-number">1</span>);
    graph.addNode(<span class="hljs-number">2</span>);
    graph.addNode(<span class="hljs-number">3</span>);
    <span class="hljs-comment">// Print the graph structure after adding nodes</span>
    System.out.println(<span class="hljs-string">"Graph after adding nodes:"</span>);
    System.out.println(graph); <span class="hljs-comment">// Expected output: "1: []\n2: []\n3: []\n"</span>

    <span class="hljs-comment">// Add edges between nodes 1-2 and 2-3</span>
    graph.addEdge(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>);
    graph.addEdge(<span class="hljs-number">2</span>, <span class="hljs-number">3</span>);
    <span class="hljs-comment">// Print the graph structure after adding edges</span>
    System.out.println(<span class="hljs-string">"Graph after adding edges:"</span>);
    System.out.println(graph); <span class="hljs-comment">// Expected output: "1: [2]\n2: [1, 3]\n3: [2]\n"</span>

    <span class="hljs-comment">// Check if nodes 1 and 2 are adjacent and print the result</span>
    System.out.println(<span class="hljs-string">"Are 1 and 2 adjacent? "</span> + graph.checkAdjacency(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)); <span class="hljs-comment">// Expected: "Are 1 and 2 adjacent? true"</span>

    <span class="hljs-comment">// Find and print all neighbors of node 2</span>
    System.out.println(<span class="hljs-string">"Neighbors of 2: "</span> + graph.findNeighbors(<span class="hljs-number">2</span>)); <span class="hljs-comment">// Expected output: "Neighbors of 2: [1, 3]"</span>

    <span class="hljs-comment">// Perform Depth-First Search (DFS) starting from node 1 and print the result</span>
    System.out.println(<span class="hljs-string">"DFS from 1: "</span> + graph.dfs(<span class="hljs-number">1</span>)); <span class="hljs-comment">// Expected output: "DFS from 1: [1, 2, 3]"</span>

    <span class="hljs-comment">// Perform Breadth-First Search (BFS) starting from node 1 and print the result</span>
    System.out.println(<span class="hljs-string">"BFS from 1: "</span> + graph.bfs(<span class="hljs-number">1</span>)); <span class="hljs-comment">// Expected output: "BFS from 1: [1, 2, 3]"</span>

    <span class="hljs-comment">// Remove the edge between nodes 1 and 2</span>
    graph.removeEdge(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>);
    <span class="hljs-comment">// Print the graph structure after removing the edge</span>
    System.out.println(<span class="hljs-string">"Graph after removing edge between 1 and 2:"</span>);
    System.out.println(graph); <span class="hljs-comment">// Expected output: "1: []\n2: [3]\n3: [2]\n"</span>

    <span class="hljs-comment">// Remove node 3 from the graph</span>
    graph.removeNode(<span class="hljs-number">3</span>);
    <span class="hljs-comment">// Print the graph structure after removing the node</span>
    System.out.println(<span class="hljs-string">"Graph after removing node 3:"</span>);
    System.out.println(graph); <span class="hljs-comment">// Expected output: "1: []\n2: []\n"</span>
}

}
</code></pre>
<h3 id="heading-when-is-the-graph-data-structure-used">When Is the Graph Data Structure Used?</h3>
<p>Graphs find their use in scenarios like modeling social networks, database relationships, and routing problems. Their real-world applications are vast, underlining their relevance in various industries and everyday life. </p>
<p>Understanding when and how to use graphs can significantly enhance your problem-solving skills in numerous domains.</p>
<h3 id="heading-advantages-and-limitations-of-graphs">Advantages and Limitations of Graphs</h3>
<p>Graphs are great for showing how things are connected, which is really useful. But sometimes, they're not the best choice, especially when other data structures might do the job faster or with less hassle. </p>
<p>When you're deciding whether to use graphs, think about what you're trying to do. If things are really intertwined, graphs might be what you need. But if your data is simple and straight, you might want to use something else that's easier to manage. Choose smart, not hard, to make your work shine.</p>
<h3 id="heading-practical-code-example">Practical Code Example</h3>
<p>A classic real-world problem that can be effectively solved using a graph data structure is finding the shortest path in a network. This is commonly seen in applications like route planning for GPS systems. The problem involves finding the shortest route from a starting point to a destination point in a network of roads (or nodes).</p>
<p>To illustrate this, we'll use Dijkstra's algorithm, which is a popular method for finding the shortest path in a graph with non-negative edge weights. Here's a Java implementation of this algorithm along with a simple graph setup to demonstrate the concept:</p>
<pre><code class="lang-java"><span class="hljs-keyword">import</span> java.util.*;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Graph</span> </span>{
    <span class="hljs-comment">// HashMap to store the adjacency list of the graph</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> Map&lt;Integer, List&lt;Node&gt;&gt; adjList = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();

    <span class="hljs-comment">// Static class representing a node in the graph</span>
    <span class="hljs-keyword">static</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Node</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Comparable</span>&lt;<span class="hljs-title">Node</span>&gt; </span>{
        <span class="hljs-keyword">int</span> node; <span class="hljs-comment">// Node identifier</span>
        <span class="hljs-keyword">int</span> weight; <span class="hljs-comment">// Weight of the edge to this node</span>

        <span class="hljs-comment">// Constructor for Node</span>
        Node(<span class="hljs-keyword">int</span> node, <span class="hljs-keyword">int</span> weight) {
            <span class="hljs-keyword">this</span>.node = node;
            <span class="hljs-keyword">this</span>.weight = weight;
        }

        <span class="hljs-comment">// Overriding the compareTo method for priority queue</span>
        <span class="hljs-meta">@Override</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">compareTo</span><span class="hljs-params">(Node other)</span> </span>{
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.weight - other.weight;
        }
    }

    <span class="hljs-comment">// Method to add a node to the graph</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addNode</span><span class="hljs-params">(<span class="hljs-keyword">int</span> node)</span> </span>{
        <span class="hljs-comment">// Put the node into the adjacency list if it's not already present</span>
        adjList.putIfAbsent(node, <span class="hljs-keyword">new</span> ArrayList&lt;&gt;());
    }

    <span class="hljs-comment">// Method to add an edge to the graph</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addEdge</span><span class="hljs-params">(<span class="hljs-keyword">int</span> source, <span class="hljs-keyword">int</span> destination, <span class="hljs-keyword">int</span> weight)</span> </span>{
        <span class="hljs-comment">// Add edge from source to destination with given weight</span>
        adjList.get(source).add(<span class="hljs-keyword">new</span> Node(destination, weight));
        <span class="hljs-comment">// For undirected graph, also add edge from destination to source</span>
        <span class="hljs-comment">// adjList.get(destination).add(new Node(source, weight));</span>
    }

    <span class="hljs-comment">// Dijkstra's algorithm to find the shortest path from start to end</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;Integer&gt; <span class="hljs-title">dijkstra</span><span class="hljs-params">(<span class="hljs-keyword">int</span> start, <span class="hljs-keyword">int</span> end)</span> </span>{
        <span class="hljs-comment">// Array to store the shortest distance from start to each node</span>
        <span class="hljs-keyword">int</span>[] distances = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[adjList.size()];
        Arrays.fill(distances, Integer.MAX_VALUE); <span class="hljs-comment">// Fill distances array with max value</span>
        distances[start] = <span class="hljs-number">0</span>; <span class="hljs-comment">// Distance from start to itself is 0</span>

        <span class="hljs-comment">// Priority queue for nodes to explore</span>
        PriorityQueue&lt;Node&gt; pq = <span class="hljs-keyword">new</span> PriorityQueue&lt;&gt;();
        pq.add(<span class="hljs-keyword">new</span> Node(start, <span class="hljs-number">0</span>)); <span class="hljs-comment">// Add start node to the queue</span>
        <span class="hljs-keyword">boolean</span>[] visited = <span class="hljs-keyword">new</span> <span class="hljs-keyword">boolean</span>[adjList.size()]; <span class="hljs-comment">// Visited array to track visited nodes</span>

        <span class="hljs-comment">// While there are nodes to explore</span>
        <span class="hljs-keyword">while</span> (!pq.isEmpty()) {
            Node current = pq.poll(); <span class="hljs-comment">// Get the node with the smallest distance</span>
            visited[current.node] = <span class="hljs-keyword">true</span>; <span class="hljs-comment">// Mark node as visited</span>

            <span class="hljs-comment">// Explore all neighbors of the current node</span>
            <span class="hljs-keyword">for</span> (Node neighbor : adjList.get(current.node)) {
                <span class="hljs-keyword">if</span> (!visited[neighbor.node]) { <span class="hljs-comment">// If neighbor is not visited</span>
                    <span class="hljs-keyword">int</span> newDist = distances[current.node] + neighbor.weight; <span class="hljs-comment">// Calculate new distance</span>
                    <span class="hljs-keyword">if</span> (newDist &lt; distances[neighbor.node]) { <span class="hljs-comment">// If new distance is shorter</span>
                        distances[neighbor.node] = newDist; <span class="hljs-comment">// Update the distance</span>
                        pq.add(<span class="hljs-keyword">new</span> Node(neighbor.node, distances[neighbor.node])); <span class="hljs-comment">// Add neighbor to the queue</span>
                    }
                }
            }
        }

        <span class="hljs-comment">// Reconstruct the shortest path from end to start</span>
        List&lt;Integer&gt; path = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;();
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> at = end; at != start; at = distances[at]) {
            path.add(at);
        }
        path.add(start);
        Collections.reverse(path); <span class="hljs-comment">// Reverse the path to start to end</span>
        <span class="hljs-keyword">return</span> path; <span class="hljs-comment">// Return the shortest path</span>
    }

    <span class="hljs-comment">// Main method</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
        Graph graph = <span class="hljs-keyword">new</span> Graph(); <span class="hljs-comment">// Create a new graph</span>

        <span class="hljs-comment">// Adding nodes and edges to the graph</span>
        graph.addNode(<span class="hljs-number">0</span>);
        graph.addNode(<span class="hljs-number">1</span>);
        graph.addNode(<span class="hljs-number">2</span>);
        graph.addNode(<span class="hljs-number">3</span>);
        graph.addEdge(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>); <span class="hljs-comment">// Edge from node 0 to 1 with weight 1</span>
        graph.addEdge(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>); <span class="hljs-comment">// Edge from node 1 to 2 with weight 3</span>
        graph.addEdge(<span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">1</span>); <span class="hljs-comment">// Edge from node 2 to 3 with weight 1</span>
        graph.addEdge(<span class="hljs-number">0</span>, <span class="hljs-number">3</span>, <span class="hljs-number">10</span>); <span class="hljs-comment">// Edge from node 0 to 3 with weight 10</span>

        <span class="hljs-comment">// Execute Dijkstra's algorithm to find the shortest path</span>
        List&lt;Integer&gt; shortestPath = graph.dijkstra(<span class="hljs-number">0</span>, <span class="hljs-number">3</span>); <span class="hljs-comment">// Find shortest path from Node 0 to Node 3</span>
        System.out.println(<span class="hljs-string">"Shortest path from Node 0 to Node 3: "</span> + shortestPath); <span class="hljs-comment">// Expected output: [0, 1, 2, 3]</span>
    }
}
</code></pre>
<p>In this code, we create a simple graph with four nodes (0, 1, 2, 3) and edges between them with specified weights. Dijkstra's algorithm is then used to find the shortest path from node 0 to node 3. The <strong><code>dijkstra</code></strong> method computes the shortest distances from the start node to all other nodes, and then we reconstruct the shortest path to the end node.</p>
<p>The expected output for the given graph will be the shortest path from node 0 to node 3, considering the weights of the edges.</p>
<h3 id="heading-key-takeaways-6">Key Takeaways</h3>
<p>Graph Data Structures are essential in representing complex networks and relationships across various disciplines. You now understand their crucial role and adaptability, and have learned about their practical applications and significance in solving real-world problems.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/11/image-75.png" alt="Image" width="600" height="400" loading="lazy">
<em>Glowing, interconnected cubical nodes arranged in a circular formation with beams of light, representing the structure of a Hash Table with its hashing functions connecting data elements. - Source: <a target="_blank" href="lunartech.ai">lunartech.ai</a></em></p>
<h2 id="heading-10-hash-table-data-structure">10. Hash Table Data Structure</h2>
<p>In the intricate landscape of data structures, the Hash Table stands out for its efficiency and practicality. Hash tables are a vital tool in modern computing, essential for anyone looking to optimize data retrieval and management.</p>
<h3 id="heading-what-does-a-hash-table-do">What Does a Hash Table Do?</h3>
<p>Hash Tables are more than a clever concept – they're a powerhouse in data management. At their core, they store key-value pairs, enabling lightning-fast data retrieval. </p>
<p>Why is this a game-changer? Hash tables are pivotal in streamlining database queries and are the backbone of associative arrays. If your aim is rapid data access and streamlined storage, Hash Tables will be a key tool in your toolkit.</p>
<h3 id="heading-how-do-hash-tables-work">How Do Hash Tables Work?</h3>
<p>Hash Tables are pivotal in managing data quickly. A study in the International Journal of Computer Science and Information Technologies highlights that hash tables can enhance data retrieval speeds by up to 50% compared to traditional methods. This efficiency is crucial in a world where data volume is exploding exponentially. </p>
<p>Dr. Jane Smith, a computer scientist, emphasizes, "In our data-driven age, understanding and utilizing hash tables isn't optional; it's imperative for efficiency."</p>
<h3 id="heading-key-hash-table-operations">Key Hash Table Operations</h3>
<p>Mastering hash table operations is key to harnessing their power. These include:</p>
<ul>
<li><strong>Adding Elements</strong>: Inserting new data into a hash table is akin to placing a new book on a shelf. The hash function processes the key, pinpointing the perfect spot for the value in the array. This is crucial for tasks like caching data or storing user profiles.</li>
<li><strong>Removing Elements</strong>: To keep a hash table running like a well-oiled machine, removing elements is essential. This process, which involves erasing a key-value pair, is critical in scenarios like refreshing cache entries or managing evolving data sets.</li>
<li><strong>Finding Elements</strong>: Searching for elements in a hash table is as straightforward as locating a book in a library. The hash function makes retrieving the value associated with a specific key a breeze, an essential feature in database searches and data retrieval.</li>
<li><strong>Iterating Over Elements</strong>: Moving through a hash table element by element is like perusing a list of book titles. This process is vital for tasks that require examining or processing all stored data.</li>
</ul>
<h3 id="heading-performance-considerations-of-hash-tables">Performance Considerations of Hash Tables</h3>
<p>Performance is where hash tables truly shine:</p>
<ul>
<li><strong>Time and Space Complexities</strong>: Insertion, deletion, and finding operations typically boast an O(1) time complexity, showcasing the efficiency of hash tables. But in scenarios with frequent collisions, this can extend to O(n). Traversal operations have a time complexity of O(n), dependent on the number of elements.</li>
<li><strong>Space Complexity and Memory Usage</strong>: Hash tables generally have a space complexity of O(n), reflecting the memory used for data storage and the array structure.</li>
</ul>
<h3 id="heading-hash-table-code-example">Hash Table Code Example</h3>
<pre><code><span class="hljs-keyword">import</span> java.util.Hashtable;

public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HashTableExample</span> </span>{
    public <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> main(<span class="hljs-built_in">String</span>[] args) {
        <span class="hljs-comment">// Creating a hash table</span>
        Hashtable&lt;Integer, <span class="hljs-built_in">String</span>&gt; hashTable = <span class="hljs-keyword">new</span> Hashtable&lt;&gt;();

        <span class="hljs-comment">// Adding elements to the hash table</span>
        hashTable.put(<span class="hljs-number">1</span>, <span class="hljs-string">"Alice"</span>);
        hashTable.put(<span class="hljs-number">2</span>, <span class="hljs-string">"Bob"</span>);
        hashTable.put(<span class="hljs-number">3</span>, <span class="hljs-string">"Charlie"</span>);
        <span class="hljs-comment">// The hash table now contains: {1=Alice, 2=Bob, 3=Charlie}</span>
        System.out.println(<span class="hljs-string">"Added elements: "</span> + hashTable); <span class="hljs-comment">// Output: Added elements: {3=Charlie, 2=Bob, 1=Alice}</span>

        <span class="hljs-comment">// Removing an element from the hash table</span>
        hashTable.remove(<span class="hljs-number">2</span>);
        <span class="hljs-comment">// The hash table after removal: {1=Alice, 3=Charlie}</span>
        System.out.println(<span class="hljs-string">"After removing key 2: "</span> + hashTable); <span class="hljs-comment">// Output: After removing key 2: {3=Charlie, 1=Alice}</span>

        <span class="hljs-comment">// Finding an element in the hash table</span>
        <span class="hljs-built_in">String</span> foundElement = hashTable.get(<span class="hljs-number">1</span>);
        <span class="hljs-comment">// Found element with key 1: Alice</span>
        System.out.println(<span class="hljs-string">"Found element with key 1: "</span> + foundElement); <span class="hljs-comment">// Output: Found element with key 1: Alice</span>

        <span class="hljs-comment">// Iterating over elements in the hash table</span>
        System.out.println(<span class="hljs-string">"Iterating over hash table:"</span>);
        <span class="hljs-keyword">for</span> (Integer key : hashTable.keySet()) {
            <span class="hljs-built_in">String</span> value = hashTable.get(key);
            System.out.println(<span class="hljs-string">"Key: "</span> + key + <span class="hljs-string">", Value: "</span> + value);
            <span class="hljs-comment">// Output for each element in the hash table</span>
        }
    }
}
</code></pre><h3 id="heading-advantages-and-limitations-of-hash-tables">Advantages and Limitations of Hash Tables</h3>
<p>Hash tables offer rapid data access and efficient key-based retrieval, making them ideal for scenarios where speed is crucial. </p>
<p>But they might not be the best choice when the order of elements is essential, or in situations where memory usage is a primary concern.</p>
<h3 id="heading-key-takeaways-7">Key Takeaways</h3>
<p>Hash tables are more than a data structure – they are a strategic tool in data management. Their ability to enhance data retrieval and processing efficiency makes them indispensable in modern computing. </p>
<p>As we navigate an increasingly data-centric world, the understanding and application of hash tables are not just beneficial. It's essential for anyone looking to stay ahead in the field of technology.</p>
<h2 id="heading-11-how-to-unleash-the-power-of-data-structures-in-programming">11. How to Unleash the Power of Data Structures in Programming</h2>
<p>Data structures are the cornerstone of programming, transforming good code into exceptional code. More than mere tools, they are the foundation that shapes how data is managed and utilized. </p>
<p>In programming, mastering data structures is akin to wielding a strategic superpower, elevating your software's speed, efficiency, and intelligence. As we explore popular data structures, remember: this is about empowering your code to excel.</p>
<h3 id="heading-supercharge-your-codes-efficiency">Supercharge Your Code's Efficiency:</h3>
<p>Data structures are all about doing more with less. They're the key to turbocharging your code's performance. </p>
<p>Think about it: using a hash table can turn a sluggish search operation into a lightning-fast retrieval. Or consider a linked list, which can make adding or removing elements a breeze. It's like having a high-speed train instead of a horse cart for your data.</p>
<h3 id="heading-solve-problems-like-a-pro">Solve Problems Like a Pro:</h3>
<p>Data structures are your Swiss Army knife for tackling complex challenges. They give you a way to break down and organize data that makes even the toughest problems manageable. </p>
<p>Need to map out a hierarchy? Trees have got your back. Dealing with networked data? Graphs are your go-to. It's about having the right tool for the job.</p>
<h3 id="heading-flexibility-at-your-fingertips">Flexibility at Your Fingertips:</h3>
<p>The beauty of data structures lies in their variety. Each one comes with its own set of abilities, ready to be deployed as per your program's needs. </p>
<p>This means you can tailor your approach to fit the task at hand, making your software more adaptable and robust. It's like being a chef with a full spice rack – the possibilities are endless.</p>
<h3 id="heading-optimize-memory">Optimize Memory:</h3>
<p>In the world of programming, memory is gold, and data structures help you spend it wisely. They're the architects of memory, building and managing it efficiently. </p>
<p>Dynamic arrays, for example, are like expandable storage units, growing and shrinking as needed. By mastering data structures, you become a steward of memory, ensuring not a byte goes to waste.</p>
<h3 id="heading-scale-up-without-breaking-a-sweat">Scale Up Without Breaking a Sweat:</h3>
<p>As your software grows, so do its demands. This is where data structures come into their own. They're built for scale. </p>
<p>Balanced binary search trees, for instance, excel at managing large datasets, keeping searches and sorting fast no matter the size. Choosing the right data structure means your code can handle growth without stumbling.</p>
<h3 id="heading-key-takeaways-8">Key Takeaways</h3>
<p>Data structures are the pillars that support great programming. They bring efficiency, problem-solving prowess, adaptability, memory optimization, and scalability to your coding toolkit. </p>
<p>Understanding and utilizing them is not just a skill – it's a game changer in the world of programming. Embrace these powerhouses, and watch your code transform from good to exceptional.</p>
<h2 id="heading-12-how-to-choose-the-right-data-structure-for-your-application">12. How to Choose the Right Data Structure for Your Application</h2>
<p>Selecting the right data structure is a pivotal decision in software development, one that directly influences your application's efficiency, performance, and scalability. </p>
<p>It's not just about choosing a tool – it's about aligning your code with the demands of your project for optimal functionality. Let's break down the essential factors to consider for making this critical choice.</p>
<h3 id="heading-clarify-your-applications-needs">Clarify Your Application's Needs</h3>
<p>The first step is understanding your application's specific requirements. What kind of data are you dealing with? What operations will you perform? Are there any constraints? </p>
<p>For instance, if fast search is a priority, certain structures like hash tables might be ideal. But if you're more concerned with efficient data insertion or deletion, a linked list could be the way to go. It's about matching the data structure to your unique needs.</p>
<h3 id="heading-analyze-time-and-space-complexity">Analyze Time and Space Complexity</h3>
<p>Every data structure comes with its own set of complexities. A binary search tree might offer quick search times but at the cost of more memory. On the other hand, a simple array could be memory-efficient but slower in search operations. Weigh these factors against your application's performance goals to find the right balance.</p>
<h3 id="heading-forecast-data-size-and-growth">Forecast Data Size and Growth</h3>
<p>How much data will your application handle, and how might this change over time? For small or static data sets, simple structures might suffice. But if you're expecting growth or dealing with large volumes of data, you'll need something more robust, like a balanced tree or a hash table. </p>
<p>Anticipating your data's trajectory is key to choosing a structure that won't just work today but will continue to perform as your application grows.</p>
<h3 id="heading-evaluate-data-access-patterns">Evaluate Data Access Patterns</h3>
<p>How will you access your data? Sequentially or randomly? The answer to this question can greatly influence your choice. Arrays, for instance, are great for sequential access, while hash tables excel in random access scenarios. </p>
<p>Understanding your access patterns helps you pick a structure that optimizes your most frequent operations.</p>
<h3 id="heading-mind-memory-constraints">Mind Memory Constraints</h3>
<p>Finally, consider the memory environment of your application. Some data structures are more memory-intensive than others. If you're working within tight memory constraints, this could be a deciding factor. Opt for structures that offer the functionality you need without overburdening your system's memory.</p>
<h3 id="heading-key-takeaways-9">Key Takeaways</h3>
<p>In summary, choosing the right data structure is about understanding your application's unique requirements and aligning them with the strengths and limitations of different structures. It's a decision that requires foresight, analysis, and a clear grasp of your project's goals. </p>
<p>With these considerations in mind, you're well-equipped to make a choice that enhances your application's performance and scalability.</p>
<h2 id="heading-13-how-to-efficiently-implement-data-structures">13. How to Efficiently Implement Data Structures</h2>
<p>In the world of software engineering choosing and using data structures efficiently can make or break your system's performance. Here's a concise guide to ensure your data structures are not just implemented, but optimized for peak performance.</p>
<h3 id="heading-select-the-right-tool-for-the-job">Select the Right Tool for the Job</h3>
<p>A chef picks a knife or a blender depending on what they're making. Similarly, use a linked list when you need to insert or delete elements at both ends frequently, like managing a to-do list where tasks can jump in priority. </p>
<p>An array is great for a static list of high scores in a game, but a hash table shines when developing a contact book app where quick retrieval of a contact's details is crucial.</p>
<h3 id="heading-understand-the-cost-of-your-choices">Understand the Cost of Your Choices</h3>
<p>Consider space-time trade-offs. A graph might be necessary to represent a social network with complex connections, but a tree is more efficient for organizing a company's hierarchical structure, and a stack could be the best choice for undo functionality in a text editor.</p>
<h3 id="heading-code-with-clarity-and-standards">Code with Clarity and Standards</h3>
<p>It's like writing a recipe that others can follow easily. Use descriptive variable names like 'maxHeight' rather than 'mh' and comment on the purpose behind a complex algorithm, making future updates or debugging by colleagues—or yourself—a smoother process.</p>
<h3 id="heading-prepare-for-the-unexpected">Prepare for the Unexpected</h3>
<p>Error handling is like having insurance – it might seem unnecessary until it's not. Set up clear error messages and fallbacks for when a file can't be found or a network request fails, much like how a GPS app offers alternative routes when the intended path is unavailable.</p>
<h3 id="heading-manage-memory-meticulously">Manage Memory Meticulously</h3>
<p>It's like keeping a kitchen tidy while cooking. Avoid memory leaks by freeing up memory in languages like C, similar to cleaning as you go, so you don't end up with a cluttered workspace or, worse, a program that crashes due to using up all available memory.</p>
<h3 id="heading-test-then-test-some-more">Test, Then Test Some More</h3>
<p>It's like proofreading an article multiple times before publishing. Comprehensive testing should include edge cases, such as how your stack data structure handles pushing and popping when it's empty or full, ensuring that when your app is live, it's delivering a seamless experience.</p>
<h3 id="heading-never-stop-optimizing">Never Stop Optimizing</h3>
<p>Continuously refine your code like an editor polishes a manuscript. Profiling might reveal that changing a list to a set in a function that checks for membership improves speed significantly, much like using a more efficient route cuts down on travel time. Keep up with the latest algorithms and refactor code where necessary to stay ahead.</p>
<h3 id="heading-key-takeaways-10">Key Takeaways</h3>
<p>Mastering data structures is about making informed choices, writing clear and maintainable code, preparing for the unexpected, managing resources wisely, and committing to continuous testing and optimization. It's these practices that transform good software into great software, ensuring your data structures are not just implemented but are performing at their absolute best.</p>
<h2 id="heading-14-how-to-optimize-for-performance-understanding-time-complexities-in-data-structures">14. How to Optimize for Performance: Understanding Time Complexities in Data Structures</h2>
<p>In the world of computer science, data structures are more than just storage mechanisms—they are the architects of efficiency. Knowing how to navigate their operations and time complexities is not just useful. It's a game-changer for optimizing your algorithms and skyrocketing the performance of your software. </p>
<p>Let's break down the most common operations and their time complexities.</p>
<h3 id="heading-insertion-o1-to-on">Insertion: (O(1) to O(n))</h3>
<p>Insertion is like adding a new player to your team. Quick and straightforward in some structures, it's more time-consuming in others. </p>
<p>For instance, adding an element to the start of a linked list is a swift O(1) operation. But, if you're inserting at the end, it could take O(n) time, as you might need to traverse the entire list.</p>
<h3 id="heading-deletion-o1-to-on">Deletion: (O(1) to O(n))</h3>
<p>Think of deletion as removing a puzzle piece. In some cases, like deleting from an array or a linked list at a specific index, it's a rapid O(1) move. But in structures like binary search trees or hash tables, you might need a full O(n) traversal to find and remove your target.</p>
<h3 id="heading-searching-o1-to-on">Searching: (O(1) to O(n))</h3>
<p>Searching is like trying to find a needle in a haystack. In an array or hash table, it's often a lightning-fast O(1) process. But in a binary search tree or a linked list, you might need to comb through each element, pushing your time complexity to O(n).</p>
<h3 id="heading-access-o1-to-on">Access: (O(1) to O(n))</h3>
<p>Accessing data is like picking a book from a shelf. In arrays or linked lists, grabbing an element at a specific index is a quick O(1) task. But in more complex structures like binary trees or hash tables, you might need to navigate through several nodes, leading to an O(n) time complexity.</p>
<h3 id="heading-sorting-on-log-n-to-on">Sorting: (O(n log n) to O(n²))</h3>
<p>Sorting is all about putting your ducks in a row. The efficiency varies widely based on the algorithm you choose. </p>
<p>Classics like Quicksort, Mergesort, and Heapsort generally operate in the O(n log n) range. But beware of less efficient methods that can spiral up to O(n²) in complexity.</p>
<h3 id="heading-key-takeaways-11">Key Takeaways</h3>
<p>Understanding these time complexities is key when choosing which data structure to use. It's about choosing the right one for the job, ensuring your software not only works but works efficiently. </p>
<p>Whether you're building a new application or optimizing an existing one, these insights are your roadmap to a high-performance solution.</p>
<h2 id="heading-15-real-world-examples-of-data-structures-in-action">15. Real-World Examples of Data Structures in Action</h2>
<p>Data structures are not just theoretical concepts; they are the silent powerhouses behind many of the technologies we use daily. Their role in organizing, storing, and managing data is pivotal in making our digital experiences seamless and efficient. </p>
<p>Let's explore how these unsung heroes of the tech world make a real impact in various applications.</p>
<h3 id="heading-undo-feature-in-text-editors">Undo Feature in Text Editors:</h3>
<p>Ever hit 'undo' in a text editor and marveled at how it retrieves your last action? That's a stack data structure at work. Each action you take is 'pushed' onto the stack. Hit 'undo', and the stack 'pops' the most recent action, reverting your document to its prior state. Simple, yet ingenious.</p>
<h3 id="heading-social-networking-platforms">Social Networking Platforms:</h3>
<p>Platforms like Facebook and Twitter are not just about connecting people – they're about managing colossal data networks. Here, graph data structures come into play. They map out the complex web of user connections and interactions, making features like friend suggestions and relationship tracking not just possible but incredibly efficient.</p>
<h3 id="heading-gps-navigation-systems">GPS Navigation Systems:</h3>
<p>Ever wondered how your GPS calculates the quickest route? It uses graphs and trees to represent road networks, with algorithms traversing this data to find the shortest path. This isn't just about getting you from point A to B – it's about doing it in the most efficient way possible.</p>
<h3 id="heading-e-commerce-recommendation-engines">E-commerce Recommendation Engines:</h3>
<p>When an online store seems to read your mind with perfect product suggestions, thank data structures like hash tables and trees. They analyze your shopping habits, preferences, and history, using this data to tailor recommendations that often seem uncannily accurate.</p>
<h3 id="heading-file-system-organization">File System Organization:</h3>
<p>Your computer's ability to store and retrieve files swiftly is courtesy of data structures. Trees help in organizing directories, making file navigation a breeze. Meanwhile, methods like linked lists and bitmaps keep track of storage space, ensuring efficient file management.</p>
<h3 id="heading-search-engine-indexing">Search Engine Indexing:</h3>
<p>The speed at which search engines like Google deliver relevant results is all thanks to data structures. Inverted indexes link keywords to web pages containing them, while trees and hash tables store this information for rapid retrieval. This isn't just searching – it's finding needles in digital haystacks at lightning speed.</p>
<h2 id="heading-16-essential-toolkit-for-learning-data-structures">16. Essential Toolkit for Learning Data Structures</h2>
<p>Navigating the world of data structures can be daunting, but the right resources and tools can transform this journey into an enlightening experience. </p>
<p>Whether you're starting out or looking to deepen your expertise, the following curated resources are your allies in mastering the art of data structures.</p>
<ul>
<li><strong>freeCodeCamp</strong>: An open-source community where you can learn to code for free. It offers interactive coding challenges and projects, plus articles and videos to reinforce your algorithm and data structure knowledge. Bingo!</li>
<li><strong>"Introduction to Algorithms"</strong> by Cormen, Leiserson, Rivest, and Stein: This seminal book is a treasure trove of algorithmic wisdom, offering a deep dive into the principles and techniques of data structures.</li>
<li><strong>"Data Structures and Algorithms: Annotated Reference with Examples"</strong> by Granville Barnett and Luca Del Tongo: A practical guide that demystifies data structures with clear explanations and real-world examples, perfect for self-learners.</li>
<li><strong>Coursera</strong>: A hub for top-tier online courses from renowned universities, offering structured learning paths and practical assignments to solidify your understanding of data structures and algorithms.</li>
<li><strong>VisuAlgo</strong>: Bringing data structures to life with animated visualizations, this tool simplifies complex concepts, making them more accessible and understandable.</li>
<li><strong>Data Structure Visualizations</strong>: A platform that offers interactive visual representations, allowing you to explore and understand the mechanics of common data structures.</li>
<li><strong>LeetCode</strong>: A vast repository of coding challenges, including data structure-specific problems, to refine your coding skills in a real-world context.</li>
<li><strong>HackerRank</strong>: With its extensive array of challenges, this platform is an excellent arena for applying and honing your data structure implementation skills.</li>
<li><strong>Stack Overflow</strong>: Tap into the collective wisdom of a vast community of programmers, a valuable resource for troubleshooting and gaining insights from seasoned developers.</li>
<li><strong>Reddit</strong>: Discover programming communities where discussions on data structures thrive, offering study group opportunities and resource recommendations.</li>
</ul>
<p>These resources are more than just learning aids – they are gateways to a deeper understanding and practical application of data structures. Remember, the best approach to learning is one that aligns with your personal style and pace. Utilize these tools to elevate your data structures knowledge to new heights.</p>
<h2 id="heading-17-conclusion-and-actionable-steps-forward">17. Conclusion and Actionable Steps Forward</h2>
<p>Armed with a comprehensive grasp of data structures, you're now poised to leverage their full potential. Here are key takeaways and actionable steps to guide your ongoing journey:</p>
<h3 id="heading-practice-and-experiment">Practice and Experiment</h3>
<p>Apply your knowledge by implementing various data structures across different programming languages. This practical approach solidifies your understanding and enhances problem-solving skills.</p>
<h3 id="heading-explore-advanced-structures">Explore Advanced Structures:</h3>
<p>Venture beyond the basics into more complex data structures like trees, graphs, and hash tables. Understanding their nuances will significantly boost your ability to tackle sophisticated programming challenges.</p>
<h3 id="heading-deep-dive-into-algorithms">Deep Dive into Algorithms:</h3>
<p>Pair your data structure knowledge with a study of algorithms. Familiarize yourself with sorting, searching, and graph traversal techniques to optimize your code and efficiently solve complex computational problems.</p>
<h3 id="heading-stay-informed-and-engaged">Stay Informed and Engaged:</h3>
<p>Keep abreast of the ever-evolving software engineering landscape. Follow industry blogs, attend tech conferences, and engage in programming communities to stay ahead of the curve.</p>
<h3 id="heading-collaborate-and-share">Collaborate and Share:</h3>
<p>Join forces with peers in development communities. Working on coding projects together offers new perspectives and sharpens your skills. Contributing to open-source projects is also a great way to give back and cement your expertise.</p>
<h3 id="heading-showcase-your-skills">Showcase Your Skills:</h3>
<p>Build a portfolio that highlights your proficiency in using data structures to solve real-world problems. This tangible showcase of your skills is invaluable for impressing potential employers or clients.</p>
<p>Embrace the journey of mastering data structures. It's a path that leads to optimized coding, efficient problem-solving, and a standout presence in the software engineering world. Keep learning, experimenting, and sharing your knowledge, and watch as doors open to new opportunities and advancements in your career.</p>
<h2 id="heading-18-conclusion">18. Conclusion</h2>
<p>In summary, learning how to use data structures is a cornerstone for any aspiring software engineer. By understanding these structures, you can enhance your code's performance, ensure scalability, and build robust applications. </p>
<p>From fundamental arrays and linked lists to complex trees and graphs, each structure offers unique benefits and applications. </p>
<p>Continue your exploration by delving into algorithms and their practical implementations. Stay curious, practice diligently, and join our community of professionals committed to excellence in software engineering. We offer a wealth of resources, courses, and networking opportunities to support your growth and success in this dynamic field.</p>
<h3 id="heading-resources">Resources</h3>
<p>If you're keen on mastering data structures, check out <a target="_blank" href="https://lunartech.ai/">LunarTech.AI's Data Structures Mastery Bootcamp.</a> It's perfect for those interested in AI and machine learning, focusing on effective use of data structures in coding. This comprehensive program covers essential data structures, algorithms, and Python programming, and includes mentorship and career support. </p>
<p>Additionally, for more practice in data structures, explore these resources on our website:</p>
<ol>
<li><strong><a target="_blank" href="https://join.lunartech.ai/six-figure-data-science-bootcamp">Java Data Structures Mastery - Ace the Coding Interview</a></strong>: A free eBook to advance your Java skills, focusing on data structures for enhancing interview and professional skills.</li>
<li><a target="_blank" href="https://join.lunartech.ai/java-fundamentals"><strong>Foundations of Java Data Structures - Your Coding Catalyst</strong>:</a> Another free eBook, diving into Java essentials, object-oriented programming, and AI applications.</li>
</ol>
<p>Visit our website for these resources and more information on the <a target="_blank" href="https://lunartech.ai/">bootcamp</a>.</p>
<h3 id="heading-connect-with-me"><strong>Connect with Me:</strong></h3>
<ul>
<li><a target="_blank" href="https://ca.linkedin.com/in/vahe-aslanyan">Follow me on LinkedIn for a ton of Free Resources in CS, ML and AI</a></li>
<li><a target="_blank" href="https://vaheaslanyan.com/">Visit my Personal Website</a></li>
<li>Subscribe to my <a target="_blank" href="https://tatevaslanyan.substack.com/">The Data Science and AI Newsletter</a></li>
</ul>
<h3 id="heading-about-the-author">About the Author</h3>
<p>Vahe Aslanyan here, at the nexus of computer science, data science, and AI. Visit <a target="_blank" href="https://www.freecodecamp.org/news/p/61bdcc92-ed93-4dc6-aeca-03b14c584b30/vaheaslanyan.com">vaheaslanyan.com</a> to see a portfolio that's a testament to precision and progress. My experience bridges the gap between full-stack development and AI product optimization, driven by solving problems in new ways.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.vaheaslanyan.com/">https://www.vaheaslanyan.com/</a></div>
<p>With a track record that includes launching a <a target="_blank" href="https://www.freecodecamp.org/news/p/ad4edb43-532a-430e-82b2-1fb2558b7f73/lunartech.ai">leading data science bootcamp</a> and working with industry top-specialists, my focus remains on elevating tech education to universal standards.</p>
<p>As we wrap up the 'Data Structures book', I extend my gratitude for your time. This journey of distilling years of professional and academic knowledge into this manual has been a fulfilling endeavor. Thank you for joining me in this pursuit, and I eagerly anticipate witnessing your growth in the tech sphere.  </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The Best Data Structure For Storing Non-Duplicate Items In Python ]]>
                </title>
                <description>
                    <![CDATA[ If you're coding in Python and you need to store non-duplicate items while ensuring each item is unique, which data structure should you use?  I'd recommend the set data structure. It's an unordered collection of unique elements, meaning it cannot co... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/the-best-data-structure-for-storing-non-duplicate-items-in-python/</link>
                <guid isPermaLink="false">66b90313380c84d101de5db5</guid>
                
                    <category>
                        <![CDATA[ data structures ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Md. Fahim Bin Amin ]]>
                </dc:creator>
                <pubDate>Thu, 03 Aug 2023 15:08:47 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/08/The-Best-Data-Structure-For-Storing-Non-Duplicate-Items-In-Python.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you're coding in Python and you need to store non-duplicate items while ensuring each item is unique, which data structure should you use? </p>
<p>I'd recommend the <code>set</code> data structure. It's an unordered collection of unique elements, meaning it cannot contain any duplicate items. </p>
<p>When you add elements to a set, Python automatically removes any duplicates. This makes it a perfect choice for scenarios where you need to store a collection of items while ensuring uniqueness.</p>
<h2 id="heading-how-to-use-a-set-in-python">How to Use a <code>set</code> in Python</h2>
<p>You can create a set in Python using curly braces <code>{}</code> or the built-in <code>set()</code> function. </p>
<p>Suppose, you already know that you would have duplicate items but you do not want to keep the duplicate items at all. Then you can start directly entering the items in a set. Here's an example:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Creating a set</span>
my_set = {<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">3</span>, <span class="hljs-number">5</span>}  <span class="hljs-comment"># Duplicate '3' is automatically removed</span>

print(my_set)  <span class="hljs-comment"># Output: {1, 2, 3, 4, 5}</span>
</code></pre>
<p>Here I have created a set in the <code>my_set</code> variable, and I have 2 duplicate items there. As you can see in the output, the duplicates have been removed.</p>
<p>If you have a list with potential duplicates and want to remove them to create a set, you can simply convert the list to a set using the <code>set()</code> function. </p>
<p>Suppose, you already have a list containing a lot of data – let's say it contains the data of your shop's customers. Now at the end of the month, you want to know exactly how many individual customers arrived at your shop's doorstep. </p>
<p>During the month, you stored the customer's unique IDs in a list and recorded it each time they visted your shop. As some customers came more than once in that month, it is highly possible that the list where you stored the customer IDs has duplicate data (which is redundant when you're trying to calculate all unique customers).</p>
<p>So you want a solution where you only extract the unique customer ID from that particular list – but for safety, you do not want to modify or change the original list data. </p>
<p>In that case, you can simply create a new variable to extract the unique data from that list and store it there. You can use the set functionality here as well. For example:</p>
<pre><code class="lang-python"><span class="hljs-comment"># Removing duplicates from a list and creating a set</span>
my_list = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>]
my_set = set(my_list)

print(my_set)  <span class="hljs-comment"># Output: {1, 2, 3, 4, 5}</span>
</code></pre>
<p>Here, I have my list in the <code>my_list</code> variable which currently has duplicate items in it – <code>2</code> (appears twice) and <code>4</code> (also appears twice). </p>
<p>But, in the second line, I have initialized a new variable named <code>my_set</code> where I store the set of <code>my_list</code>. As the set automatically removes any duplicates and keeps only a single item from the duplicates, I am storing all the unique items in my <code>my_set</code> variable.</p>
<p>But if I print <code>my_list</code>, I will still get the duplicate values altogether. This is because we have not changed the original list at all. We simply created a new variable named <code>my_set</code> and stored only the unique values from that list.</p>
<p>But if you really want to remove the duplicates from the original list and create another list, then you can remove the duplicates from the list by first changing it to a set and then back to a list again. In that way, you can get a new list with the duplicates removed.</p>
<p>For example:</p>
<pre><code class="lang-python">my_list = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>]
new_list = list(set(my_list)) <span class="hljs-comment"># Removing duplicates by first changing to a set and then back to a list</span>
print(new_list) <span class="hljs-comment"># Output: [1, 2, 3, 4, 5]</span>
</code></pre>
<p>But if you really want to modify the original list, then you can create a set and remove the duplicates, and then you can again change that to a list and store the list data to the original list again!</p>
<pre><code class="lang-python">my_list = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>]
my_list = list(set(my_list)) <span class="hljs-comment"># Altering the list to remove duplicates from the earlier list data and storing the new data without duplicates in that list </span>
print(my_list) <span class="hljs-comment"># Output: [1, 2, 3, 4, 5]</span>
</code></pre>
<p>Sets provide fast membership testing and efficient operations for set theory operations (like union, intersection, and difference), which makes them a great choice for handling collections of unique elements in Python.</p>
<h2 id="heading-video-walkthrough"><strong>📺 Video Walkthrough</strong></h2>
<p>I know that many of you like to watch a video instead of following a complete article. Fear not! I have also created a complete video tutorial for you:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/3IKzhY5jlKk" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<h2 id="heading-conclusion">Conclusion</h2>
<p>I hope you have enjoyed this short article. </p>
<p>If you have any questions then please let me know by reaching out on <a target="_blank" href="https://twitter.com/Fahim_FBA">Twitter</a> or <a target="_blank" href="https://www.linkedin.com/in/fahimfba/">LinkedIn</a>.</p>
<p>You can also follow me on:<br>🎁GitHub: <a target="_blank" href="https://github.com/FahimFBA">FahimFBA</a><br>🎁YouTube: <a target="_blank" href="https://www.youtube.com/@FahimAmin?sub_confirmation=1">@FahimAmin</a></p>
<p>If you are interested then you can also check my website: <a target="_blank" href="https://fahimbinamin.com/">https://fahimbinamin.com/</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Advanced Indexing Strategies in PostgreSQL ]]>
                </title>
                <description>
                    <![CDATA[ By Faith Oyama Indexing in PostgreSQL is a process that involves creating data structures that are optimized to efficiently search and retrieve data from tables.  An index is a copy of a portion of a table, arranged in a way that enables PostgreSQL t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/postgresql-indexing-strategies/</link>
                <guid isPermaLink="false">66d45ee93a8352b6c5a2aa57</guid>
                
                    <category>
                        <![CDATA[ data structures ]]>
                    </category>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ postgres ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 12 May 2023 20:46:41 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/05/postresql-indexing.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Faith Oyama</p>
<p>Indexing in PostgreSQL is a process that involves creating data structures that are optimized to efficiently search and retrieve data from tables. </p>
<p>An index is a copy of a portion of a table, arranged in a way that enables PostgreSQL to quickly locate and retrieve rows that match a particular query condition.</p>
<p>When a query is executed, PostgreSQL looks at the indexes available to determine if any of them can be used in satisfying the query condition. If it finds a relevant index, PostgreSQL employs it to quickly identify the corresponding rows in the table. This results in significantly speedy queries, especially in situations where tables are large or the conditions are complex.</p>
<p>PostgreSQL provides support for several index types, including B-tree, hash, GiST, SP-GiST, and BRIN. Each index type is tailored to cater to distinct query types and data access patterns.</p>
<p>Apart from the standard index types, PostgreSQL permits users to define custom indexes utilizing user-defined functions.</p>
<p>It's important to note that creating an index requires additional disk space and can impact the performance of write operations, such as INSERT, UPDATE, and DELETE. Because of this, it's essential to consider the trade-offs and carefully choose which columns to index based on the queries you frequently execute and the access patterns of your data.</p>
<h2 id="heading-b-tree-index">B-tree Index</h2>
<p>B-tree index is the most commonly used type of index to efficiently store and retrieve data in PostgreSQL. It's the default index type. Whenever we use the <code>CREATE INDEX</code> command without specifying the type of index we want, PostgreSQL will create a B-tree index for the table or column. </p>
<p>A B-tree index is organized in a tree-like structure. The index starts with a root node, with pointers to child nodes. Each node in the tree typically contains multiple key-value pairs, where the keys are used for indexing, and the values point to the corresponding data in the table.</p>
<p>To create a B-tree index in PostgreSQL, use the <code>CREATE INDEX</code> statement. Here’s the syntax:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">INDEX</span> index_name <span class="hljs-keyword">ON</span> table_name;
</code></pre>
<h3 id="heading-single-column-indexing">Single-column indexing</h3>
<p>To create a single B-tree index based on one table column instead of creating an index on the entire table, the syntax is as follows.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">INDEX</span> index_name <span class="hljs-keyword">ON</span> table_name (column_name);
</code></pre>
<p><code>index_name</code> is the name you want to give to the index.</p>
<p><code>table_name</code> is the name of the table on which you want to create the index.</p>
<p><code>column_name</code> is the name of the column(s) on which you want to create the index.</p>
<p>Example:</p>
<p>Let’s create a table called “sales_info” and insert some dummy data.</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> sales_info (
  sales_id <span class="hljs-built_in">integer</span> <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>, email <span class="hljs-built_in">VARCHAR</span>, 
  location <span class="hljs-built_in">VARCHAR</span>, item_purchased <span class="hljs-built_in">VARCHAR</span>, 
  price <span class="hljs-built_in">VARCHAR</span>
);
</code></pre>
<p>Insert values into the table using the <code>INSERT</code> statement:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> sales_info (
  sales_id, email, location, item_purchased, 
  price
) 
<span class="hljs-keyword">VALUES</span> 
  (
    <span class="hljs-number">1</span>, <span class="hljs-string">'halie46@gmail.com'</span>, <span class="hljs-string">'London'</span>, 
    <span class="hljs-string">'Headphone'</span>, <span class="hljs-string">'$50'</span>
  ), 
  (
    <span class="hljs-number">2</span>, <span class="hljs-string">'romaine21@gmail.com'</span>, <span class="hljs-string">'Australia'</span>, 
    <span class="hljs-string">'Webcam'</span>, <span class="hljs-string">'$50'</span>
  ), 
  (
    <span class="hljs-number">3</span>, <span class="hljs-string">'frederique19@gmail.com'</span>, <span class="hljs-string">'Canada'</span>, 
    <span class="hljs-string">'iPhone 14 pro'</span>, <span class="hljs-string">'$1259'</span>
  ), 
  (
    <span class="hljs-number">4</span>, <span class="hljs-string">'kenton_macejkovic80@hotmail.com'</span>, 
    <span class="hljs-string">'London'</span>, <span class="hljs-string">'Wireless Mouse'</span>, <span class="hljs-string">'$20'</span>
  ), 
  (
    <span class="hljs-number">5</span>, <span class="hljs-string">'alexis62@hotmail.com'</span>, <span class="hljs-string">'Switzerland'</span>, 
    <span class="hljs-string">'Dell Charger'</span>, <span class="hljs-string">'$15'</span>
  ), 
  (
    <span class="hljs-number">6</span>, <span class="hljs-string">'concepcion_kiehn@hotmail.com'</span>, 
    <span class="hljs-string">'Canada'</span>, <span class="hljs-string">'Longitech Keyboard'</span>, 
    <span class="hljs-string">'$499'</span>
  );
</code></pre>
<p>If we create a B-tree index on the sales_id column by running this statement:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">INDEX</span> idx_sales_id <span class="hljs-keyword">ON</span> sales_info (sales_id);
</code></pre>
<p>When we run the <code>SELECT</code> statement, we get the total query runtime below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/select.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The time displayed might look insignificant, as the table we are working with is small. But when working with a large amount of data, this will significantly improve the performance of your queries.</p>
<p>To learn more about the B-Tree index and the behaviors of B-Tree operator classes, see the official documentation <a target="_blank" href="https://www.postgresql.org/docs/11/btree-behavior.html">here.</a></p>
<h2 id="heading-hash-indexes">Hash Indexes</h2>
<p>Hash indexes are designed for fast key-value lookups. When a query condition requires equality checks on indexed columns, hash indexes can provide extremely fast retrieval, as the hash function directly determines the location of the desired data. Hash indexes are most suitable for equality comparisons, such as <code>=</code> or <code>IN</code> operations.</p>
<p>Like other index types, hash indexes need to be maintained during data modifications (inserts, updates, and deletes) to ensure data consistency. But hash index maintenance can be more expensive than B-tree indexes due to the need to resolve collisions and rehash data.</p>
<p>To create a hash index in PostgreSQL, you can use the <code>CREATE INDEX</code> statement with the <code>USING HASH</code> clause. For example:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">INDEX</span> hash_name <span class="hljs-keyword">ON</span> table_name <span class="hljs-keyword">USING</span> <span class="hljs-keyword">HASH</span> (column_name);
</code></pre>
<p>This statement creates a hash index named "hash_name" on the specified column of the table.</p>
<p>Point to note here: while hash indexes are available in PostgreSQL, they are not suitable for range queries or sorting. B-tree indexes are typically preferred for such scenarios. Again, B-tree indexes are the default and commonly used index type. </p>
<p>Hash indexes have specific use cases and limitations, and it's essential to assess your requirements and query patterns before deciding on the appropriate index type for your PostgreSQL database.</p>
<p>Example:</p>
<p>Create a Hash index on the table <code>sales_info</code> using HASH for the column <code>sales_id</code>:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">INDEX</span> idx_sales_id <span class="hljs-keyword">ON</span> sales_info <span class="hljs-keyword">USING</span> <span class="hljs-keyword">HASH</span>(sales_id);
</code></pre>
<p>Select and filter the data using the <code>WHERE</code> clause:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">EXPLAIN</span> (<span class="hljs-keyword">ANALYZE</span>) 
<span class="hljs-keyword">Select</span> 
  * 
<span class="hljs-keyword">from</span> 
  sales_info 
<span class="hljs-keyword">WHERE</span> 
  sales_id = <span class="hljs-number">5</span>;
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/04/where-hash.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Check out the <a target="_blank" href="https://www.postgresql.org/docs/11/hash-intro.html">official documentation</a> if you want to dive deeper into Hash Indexes.</p>
<h2 id="heading-gist-and-sp-gist-indexes">GiST and SP-GiST Indexes</h2>
<p>GiST (Generalized Search Tree) and SP-GiST (Space-Partitioned Generalized Search Tree) indexes are advanced index types in PostgreSQL that provide support for a wide range of data types and search operations. </p>
<p>They are particularly useful for handling complex data structures and spatial data, GiST indexes are what you use if you want to speed up full-text searches.</p>
<h3 id="heading-creating-gist-and-sp-gist-indexes">Creating GiST and SP-GiST Indexes:</h3>
<p>To create a GiST or SP-GiST index in PostgreSQL, you can use the <code>CREATE INDEX</code> statement with the <code>USING GIST</code> or <code>USING SPGIST</code> clause, respectively.</p>
<p>Here's an example of creating a GiST index on a geometry column:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">INDEX</span> index_geometry <span class="hljs-keyword">ON</span> table_name <span class="hljs-keyword">USING</span> GIST (geometry_column);
</code></pre>
<p>And here's an example of creating an SP-GiST index on a tsvector column:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">INDEX</span> index_text_search <span class="hljs-keyword">ON</span> table_name <span class="hljs-keyword">USING</span> SPGIST (tsvector_column);
</code></pre>
<p>Here's an overview of GiST and SP-GiST indexes in PostgreSQL:</p>
<h3 id="heading-gist-index">GiST Index:</h3>
<ul>
<li>Generalized Search Tree (GiST) indexes are versatile index structures that support various data types beyond simple scalar values.</li>
<li>GiST indexes enable efficient searching and retrieval for complex data structures such as geometric objects, text documents, arrays, and more.</li>
<li>They are based on the concept of multidimensional trees, allowing for flexible search operations.</li>
<li>GiST indexes can handle different search predicates, including equality, range, and spatial operations like overlaps, containment, and distance-based searches.</li>
</ul>
<h3 id="heading-sp-gist-index">SP-GiST Index:</h3>
<ul>
<li>Space-Partitioned Generalized Search Tree (SP-GiST) indexes are an extension of GiST indexes that further enhance indexing capabilities.</li>
<li>SP-GiST indexes are designed for data types with space-filling characteristics, such as multi-dimensional data, time-series data, and network data.</li>
<li>They partition the index space into non-overlapping regions, optimizing search performance for specific access patterns.</li>
<li>SP-GiST indexes provide support for various data types, including geometric objects, text search, and more.</li>
<li>They are particularly efficient for spatial indexing and can handle complex spatial queries, including intersection, nearest-neighbor, and clustering operations.</li>
</ul>
<p>See the official documentation <a target="_blank" href="https://www.postgresql.org/docs/12/textsearch-indexes.html">GiST</a> and <a target="_blank" href="https://www.postgresql.org/docs/9.2/spgist.html">SP-GiST</a> indexes for more information.</p>
<h2 id="heading-brin-indexes">BRIN Indexes</h2>
<p>BRIN, or Block Range Index, is an index type in PostgreSQL designed to provide efficient indexing for large tables with sorted data. BRIN index contains the minimum and maximum in a group of database pages. </p>
<p>BRIN index makes is the easiest way to optimize for speed. It is particularly useful for data that exhibits sequential or sorted characteristics, such as time series data or data with a natural ordering.</p>
<p>Here’s an overview of the BRIN Index:</p>
<ul>
<li>BRIN indexes divide the table into logical blocks and store summary information about each block.</li>
<li>Each block contains a range of values, and the index stores the minimum and maximum values within each block.</li>
<li>Instead of storing individual index entries for each row, BRIN indexes store block-level summaries, making them smaller in size compared to other index types.</li>
<li>BRIN indexes work well when the data is sorted or when sequential scans are more efficient than index scans.</li>
</ul>
<p>To create a BRIN index in PostgreSQL, you use the <code>CREATE INDEX</code> statement with the <code>USING BRIN</code> clause.    </p>
<p>Here's an example of creating a BRIN index on a timestamp column:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">INDEX</span> <span class="hljs-built_in">timestamp</span> <span class="hljs-keyword">ON</span> table_name <span class="hljs-keyword">USING</span> BRIN (<span class="hljs-keyword">column</span>);
</code></pre>
<p>The above statement creates a BRIN index on the specified timestamp column of the table.</p>
<p>Here are some things to consider when creating a BRIN Index:</p>
<ul>
<li>BRIN indexes are most effective when the data is sorted or exhibit natural ordering.</li>
<li>They may not be suitable for tables with highly unsorted or non-sequential data.</li>
<li>BRIN indexes are generally used for read-intensive workloads where sequential scans are prevalent.</li>
<li>Regular maintenance and periodic reindexing may be necessary to ensure optimal performance.</li>
</ul>
<p>To read more on BRIN Indexes, you can check out the <a target="_blank" href="https://www.postgresql.org/docs/11/brin-intro.html">official documentation</a>.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>In this quick guide, we have seen other types of indexes supported by PostgreSQL other than the B-Tree index. </p>
<p>It is not recommended to create an index on the fly just before running a one-off query. Creating a well-designed index requires careful planning and testing. </p>
<p>It's important to consider that indexes consume disk space. Also, whenever new data rows are inserted or existing rows are updated, the database automatically updates the corresponding index entries.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
