<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>배움 저장소</title>
    <link>https://hoplite.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 26 Aug 2026 11:33:15 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>시옷지읏</managingEditor>
    <item>
      <title>[Data Structures] 챕터12. 그래프</title>
      <link>https://hoplite.tistory.com/174</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트리와 달리 그래프는 한 정점(Vertex)가 여러 다른 정점을 가리킬 수 있다&lt;/li&gt;
&lt;li&gt;그래프는 두 정점이 서로를 가르킬 수 있다&lt;/li&gt;
&lt;li&gt;연결된 상태를 간선(Edge)으로 표시한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;인접 행렬(Adjacent Matrix Graph)&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인접행렬은 정점간 연결관계를 행렬로 표시한다&lt;/li&gt;
&lt;li&gt;2차원 배열을 사용하여 정점의 연결 관계를 나타낸다. X행의 X 정점과 다른 정점과 연결 여부를 표시한다&lt;/li&gt;
&lt;li&gt;인접 행렬로 그래프 그리기 &lt;a href=&quot;https://graphonline.ru/en/create_graph_by_matrix&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://graphonline.ru/en/create_graph_by_matrix&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;visited_ 값은 traversal을 확인할 때 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;깊이 우선 탐색(Depth First Search)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;방문한 정점을 깊이 파고든다&lt;/li&gt;
&lt;li&gt;스택을 활용한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;너비 우선 탐색(Breadth First Search)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;중심이 되는 정점과 연결되어있는 정점을 모두 방문한 뒤 다음 레벨로 파고든다&lt;/li&gt;
&lt;li&gt;큐를 활용한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;구현하기&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6v7Ef/btsCyad0WOd/IGkgVuvZsmjX2r7FKyykO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6v7Ef/btsCyad0WOd/IGkgVuvZsmjX2r7FKyykO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6v7Ef/btsCyad0WOd/IGkgVuvZsmjX2r7FKyykO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6v7Ef%2FbtsCyad0WOd%2FIGkgVuvZsmjX2r7FKyykO1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;340&quot; height=&quot;280&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;280&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;InsertEdge&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1703257083860&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void InsertEdge(int u, int v) // 여기서 u, v는 인덱스
{
    assert(u &amp;lt; n_ &amp;amp;&amp;amp; v &amp;lt; n_);

    matrix_[u][v] = 1;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;DepthFirstTraversal&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1703257111498&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void DepthFirstTraversal(int v) // v는 인덱스
{
    if (visited_[v]) return;

    visited_[v] = true;

    cout &amp;lt;&amp;lt; vertices_[v].item &amp;lt;&amp;lt; &quot; &quot;;

    for (int c = 0; c &amp;lt; n_; ++c)
        if (matrix_[v][c])
            DepthFirstTraversal(c);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;IterDFS&lt;/h4&gt;
&lt;pre id=&quot;code_1703257138957&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void IterDFT()
{
    ResetVisited();

    int v = 0;

    Stack&amp;lt;int&amp;gt; s;
    s.Push(v);
    visited_[v] = true;

    while (!s.IsEmpty())
    {
        v = s.Top();
        s.Pop();

        cout &amp;lt;&amp;lt; vertices_[v].item &amp;lt;&amp;lt; &quot; &quot;;

        for (int c = n_-1; 0&amp;lt;= c; --c)
        {
            if (matrix_[v][c] &amp;amp;&amp;amp; !visited_[c])
            {
                visited_[c] = true;
                s.Push(c);
            }
        }

        cout &amp;lt;&amp;lt; &quot;Stack :&quot;;
        s.Print();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;BreadthFirstTraversal&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1703257154169&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void BreadthFirstTraversal()
{
    int v = 0; // 0번에서 시작

    Queue&amp;lt;int&amp;gt; q;

    ResetVisited();

    visited_[v] = true;
    q.Enqueue(v);
    while (!q.IsEmpty())
    {
        v = q.Front();
        q.Dequeue();

        cout &amp;lt;&amp;lt; v &amp;lt;&amp;lt; &quot; &quot;;

        for (int c = 0; c &amp;lt; n_; ++c)
            if (matrix_[v][c] &amp;amp;&amp;amp; !visited_[c])
            {
                visited_[c] = true;
                q.Enqueue(c);
            }

        cout &amp;lt;&amp;lt; &quot;Queue: &quot;;
        q.Print();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;인접리스트(Adjacent List)&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmaqek/btsCyvvsYUc/1aI9K1buMrS8HKSfT1l6Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmaqek/btsCyvvsYUc/1aI9K1buMrS8HKSfT1l6Kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmaqek/btsCyvvsYUc/1aI9K1buMrS8HKSfT1l6Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbmaqek%2FbtsCyvvsYUc%2F1aI9K1buMrS8HKSfT1l6Kk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;340&quot; height=&quot;280&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;280&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;InsertEdge&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존의 Node를 뒤로 밀어넣는다&lt;/p&gt;
&lt;pre id=&quot;code_1703310780182&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void InsertEdge(int u, int v) // 여기서 u, v는 인덱스
{
    assert(u &amp;lt; n_ &amp;amp;&amp;amp; v &amp;lt; n_);

    Node* temp = new Node{ v, list_[u] };
    list_[u] = temp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;구현하기&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;DepthFirstTraversal&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1703311734938&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void DepthFirstTraversal(int v) // v는 인덱스
{
    if (visited_[v]) return;
    visited_[v] = true;

    cout &amp;lt;&amp;lt; vertices_[v].item &amp;lt;&amp;lt; &quot; &quot;;

    Node* current = list_[v];
    while (current)
    {
        DepthFirstTraversal(current-&amp;gt;vertex);
        current = current-&amp;gt;next;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;IterDFT&lt;/h4&gt;
&lt;pre id=&quot;code_1703311830258&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void IterDFT()
{
    ResetVisited();

    int v = 0;

    Stack&amp;lt;int&amp;gt; s;
    visited_[v] = true;
    s.Push(v);

    while (!s.IsEmpty())
    {
        v = s.Top();
        s.Pop();
        cout &amp;lt;&amp;lt; vertices_[v].item &amp;lt;&amp;lt; &quot; &quot;;

        Node* linked = list_[v];
        while (linked)
        {
            if (!visited_[linked-&amp;gt;vertex])
            {
                visited_[linked-&amp;gt;vertex] = true;
                s.Push(linked-&amp;gt;vertex);
            }
            linked = linked-&amp;gt;next;
        }

        cout &amp;lt;&amp;lt; &quot;Stack:&quot;;
        s.Print();
        cout &amp;lt;&amp;lt; endl;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;BreathFirstTraversal&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1703311913384&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void BreadthFirstTraversal()
{
    ResetVisited();

    int v = 0;

    Queue&amp;lt;int&amp;gt; q;
    visited_[v] = true;
    q.Enqueue(v);

    while (!q.IsEmpty())
    {
        v = q.Front();
        q.Dequeue();

        cout &amp;lt;&amp;lt; vertices_[v].item &amp;lt;&amp;lt; &quot; &quot;;

        Node* linked = list_[v];
        while (linked)
        {
            if (!visited_[linked-&amp;gt;vertex])
            {
                visited_[linked-&amp;gt;vertex] = true;
                q.Enqueue(linked-&amp;gt;vertex);
            }
            linked = linked-&amp;gt;next;
        }

        cout &amp;lt;&amp;lt; &quot;Queue: &quot;;
        q.Print();
        cout &amp;lt;&amp;lt; endl;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/Data Structure</category>
      <category>Honglab</category>
      <category>홍랩</category>
      <category>홍정모</category>
      <author>시옷지읏</author>
      <guid isPermaLink="true">https://hoplite.tistory.com/174</guid>
      <comments>https://hoplite.tistory.com/174#entry174comment</comments>
      <pubDate>Sat, 23 Dec 2023 15:29:05 +0900</pubDate>
    </item>
    <item>
      <title>[Data Structures] 챕터11. 해슁(Hashing)</title>
      <link>https://hoplite.tistory.com/173</link>
      <description>&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;보간탐색&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인덱스와 값의 크기는 비례하다고 가정&lt;/li&gt;
&lt;li&gt;작은 값은 작은 인덱스부터 탐색한다. 큰 값은 큰 인덱스부터 탐색한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1436&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXdcXc/btsCwe1bP39/0EKt9DFCIWhAy7QzLKxywk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXdcXc/btsCwe1bP39/0EKt9DFCIWhAy7QzLKxywk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXdcXc/btsCwe1bP39/0EKt9DFCIWhAy7QzLKxywk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXdcXc%2FbtsCwe1bP39%2F0EKt9DFCIWhAy7QzLKxywk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1436&quot; height=&quot;362&quot; data-origin-width=&quot;1436&quot; data-origin-height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &lt;b&gt;첫 값부터 마지막 값 사이의 길이 : 첫 값부터 x값까지 길이&lt;/b&gt;&amp;nbsp; = 인덱스 길이 : Position 길이&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #36394d; text-align: center;&quot;&gt;(arr[high] - arr[low]) : (x - arr[low]) = (high - low) : (pos - low)&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #36394d; text-align: center;&quot;&gt;이 때 버림을 활용하여 index 값이&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703223876625&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int InterpolationSearch(int arr[], int low, int high, int x)
{
    rec_count++;

    if (low &amp;lt;= high &amp;amp;&amp;amp; x &amp;gt;= arr[low] &amp;amp;&amp;amp; x &amp;lt;= arr[high])
    {
        int pos = (low + high) / 2; // 이진 탐색 (중간)

        // (arr[high] - arr[low]) : (x - arr[low]) = (high - low) : (pos - low) 
        float tofloor = (high - low) * (x - arr[low]) / (arr[high] - arr[low]);
        pos = int(tofloor) + low;

        if (arr[pos] == x)
            return pos;

        if (arr[pos] &amp;lt; x)
            return InterpolationSearch(arr, pos + 1, high, x);

        if (arr[pos] &amp;gt; x)
            return InterpolationSearch(arr, low, pos - 1, x);
    }

    return -1;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;색인 순차 탐색&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원 배열을 각 m개로 나누고 나누어진 배열의 첫 값을 인덱스 배열에 등록한다. 인덱스 배열의 개수는 n/m이다.&lt;/li&gt;
&lt;li&gt;인덱스 배열을 참고하여 값을 찾으면 인덱스 배열에 있는 n/m개를 순회하고 나누어진 배열의 원소 m개를 탐색한다.&lt;/li&gt;
&lt;li&gt;값 8을 찾기 위해 인덱스 요약 표를 보자.&amp;nbsp; 인덱스 0부터 3 사이가 8의 자리이다. 해당 범위만 탐색하면 효율적이다&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;525&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blU8DT/btsCwcCBngy/zl76bjjvaNiihHFdCr4kZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blU8DT/btsCwcCBngy/zl76bjjvaNiihHFdCr4kZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blU8DT/btsCwcCBngy/zl76bjjvaNiihHFdCr4kZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblU8DT%2FbtsCwcCBngy%2Fzl76bjjvaNiihHFdCr4kZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;525&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;525&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;시간복잡도&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시간복잡도 : O( m + n/m )&lt;/li&gt;
&lt;li&gt;이 때 이진탐색( &lt;a href=&quot;https://hoplite.tistory.com/163&quot;&gt;https://hoplite.tistory.com/163&lt;/a&gt; )을 활용하면 시간복잡도는 O ( log(m) + n/m )&lt;/li&gt;
&lt;li&gt;위는 인덱스 배열의 개수를 n/m이라 가정. 인덱스 배열의 개수를 m이라고 가정하면 위의 식은 변형되어야 한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;구현하기&lt;/h3&gt;
&lt;pre id=&quot;code_1703229633786&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;

using namespace std;

int SequentialSearch(int arr[], int start, int stop, int x)
{
    for (int i = start; i &amp;lt; stop; i++)
    {
        if (arr[i] == x)
            return i;
    }

    return -1;
}

int main()
{
    int arr[] = { 1, 2, 8, 13, 22, 45, 55, 75, 88 };
    int n = sizeof(arr) / sizeof(arr[0]);

    int keys[] = { 1, 13, 55 };
    int kn = sizeof(keys) / sizeof(keys[0]);

    int indices[] = { 0, 3, 6, n }; // 마지막에 n 하나 더 추가

    /* 풀이 */

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내풀이&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703229713229&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int main()
{
    
    for (int x : {1, 2, 8, 13, 22, 45, 55, 75, 88, 99, -1, 47, 101, 1000, 7, 10, 50, 60 })
    {
        if (x &amp;lt; arr[0] || x &amp;gt; arr[n - 1])
            cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; &quot; was not found&quot; &amp;lt;&amp;lt; endl;
        else
        {
            int found = -1;
            for (int i = 1; i &amp;lt; kn; ++i)
            {
                if (keys[i - 1] &amp;lt;= x &amp;amp;&amp;amp; x &amp;lt; keys[i])
                    found = SequentialSearch(arr,indices[i - 1], indices[i], x);
            }

            if (keys[kn - 1] &amp;lt;= x)
                found = SequentialSearch(arr, indices[kn - 1], n, x);

            if (found != -1)
                cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; &quot; was found at &quot; &amp;lt;&amp;lt; found &amp;lt;&amp;lt; endl;
            else
                cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; &quot; was not found&quot; &amp;lt;&amp;lt; endl;
        }
    }
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;추천풀이&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703229751966&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int main()
{
    ...
    for (int x : {1, 2, 8, 13, 22, 45, 55, 75, 88, 99, -1, 47, 101, 1000, 7, 10, 50, 60 })
    {
        if (x &amp;lt; arr[0] || x &amp;gt; arr[n - 1])
            cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; &quot; was not found&quot; &amp;lt;&amp;lt; endl;
        else
        {
            // 인덱스 테이블에서 검색할 범위 결정
            int kIdx = 0;
            while (kIdx &amp;lt; kn - 1 &amp;amp;&amp;amp; keys[kIdx + 1] &amp;lt;= x)
                kIdx++;

            // 색인 표의 범위에 따라서 선형 탐색
            // indices[kIdx] 이상 indices[kIdx+1] 미만에 대해 검색
            // 이때 indices 배열 마지막에 추가로 n을 저장해뒀기 때문에 kIdx+1 사용 가능
            int found = SequentialSearch(arr, indices[kIdx], indices[kIdx + 1], x);
            if (found &amp;gt;= 0)
                cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; &quot; was found at &quot; &amp;lt;&amp;lt; found &amp;lt;&amp;lt; endl;
            else
                cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; &quot; was not found&quot; &amp;lt;&amp;lt; endl;
        }
    }
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;해쉬 테이블&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;key 값과 value 값을 함께 저장한다.&lt;/li&gt;
&lt;li&gt;각 값은 key 값을 index로 배열에 저장한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;key 값의 범위가 아주 넓고 삽입되는 아이템의 개수가 적을 때&lt;/b&gt; 모든 경우의 수를 담는 배열을 만드는 건 비효율적이다&lt;/li&gt;
&lt;li&gt;이 때 key 값을 정해진 배열 범위로 변환하는 함수를 Hash Function이라 한다 &lt;i&gt;예) 나머지 연산자&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;충돌 : 빈 공간이 남아있지만 중복된 Hash 값 때문에 예전 값을 잊어버리는 경우 / 덮어쓸 수 없는 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;팁&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #36394d; text-align: start;&quot;&gt;size_t = unsigned long long : 부호가 없는 64비트 정수&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #36394d; text-align: start;&quot;&gt;키값이 비슷하더라도 변환된 해쉬값은 아주 달라지는 것이 일반적이다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예) &lt;a href=&quot;https://www.pelock.com/products/hash-calculator&quot;&gt;Hash Calculator Online &amp;mdash; String &amp;amp; File Hash Generator (pelock.com)&lt;/a&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;apple&quot;의&amp;nbsp; &amp;nbsp;md2 해쉬값 8015C9542CAC74759F9F7196394CC25D&lt;/li&gt;
&lt;li&gt;&quot;apple1&quot;의 md2 해쉬값 BC3BFE69BCDC1DD4EA055ADF80D3BAA6 &amp;lt;- &quot;1&quot; 차이로 크게 달라짐&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Hash로 저장하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;아래 구현에서 동일한 Hash값이 만들어지는 서로 다른 두 Item이 삽입되면 이전에 저장된 값을 잊어버린다&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703232971459&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Insert(const Item&amp;amp; item)
{
    size_t index = HashFunc(item.key); // 키를 인덱스로 사용
    table_[index] = item;
}

V Get(const K&amp;amp; key)
{
    size_t index = HashFunc(key);
    return table_[index].value;
}

// 정수 -&amp;gt; 해쉬값
size_t HashFunc(const int&amp;amp; key)
{
    return key % capacity_;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;충돌 처리하기(중복된 Hash 값 처리하기)&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;1. 개방 주소법(Open Addressing)&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개방 주소법은 빈공간을 찾아 값을 저장한다&lt;/li&gt;
&lt;li&gt;선형조사법이라고도 한다 (한 칸씩 이동하여 값을 확인)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Insert&lt;/h4&gt;
&lt;pre id=&quot;code_1703234054925&quot; class=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;void Insert(const Item&amp;amp; item)
{
    size_t index = HashFunc(item.key); // 키를 인덱스로 사용
	
    // int()의 초기값은 0
    while (table_[index].key != 0)
        ++index;

    table_[index] = item;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Get&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;내구현&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1703234108494&quot; class=&quot;n1ql&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;V Get(const K&amp;amp; key)
{
    size_t index = HashFunc(key);
    while (index &amp;lt; capacity_ &amp;amp;&amp;amp; table_[index].key != key)
        ++index;

    return index &amp;lt; capacity_ ? table_[index].value : 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추천구현&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;(index + i) % capacity에서 i 값이 0부터 capacity -1까지 순회함을 확인하자&lt;/li&gt;
&lt;li&gt;index 값 temp는 처음 얻은 HashFunc 값에서 바로 직전 값까지 한바퀴를 순회한다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1703234185773&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;V Get(const K&amp;amp; key)
{
    size_t index = HashFunc(key);
    for (int i = 0; i &amp;lt; capacity_; i++)
    {
        size_t temp = (index + i) % capacity_; // index를 덮어쓰는 것이 아니라 임시 변수 만들기 
        if (table_[temp].key == key)
            return table_[temp].value;
    }
    return 0; // 정수 int()의 초기값은 0
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;숫자가 아닌 자료형을 Key 값으로 사용하기(String)&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;HashFunc&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1703235674254&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 문자열을 정수 인덱스(해쉬값)로 변환
// Horner's method
size_t HashFunc(const string&amp;amp; s)
{
    int g = 31;

    size_t index = 0;
    for (int i = 0; i &amp;lt; s.size(); ++i)
        //index += int(s.at(i)); // 1) AB와 BA가 같은 Hash 값을 가진다
        index = g * index + int(s.at(i)); 
        // 2) g * (g * int('A') + int('B')) + int('C')
        // 따라서 AB와 BA가 달라진다.

    return index % capacity_;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Insert&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;key값을 K의 기본 생성자와 비교하여 비어있는 값을 확인한다&lt;/b&gt;. K가 문자열일 때 K()는 비어있는 문자열이다.&lt;/p&gt;
&lt;pre id=&quot;code_1703235128831&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Insert(const Item&amp;amp; item)
{
    size_t index = HashFunc(item.key); // 키를 인덱스로 사용

    if (table_[index].key != K())
        cout &amp;lt;&amp;lt; &quot;Collision!&quot; &amp;lt;&amp;lt; endl;

    // key가 int 자료형일 때 0이면 비어있는 것으로 가정
    // key가 문자열 자료형일 때 길이가 0이면 비어있는 것으로 가정
    //while (table_[index].key != K()) 
    //    index = (index + i) % capacity_; // infinite loop
    //table_[index % capacity_] = item;

    for (int i = 0; i &amp;lt; capacity_; ++i)
    {
        index = (index + i) % capacity_;
        if (table_[index].key == K())
        {
            table_[index] = item;
            return;
        }
    }

    std::cout &amp;lt;&amp;lt; &quot;Failed to insert\n&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Get&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내구현&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1703235319884&quot; class=&quot;n1ql&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;V Get(const K&amp;amp; key)
{
    size_t index = HashFunc(key);
    while (index &amp;lt; capacity_ &amp;amp;&amp;amp; table_[index].key != key)
        ++index;

    return index &amp;lt; capacity_ ? table_[index].value : V(); // 빈 생성자를 호출하여 반환
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추천구현&lt;/p&gt;
&lt;pre id=&quot;code_1703235339552&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;V Get(const K&amp;amp; key)
{
    size_t index = HashFunc(key);
    for (int i = 0; i &amp;lt; capacity_; i++)
    {
        size_t temp = (index + i) % capacity; 
        if (table_[temp].key == key)
            return table_[temp].value;
    }
    return V();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Chainning&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;연결리스트를 사용한다.&lt;/li&gt;
&lt;li&gt;위에서 구현한 Item* table_ 대신에 LinkedList&amp;lt;Item&amp;gt;* table_을 사용하자&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;다양한 해쉬함수&lt;/span&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;폴딩 함수&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #36394d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;큰 숫자를 해쉬값으로 변환할 때 자리수에 따라 접을 수도 있습니다&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #36394d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;123456789를 123 + 456 + 789 로 3자리씩 더한다&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #36394d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Quadratic probing(이차 조사법)&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #36394d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;선형 조사법은 충돌이 많은 경우 배열 일부에 몰려 저장된다. 이를 해결하기위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #36394d; text-align: start;&quot;&gt;Quadratic Probing&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;를 사용할 수 있다&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703237891222&quot; class=&quot;matlab&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;size_t temp = (index + i*i) % capacity;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #36394d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;참고 &lt;a title=&quot;Quadratc Probing&quot; href=&quot;https://www.codingeek.com/data-structure/complete-guide-open-addressing-classification-eliminate-collisions/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.codingeek.com/data-structure/complete-guide-open-addressing-classification-eliminate-collisions/&lt;/a&gt;&lt;/p&gt;</description>
      <category>CS/Data Structure</category>
      <category>Honglab</category>
      <category>홍랩</category>
      <category>홍정모</category>
      <author>시옷지읏</author>
      <guid isPermaLink="true">https://hoplite.tistory.com/173</guid>
      <comments>https://hoplite.tistory.com/173#entry173comment</comments>
      <pubDate>Fri, 22 Dec 2023 22:38:41 +0900</pubDate>
    </item>
    <item>
      <title>[Data Structures] 챕터10. 정렬</title>
      <link>https://hoplite.tistory.com/172</link>
      <description>&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;쉘 정렬&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Insertion Sort는 바로 옆 값을 값을 비교하고 정렬한다. Shell Sort는 멀리 있는 값을 비교하고 정렬하여 효율을 얻는다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;성능&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Worst : O(n^2)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Average : O(n^1.5)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;구현하기&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1703130823959&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void ShellSort(int arr[], int n)
{
    for (int gap = n / 2; gap &amp;gt; 0; gap /= 2)
    {
        cout &amp;lt;&amp;lt; &quot;         &quot;;
        Print(arr, n);

        InsertionSort(arr, n, gap);
    }

    cout &amp;lt;&amp;lt; &quot;         &quot;;
    Print(arr, n);
    cout &amp;lt;&amp;lt; endl;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Insertion Sort&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내구현&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1703130845438&quot; class=&quot;cpp&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;void InsertionSort(int arr[], int n, int gap) // gap 추가
{
    cout &amp;lt;&amp;lt; &quot;gap = &quot; &amp;lt;&amp;lt; gap &amp;lt;&amp;lt; endl;

    for (int i = gap; i &amp;lt; n; i += 1)
    {
        cout &amp;lt;&amp;lt; &quot;Before : &quot;;
        Print(arr, n, i, gap);

        if (arr[i-gap] &amp;gt; arr[i])
            std::swap(arr[i-gap], arr[i]);

        int j;
        for(j=i; 0 &amp;lt;= j-gap ; j-=gap)
            if(arr[j-gap] &amp;gt; arr[j])
                std::swap(arr[j - gap], arr[j]);

        cout &amp;lt;&amp;lt; &quot; After : &quot;;
        Print(arr, n, i, gap);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추천구현&lt;/p&gt;
&lt;pre id=&quot;code_1703131174366&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void InsertionSort(int arr[], int n, int gap) // gap 추가
{
    cout &amp;lt;&amp;lt; &quot;gap = &quot; &amp;lt;&amp;lt; gap &amp;lt;&amp;lt; endl;

    for (int i = gap; i &amp;lt; n; i += 1)
    {
        cout &amp;lt;&amp;lt; &quot;Before : &quot;;
        Print(arr, n, i, gap);

        if (arr[i - gap] &amp;gt; arr[i])
            std::swap(arr[i - gap], arr[i]);

        int key = arr[i];
        int j = i;
        for (; (0 &amp;lt;= j - gap) &amp;amp;&amp;amp; (key &amp;lt; arr[j-gap]); j -= gap)
            arr[j] = arr[j - gap];
        arr[j] = key;

        cout &amp;lt;&amp;lt; &quot; After : &quot;;
        Print(arr, n, i, gap);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;병합 정렬(Merge Sort)&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;특징&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;낱개로 나누어 합치면서 정렬한다&lt;/li&gt;
&lt;li&gt;시간복잡도 : O(n * Log n)&lt;/li&gt;
&lt;li&gt;공간복잡도 : O(n)&lt;/li&gt;
&lt;li&gt;Merge 순서를 유지하는 Stable 정렬이다&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;986&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ec2uL5/btsCksNyLl5/NaIfJurAkXnBfUxBXnlOy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ec2uL5/btsCksNyLl5/NaIfJurAkXnBfUxBXnlOy1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ec2uL5/btsCksNyLl5/NaIfJurAkXnBfUxBXnlOy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fec2uL5%2FbtsCksNyLl5%2FNaIfJurAkXnBfUxBXnlOy1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;325&quot; height=&quot;313&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;986&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정렬된 그룹을 합치므로 Two pointer로 구현할 수 있다(희소다항식에서 활용하였음)&lt;/p&gt;
&lt;pre id=&quot;code_1703133294675&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void MergeSort(int arr[], int merged[], int left, int right)
{
    int mid;
    if (left &amp;lt; right)
    {
        mid = (left + right) / 2;

        MergeSort(arr, merged, left, mid);
        MergeSort(arr, merged, mid + 1, right);

        Merge(arr, merged, left, mid, right);
    }
}

int main()
{
    int arr[] = { 38, 27, 43, 3, 9, 82, 10 }; // https://en.wikipedia.org/wiki/Merge_sort
    int n = sizeof(arr) / sizeof(arr[0]);

    int* merged = new int[n]; // 추가 메모리 필요

    Print(arr, 0, n - 1);
    cout &amp;lt;&amp;lt; endl;

    MergeSort(arr, merged, 0, n - 1);

    Print(merged, 0, n - 1);
    cout &amp;lt;&amp;lt; endl;

    delete[] merged;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;구현하기&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Merge&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1703133259531&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Merge(int init[], int merged[], int left, int mid, int right)
{
    int i, j, k, l;
    i = left;
    j = mid + 1;
    k = left;

    cout &amp;lt;&amp;lt; &quot;  Left : &quot;;
    Print(init, left, mid);
    cout &amp;lt;&amp;lt; &quot; Right : &quot;;
    Print(init, mid + 1, right);

    // 인덱스를 2개 이용해서 정렬하면서 merge
    k = left;
    while (i &amp;lt;= mid &amp;amp;&amp;amp; j &amp;lt;= right)
    {
        if (init[i] &amp;gt; init[j])
            merged[k++] = init[j++];
        else // it also handle init[i] == init[j]
            merged[k++] = init[i++];
    }

    // 남은 내용들 복사
    for (; i &amp;lt;= mid; ++i)
        merged[k++] = init[i];

    for (; j &amp;lt;= right; ++j)
        merged[k++] = init[j];

    // merged -&amp;gt; init 복사
    for (l = left; l &amp;lt;= right; l++)
        init[l] = merged[l];

    cout &amp;lt;&amp;lt; &quot;Merged : &quot;;
    Print(init, left, right);
    cout &amp;lt;&amp;lt; endl;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;퀵 정렬(Quick Sort)&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시간복잡도
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;best :&lt;/b&gt; O(n*log n)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;worst :&lt;/b&gt; O(n^2)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;공간복잡도 O(log n)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;구현하기&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Partition&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무한 Loop에 빠질 수 있다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1703139088461&quot; class=&quot;cpp&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;int Partition(int arr[], int low, int high, int n)
{
    int pivot = arr[size_t(floorf((high - low) / 2.0f)) + low];

    int i = low;
    int j = high;

    while (true)
    {
        while (arr[i] &amp;lt; pivot) // 1) arr[i] == pivot 그리고
            ++i;

        while (pivot &amp;lt; arr[j]) // 2) arr[j] == pivot일 경우 무한 loop
            --j;

        if (i &amp;gt;= j) break;

        std::swap(arr[i], arr[j]);


        cout &amp;lt;&amp;lt; &quot;pivot=&quot; &amp;lt;&amp;lt; pivot &amp;lt;&amp;lt; &quot;, i=&quot; &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &quot;, j=&quot; &amp;lt;&amp;lt; j &amp;lt;&amp;lt; endl;
        cout &amp;lt;&amp;lt; &quot;         &quot;;
        Print(arr, low, high, n);
    }

    return (i+j)/2;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;추천구현&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703139403215&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Hoare partition scheme
int Partition(int arr[], int low, int high, int n)
{
    int pivot = arr[size_t(floorf((high - low) / 2.0f)) + low];
    int i = low - 1;
    int j = high + 1;

    while (true)
    {
        do ++i;
        while (arr[i] &amp;lt; pivot);

        do --j;
        while (pivot &amp;lt; arr[j]);

        if (i &amp;gt;= j) break;

        std::swap(arr[i], arr[j]);


        cout &amp;lt;&amp;lt; &quot;pivot=&quot; &amp;lt;&amp;lt; pivot &amp;lt;&amp;lt; &quot;, i=&quot; &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &quot;, j=&quot; &amp;lt;&amp;lt; j &amp;lt;&amp;lt; endl;
        cout &amp;lt;&amp;lt; &quot;         &quot;;
        Print(arr, low, high, n);
    }

    return j;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;기수정렬(Radix Sort)&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;특징&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;숫자를 쉽게 정렬할 수 있다. 실수나 문자열을 정렬하기 어렵다.&lt;/li&gt;
&lt;li&gt;시간복잡도 : O(n)&lt;/li&gt;
&lt;li&gt;공간복잡도 : O(n + w)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;10진수일 때 w=10, 16진수일 때 w=16&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;GPU연산에서 많이 사용한다(메모리를 아껴야할 때 Quick Sort처럼 메모리가 필요없는 정렬을 사용한다)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;구현하기&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1703144395765&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &quot;../shared/Queue.h&quot;

using namespace std;

int main()
{
    int arr[] = { 170, 45, 75, 90, 802, 24, 2, 66 };
    int n = sizeof(arr) / sizeof(arr[0]);

    Print(arr, n);

    Queue&amp;lt;int&amp;gt; queues[10];

    int m = GetMax(arr, n); // 가장 큰 자리수를 찾기 위해서

    for (int exp = 1; m / exp &amp;gt; 0; exp *= 10)
    {
        for (int i = 0; i &amp;lt; n; ++i)
        {
            int rem = (arr[i] / exp) % 10;
            assert(0 &amp;lt;= rem); 
            assert(rem &amp;lt;= 10);
            queues[rem].Enqueue(arr[i]);
        }

        //for (int idx = 0; idx &amp;lt; 10; ++idx)
        //{
        //	cout &amp;lt;&amp;lt; &quot;i=&quot; &amp;lt;&amp;lt; idx &amp;lt;&amp;lt; &quot;\t&quot;;
        //	Queue&amp;lt;int&amp;gt; temp = Queue&amp;lt;int&amp;gt;{ queues[idx] };
        //	while (!temp.IsEmpty())
        //	{
        //		cout &amp;lt;&amp;lt; temp.Front() &amp;lt;&amp;lt; &quot; &quot;;
        //		temp.Dequeue();
        //	}
        //	cout &amp;lt;&amp;lt; endl;
        //}

        int count = 0;
        for (int idx = 0; idx &amp;lt; 10; ++idx)
        {
            for(; !queues[idx].IsEmpty(); ++count)
            {
                arr[count] = queues[idx].Front();
                queues[idx].Dequeue();
            }
        }

        Print(arr, n);
    }

    return 0;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>CS/Data Structure</category>
      <category>Honglab</category>
      <category>홍랩</category>
      <category>홍정모</category>
      <author>시옷지읏</author>
      <guid isPermaLink="true">https://hoplite.tistory.com/172</guid>
      <comments>https://hoplite.tistory.com/172#entry172comment</comments>
      <pubDate>Fri, 22 Dec 2023 14:20:45 +0900</pubDate>
    </item>
    <item>
      <title>[Data Structures] 챕터9. 이진탐색트리</title>
      <link>https://hoplite.tistory.com/171</link>
      <description>&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;이진탐색트리&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;시간복잡도 &lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;균형잡힌 트리:&lt;/b&gt; O(Log N)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Worst :&lt;/b&gt; O(N)&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;이진 탐색 트리의 한계&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;완전 이진 트리가 아니므로 비효율적으로 작동할 수 있다&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;역순으로 정렬된 배열 값을 모두 넣을 경우&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;양 서브트리의 깊이가 비슷할 때 효율적이다&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;386&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/X2P1V/btsCeyr9PEf/SBI1oog9XBBl2w1aqh4xR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/X2P1V/btsCeyr9PEf/SBI1oog9XBBl2w1aqh4xR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/X2P1V/btsCeyr9PEf/SBI1oog9XBBl2w1aqh4xR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FX2P1V%2FbtsCeyr9PEf%2FSBI1oog9XBBl2w1aqh4xR0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;359&quot; height=&quot;218&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;386&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;616&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmraSv/btsCc5qefln/y3jmk7F3eMTXmYCQ9Rvv00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmraSv/btsCc5qefln/y3jmk7F3eMTXmYCQ9Rvv00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmraSv/btsCc5qefln/y3jmk7F3eMTXmYCQ9Rvv00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmraSv%2FbtsCc5qefln%2Fy3jmk7F3eMTXmYCQ9Rvv00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;337&quot; height=&quot;345&quot; data-origin-width=&quot;602&quot; data-origin-height=&quot;616&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;구현하기&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;IterGet&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1702964304422&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Item* IterGet(const K&amp;amp; key)
{
    Node* cur = root_;

    while (cur)
    {
        if (cur-&amp;gt;left &amp;amp;&amp;amp; key &amp;lt; cur-&amp;gt;item.key)
            cur = cur-&amp;gt;left;
        else if (cur-&amp;gt;right &amp;amp;&amp;amp; cur-&amp;gt;item.key &amp;lt; key)
            cur = cur-&amp;gt;right;
        else // handle two case (cur-&amp;gt;item == key) &amp;amp; (empty child, No matching)
            return &amp;amp;cur-&amp;gt;item;
    }

    return nullptr;  // no matching
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Insert&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;상위 스택에서 node의 왼쪽 혹은 오른쪽 값을 할당한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1702964714576&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Node* Insert(Node* node, const Item&amp;amp; item)
{
    if (!node)
        return new Node{ item, nullptr, nullptr };

    if (item.key &amp;lt; node-&amp;gt;item.key)
        node-&amp;gt;left = Insert(node-&amp;gt;left, item);
    else if (node-&amp;gt;item.key &amp;lt; item.key)
        node-&amp;gt;right = Insert(node-&amp;gt;right, item);
    else // node-&amp;gt;item.key == item.key
        node-&amp;gt;item = item;

    return node;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;IterInsert&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;내구현&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1702964967272&quot; class=&quot;livescript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;void IterInsert(const Item&amp;amp; item)
{
    if (!root_) root_ = new Node{ item, nullptr, nullptr };
    Node* cur = root_;

    while (cur)
    {
        if (cur-&amp;gt;item.key &amp;lt; item.key)
        {
            if(!cur-&amp;gt;right)
            {
                cur-&amp;gt;right = new Node{ item, nullptr, nullptr };
                break;
            }

            cur = cur-&amp;gt;right;
        }
        else if (item.key &amp;lt; cur-&amp;gt;item.key)
        {
            if (!cur-&amp;gt;left)
            {
                cur-&amp;gt;left = new Node{ item, nullptr, nullptr };
                break;
            }

            cur = cur-&amp;gt;left;
        }
        else
        {
            cur-&amp;gt;item = item;
            break;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;추천구현&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;포인터 2개를 사용하면 편하게 부모 값을 저장할 수 있다(포인터 하나 만 쓰려면 반복문 조건으로 손자 노드를 확인해야함)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1702966251950&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void IterInsert(const Item&amp;amp; item)
{
    if (!root_) root_ = new Node{ item, nullptr, nullptr };

    Node* cur = root_;
    Node* pre = nullptr;

    while (cur)
    {
        pre = cur;
        if (cur-&amp;gt;item.key &amp;lt; item.key)
            cur = cur-&amp;gt;right;
        else if (item.key &amp;lt; cur-&amp;gt;item.key)
            cur = cur-&amp;gt;left;
        else
        {
            cur-&amp;gt;item = item;
            return;
        }
    }

    cur = new Node{ item, nullptr, nullptr };
    if(item.key &amp;lt; pre-&amp;gt;item.key)
        pre-&amp;gt;left = cur;
    else if(pre-&amp;gt;item.key &amp;lt; item.key)
        pre-&amp;gt;right = cur;
    else // it already handled when pre is cur. 
        assert(false); // pre is cur-&amp;gt;right or cur-&amp;gt;left
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Remove&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;내구현&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1702966997378&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Node* Remove(Node* node, const K&amp;amp; key)
{
    if (!node) return node;

    if (key &amp;lt; node-&amp;gt;item.key)
        node-&amp;gt;left = Remove(node-&amp;gt;left, key);
    else if (key &amp;gt; node-&amp;gt;item.key)
        node-&amp;gt;right = Remove(node-&amp;gt;right, key);
    else
    {
        // case 1. remove node which have two children
         if (node-&amp;gt;left &amp;amp;&amp;amp; node-&amp;gt;right)
        {
            // If right node has a child, take it.
            Node* subCurrent = node-&amp;gt;right; // subtree's root
            if (subCurrent-&amp;gt;left)
            {
                while (subCurrent-&amp;gt;left)
                {
                    if (!subCurrent-&amp;gt;left-&amp;gt;left)
                        break;

                    subCurrent = subCurrent-&amp;gt;left;
                }

                Node* child = subCurrent-&amp;gt;left;
                subCurrent-&amp;gt;left = nullptr;
                child-&amp;gt;left = node-&amp;gt;left;
                child-&amp;gt;right = node-&amp;gt;right;
                delete node;

                return child;
            }
            else // No left, so return current because it is in-order.
            {
                subCurrent-&amp;gt;left = node-&amp;gt;left;
                delete node;
                return subCurrent;
            }

        }
        // case 2. remove node which had a child (connecting pre and post)
        // case 3. remove node which had no child
        else
        {
             // case 3 just assign nullptr to temp
            Node* temp = node-&amp;gt;left ? node-&amp;gt;left : node-&amp;gt;right;
            delete node;
            return temp;
        }
    }

    return node;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;추천구현&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1702969427254&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Node* Remove(Node* node, const K&amp;amp; key)
{
    if (!node) return node;

    if (key &amp;lt; node-&amp;gt;item.key)
        node-&amp;gt;left = Remove(node-&amp;gt;left, key);
    else if (key &amp;gt; node-&amp;gt;item.key)
        node-&amp;gt;right = Remove(node-&amp;gt;right, key);
    else
    {	// when left is nullptr or right is nullptr or both are nullptr
        if (!node-&amp;gt;left || !node-&amp;gt;right)
        {
            Node* temp = node-&amp;gt;left ? node-&amp;gt;left : node-&amp;gt;right;
            delete node;
            return temp;
        }
        else
        {
            Node* temp = MinKeyLeft(node-&amp;gt;right);
            node-&amp;gt;item = temp-&amp;gt;item; // copy value on target node

            // Remove a duplicates on subtree.
            node-&amp;gt;right = Remove(node-&amp;gt;right, temp-&amp;gt;item.key);
            // &quot;assign value on node-&amp;gt;right&quot; handle edge case for
            // removed one is just node-&amp;gt;right. it return nullptr
        }
    }

    return node;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;균형잡힌 탐색트리(AVL Tree / &lt;span style=&quot;background-color: #ffffff; color: #36394d; text-align: start;&quot;&gt;&lt;span&gt;S&lt;/span&gt;elf-Balancing Binary Search Tree)&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;Balance의 크기 :&lt;/b&gt; 왼쪽 자식이 Root인 SubTree의 레벨과 오른쪽&amp;nbsp; 자식이 Root인 SubTree의 레벨 차이&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;해당 노드 자식간 Balance의 절대값이 2이상일 때 재배열한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;성능&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AVL 트리는 균형이 맞춰져 있어 삽입, 삭제, 탐색의 평균/최악 시간 복잡도는 O(logN)&lt;/li&gt;
&lt;li&gt;높이는 매번 새로 계산하거나, 최적화를 위해 Node에 저장해서 값이 바뀔때만 업데이트 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;Reference&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;가시화 도구&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://www.cs.usfca.edu/~galles/visualization/AVLtree.html&quot;&gt;https://www.cs.usfca.edu/~galles/visualization/AVLtree.html&lt;/a&gt; &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://zuramai.github.io/binary-search-tree/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://zuramai.github.io/binary-search-tree/&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;구현방법&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://www.geeksforgeeks.org/introduction-to-avl-tree/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.geeksforgeeks.org/introduction-to-avl-tree/&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;a href=&quot;https://www.tutorialspoint.com/data_structures_algorithms/avl_tree_algorithm.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.tutorialspoint.com/data_structures_algorithms/avl_tree_algorithm.htm&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 Left Rotation(왼쪽 위로 끌어올림)에서 B가 왼쪽 자식을 가질 수 있다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;272&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w1FoK/btsCkpCLF4F/LY3H4wdkVwoC8XmBq3lEu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w1FoK/btsCkpCLF4F/LY3H4wdkVwoC8XmBq3lEu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w1FoK/btsCkpCLF4F/LY3H4wdkVwoC8XmBq3lEu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw1FoK%2FbtsCkpCLF4F%2FLY3H4wdkVwoC8XmBq3lEu1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;290&quot; height=&quot;272&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;272&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 Left Rotation 이전에도 A는 오른쪽 자식을 가지므로 연결관계를 변경해주어 처리하자&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;278&quot; data-origin-height=&quot;206&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czlRn8/btsClXZZNmu/ZTO4RSKE2C2eUQso1KRV0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czlRn8/btsClXZZNmu/ZTO4RSKE2C2eUQso1KRV0K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czlRn8/btsClXZZNmu/ZTO4RSKE2C2eUQso1KRV0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FczlRn8%2FbtsClXZZNmu%2FZTO4RSKE2C2eUQso1KRV0K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;278&quot; height=&quot;206&quot; data-origin-width=&quot;278&quot; data-origin-height=&quot;206&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Right Rotation(오른쪽 위로 끌어올림)도 위와 같이 처리할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Balance&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;왼쪽 자식의 높이가 높으면 양수, 오른쪽 사직의 높이가 높으면 음수이다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자식 Subtree의 높이&lt;/b&gt;를 측정한다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1703059530332&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int Balance(Node* node)
{
    if (node)
        return Base::Height(node-&amp;gt;left) - Base::Height(node-&amp;gt;right);
    else
        return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;구현하기&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Insert&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1703065961730&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Node* Insert(Node* node, const Item&amp;amp; item)
{
    if (!node)
        return new Node{ item, nullptr, nullptr };

    const auto&amp;amp; key = item.key;

    if (key &amp;lt; node-&amp;gt;item.key)
        node-&amp;gt;left = Insert(node-&amp;gt;left, item);
    else if (key &amp;gt; node-&amp;gt;item.key)
        node-&amp;gt;right = Insert(node-&amp;gt;right, item);
    else
    {
        node-&amp;gt;item = item;
        return node;
    }

    // It works recursivly, So below executed after inserting node on child

    // It subtract btw child's height
    int balance = Balance(node);

    // Ref : https://www.geeksforgeeks.org/introduction-to-avl-tree/
    // balance가 0, 1, -1 이면 조절할 필요가 없다고 판단
    // LL -&amp;gt; Right Rotation
    if (balance &amp;gt; 1 &amp;amp;&amp;amp; Balance(node-&amp;gt;left) &amp;gt;= 0) // node-&amp;gt;left-&amp;gt;left must exist
        node = RotateRight(node);                // because blance &amp;gt; 1
    // Even if Balance(node-&amp;gt;left) == 0 do this because left-left

    // RR -&amp;gt; Left Rotation
    else if (balance &amp;lt; -1 &amp;amp;&amp;amp; Balance(node-&amp;gt;right) &amp;lt;= 0) // node-&amp;gt;right-&amp;gt;right must exist
        node = RotateLeft(node);				   // because blance &amp;gt; 1

    // LR -&amp;gt; Left-Right Rotation
    else if (balance &amp;gt; 1 &amp;amp;&amp;amp; Balance(node-&amp;gt;left) &amp;lt; 0)
    {
        node-&amp;gt;left = RotateLeft(node-&amp;gt;left);
        node = RotateRight(node);
    }

    // RL -&amp;gt; Right-Left Rotation
    else if (balance &amp;lt; -1 &amp;amp;&amp;amp; Balance(node-&amp;gt;right) &amp;gt; 0)
    {
        node-&amp;gt;right = RotateRight(node-&amp;gt;right);
        node = RotateLeft(node);
    }

    return node;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Remove&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;위 Insert 로직을 그대로 가져왔다&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1703065993725&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Node* Remove(Node* node, const K&amp;amp; key)
{
    // BST와 동일
    if (!node) return node;

    if (key &amp;lt; node-&amp;gt;item.key)
        node-&amp;gt;left = Remove(node-&amp;gt;left, key);
    else if (key &amp;gt; node-&amp;gt;item.key)
        node-&amp;gt;right = Remove(node-&amp;gt;right, key);
    else
    {
        if (!node-&amp;gt;left)
        {
            Node* temp = node-&amp;gt;right;
            delete node;
            return temp;
        }
        else if (!node-&amp;gt;right)
        {
            Node* temp = node-&amp;gt;left;
            delete node;
            return temp;
        }

        Node* temp = MinKeyNode(node-&amp;gt;right);
        node-&amp;gt;item = temp-&amp;gt;item;
        node-&amp;gt;right = Remove(node-&amp;gt;right, temp-&amp;gt;item.key);
    }

    if (node == NULL)
        return node;

    // 균형 잡기
    int balance = Balance(node);
    if (balance &amp;gt; 1 &amp;amp;&amp;amp; Balance(node-&amp;gt;left) &amp;gt;= 0)
        node = RotateRight(node);
    else if (balance &amp;lt; -1 &amp;amp;&amp;amp; Balance(node-&amp;gt;right) &amp;lt;= 0)
        node = RotateLeft(node);
    else if (balance &amp;gt; 1 &amp;amp;&amp;amp; Balance(node-&amp;gt;left) &amp;lt; 0)
    {
        node-&amp;gt;left = RotateLeft(node-&amp;gt;left);
        node = RotateRight(node);
    }
    else if (balance &amp;lt; -1 &amp;amp;&amp;amp; Balance(node-&amp;gt;right) &amp;gt; 0)
    {
        node-&amp;gt;right = RotateRight(node-&amp;gt;right);
        node = RotateLeft(node);
    }
    return node;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;영어사전 만들기&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;구현하기&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;MyString&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1703126355965&quot; class=&quot;cpp&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;#pragma once

#include &amp;lt;iostream&amp;gt;
#include &amp;lt;algorithm&amp;gt; // swap
#include &amp;lt;cassert&amp;gt;
#include &amp;lt;ostream&amp;gt;

class MyString
{
public:
	...
    bool Validate()
    {
        for (int i = 0; i &amp;lt; size_; i++)
        {
            if ('a' &amp;lt;= str_[i] &amp;amp;&amp;amp; str_[i] &amp;lt;= 'z'){}
            else return false;
        }
        return true;
    }

    friend std::ostream&amp;amp; operator &amp;lt;&amp;lt; (std::ostream &amp;amp; os, const MyString &amp;amp;Str)
    {
        for (int i = 0; i &amp;lt; Str.size_; i++)
            std::cout &amp;lt;&amp;lt; Str.str_[i];

        return os;
    }

    friend bool operator &amp;gt; (const MyString&amp;amp; a, const MyString&amp;amp; b)
    {
        for (int i = 0; i &amp;lt; std::min(a.Length(), b.Length()); ++i)
            if (a.str_[i] != b.str_[i])
                return a.str_[i] &amp;gt; b.str_[i];

        return a.Length() &amp;gt; b.Length();
    }

    friend bool operator &amp;lt; (const MyString&amp;amp; a, const MyString&amp;amp; b)
    {
        for (int i = 0; i &amp;lt; std::min(a.Length(), b.Length()); ++i)
            if (a.str_[i] != b.str_[i])
                return a.str_[i] &amp;lt; b.str_[i];

        return a.Length() &amp;lt; b.Length();
    }

    friend bool operator &amp;lt;= (const MyString&amp;amp; a, const MyString&amp;amp; b)
    {
        for (int i = 0; i &amp;lt; std::min(a.Length(), b.Length()); ++i)
            if (a.str_[i] != b.str_[i])
                return a.str_[i] &amp;lt;= b.str_[i];

        return a.Length() &amp;lt;= b.Length();
    }

    friend bool operator &amp;gt;= (const MyString&amp;amp; a, const MyString&amp;amp; b)
    {
        for (int i = 0; i &amp;lt; std::min(a.Length(), b.Length()); ++i)
            if (a.str_[i] != b.str_[i])
                return a.str_[i] &amp;gt;= b.str_[i];

        return a.Length() &amp;gt;= b.Length();
    }

    friend bool operator == (const MyString&amp;amp; a, const MyString&amp;amp; b)
    {
        if (a.Length() != b.Length())
            return false;

        for (int i = 0; i &amp;lt; a.Length(); ++i)
            if (a.str_[i] != b.str_[i])
                return false;

        return true;
    }
private:
    char* str_ = nullptr; // 마지막에 '\0' 없음
    int size_ = 0; // 글자 수
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;main.cpp&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1703126400936&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;fstream&amp;gt;
#include &amp;lt;string&amp;gt;
#include &quot;MyString.h&quot;
#include &quot;../shared/AVL.h&quot;

using namespace std;

using Item = AVL&amp;lt;MyString, MyString&amp;gt;::Item;

void TestComparison()
{
    MyString A = MyString(&quot;apple&quot;);
    MyString B = MyString(&quot;board&quot;);
    MyString C = MyString(&quot;cancel&quot;);

    cout &amp;lt;&amp;lt; boolalpha;
    cout &amp;lt;&amp;lt; (A &amp;gt; B)  &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; (A &amp;lt; B)  &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; (A &amp;gt;= B) &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; (A &amp;lt;= B) &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; (A == B) &amp;lt;&amp;lt; endl;
}

void ReadFileAndRichingDictionary(AVL&amp;lt;MyString, MyString&amp;gt; &amp;amp;bst)
{
    /* Read Files*/
    string temp;

    ifstream myfile(&quot;eng_dic.txt&quot;);
    if (myfile.is_open())
    {
        while (getline(myfile, temp))
        {
            MyString word{ temp.c_str() };
            getline(myfile, temp);

            MyString meaning{ temp.c_str() };

            if (word.Validate())
            {
                bst.IterInsert(*(new Item{ word, meaning }));
            }
        }
        myfile.close();
    }
    else cout &amp;lt;&amp;lt; &quot;Unable to open file&quot;;
}

int main() {
    AVL&amp;lt;MyString, MyString&amp;gt; bst;


    // Test
    //{
        //bst.Insert(Item{ MyString{&quot;aaa&quot;}, MyString{&quot; 1&quot;} });
        //bst.Insert(Item{ MyString{&quot;decr&quot;}, MyString{&quot; D&quot;} });

        //bst.Insert(Item{ MyString{&quot;cold&quot;}, MyString{&quot; C&quot;} });

        //bst.Insert(Item{ MyString{&quot;appl&quot;}, MyString{&quot; A&quot;} });
        //bst.Insert(Item{ MyString{&quot;aca&quot;}, MyString{&quot; 3&quot;} });
        //bst.Insert(Item{ MyString{&quot;aba&quot;}, MyString{&quot; 2&quot;} });
        //bst.Print2D();
    //}


    // Remove Bugs
    //{
    //    Item *item1 = new Item{ MyString{&quot;abandonment&quot;}, MyString{&quot; 4&quot;} };
    //    bst.Insert(*item1);
    //    Item* item2 = new Item{ MyString{&quot;abandonment&quot;}, MyString{&quot; D&quot;} };
    //    bst.Insert(*item2);
    //}


    ReadFileAndRichingDictionary(bst);
    cout &amp;lt;&amp;lt; &quot;Dictionary Created!&quot; &amp;lt;&amp;lt; endl;

    string temp;
    while (std::cin &amp;gt;&amp;gt; temp)
    {
        auto* Found = bst.IterGet(MyString{ temp.c_str()});
        if (Found)
        {
            cout &amp;lt;&amp;lt; &quot;key: &quot; &amp;lt;&amp;lt; Found-&amp;gt;key &amp;lt;&amp;lt; endl;
            cout &amp;lt;&amp;lt; &quot;\tval: &quot; &amp;lt;&amp;lt; Found-&amp;gt;value &amp;lt;&amp;lt; endl;
        }
        else
            cout &amp;lt;&amp;lt; &quot;No result&quot; &amp;lt;&amp;lt; endl;
    }

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/Data Structure</category>
      <category>Honglab</category>
      <category>홍랩</category>
      <category>홍정모</category>
      <author>시옷지읏</author>
      <guid isPermaLink="true">https://hoplite.tistory.com/171</guid>
      <comments>https://hoplite.tistory.com/171#entry171comment</comments>
      <pubDate>Thu, 21 Dec 2023 12:00:09 +0900</pubDate>
    </item>
    <item>
      <title>[Data Structures] 챕터8. 힙</title>
      <link>https://hoplite.tistory.com/170</link>
      <description>&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최대 힙(Max Heap)과 Top에서 최대값을 출력한다. 최소 힙(Min Heap) Top에서 최소값을 출력한다.&lt;/li&gt;
&lt;li&gt;보관된 값은 정렬되어있지 않다.&lt;/li&gt;
&lt;li&gt;트리 개념을 활용하여 배열로 구현한다.&lt;/li&gt;
&lt;li&gt;최대값 혹은 최소값을 매 번 꺼낼 때 유리한 자료구조이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;최대 힙(Max Heap)&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 구현원리&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;완전 이진 트리를 항상 유지한다&lt;/li&gt;
&lt;li&gt;Root 값은 항상 최대값이다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;2. 값 저장하기&lt;/span&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;따라서 값을 추가할 때 완전 이진 트리를 유지할 수 있는, 왼쪽에서 비어있는 순서대로 값을 대입한다&lt;/li&gt;
&lt;li&gt;대입&lt;b&gt;될&lt;/b&gt; 노드와 해당 노드의 부모를 비교한다&lt;/li&gt;
&lt;li&gt;대입&lt;b&gt;될&lt;/b&gt; 노드가 부모보다 크다면 자리를 바꾼다(Root까지 반복진행한다)&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;항상 자식이 부모보다 작다&lt;/li&gt;
&lt;li&gt;Swap이 아닌 Shift를 쓰자(새로 만든 노드는 완전 이진 트리를 만들 수 있는 자리에 넣지 않고 비워두고 비교한다)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;두 자식의 값을 비교할 수는 없지만 부모는 자식보다 항상 큰 값을 가지므로 효율적으로 최대 값을 찾을 수 있다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;3. 값 꺼내오기&lt;/span&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Root 노드를 꺼낸 뒤, 완전이진트리 기준 최하위 노드를 Root 노드로 가져와 자식과 비교해나간다.&lt;/li&gt;
&lt;li&gt;가져온 노드를 왼쪽 자식 오른쪽 자식과 비교하여 큰 값과 대체한다&lt;/li&gt;
&lt;li&gt;대체된 위치에서 1.과 2.를 반복한다&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;구현하기&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열 사용, 0번은 비워 둔다&lt;/li&gt;
&lt;li&gt;완전이진트리이므로 1번 index부터 해당 index의 위치를 파악할 수 있다.&lt;/li&gt;
&lt;li&gt;부모 노드를 index로 찾을 수 있다(Index / 2 = parent)&lt;/li&gt;
&lt;li&gt;자식 노드를 index로 찾을 수 있다(Index*2 = left child, Index*2+1 = right child)&lt;/li&gt;
&lt;li&gt;값을 추가할 때 배열의 맨 마지막에 넣어준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Push&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;삽입 성능 : O( LogN ) &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1702723007796&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Push(const T&amp;amp; item)
{
    if (size_ == capacity_)
        Resize(capacity_ * 2);

    // 삽입: 일단 맨 마지막에 삽입한 후에 부모 노드로 올린다.
    size_ += 1;
    int current = size_; // 마지막에 추가가될 위치 (인덱스) // size_ == last index

    // heap_[0] had a trash value
    while (current != 1 &amp;amp;&amp;amp; heap_[current/2] &amp;lt; item) // 부모 위치의 값이 추가하려는 값보다 작다면
    {	
        heap_[current] = heap_[current / 2]; // 부모 위치의 값을 자식 위치로 복사해서 내린다.
        current = current / 2;
    }

    heap_[current] = item; // 최종적으로 결정된 위치에 복사
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Pop&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #333333; text-align: start;&quot;&gt;삭제 성능 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #333333; text-align: start;&quot;&gt;O( LogN ) &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1702723913390&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Pop()
{
    assert(!IsEmpty());

    using namespace std;
    cout &amp;lt;&amp;lt; &quot;Pop()&quot; &amp;lt;&amp;lt; endl;

    heap_[1].~T(); // 소멸자 호출 

    // 삭제: 가장 마지막 값을 루트로 옮긴 후에 내려 보낸다.
    T last_item = heap_[size_]; // 마지막 아이템 복사
    size_--;					// 크기 줄이기

    int current = 1;			// 루트 노드에서 시작
    int child = 2;				// current * 2 (루트의 왼쪽 자식 인덱스)
    while (child &amp;lt;= size_) // 자식이 있는지 확인
    {
        if (child &amp;lt; size_) // right child가 존재하는가?
            // left, right 중에서 더 큰 자식의 인덱스를 찾는다. 
            child = heap_[child] &amp;lt; heap_[child+1]? child+1 : child; 

        // 현재(current) 값이 자식 중 큰 값 보다 크면 더이상 적절한 위치를 찾을 필요가 없다. 루프 중단
        if (heap_[child] &amp;lt;= last_item)
            break;

        // 자식 값을 부모 위치로 복사, 
        heap_[current] = heap_[child];

        // 그 자식 위치로 current 인덱스 변경, child 인덱스도 그 다음 자식 위치로 변경
        current = child;
        child = current * 2;
    }

    heap_[current] = last_item;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;힙정렬&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;힙의 Push와 Pop을 이용하여 정렬할 수 있다.&lt;/li&gt;
&lt;li&gt;이 때 동일한 값이 왼쪽 자식이나 오른쪽 자식에 들어갈 수 있으므로 들어갔을 때의 순서가 보장되않는다. 따라서 Unstable 정렬이다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시간복잡도 :&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Push/Pop 모두 O(Log N)이므로 N개를 정렬하면 O(N*Log N)이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공간복잡도 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;배열을 따로 사용할 때 O(N). 힙 배열 내부에서 정렬할 때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;O(1)&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;공간복잡도 O(1) 구현하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://www.geeksforgeeks.org/heap-sort/&quot;&gt;https://www.geeksforgeeks.org/heap-sort/&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;힙에서 꺼낸 가장 큰 값을 배열 마지막 index에 위치한다.&lt;/li&gt;
&lt;li&gt;마지막 index를 제외한 값으로 1.을 반복한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;우선순위 큐(Priority Queue)&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선순위 큐는 힙을 사용하여 구현할 수 있다&lt;/p&gt;
&lt;pre id=&quot;code_1702734235138&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;

#include &quot;../shared/MaxHeap.h&quot;

using namespace std;

struct Patient
{
    int severity; // &amp;lt;- 중증도, 정렬할 때의 1차적인 키(key)로 사용됨
    int time;	  // &amp;lt;- 도착시간, 정렬할 때의 2차적인 키(key)로 사용됨, 중증도가 같을 때는 먼저 온 순서
    const char* name;

    // 우선순위 관점에서 봤을 때 a &amp;gt;= b 인지를 반환하는 함수
    friend bool operator &amp;gt;= (const Patient&amp;amp; a, const Patient&amp;amp; b)
    {
        if (a.severity == b.severity) // 우선순위가 같을 때는 시간을 기준으로 다시 판단 (선착순)
            return a.time &amp;lt;= b.time;   // 숫자로써 time이 작은 것이 먼저 왔다는 의미니까 최종 우선순위가 더 높다.
        else
            return a.severity &amp;gt; b.severity; // 우선순위가 큰 쪽 기준
    }

    friend bool operator &amp;lt; (const Patient&amp;amp; a, const Patient&amp;amp; b)
    {
        return !(a &amp;gt;= b); // 앞의 ! 주의 (operator &amp;gt;= 활용) 
    }

    friend bool operator &amp;lt;= (const Patient&amp;amp; a, const Patient&amp;amp; b)
    {
        if (a.severity == b.severity) // 우선순위가 같을 때는 시간을 기준으로 다시 판단 (선착순)
            return a.time &amp;gt;= b.time;   // 숫자로써 time이 작은 것이 먼저 왔다는 의미니까 최종 우선순위가 더 높다.
        else
            return a.severity &amp;lt;= b.severity; // 우선순위가 큰 쪽 기준
    }


    friend std::ostream&amp;amp; operator &amp;lt;&amp;lt; (std::ostream&amp;amp; os, const Patient&amp;amp; p)
    {
        // TODO: 필요하면 구현
        return os;
    }
};

int main()
{
    // 응급실
    MaxHeap&amp;lt;Patient&amp;gt; h;

    // 우선순위가 더 높은 환자 먼저 치료
    // 더 중증인 경우(severity가 큰 경우) 우선순위가 높다.
    // 증상의 무거운 정도가 동일하다면(severity가 같다면) 먼저 온 환자 먼저 치료(time이 작은 환자 먼저)

    h.Push({ 1, 0, &quot;Ironman&quot; });   // 중증도 1의 Ironman 시간 0에 도착
    h.Push({ 1, 1, &quot;Nick Fury&quot; }); // 중증도 1의 Nick Fury 시간 1에 도착
    h.Push({ 3, 2, &quot;Hulk&quot; });      // 중증도 3의 Hulk 시간 2에 도착

    cout &amp;lt;&amp;lt; h.Top().name &amp;lt;&amp;lt; endl;  // 중증도가 높은 Hulk 먼저 치료
    h.Pop();

    cout &amp;lt;&amp;lt; h.Top().name &amp;lt;&amp;lt; endl;  // 중증도가 동일하지만 먼저 도착한 Ironman
    h.Pop();
    h.Push({ 2, 3, &quot;Blue Beetle&quot; });

    cout &amp;lt;&amp;lt; h.Top().name &amp;lt;&amp;lt; endl;  // 늦게 도착했지만 중증도가 높은 Blue Beetle
    h.Pop();

    cout &amp;lt;&amp;lt; h.Top().name &amp;lt;&amp;lt; endl;  // 마지막으로 Nick Fury
    h.Pop();

    /* 출력 예시
    Hulk
    Ironman
    Blue Beetle
    Nick Fury
    */

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Fixed Priority Queue&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;pre id=&quot;code_1702833718278&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;cassert&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;iomanip&amp;gt;

class FixedPriorityQueue;

struct Node
{
    int item;
    int idx = -1;
    Node* link = nullptr;
    friend std::ostream&amp;amp; operator &amp;lt;&amp;lt; (std::ostream&amp;amp; os, const Node&amp;amp; b)
    {
        os &amp;lt;&amp;lt; b.item;
        return os;
    }

    friend bool operator &amp;lt; (const Node&amp;amp; a, const Node&amp;amp; b)
    {
        return a.item &amp;lt; b.item;
    }

    friend bool operator &amp;gt;= (const Node&amp;amp; a, const Node&amp;amp; b)
    {
        return a.item &amp;gt;= b.item;
    }

    friend bool operator &amp;gt; (const Node&amp;amp; a, const Node&amp;amp; b)
    {
        return a.item &amp;gt; b.item;
    }

    friend bool operator &amp;lt;= (const Node&amp;amp; a, const Node&amp;amp; b)
    {
        return a.item &amp;lt;= b.item;
    }
};


class Heap
{
public:
    Heap(int cap = 10)
    {
        assert(cap &amp;gt; 0);

        capacity_ = cap;
        size_ = 0;
        heap_ = new Node*[capacity_ + 1];
    }

    void Resize(int new_capacity)
    {
        Node** new_heap = new Node*[new_capacity];
        memcpy(new_heap, heap_, sizeof(Node) * (size_ + 1));
        if (heap_) delete[] heap_;
        heap_ = new_heap;
        capacity_ = new_capacity;
    }

    Node* Top()
    {
        return heap_[1];
    }

    bool IsEmpty()
    {
        return size_ == 0;
    }

    void Print()
    {
        using namespace std;
        cout &amp;lt;&amp;lt; &quot;Index: &quot;;
        for (int i = 1; i &amp;lt;= size_; i++)
            cout &amp;lt;&amp;lt; setw(3) &amp;lt;&amp;lt; i;
        cout &amp;lt;&amp;lt; endl;

        cout &amp;lt;&amp;lt; &quot;Value: &quot;;
        for (int i = 1; i &amp;lt;= size_; i++)
            cout &amp;lt;&amp;lt; setw(3) &amp;lt;&amp;lt; *heap_[i];
        cout &amp;lt;&amp;lt; endl;

        cout &amp;lt;&amp;lt; &quot;idx:   &quot;;
        for (int i = 1; i &amp;lt;= size_; i++)
            cout &amp;lt;&amp;lt; setw(3) &amp;lt;&amp;lt; heap_[i]-&amp;gt;idx;
        cout &amp;lt;&amp;lt; endl;

        cout &amp;lt;&amp;lt; &quot;addr: &quot;;
        for (int i = 1; i &amp;lt;= size_; i++)
            cout &amp;lt;&amp;lt; setw(18) &amp;lt;&amp;lt; heap_[i];
        cout &amp;lt;&amp;lt; endl;

        cout &amp;lt;&amp;lt; &quot;link: &quot;;
        for (int i = 1; i &amp;lt;= size_; i++)
            cout &amp;lt;&amp;lt; setw(18) &amp;lt;&amp;lt; heap_[i]-&amp;gt;link;
        cout &amp;lt;&amp;lt; endl &amp;lt;&amp;lt; endl;
    }

    void Push(const Node* item)
    {
        if (this-&amp;gt;size_ == this-&amp;gt;capacity_)
            Resize(this-&amp;gt;capacity_ * 2);

        this-&amp;gt;size_ += 1;
    }

    void Pop()
    {
        assert(!this-&amp;gt;IsEmpty());

        using namespace std;
        cout &amp;lt;&amp;lt; &quot;Pop()&quot; &amp;lt;&amp;lt; endl;

        this-&amp;gt;heap_[1]-&amp;gt;~Node();
        delete this-&amp;gt;heap_[1];
    }

protected:
    Node** heap_ = nullptr;
    int size_ = 0;
    int capacity_ = 0;

    friend FixedPriorityQueue;
};


class MaxHeap : public Heap
{
public:
    MaxHeap(int capacity=10) : Heap(capacity){}

    void Push(Node* item)
    {
        Heap::Push(item);

        int current = this-&amp;gt;size_;

        // heap_[0] had a trash value
        while (current != 1 &amp;amp;&amp;amp; *(this-&amp;gt;heap_[current / 2]) &amp;lt; *item)
        {
            this-&amp;gt;heap_[current] = this-&amp;gt;heap_[current / 2];
            this-&amp;gt;heap_[current]-&amp;gt;idx = current;
            
            current = current / 2;
        }

        this-&amp;gt;heap_[current] = item;
        this-&amp;gt;heap_[current]-&amp;gt;idx = current;
    }

    void Pop()
    {
        Heap::Pop();

        Node *last_item = this-&amp;gt;heap_[this-&amp;gt;size_];
        this-&amp;gt;size_--;

        int current = 1;
        int child = 2;
        while (child &amp;lt;= this-&amp;gt;size_)
        {
            // Dereferencing it to compare!!!! else compare address
            if (child &amp;lt; this-&amp;gt;size_ &amp;amp;&amp;amp; *(this-&amp;gt;heap_[child]) &amp;lt; *(this-&amp;gt;heap_[child + 1]))
                child =  child + 1;

            if (*(this-&amp;gt;heap_[child]) &amp;lt;= *last_item)
                break;

            this-&amp;gt;heap_[current] = this-&amp;gt;heap_[child];
            this-&amp;gt;heap_[current]-&amp;gt;idx = current;

            //cout &amp;lt;&amp;lt; &quot;Current = &quot; &amp;lt;&amp;lt; current &amp;lt;&amp;lt; &quot;, child = &quot; &amp;lt;&amp;lt; child &amp;lt;&amp;lt; endl;
            //Print();

            current = child;
            child = current * 2;
        }

        this-&amp;gt;heap_[current] = last_item;
        this-&amp;gt;heap_[current]-&amp;gt;idx = current;
    }
};


class MinHeap : public Heap
{
public:
    MinHeap(int capacity=10) : Heap(capacity) {}

    void Push(Node* item)
    {
        Heap::Push(item);

        int current = this-&amp;gt;size_;

        // heap_[0] had a trash value
        while (current != 1 &amp;amp;&amp;amp; *(this-&amp;gt;heap_[current / 2]) &amp;gt; *item) 
        {
            this-&amp;gt;heap_[current] = this-&amp;gt;heap_[current / 2];
            this-&amp;gt;heap_[current]-&amp;gt;idx = current;

            current = current / 2;
        }

        this-&amp;gt;heap_[current] = item;
        this-&amp;gt;heap_[current]-&amp;gt;idx = current;
    }

    void Pop()
    {
        Heap::Pop();

        Node* last_item = this-&amp;gt;heap_[this-&amp;gt;size_];
        this-&amp;gt;size_--;

        int current = 1;
        int child = 2;
        while (child &amp;lt;= this-&amp;gt;size_)
        {
            // Dereferencing it to compare!!!! else compare address
            if (child &amp;lt; this-&amp;gt;size_ &amp;amp;&amp;amp; *(this-&amp;gt;heap_[child]) &amp;gt; *(this-&amp;gt;heap_[child + 1]))
                child = child + 1;
            
            if (*last_item  &amp;lt;= *(this-&amp;gt;heap_[child]))
                break;

            this-&amp;gt;heap_[current] = this-&amp;gt;heap_[child];
            this-&amp;gt;heap_[current]-&amp;gt;idx = current;

            //cout &amp;lt;&amp;lt; &quot;Current = &quot; &amp;lt;&amp;lt; current &amp;lt;&amp;lt; &quot;, child = &quot; &amp;lt;&amp;lt; child &amp;lt;&amp;lt; endl;
            //Print();

            current = child;
            child = current * 2;

        }

        this-&amp;gt;heap_[current] = last_item;
        this-&amp;gt;heap_[current]-&amp;gt;idx = current;
    }
};


class FixedPriorityQueue
{
public:
    FixedPriorityQueue(int capacity)
    {
        maxHeap_ = MaxHeap(capacity);
        minHeap_ = MinHeap(capacity);
        size_ = capacity;
    }

    void Push(const int&amp;amp; item)
    {
        using namespace std;

        Node *maxNode = new Node{ item };
        Node *minNode = new Node{ item };
        maxNode-&amp;gt;link = minNode;
        minNode-&amp;gt;link = maxNode;

        if (maxHeap_.size_ == size_)
        {
            // minHeap_.Top()-&amp;gt;link is leaf node at maxHeap
            int current = minHeap_.Top()-&amp;gt;link-&amp;gt;idx;
            minHeap_.Pop();
            minHeap_.Push(minNode);

            // compare maxNode with parent
            while (current != 1 &amp;amp;&amp;amp; *(maxHeap_.heap_[current / 2]) &amp;lt; *maxNode)
            {
                maxHeap_.heap_[current] = maxHeap_.heap_[current / 2];
                maxHeap_.heap_[current]-&amp;gt;idx = current;

                current = current / 2;
            }

            maxHeap_.heap_[current] = maxNode;
            maxHeap_.heap_[current]-&amp;gt;idx = current;
        }
        else
        {
            minHeap_.Push(minNode);
            maxHeap_.Push(maxNode);
        }
    }

    void Print()
    {
        using namespace std;
        cout &amp;lt;&amp;lt; &quot;maxHeap&quot; &amp;lt;&amp;lt; endl;
        maxHeap_.Print();

        cout &amp;lt;&amp;lt; &quot;minHeap&quot; &amp;lt;&amp;lt; endl;
        minHeap_.Print();
    }

public:
    MaxHeap maxHeap_;
    MinHeap minHeap_;
    int size_;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/Data Structure</category>
      <category>Honglab</category>
      <category>홍랩</category>
      <category>홍정모</category>
      <author>시옷지읏</author>
      <guid isPermaLink="true">https://hoplite.tistory.com/170</guid>
      <comments>https://hoplite.tistory.com/170#entry170comment</comments>
      <pubDate>Sat, 16 Dec 2023 22:44:48 +0900</pubDate>
    </item>
    <item>
      <title>[Data Structures] 챕터7. 트리</title>
      <link>https://hoplite.tistory.com/169</link>
      <description>&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;선형 vs 비선형 자료구조(Linear/ Non-Linear)&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;선형 자료구조&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 모두가 연결된 상태로 구현한다(직선으로 표현할 수 있다)&lt;/li&gt;
&lt;li&gt;리스트(List), 스택(Stack), 큐(Queue)&lt;/li&gt;
&lt;li&gt;위 자료구조를 배열 또는 연결노드로 구현할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;비선형 자료구조&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 모두가 연결되지 않은 상태이다(직선으로 표현할 수 없다)&lt;/li&gt;
&lt;li&gt;트리(Tree), 그래프(Graph)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;이진 트리 소개&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;양방향 연결 리스트와 &lt;b&gt;이진 트리&lt;/b&gt; 모두 Left와 Right 노드 포인터를 사용하지만 이진 트리는 자식-부모 관계를 다룬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;Root Node :&lt;/b&gt; 트리의 시작점으로 부모가 없다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Terminal{Leaf} Node(단말노드):&lt;/b&gt; 자식이 없는 노드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Edge :&lt;/b&gt; 노드와 노드의 연결을 가리킨다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Degree(차수) :&lt;/b&gt; 자식의 개수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Tree의 차수 :&lt;/b&gt; Tree 내에 있는 가장 큰 차수를 가진 노드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Sub Tree :&lt;/b&gt; 모든 노드는 어떤 Sub Tree의 Root이다 (구현할 때 중요)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;542&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rfhIP/btsBOgmCc87/q1zxknSc2xWgn4XRjBKh71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rfhIP/btsBOgmCc87/q1zxknSc2xWgn4XRjBKh71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rfhIP/btsBOgmCc87/q1zxknSc2xWgn4XRjBKh71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrfhIP%2FbtsBOgmCc87%2Fq1zxknSc2xWgn4XRjBKh71%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;618&quot; height=&quot;542&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;542&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Level : 루트 레벨을 0 또는 1로 본다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Height(높이) : 최고 레벨&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Depth(깊이) :&amp;nbsp;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Full Binary Tree(포화 이진 트리) :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;단말 노드 외 모든 노드의 자식이 꽉 차있는 트리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Complete Binary Tree(완전 이진 트리) :&amp;nbsp;&lt;/b&gt;단말 노드가 속한 레벨 외에는 모두 꽉 차있고 해당 단말노드의 반대방향은&amp;nbsp;모두 포화 상태인 트리&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1370&quot; data-origin-height=&quot;492&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyVCII/btsBXR5XZSM/Esa8PyVJ8ADZaUvEwN5cqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyVCII/btsBXR5XZSM/Esa8PyVJ8ADZaUvEwN5cqk/img.png&quot; data-alt=&quot;(왼) 완전이진트리O (오) 완전이진트리X&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyVCII/btsBXR5XZSM/Esa8PyVJ8ADZaUvEwN5cqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyVCII%2FbtsBXR5XZSM%2FEsa8PyVJ8ADZaUvEwN5cqk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1370&quot; height=&quot;492&quot; data-origin-width=&quot;1370&quot; data-origin-height=&quot;492&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;(왼) 완전이진트리O (오) 완전이진트리X&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;492&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cY5TL0/btsBMWVI1a6/WDo0MxtRbGkZOWLgRQMrb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cY5TL0/btsBMWVI1a6/WDo0MxtRbGkZOWLgRQMrb0/img.png&quot; data-alt=&quot;완전이진트리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cY5TL0/btsBMWVI1a6/WDo0MxtRbGkZOWLgRQMrb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcY5TL0%2FbtsBMWVI1a6%2FWDo0MxtRbGkZOWLgRQMrb0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2004&quot; height=&quot;492&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;492&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;완전이진트리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;이진트리 구현&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;pre id=&quot;code_1702449009896&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using Node = BinaryTree&amp;lt;int&amp;gt;::Node;

Node* n1 = new Node{ 1, nullptr, nullptr }; // 물결괄호 초기값 나열 (생성자 아님)
Node* n2 = new Node{ 2, n1, nullptr };
Node* n3 = new Node{ 3, nullptr, nullptr };
Node* n4 = new Node{ 4, nullptr, nullptr };
Node* n5 = new Node{ 5, nullptr, n4 };
Node* n6 = new Node{ 6, n2, n5 };

n1-&amp;gt;right = n3; // &amp;lt;- 연결관계 변경

/*          6
*         /   \
*        2     5
*       /       \
*      1         4
*       \
*        3
*/

BinaryTree&amp;lt;int&amp;gt; tree(n6); // &amp;lt;- n6의 주소를 root node로&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;트리 순회(Tree Traversal methods)&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;PreOrder&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;현재 노드를 먼저 처리한다.&lt;/li&gt;
&lt;li&gt;해당 노드에서 작업을 마친 후 왼쪽 자식&amp;gt;오른쪽 자식 순으로 순회&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;PostOrder&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;현재 노드를 나중에 처리한다.&lt;/li&gt;
&lt;li&gt;왼쪽 자식&amp;gt;오른쪽 자식으로 순회한 이후 해당 노드에서 작업&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;InOrder&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;왼쪽 자식을 순회한 이후 자신을 처리한다&lt;/li&gt;
&lt;li&gt;자신을 처리한 이후 오른쪽 자식을 순회한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Level Order&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;높은 레벨부터 처리한다&lt;/li&gt;
&lt;li&gt;재귀호출 X&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PreOrder, PostOrder, InOrder를 &lt;b&gt;Iterative를 활용하여 구현&lt;/b&gt;해보자(Queue와 Stack을 활용)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Template Intellisense 활용하기&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;349&quot; data-origin-height=&quot;119&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0Pvxf/btsBQjQNa9L/jsPuPCkHXfXJwiLvKq9Bok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0Pvxf/btsBQjQNa9L/jsPuPCkHXfXJwiLvKq9Bok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0Pvxf/btsBQjQNa9L/jsPuPCkHXfXJwiLvKq9Bok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0Pvxf%2FbtsBQjQNa9L%2FjsPuPCkHXfXJwiLvKq9Bok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;349&quot; height=&quot;119&quot; data-origin-width=&quot;349&quot; data-origin-height=&quot;119&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;구현하기&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Sum&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내풀이&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1702532651923&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int Sum(Node* node)
{
    int total = node-&amp;gt;item;
    if (node-&amp;gt;left)
        total += Sum(node-&amp;gt;left);

    if (node-&amp;gt;right)
        total += Sum(node-&amp;gt;right);

    return total;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;추천풀이&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1702532712218&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int Sum(Node* node)
{
    if (!node) return 0;
    return node-&amp;gt;item + Sum(node-&amp;gt;left) + Sum(node-&amp;gt;right);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Height&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;내풀이&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1702532759598&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int Height(Node* node)
{
    if (node-&amp;gt;left || node-&amp;gt;right)
    {
        int bigger = 0;
        if (node-&amp;gt;left)
            bigger = Height(node-&amp;gt;left) + 1;

        if (node-&amp;gt;right)
        {
            int right = Height(node-&amp;gt;right) + 1;
            bigger = bigger &amp;lt; right ? right : bigger;
        }

        return bigger;
    }

    return 1; // TODO:
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1702532935706&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int Height(Node* node)
{
    if(!node) return 0; // exit condition for recursive call
                        // Because node is null character, return 0
                        // Set -1 if base level is 0
    return std::max(Height(node-&amp;gt;left), Height(node-&amp;gt;right)) + 1;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Level Order&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1702533175242&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void LevelOrder()
{
    Queue&amp;lt;Node*&amp;gt; q;
    Node* current = root_;
    while (current)
    {
        Visit(current);

        if(current-&amp;gt;left) q.Enqueue(current-&amp;gt;left);
        if(current-&amp;gt;right) q.Enqueue(current-&amp;gt;right);
        if (q.IsEmpty()) break;

        current = q.Front();
        q.Dequeue();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;IterPreOrder&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1702533263903&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void IterPreorder()
{
    if (!root_) return;

    Stack&amp;lt;Node*&amp;gt; s;
    s.Push(root_);

    while (!s.IsEmpty())
    {
        Node* current = s.Top();
        s.Pop();

        Visit(current);
        if(current-&amp;gt;right)
            s.Push(current-&amp;gt;right);
        if (current-&amp;gt;left)
            s.Push(current-&amp;gt;left);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;IterInOrder&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1702533961820&quot; class=&quot;pgsql&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;void IterInorder()
{
    if (!root_) return;

    Stack&amp;lt;Node*&amp;gt; s;

    Node* current = root_;
    while (current || !s.IsEmpty())
    {
        while (current) // 1) Creating temporary value is not needed
        {
            s.Push(current);
            current = current-&amp;gt;left;
        }

        current = s.Top(); // 2) since a new value is always assigned anyway
        s.Pop();

        Visit(current);
        current = current-&amp;gt;right; // assign nullptr if right is empty
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;IterPostOrder&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1702538188931&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void IterPostorder()
{
    if (!root_) return;

    Stack&amp;lt;Node*&amp;gt; s1, s2;

    s1.Push(root_); // Reversed version of IterPreOrder
    while (!s1.IsEmpty())
    {
        Node* current = s1.Top();
        s1.Pop();
        s2.Push(current);

        // Stack Left first. It save right first at s2
        // So reversed version correctly poping out left first.
        if(current-&amp;gt;left) s1.Push(current-&amp;gt;left);
        if(current-&amp;gt;right) s1.Push(current-&amp;gt;right);
    }


    while (!s2.IsEmpty())
    {
        Visit(s2.Top());
        s2.Pop();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;수식 계산 트리&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;구현하기&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Evaluate&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내구현&lt;/p&gt;
&lt;pre id=&quot;code_1702638393753&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int Evaluate(Node* node)
{		
    Stack&amp;lt;Node*&amp;gt; s1, s2;
    s1.Push(node);
    while (!s1.IsEmpty())
    {
        Node* current = s1.Top();
        s1.Pop();

        s2.Push(current);

        if(current-&amp;gt;left)  s1.Push(current-&amp;gt;left);
        if(current-&amp;gt;right) s1.Push(current-&amp;gt;right);
    }

    Stack&amp;lt;char&amp;gt; save;
    int total = 0;
    while (!s2.IsEmpty())
    {
        char c = s2.Top()-&amp;gt;item;
        s2.Pop();

        if ('0' &amp;lt;= c &amp;amp;&amp;amp; c &amp;lt;= '9')
            save.Push(c);
        else
        {
            int second = save.Top() - '0';
            save.Pop();

            int first = save.Top() - '0';
            save.Pop();

            if (c == '+') save.Push((first + second) +'0');
            if (c == '-') save.Push((first - second) +'0');
            if (c == '*') save.Push((first * second) +'0');
            if (c == '/') save.Push((first / second) +'0');
        }
    }

    total = save.Top() - '0';
    return total;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추천구현&lt;/p&gt;
&lt;pre id=&quot;code_1702638878731&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int Evaluate(Node* node)
{
    if (!node) return 0;

    if(node-&amp;gt;item == '+') return Evaluate(node-&amp;gt;left) + Evaluate(node-&amp;gt;right);
    if(node-&amp;gt;item == '-') return Evaluate(node-&amp;gt;left) - Evaluate(node-&amp;gt;right);
    if(node-&amp;gt;item == '*') return Evaluate(node-&amp;gt;left) * Evaluate(node-&amp;gt;right);
    if(node-&amp;gt;item == '/') return Evaluate(node-&amp;gt;left) / Evaluate(node-&amp;gt;right);

    return node-&amp;gt;item - '0';
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Infix&lt;/h2&gt;
&lt;pre id=&quot;code_1702638437494&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Infix(Node* node) {
    if (!node) return;

    if(!IsDigit(node-&amp;gt;item)) std::cout &amp;lt;&amp;lt; &quot;(&quot;;
    Infix(node-&amp;gt;left);
    std::cout &amp;lt;&amp;lt; node-&amp;gt;item;
    Infix(node-&amp;gt;right);
    if (!IsDigit(node-&amp;gt;item)) std::cout &amp;lt;&amp;lt; &quot;)&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Postfix&lt;/h4&gt;
&lt;pre id=&quot;code_1702638462485&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Postfix(Node* node) {
    Stack&amp;lt;Node*&amp;gt; s1, s2;
    s1.Push(node);
    while (!s1.IsEmpty())
    {
        Node* current = s1.Top();
        s1.Pop();

        s2.Push(current);

        if (current-&amp;gt;left)  s1.Push(current-&amp;gt;left);
        if (current-&amp;gt;right) s1.Push(current-&amp;gt;right);
    }

    int total = 0;
    while (!s2.IsEmpty())
    {
        Visit(s2.Top());
        s2.Pop();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;ExpressionTree&lt;/h4&gt;
&lt;pre id=&quot;code_1702638487777&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ExpressionTree(const char* infix)
{
    // Infix -&amp;gt; Postfix (예제 재사용)
    Queue&amp;lt;char&amp;gt; q;
    for (int i = 0; infix[i] != '\0'; i++)
        q.Enqueue(infix[i]);
    cout &amp;lt;&amp;lt; &quot;  Infix: &quot;;
    q.Print();
    Queue&amp;lt;char&amp;gt; postfix;
    InfixToPostfix(q, postfix);
    cout &amp;lt;&amp;lt; &quot;Postfix: &quot;;
    postfix.Print();

    // Postfix -&amp;gt; Expression tree
    Stack&amp;lt;Node*&amp;gt; s, chars; // use another stack
    while (!postfix.IsEmpty())
    {
        char c = postfix.Front();
        postfix.Dequeue();

        Node* newNode = new Node{ c };
        if (c &amp;gt;= '0' &amp;amp;&amp;amp; c &amp;lt;= '9')
            chars.Push(newNode);
        else
        {
            Node* second = chars.Top();
            chars.Pop();
            Node* first = chars.Top();
            chars.Pop();

            newNode-&amp;gt;left = first;
            newNode-&amp;gt;right = second;

            chars.Push(newNode);
        }
    }

    assert(chars.Size() == 1);
    root_ = chars.Top();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;쓰레드&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Leaf 노드는 자식이 없다. 이를 활용하여 스택을 사용하지 않고 Iterative In Order를 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Leaf 노드가 다음 노드를 가리키는 링크를 가지고 있을 때 쓰레드(thread)라고 부른다. 이를 구분하기 위한 값을 노드에 추가하였다.&lt;/p&gt;
&lt;pre id=&quot;code_1702705287570&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct Node
{
    T data = T();
    Node* left = nullptr; // Left child
    Node* right = nullptr; // Right child
    int right_thread = 0; // &amp;lt;- right 링크가 쓰레드인지 구분
};&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;988&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdAd00/btsB3byhlHb/EUPK0NzIrR13ejYsmFGR71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdAd00/btsB3byhlHb/EUPK0NzIrR13ejYsmFGR71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdAd00/btsB3byhlHb/EUPK0NzIrR13ejYsmFGR71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdAd00%2FbtsB3byhlHb%2FEUPK0NzIrR13ejYsmFGR71%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;436&quot; height=&quot;341&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;988&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1702708587772&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Node* Next(Node* node)
{
    Node* next = node-&amp;gt;right;

    if (!next) return nullptr; // 종료
    if (next &amp;amp;&amp;amp; node-&amp;gt;right_thread) return next; // 오른쪽 링크가 쓰레드라면 바로 반환

    while (next-&amp;gt;left) next = next-&amp;gt;left; // Inorder 예시라서 가장 마지막 left로 이동

    return next; // (left가 없었다면 right 반환) left가 있었다면 가장 마지막 left 반환
}

void Inorder(Node* node)
{
    while (node-&amp;gt;left) node = node-&amp;gt;left; // Inorder라서 가장 마지막 left로 이동

    do
    {
        cout &amp;lt;&amp;lt; node-&amp;gt;data &amp;lt;&amp;lt; &quot; &quot;; // Visit
        node = Next(node); // 다음 노드를 찾는다
    } while (node);

    cout &amp;lt;&amp;lt; endl;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>CS/Data Structure</category>
      <category>Honglab</category>
      <category>홍랩</category>
      <category>홍정모</category>
      <author>시옷지읏</author>
      <guid isPermaLink="true">https://hoplite.tistory.com/169</guid>
      <comments>https://hoplite.tistory.com/169#entry169comment</comments>
      <pubDate>Sat, 16 Dec 2023 15:39:48 +0900</pubDate>
    </item>
    <item>
      <title>[Data Structures] 챕터6. 연결 리스트</title>
      <link>https://hoplite.tistory.com/168</link>
      <description>&lt;pre id=&quot;code_1702375347539&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Node* current = first_;
while(current-&amp;gt;next)
{
	current = current-&amp;gt;next;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;순차 표현 vs 연결 표현&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Sequential Representation&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;장점 :&lt;/b&gt; 데이터를 묶음별로 다룰 수 있어 효율적이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단점 :&lt;/b&gt; 중간에 데이터를 삽입하거나 제거하면, 그 뒤의 데이터를 이동시켜야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;따라서 Sequential Representation은 &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;많은 데이터를 읽어들이는데 유리하다&lt;/li&gt;
&lt;li&gt;데이터를 연속적인 데이터 중간에 추가하거나 제거하는데 불리하다&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Linked Representation&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;장점 :&lt;/b&gt;&lt;span&gt; 중간에 데이터를 삽입하거나 제거하는 일이 빠르다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단점 :&lt;/b&gt;&lt;span&gt; 다음 Node에 접근하기 위해 이전에 존재하는 모든 Node를 거쳐야하므로 비효율적이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 삽입하거나 삭제할 때 해당 노르를 제거하거나 추가한 뒤 앞뒤 노드와 연결관계를 재설정하면 된다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;참고&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;CPU에서 메모리로 데이터를 읽어들일 때 메모리 대역폭에 맞춰서 주변 데이터를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;블럭 단위로 읽어와서&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;일단 캐쉬에 넣어둔다. 그 다음에 요청하는 데이터가 캐쉬에 들어 있다면 재빠르게 가져오고 그렇지 않다면 다시 메인 메모리에서 데이터를 또 다시 블럭 단위로 가져옵니다. 그래서 배열 같은 순차적 자료구조에서 순서대로 데이터를 읽어오는 것은 캐쉬 효과 덕분에 아주 빠르다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;연결 노드(Linked List)&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #36394d; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 외에 추가로 링크 포인터도 저장(더 많은 메모리가 필요하다).&lt;/li&gt;
&lt;li&gt;삽입/삭제가 편리하다는 장점을 살릴 수 없는 경우에는 메모리 낭비가 된다.&lt;/li&gt;
&lt;li&gt;아이템 자체의 사이즈가 아주 큰 경우에도 포인터 하나가 추가되는 것 정도는 큰 낭비라고 볼 수 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;nullptr == 0?&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1702357350864&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int* ptr_zero = 0;       // X
int* ptr_null = nullptr; // O&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;숫자값 0과 비어있는 포인터를 구분하자. 이를 위해 비어있는 포인터를 0으로 사용하는 건 피하자&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;주소값 얻기&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;Reference&lt;/b&gt;와 &lt;b&gt;Pointer&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;amp;n.next는 포인터의 주소값을 나타낸다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1702367043535&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct Node
{
	int item = 0;
	Node* next = nullptr;

	friend ostream&amp;amp; operator&amp;lt;&amp;lt;(ostream&amp;amp; os, const Node&amp;amp; n)
	{
		cout &amp;lt;&amp;lt; &amp;amp;n &amp;lt;&amp;lt; &quot;주소값&quot; &amp;lt;&amp;lt; endl;
		cout &amp;lt;&amp;lt; n.next &amp;lt;&amp;lt; &quot;포인터(주소 값)&quot; &amp;lt;&amp;lt; endl;

		return os;
	}
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;연결노드 삭제&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1702367969034&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Node* current = first;
while (current)
{
    Node*temp = current-&amp;gt;next;
    delete current;

    current = temp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;단방향 연결 리스트(Singly Linked List)&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Linked List의 속도&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;값 찾기 : O(n)&lt;/b&gt; 모든 값을 순회해야 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;값 넣기 : O(1)&lt;/b&gt; 특정 노드 앞뒤 혹은 전체의 앞뒤에 값을 넣음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #36394d; text-align: start;&quot;&gt;삽입과 삭제의 시간 복잡도가 배열 리스트에서는&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; O(n)이지만 연결 리스트에서는 O(1)&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;여러 Linked List&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Circular List&lt;/b&gt; &lt;b&gt;:&lt;/b&gt; 맨 뒤와 앞이 연결된 Linked List.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;마지막 노드가 맨 앞을 가리키면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt; &lt;span style=&quot;background-color: #ffffff; color: #36394d; text-align: start;&quot;&gt;Linked Stack :&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #36394d; text-align: start;&quot;&gt;연결된 스택&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #36394d; text-align: start;&quot;&gt;Linked Queue : &lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #36394d; text-align: start;&quot;&gt;연결된 큐&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;구현하기&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1702376052825&quot; class=&quot;elixir&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;Node* current = first_;
while(current-&amp;gt;next)
{
	current = current-&amp;gt;next;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v1Ho2/btsBQXzxAME/C7JT6ZxhogQiq8C18B6kBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v1Ho2/btsBQXzxAME/C7JT6ZxhogQiq8C18B6kBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v1Ho2/btsBQXzxAME/C7JT6ZxhogQiq8C18B6kBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv1Ho2%2FbtsBQXzxAME%2FC7JT6ZxhogQiq8C18B6kBk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;660&quot; height=&quot;110&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;110&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1702376055175&quot; class=&quot;elixir&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;Node* current = first_;
while(current-&amp;gt;next &amp;amp;&amp;amp; current-&amp;gt;next-&amp;gt;next)
{
	current = current-&amp;gt;next;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D2sGJ/btsBKfgGnb4/XMcZycaLg0FpsLULoBorTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D2sGJ/btsBKfgGnb4/XMcZycaLg0FpsLULoBorTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D2sGJ/btsBKfgGnb4/XMcZycaLg0FpsLULoBorTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD2sGJ%2FbtsBKfgGnb4%2FXMcZycaLg0FpsLULoBorTK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;660&quot; height=&quot;110&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;110&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 current-&amp;gt;next와 current-&amp;gt;next-&amp;gt;next가 nullptr인 두 가지 경우의 예외를 처리해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;PushFront&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1702376386426&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void PushFront(T item)
{
    // 새로운 노드 만들기
    Node* newNode = new Node; // O(1)
    newNode-&amp;gt;item = item;

    // 연결 관계 정리
    newNode-&amp;gt;next = first_;
    first_ = newNode;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;PushBack&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1702376814089&quot; class=&quot;crmsh&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;void PushBack(T item)
{
    if (first_)
    {
        Node* current = first_;
        while (current-&amp;gt;next)
            current = current-&amp;gt;next;

        Node* newNode = new Node;
        newNode-&amp;gt;item = item;
        newNode-&amp;gt;next = nullptr;

        current-&amp;gt;next = newNode;
    }
    else
        PushFront(item);
}&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;while반복문 조건에 current를 넣을 경우 반복문 종료 이후 current는 nullptr가 된다.&lt;/li&gt;
&lt;li&gt;이 때 current에 동적할당 받은 새 주소를 할당받아도 마지막 바로 앞 노드의 next 포인터는 여전히 nullptr를 가리킨다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Copy Constructor&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내 구현&lt;/b&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1702376978395&quot; class=&quot;haxe&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;SinglyLinkedList(const SinglyLinkedList&amp;amp; list)
{
    Node* current= list.first_;
    Node* newCurrent = new Node;
    first_ = newCurrent;

    while (current)
    {
        newCurrent-&amp;gt;item = current-&amp;gt;item;

        if (current-&amp;gt;next)
        {
            newCurrent-&amp;gt;next = new Node;
            newCurrent = newCurrent-&amp;gt;next;
        }

        current = current-&amp;gt;next;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;추천 구현&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1702377082320&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SinglyLinkedList(const SinglyLinkedList&amp;amp; list)
{
    Node* current = list.first_;

    while (current)
    {
        this-&amp;gt;PushBack(current-&amp;gt;item); // handle &quot;fisrt_&quot;
        current = current-&amp;gt;next;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Reverse&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 :&amp;nbsp;&lt;/b&gt;&lt;b&gt;&lt;a title=&quot;Reverse 구현 애니메이션&quot; href=&quot;https://www.geeksforgeeks.org/reverse-a-linked-list/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.geeksforgeeks.org/reverse-a-linked-list/&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1702377970679&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Reverse()
{
    Node* current = first_;
    Node* previous = nullptr;

    while (current)
    {
        Node* next = current-&amp;gt;next;
        current-&amp;gt;next = previous;

        previous = current;
        current = next;
    }

    first_ = previous;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Find&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1702378195419&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Node* Find(T item)
{
    Node* current = first_;
    while (current)
    {
        if (current-&amp;gt;item == item)
            return current;

        current = current-&amp;gt;next;
    }

    return nullptr;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;InsertBack&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1702378175655&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void InsertBack(Node* node, T item)
{
    Node* newNode = new Node;
    newNode-&amp;gt;item = item;
    newNode-&amp;gt;next = node-&amp;gt;next;
    node-&amp;gt;next = newNode;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Remove&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 값을 삭제하는 경우 예외처리&lt;/p&gt;
&lt;pre id=&quot;code_1702378467731&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Remove(Node* n)
{
    assert(first_);

    if (first_ == n)
    {
        first_ = first_-&amp;gt;next;
        delete n;

        return;
    }

    Node* current = first_;
    while (current-&amp;gt;next) // check next of current instead of current
    {                     // because it could be nullptr
        if (current-&amp;gt;next == n)
        {
            current-&amp;gt;next = n-&amp;gt;next;
            delete n;

            break;
        }

        current = current-&amp;gt;next;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;PopBack&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내구현&lt;/b&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1702379566099&quot; class=&quot;cpp&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;void PopBack()
{
    if (IsEmpty())
    {
        using namespace std;
        cout &amp;lt;&amp;lt; &quot;Nothing to Pop in PopBack()&quot; &amp;lt;&amp;lt; endl;
        return;
    }

    assert(first_);
    Node* previous = nullptr;
    Node* current = first_;

    while (current-&amp;gt;next)
    {
        previous = current;
        current = current-&amp;gt;next;
    }

    if (previous)
    {
        delete previous-&amp;gt;next;
        previous-&amp;gt;next = nullptr;
    }
    else {
        delete first_;
        first_ = nullptr;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;추천구현&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1702379575857&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void PopBack()
{
    if (IsEmpty())
    {
        using namespace std;
        cout &amp;lt;&amp;lt; &quot;Nothing to Pop in PopBack()&quot; &amp;lt;&amp;lt; endl;
        return;
    }

    assert(first_);
    Node* current = first_;

    if (current-&amp;gt;next)
    {
        while (current-&amp;gt;next-&amp;gt;next)
            current = current-&amp;gt;next;

        delete current-&amp;gt;next;
        current-&amp;gt;next = nullptr;
    }
    else
    {
        delete first_;
        first_ = nullptr;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Clear&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1702380233851&quot; class=&quot;pgsql&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;void Clear()
{
    Node* current = first_;
    while (current)
    {
        Node* temp = current-&amp;gt;next;
        delete current;

        current = temp;
    }

    first_ = nullptr;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1702380275699&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Clear()
{
    while (first_)
        PopFront();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;연결 다항식 실습(희소 다항식 구현하기)&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부모 Class에 있는 struct Name불러쓰기&lt;/p&gt;
&lt;pre id=&quot;code_1702387420729&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename T&amp;gt;
class SinglyLinkedList
{
public:
    struct Node
    {
        T item = T();
        Node* next = nullptr;
    };
	...
};

class LinkedPolynomial : public SinglyLinkedList&amp;lt;Term&amp;gt;
{
public:
	typedef SinglyLinkedList&amp;lt;Term&amp;gt;::Node Node;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;구현하기&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;NewTerm&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1702397281036&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void NewTerm(float coef, int exp)
{
    if (first_ == nullptr)
    {
        first_ = new Node;
        first_-&amp;gt;next = nullptr;
        first_-&amp;gt;item = Term{ coef, exp };
        return;
    }

    Node* current = first_;
    Node* previous = nullptr;
    while (current)
    {
        if (exp == current-&amp;gt;item.exp)
        {
            current-&amp;gt;item.coef += coef;
            return;
        }
        else if (exp &amp;lt; current-&amp;gt;item.exp)
        {
            Node* newNode = new Node;
            newNode-&amp;gt;item = Term{ coef, exp };
            if (previous)
            {
                Node* temp = previous-&amp;gt;next;
                previous-&amp;gt;next = newNode;
                newNode-&amp;gt;next = temp;
            }
            else
            {
                newNode-&amp;gt;next = first_;
                first_ = newNode;
            }
            return;
        }

        previous = current;
        current = current-&amp;gt;next;
    }

    Node* newNode = new Node;
    newNode-&amp;gt;item = Term{ coef, exp };
    previous-&amp;gt;next = newNode;
    newNode-&amp;gt;next = current;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Eval&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1702397297191&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;float Eval(float x)
{
    float temp = 0.0f;

    Node* current = first_;
    while (current)
    {
        temp += current-&amp;gt;item.coef* powf(x, (float)current-&amp;gt;item.exp);
        current = current-&amp;gt;next;
    }

    return temp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Add&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1702397334655&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;LinkedPolynomial Add(const LinkedPolynomial&amp;amp; poly)
{
    LinkedPolynomial temp;

    Node* i = this-&amp;gt;first_;
    Node* j = poly.first_;

    while (i &amp;amp;&amp;amp; j)
    {
        if (i-&amp;gt;item.exp &amp;lt; j-&amp;gt;item.exp)
        {
            temp.NewTerm(i-&amp;gt;item.coef, i-&amp;gt;item.exp);
            i = i-&amp;gt;next;
        }
        else if (i-&amp;gt;item.exp &amp;gt; j-&amp;gt;item.exp)
        {
            temp.NewTerm(j-&amp;gt;item.coef, j-&amp;gt;item.exp);
            j = j-&amp;gt;next;
        }
        else 
        {
            float sum = i-&amp;gt;item.coef + j-&amp;gt;item.coef;
            if(sum)
                temp.NewTerm(sum, i-&amp;gt;item.exp);

            i = i-&amp;gt;next;
            j = j-&amp;gt;next;
        }
    }

    for(;i;i=i-&amp;gt;next)
        temp.NewTerm(i-&amp;gt;item.coef, i-&amp;gt;item.exp);

    for(;j;j=j-&amp;gt;next)
        temp.NewTerm(j-&amp;gt;item.coef, j-&amp;gt;item.exp);

    return temp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Print&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1702397486960&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Print()
{
    bool is_first = true;

    Node* current = first_;
    while (current)
    {
        if (!is_first) cout &amp;lt;&amp;lt; &quot; + &quot;;
        else is_first = false;

        cout &amp;lt;&amp;lt; current-&amp;gt;item.coef &amp;lt;&amp;lt; &quot;x^&quot; &amp;lt;&amp;lt; current-&amp;gt;item.exp;
        current = current-&amp;gt;next;
    }

    cout &amp;lt;&amp;lt; endl;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;양방향 연결리스트(Doubly Linked List)&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;코팅 팁&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;while 반복문으로 Link의 마지막 노드를 가리키기.&lt;/p&gt;
&lt;pre id=&quot;code_1702438495426&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Node* current = first_;

if (current-&amp;gt;right)
{
    while (current-&amp;gt;right)
    {
        cout &amp;lt;&amp;lt; current-&amp;gt;item &amp;lt;&amp;lt; &quot; &quot;;
        current = current-&amp;gt;right;
    }
    cout &amp;lt;&amp;lt; current-&amp;gt;item;
}
else { // single node
    cout &amp;lt;&amp;lt; current-&amp;gt;item &amp;lt;&amp;lt; &quot; &quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;while 조건문을 code block 내부로 이동한다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1702439034914&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;while (true)
{
    cout &amp;lt;&amp;lt; current-&amp;gt;item &amp;lt;&amp;lt; &quot; &quot;;
    if (!current-&amp;gt;right)
        break;

    current = current-&amp;gt;right;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;구현하기&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1702440268322&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Reverse()
{
    Node* current = first_;

    while (current)
    {
        Node* temp = current-&amp;gt;right; // what if current-&amp;gt;right is nullptr?
        current-&amp;gt;right = current-&amp;gt;left; // you assign a value on nullptr?
        current-&amp;gt;left = temp;
        first_ = current;	// Trick for Simplifing Code 

        current = temp;
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>CS/Data Structure</category>
      <author>시옷지읏</author>
      <guid isPermaLink="true">https://hoplite.tistory.com/168</guid>
      <comments>https://hoplite.tistory.com/168#entry168comment</comments>
      <pubDate>Wed, 13 Dec 2023 13:07:24 +0900</pubDate>
    </item>
    <item>
      <title>[Data Structures] 챕터5. 큐(Queue)</title>
      <link>https://hoplite.tistory.com/167</link>
      <description>&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;원형 큐&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FIFO(First in First Out)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원형 큐에서 두 개의 index를 활용하여 비어있을 경우, 1개 있을 경우, 2개 있을경우, ..., 꽉 차있을 경우를 표현해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 경우를 각각 유일하게 표현할 수 있도록 index를 사용하는 방법은 무엇인가?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;front는 시작 index보다 1 작은 값을 가진다.&lt;/li&gt;
&lt;li&gt;rear는 가장 마지막에 추가된 index이다.&lt;/li&gt;
&lt;li&gt;front == rear일 때 원형 큐는 비어있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;위 규칙을 적용하고 capacity -1 개의 저장공간만 사용&lt;/b&gt;한다(front가 가리키는 곳은 항상 비어있다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;원형 큐의 구현 원리&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;front와 rear 모두 0 index에서 시작한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;값을 추가하면 rear를 증가시켜 해당 index에 값을 할당한다&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1980&quot; data-origin-height=&quot;292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d521iV/btsA7t0qM9S/8io8AyKK78OtYxE4jM2OyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d521iV/btsA7t0qM9S/8io8AyKK78OtYxE4jM2OyK/img.png&quot; data-alt=&quot;3.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d521iV/btsA7t0qM9S/8io8AyKK78OtYxE4jM2OyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd521iV%2FbtsA7t0qM9S%2F8io8AyKK78OtYxE4jM2OyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1980&quot; height=&quot;292&quot; data-origin-width=&quot;1980&quot; data-origin-height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;3.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;값을 뺄 때 front&amp;nbsp; 값을 증가시키고 해당 index에 있는 값을 지운다.&lt;/li&gt;
&lt;li&gt;rear 값이 capacity를 넘어가면 0에서 시작한다. &lt;b&gt;rear = (rear + 1) % capacity&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1978&quot; data-origin-height=&quot;291&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7c7VQ/btsA5fg5MlW/egN6esyRZ2aE3o0c4wgwyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7c7VQ/btsA5fg5MlW/egN6esyRZ2aE3o0c4wgwyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7c7VQ/btsA5fg5MlW/egN6esyRZ2aE3o0c4wgwyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7c7VQ%2FbtsA5fg5MlW%2FegN6esyRZ2aE3o0c4wgwyk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1978&quot; height=&quot;291&quot; data-origin-width=&quot;1978&quot; data-origin-height=&quot;291&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 rear와 front가 같아지면 empty와 구분할 수 없으므로 capacity = capacity -1이 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;287&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mgClK/btsA7vw8TbL/WkcIKKM8TFk5kkrhuFjLaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mgClK/btsA7vw8TbL/WkcIKKM8TFk5kkrhuFjLaK/img.png&quot; data-alt=&quot;index 1은 비워야 한다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mgClK/btsA7vw8TbL/WkcIKKM8TFk5kkrhuFjLaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmgClK%2FbtsA7vw8TbL%2FWkcIKKM8TFk5kkrhuFjLaK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;262&quot; height=&quot;114&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;287&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;index 1은 비워야 한다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;구현&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1701253790425&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int Size() const
{    
    // front_ == rear_ 일 때 Size = 0
    if (front_ &amp;lt;= rear_)
        return rear_ - front_;

    // front ~ (capacity-1)의 개수 +  0 ~ rear의 개수
    // (capacity - front -1)      +    (rear_ + 1)
    return capacity_ - front_ + rear_;

    //            비어있는 공간 개수
    // capacity  -  (front - rear)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;ReSize&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;반복문 사용&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;내구현(if-else로 나누어 처리)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701254237720&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Resize() // 2배씩 증가
{
    T* NewQueue= new T[capacity_ * 2];
    
    if (front_ &amp;gt; rear_)
    {
        for (int i = front_+1; i &amp;lt; capacity_; ++i)
            NewQueue[i - front_] = queue_[i]; // start idx is 1 not 0

        for (int i = 0;i &amp;lt;= rear_; ++i)
            NewQueue[capacity_ - front_ + i] = queue_[i]; // capacity_ - front_ = new start idx position
        // 예제 활용하기 front_=4, capacity=6
        // idx 4는 비어있고 idx 5는 값을 가지며 6-4 = 2이다
        // 이를 0으로 shift하면 idx 2(capacity - front)부터 채우면 된다.

        front_ = 0;
        rear_ = capacity_-1;
    }
    else
    {
        for (int i = 0; i &amp;lt; capacity_; ++i)
            NewQueue[i] = queue_[i];
    }
    
    delete[] queue_;
    queue_ = NewQueue;
    capacity_ *= 2;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;추천구현(% 연산자를 활용)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701254553520&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Resize()
{
    T* NewQueue= new T[capacity_ * 2];
    
    int count = 1; // start idx is 1
    for (int i = (front_ + 1) % capacity_; i != (rear_ + 1) % capacity_; i= (i+1) % capacity_)
    {
        NewQueue[count] = queue_[i]; 
        count++;
    }

    front_ = 0;
    rear_ = capacity_-1;
    delete[] queue_;
    queue_ = NewQueue;
    capacity_ *= 2;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;memcpy 사용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내구현&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701254700326&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Resize() // 2배씩 증가
{
    T* NewQueue= new T[capacity_ * 2];
    
    if (front_ &amp;gt; rear_)
    {
        // 비어있는 front_ index부터 마지막 index까지 
        memcpy(NewQueue, &amp;amp;queue_[front_], (capacity_ - front_) * sizeof(T)); // T의 크기로 할당

        // 위에서 (capacity_ - front_)개수 만큼 채웠으므로 
        // (capacity_ - front_ -1) index까지 값이 할당됨. (capacity_ - front_)에서 시작.
        memcpy(&amp;amp;NewQueue[capacity_ - front_], queue_, (rear_+1)* sizeof(T)); // T의 크기로 할당

        front_ = 0;
        rear_ = capacity_-1; // 마지막 index를 가리킴
    }
    else
        memcpy(NewQueue, queue_, capacity_ * sizeof(T));

    front_ = 0;
    rear_ = capacity_-1;
    delete[] queue_;
    queue_ = NewQueue;
    capacity_ *= 2;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;처음에 한 칸을 띄우지 않는 구현 방식(front가 마지막 index)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;강의 21:48&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Deque&lt;/h4&gt;
&lt;pre id=&quot;code_1701255359925&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Dequeue() // 큐의 첫 요소 삭제, Pop()
{
    assert(!IsEmpty());

    front_ = (front_ + 1) % capacity_;
    //queue_[front_].~T(); // 자료형이 동적할당 메모리를 가질 경우
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;조세푸스 문제&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;덱(Deque)&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Deque(Double Ended Queue) 덱&lt;/li&gt;
&lt;li&gt;양쪽을 모두 사용할 수 있다(queue의 기능을 확장)&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PushFront / PushBack, PopFront / PopBack&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;dequeue와 deque는 다르다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 구현한 Queue를 상속하면 PushBack == Enqueue, PopFront == Dequeue이므로 이미 구현되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PushFront와 PopBack만 구현하면 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;구현&lt;/h3&gt;
&lt;pre id=&quot;code_1701264190044&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename T&amp;gt;
class Deque : public Queue&amp;lt;T&amp;gt; // Deque가 사용하는 자료형 T와 동일한
{                             // 자료형을 사용하는 Queue를 상속
    typedef Queue&amp;lt;T&amp;gt; Base; // Queue&amp;lt;T&amp;gt; == Base (짧게 쓰기)
private:
    int&amp;amp; rear_ = Base::rear_;
    int&amp;amp; front_ = Base::front_;
    int&amp;amp; capacity_ =  Base::capacity_;
    T*&amp;amp; queue_ = Base::queue_;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 1)&lt;/b&gt; 위와 같이 부모 멤버 변수의 새 이름을 만들어 호출할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 2)&lt;/b&gt; 부모 클래스가 템플릿(template) 클래스일 경우 부모 클래스의 멤버를 아래와 같이 호출할 수 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;this-&amp;gt;부모 멤버&amp;nbsp; (자신의 멤버와 부모의 멤버가 헷갈릴 수 있다)&lt;/li&gt;
&lt;li&gt;Base::멤버&lt;/li&gt;
&lt;li&gt;Queue&amp;lt;T&amp;gt;::멤버&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;PushFront&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;이 때 front_는 값을 가지지 않는 index이므로 해당 index에 값을 할당하고 이동시킨다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701264297162&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void PushFront(const T&amp;amp; item)
{
    if (Base::IsFull())
        Base::Resize();

    Base::queue_[Base::front_] = item;
    Base::front_ = (Base::front_ + Base::capacity_ - 1) % Base::capacity_;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;PopBack&lt;/h4&gt;
&lt;pre id=&quot;code_1701264720745&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void PopBack()
{
    assert(!Base::IsEmpty());

    Base::rear_ = (Base::rear_ + Base::capacity_ - 1) % Base::capacity_;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;수식 계산&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;infix&amp;nbsp; &amp;nbsp;:&lt;/b&gt; 숫자 사이에 연산자를 적는다(사람이 이해하기 편함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A/B-C+D*E-A*C&lt;/p&gt;
&lt;pre id=&quot;code_1701266174954&quot; class=&quot;angelscript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt; 8 / 2 - 3 + 4 * 5 - 1 * 2 = 19&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;postfix :&lt;/b&gt; 계산 순서에 따라 숫자와 연산자를 나열한다(컴퓨터가 계산하기 편함)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AB/C-DE*+AC*-&lt;/p&gt;
&lt;pre id=&quot;code_1701266128846&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;8 2 / 3 - 4 5 * + 1 2 * - // 연산자를 만날때까지 진행
= 4 3 - 4 5 * + 1 2 * -
= 1 4 5 * + 1 2 * -
= 1 20 + 1 2 * -
= 21 1 2 * -
= 21 2 -
= 19&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;구현목표&lt;/span&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;infix를 posfix로 변환 (InfixToPostfix)&lt;/li&gt;
&lt;li&gt;posfix를 계산 (EvalPostfix)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Queue는 문자열 데이터를 저장하는 용도로 쓴다. 알고리즘(로직)은 Stack을 활용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Stack을 사용하는 이유&lt;/b&gt; : 우선순위가 높은 연산자를 먼저 계산하기 위함&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;stack에 담겨있는 연산자와 새로운 연산자를 비교하여 우선순위가 높은 연산자를 먼저 계산한다&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;구현&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1701267451774&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Function to return precedence of operators
// * is higher than - and +
int Prec(char c)
{
    if (c == '/' || c == '*')
        return 2;
    else if (c == '+' || c == '-')
        return 1;
    else
        return -1; // '('는 우선순위가 아주 낮은 것으로 처리, ')' 닫는 괄호를 만날때까지 남겨두기 위함
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1701317914456&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void InfixToPostfix(Queue&amp;lt;char&amp;gt;&amp;amp; q, Queue&amp;lt;char&amp;gt;&amp;amp; output)
{
    Stack&amp;lt;char&amp;gt; s; // 우선순위가 낮은 연산을 보류하기 위한 스택

    output.SetDebugFlag(false);

    while (!q.IsEmpty())
    {
        char c = q.Front();
        q.Dequeue();

        cout &amp;lt;&amp;lt; c &amp;lt;&amp;lt; endl;

        if (c &amp;gt;= '0' &amp;amp;&amp;amp; c &amp;lt;= '9') // 숫자(피연산자)라면 output에 추가
            output.Enqueue(c);
        else if (c == '(') // 여는 괄호라면 스택에 추가
            s.Push(c);
        else if (c == ')') // 닫는 괄호를 만나면
        {
            // 여는 괄호 전까지를 스택에서 꺼내서 출력에 넣기
            // 여는 괄호 제거
            while (s.Top() != '(')
            {
                output.Enqueue(s.Top());
                s.Pop();
            }
            s.Pop();
        }
        else // 연산자를 만나면
        {
            // 스택에서 c보다 우선순위가 높거나 같은 것들을 꺼내서 추가
            while (!s.IsEmpty() &amp;amp;&amp;amp; Prec(c) &amp;lt;= Prec(s.Top()))
            {
                output.Enqueue(s.Top());
                s.Pop();
            }

            // c는 스택에 추가
            s.Push(c);
        }

        cout &amp;lt;&amp;lt; &quot;Stack: &quot;;
        s.Print();
        cout &amp;lt;&amp;lt; &quot;Output:&quot;;
        output.Print();
        cout &amp;lt;&amp;lt; endl;
    }

    // 스택에 남아있는 것들을 모두 추가
    while (!s.IsEmpty())
    {
        output.Enqueue(s.Top());
        s.Pop();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1701317945177&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int EvalPostfix(Queue&amp;lt;char&amp;gt;&amp;amp; q)
{
    Stack&amp;lt;int&amp;gt; s;

    while (!q.IsEmpty())
    {
        char c = q.Front();
        q.Dequeue();

        cout &amp;lt;&amp;lt; c &amp;lt;&amp;lt; endl;

        if (c != '+' &amp;amp;&amp;amp; c != '-' &amp;amp;&amp;amp; c != '*' &amp;amp;&amp;amp; c != '/')
        {
            // 입력이 연산자가 아니면 일단 저장
            // 문자를 숫자로 변환 c - '0' 예: int('9' - '0') -&amp;gt; 정수 9
            s.Push(c - '0');
        }
        else
        {
            cout &amp;lt;&amp;lt; &quot;Operator: &quot; &amp;lt;&amp;lt; c &amp;lt;&amp;lt; endl;

            // 입력이 연산자이면 스택에서 꺼내서 연산에 사용
            int second = s.Top();
            s.Pop();
            int first = s.Top();
            s.Pop();

            if (c == '+')
                s.Push(first + second);
            else if (c == '-')
                s.Push(first - second);
            else if (c == '*')
                s.Push(first * second);
            else if (c == '/')
                s.Push(first / second);
            else
            {
                cout &amp;lt;&amp;lt; &quot;Wrong operator&quot; &amp;lt;&amp;lt; endl;
                exit(-1); // 강제 종료
            }
        }

        cout &amp;lt;&amp;lt; &quot;Stack: &quot;;
        s.Print();
    }

    return s.Top();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;더 해볼 것들&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #36394d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;숫자가 두자리 이상인 경우 &lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #36394d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;character 자료형은 1 2 3 4를 12, 34 혹은 123,4로 구분할 수 없다. 따라서 두자리 숫자는 하나의 자료형으로 저장해야 하므로 Queue 자료형을 string 혹은 여러 숫자를 저장할 수 있는 자료형으로 변경해야 한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #36394d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 때 기존에 구현한 Queue는 메모리 해제 delete 와 소멸자를 호출하고 있다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #36394d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;std::string은&amp;nbsp;자체적으로&amp;nbsp;메모리를&amp;nbsp;관리하므로&amp;nbsp;소멸자를&amp;nbsp;따로&amp;nbsp;호출할&amp;nbsp;필요가&amp;nbsp;없다.&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;str is not a pointer to dynamically allocated memory, so you cannot delete it. In fact, you don't have to: it is a member of a class and maneges owned memory itself.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;string 자료형에다 곧바로 memcpy을 사용할 수 없다.&lt;/p&gt;</description>
      <category>CS/Data Structure</category>
      <author>시옷지읏</author>
      <guid isPermaLink="true">https://hoplite.tistory.com/167</guid>
      <comments>https://hoplite.tistory.com/167#entry167comment</comments>
      <pubDate>Thu, 30 Nov 2023 18:04:33 +0900</pubDate>
    </item>
    <item>
      <title>[Data Structures] 챕터4. 스택(Stack)</title>
      <link>https://hoplite.tistory.com/166</link>
      <description>&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;스택&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;할 일을 쌓아둔다.&lt;/li&gt;
&lt;li&gt;LIFO(Last in First Out), 후입선출&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;용도&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #36394d; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;편집 소프트웨어의 Undo/Redo 기능 구현&lt;/li&gt;
&lt;li&gt;연산자 우선순위를 고려한 수식의 계산 예) 1 + 2 * 3 에서 + 연산을 미뤄두고 *를 먼저 수행&lt;/li&gt;
&lt;li&gt;함수 실행할 때 스택에 프레임 쌓기 - 앞에서 재귀호출 가시화 도구 가시화에서 봤듯이 나중에 호출된 함수를 끝낸 후 그 전에 호출된 함수로 돌아갈 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;구현&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1701225197460&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int Size() const
{
    return top_ + 1; // top_이 index를 가리키므로 +1을 해주자
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1701225264791&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Insert item into the TOP of the stack
void Push(const T&amp;amp; item)
{
    if (capacity_ == top_+1) // capacity는 top + 1 index를 포함해야함
        Resize(capacity_ * 2);
	
    ++top_;
    stack_[top_] = item;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Pop&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;T자료형이 내부에서 동적할당 메모리를 사용한다면 소멸자를 호출해주자.&lt;/p&gt;
&lt;pre id=&quot;code_1701226115037&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Pop()
{
    assert(!IsEmpty());
    
    stack_[top_].~T(); // T 자료형 내부에서 동적할당 메모리를 사용할 경우
    top_--;

    // 메모리를 아껴야 될 경우 Resize로 크기를 줄이자
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;미로&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;pre id=&quot;code_1701230800718&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct Pos
{
    int row;
    int col;

    friend ostream&amp;amp; operator&amp;lt;&amp;lt;(ostream&amp;amp; os, const Pos&amp;amp; pos)
    {
        cout &amp;lt;&amp;lt; &quot;(&quot; &amp;lt;&amp;lt; pos.row &amp;lt;&amp;lt; &quot;, &quot; &amp;lt;&amp;lt; pos.col &amp;lt;&amp;lt; &quot;)&quot; &amp;lt;&amp;lt; flush;
        return os;
    }
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 1) 9.2 입출력 연산자 오버로딩하기 &lt;/b&gt;&lt;a href=&quot;https://hoplite.tistory.com/100&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hoplite.tistory.com/100&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 연산자 오버로딩은 2개의 Parameter가 필요하다 &lt;br /&gt;2. 멤버 함수로 정의할 경우 1개의 Parameter가 필요하다 &lt;br /&gt;3. ostream의 멤버함수를 정의할 수 없으므로 외부 함수로 2개의 Parameter를 호출하는 형태로 함수를 정의한다.&lt;br /&gt;4. 이 때 외부에서 구현하면 private 멤버변수에 접근할 수 없다. &lt;br /&gt;5. 따라서 class 내부에서 정의 + friend keyword를 활용하여 해당 함수에서 멤버 변수의 접근권한을 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 2)&lt;/b&gt; &lt;b&gt;constexpr Keyword in C++17&lt;/b&gt; &lt;a href=&quot;https://hoplite.tistory.com/86&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hoplite.tistory.com/86&lt;/a&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;constexpr은 compile time에 초기화되는 변수이다.&lt;/span&gt;&lt;span&gt;아래와 같이 정적 배열을 정의하는데 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701231513641&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;constexpr int kNumRows = 2;
constexpr int kNumCols = 2;

char maze[kNumRows][kNumCols] = {{0,1},{2,3};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 3) &lt;/b&gt;구조체의 생성자와 임시 구조체&lt;/p&gt;
&lt;pre id=&quot;code_1701233575066&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Pos start = { 1, 1 }; // i = 1, j = 1  시작 지점
//Pos start;
//start.row = 1;
//start.col = 1;

s.Push(start); // s.Push({1, 1});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;구현&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;재귀호출&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701234512621&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int RecurMaze(Pos p)
{
    const char mark = maze[p.row][p.col];
    cout &amp;lt;&amp;lt; p &amp;lt;&amp;lt; endl;

    if (mark == 'G')
    {
        cout &amp;lt;&amp;lt; &quot;Found!&quot; &amp;lt;&amp;lt; endl;
        return 1;
    }
    
    if (mark == '1' || mark == 'X')
        return 0;
    
    maze[p.row][p.col] = 'X';

    if (RecurMaze({p.row, p.col-1})) return 1;
    if (RecurMaze({p.row, p.col+1})) return 1;
    if (RecurMaze({p.row+1, p.col})) return 1;
    if (RecurMaze({p.row-1, p.col})) return 1;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자 값 '1'으로 둘러쌓인 배열이므로 사용할 수 없는 index에 접근하는지 확인할 필요는 없다.&lt;/p&gt;
&lt;pre id=&quot;code_1701234328601&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/*L*/if (0 &amp;lt; p.col - 1)
{
    if (RecurMaze({p.row, p.col-1}) == 1)
        return 1;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;stack&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재귀 호출은 자기함수를 호출하는 순서와 순회하는 순서가 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;stack을 사용하면 push하는 순서와 순회하는 순서가 반대가 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1701234737427&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void StackMaze()
{
    Stack&amp;lt;Pos&amp;gt; s;
    s.Push({1, 1});// i = 1, j = 1  시작 지점

    // s.Print(); // 디버깅에 사용 가능
    while (!s.IsEmpty())
    {
        Pos p = s.Top();
        s.Pop();

        cout &amp;lt;&amp;lt; p &amp;lt;&amp;lt; &quot; &quot;; // 디버깅 출력

        const char mark = maze[p.row][p.col];

        if (mark == 'G')
        {
            cout &amp;lt;&amp;lt; &quot;Found!&quot; &amp;lt;&amp;lt; endl;
            break;
        }

        if (mark == 'X' || mark == '1')
            continue;
        
        maze[p.row][p.col] = 'X';

        // 재귀와 다르게 마지막 Push부터 순회함
        s.Push({ p.row, p.col-1 });
        s.Push({ p.row, p.col+1 });
        s.Push({ p.row+1, p.col });
        s.Push({ p.row-1, p.col });
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;의미&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재귀호출와 Stack을 사용한 구현은 유사하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;하노이의 탑&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N개의 Disk를 옮기려면&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;N-1개의 Disk를 임시 위치로 옮긴다.&lt;/li&gt;
&lt;li&gt;가장 아래에 있는 N 번째 Disk를 목표 위치로 옮긴다.&lt;/li&gt;
&lt;li&gt;임시 위치에 있는 N-1개의 Disk를 목표위치로 옮긴다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 N-1개의 Disk를 옮기는 일은 다시 위와 같이 처리할 수 있으므로 재귀호출로 문제를 풀 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/HongLabInc/HongLabDataStructures/blob/main/Ex0403_TowerOfHanoi/Ex0403_TowerOfHanoi.cpp&quot;&gt;https://github.com/HongLabInc/HongLabDataStructures/blob/main/Ex0403_TowerOfHanoi/Ex0403_TowerOfHanoi.cpp&lt;/a&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701240365086&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void RecurMoveDisks(int n, int from, int temp, int to)
{
    if (n == 0)
        return;

    // stack the rest on temp location
    RecurMoveDisks(n-1, from, to, temp);

    // Move bottom disk to target location
    MoveDisk(from, to);

    // move the rest on the temp to target location
    RecurMoveDisks(n - 1, temp, from, to);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/Data Structure</category>
      <author>시옷지읏</author>
      <guid isPermaLink="true">https://hoplite.tistory.com/166</guid>
      <comments>https://hoplite.tistory.com/166#entry166comment</comments>
      <pubDate>Wed, 29 Nov 2023 15:47:21 +0900</pubDate>
    </item>
    <item>
      <title>[Data Structures] 챕터3. 배열</title>
      <link>https://hoplite.tistory.com/165</link>
      <description>&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;문자열 ADT&lt;/span&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt; Data Type : 저장공간의 크기, 같은 Data Type의 연산을 정의한다. &lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Abstract Data Type&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 구현 하지 않은 Data Type.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;nbsp; 어떤 일을 해야하는 지 정의되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예)&lt;/p&gt;
&lt;pre id=&quot;code_1701061917167&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MyString
{
public:
    MyString();                       // 비어 있는 MyString() 생성
    MyString(const char* init);       // 맨 뒤에 널 캐릭터'\0'가 들어 있는 문자열로부터 초기화
    MyString(const MyString&amp;amp; str);    // MyString의 다른 instance로부터 초기화
    ~MyString();

    bool IsEmpty();
    bool IsEqual(const MyString&amp;amp; str);
    int Length();
    void Resize(int new_size);

    MyString Substr(int start, int num);    // 인덱스 start위치의 글자부터 num개의 글자로 새로운 문자열 만들기
    MyString Concat(MyString app_str);      // 뒤에 덧붙인 새로운 문자열 반환 (append)
    MyString Insert(MyString t, int start); // 중간에 삽입

    int Find(MyString pat);

    void Print();

private:
    char* str_ = nullptr; // 마지막에 '\0' 없음
    int size_ = 0; // 글자 수
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자 배열 값을 복사할 때 for 반복문 대신 &lt;b&gt;memcpy&lt;/b&gt;를 활용할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1701069082080&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 데이터 복사
for (int i = 0; i &amp;lt; size_; ++i)
    str_[i] = init[i];

// 데이터 복사
memcpy(str_, init, size_);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;복사생성자&lt;/h3&gt;
&lt;pre id=&quot;code_1701069405801&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;MyString::MyString(const MyString&amp;amp; str)
{
    // 기본 복사생성자는 포인터주소만 복사, 소멸시 오류
    size_ = str.size_;
    str_ = new char[size_];
    memcpy(str_, str.str_, size_);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;동적할당 메모리 해제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메모리 할당이 되어있지 않을 때 메모리를 해제하면 에러가 발생한다.&lt;/p&gt;
&lt;pre id=&quot;code_1701069455063&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (str_ != nullptr)
{
    delete[] str_;
    str_ = nullptr;
    size_ = 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Resize&lt;/h3&gt;
&lt;pre id=&quot;code_1701069590009&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void MyString::Resize(int new_size)
{
    if (new_size != size_)
    {
        ...
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;주의&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;동적할당 메모리를 재할당할 때 기존의 메모리를 반드시 반환해주자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Concat&lt;/h3&gt;
&lt;pre id=&quot;code_1701070469335&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;MyString MyString::Concat(MyString app_str)
{
    MyString temp;

    temp.Resize(size_ + app_str.size_);

    for (int i = 0; i &amp;lt; size_; ++i)
        temp.str_[i] = str_[i];

    for (int i = 0; i &amp;lt; app_str.size_; ++i)
        temp.str_[size_ + i] = app_str.str_[i];

    return temp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1701070425249&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for (int i = 0; i &amp;lt; app_str.size_; ++i)
    temp.str_[size_ + i] = app_str.str_[i];&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;memcpy를 활용하여 배열 포인터의 중간 index부터 복사하기&lt;/p&gt;
&lt;pre id=&quot;code_1701070206890&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;memcpy(temp.str_ + size_, app_str.str_, app_str.size_);
// or
memcpy(&amp;amp;temp.str_[size_], app_str.str_, app_str.size_);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Find&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내 구현&lt;/p&gt;
&lt;pre id=&quot;code_1701071160149&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int MyString::Find(MyString pat)
{
    for (int i = 0; i &amp;lt; size_; ++i)
    {
        if (str_[i] == pat.str_[0])
        {
            bool isEqual = true;
            for (int j = 0; j &amp;lt; pat.size_; ++j)
            {
                if (str_[i + j] != pat.str_[j])
                {
                    isEqual = false;
                    break;
                }
            }

            if (isEqual)
                return i;
        }
    }

    return -1;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우수 풀이&lt;/p&gt;
&lt;pre id=&quot;code_1701071465442&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int MyString::Find(MyString pat)
{
    // &quot;ABC&quot; 에서 &quot;DE&quot;를 찾는다면      
    //   ^ 위치에서 더 찾을 필요가 없다
    // 글자 개수가 X라면 마지막 글자부터 X-1번째는 확인하지 않아도 됨
    for (int start = 0; start &amp;lt;= Length() - pat.Length(); ++start)
    {
        for (int j = 0; j &amp;lt; pat.size_; ++j)
        {
            if (str_[start + j] != pat.str_[j])
                break;

            if (j == pat.Length() - 1)
                return start;
        }
    }

    return -1;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 빠른 풀이&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Knuth-Morris-Pratt&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Find의 최악의 시간복잡도&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원본 문자열의 길이가 n이고 찾으려는 문자열의 길이가 n일 때 시간복잡도를 계산한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2중 for루프만 보면 O( (m-n+1) * n )이다. 이 때 &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;m이 n보다 크면 &lt;/span&gt;&lt;b&gt;O(mn)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;다항식&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Eval&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;다항식&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;2x^2 = 2 * pow(x,2)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701077219938&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;float Polynomial::Eval(float x)
{
    float temp = 0.0f;

    // 힌트 std::powf(2.0f, float(3)); // 2.0f^3.0f = 8.0f (2.0f의 3.0f 제곱)
    for (int i = 0; i &amp;lt; capacity_; ++i)
    {
        if (coeffs_[i] != 0)
            temp += coeffs_[i] * powf(x, (float)i);
    }

    return temp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 i는 integer 자료형이므로 float로 형변환해주자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1020&quot; data-origin-height=&quot;440&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/U7Zvz/btsATB6auAQ/i9lDub4cLY5FFYhGKq6xk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/U7Zvz/btsATB6auAQ/i9lDub4cLY5FFYhGKq6xk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/U7Zvz/btsATB6auAQ/i9lDub4cLY5FFYhGKq6xk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FU7Zvz%2FbtsATB6auAQ%2Fi9lDub4cLY5FFYhGKq6xk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1020&quot; height=&quot;440&quot; data-origin-width=&quot;1020&quot; data-origin-height=&quot;440&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 다항식의 곱은 다음과 같은 방법으로도 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 두 다항식의 요소를 각각 하나씩 조합하여 모든 경우를 나열한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 각 조합의 내부 원소를 모두 곱한 뒤 총합하면 두 다항식의 곱이된다.&lt;/p&gt;
&lt;pre id=&quot;code_1701078840802&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Polynomial Polynomial::Mult(const Polynomial&amp;amp; poly)
{
    assert(poly.capacity_ == this-&amp;gt;capacity_); // 문제를 단순화하기 위한 가정

    Polynomial temp(this-&amp;gt;MaxDegree());

    for (int i = 0; i &amp;lt; poly.capacity_; ++i)
    {
        if (poly.coeffs_[i] == 0)
            continue;

        for (int j = 0; j &amp;lt; this-&amp;gt;capacity_; ++j)
        {
            if (this-&amp;gt;coeffs_[j] == 0)
                continue;

            if(i+j  &amp;lt; MaxDegree())
                temp.coeffs_[i+j] += poly.coeffs_[i] * this-&amp;gt;coeffs_[j];
        }
    }

    return temp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;희소다항식(Sparse Polynomial)&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;계수가 0인 항이 많은 다항식을 희소다항식(Sparse Polynomial)이라 한다&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 구현한 다항식은 최대 차수항을 기준으로 메모리 공간을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;희소다항식은 꼭 필요한 차수항만 데이터를 저장한다.&lt;/p&gt;
&lt;pre id=&quot;code_1701089445601&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct Term
{
    float coef;
    int exp;
};

class SparsePolynomial
{
private:
    Term* terms_ = nullptr;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;높은 차수를 가지고 있지만 항의 개수가 적은 경우 그냥 다항식보다 빠르다&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;구현방법&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A 다항식과 B 다항식을 더하여 C 다항식을 만든다. 이 때 두 다항식 모두 차수항이 정렬되어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;index를 사용하여 차수항이 낮은 쪽을 C 다항식에 밀어넣는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차수항이 동일할 때 합한 값을 C 다항식에 밀어넣는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내구현&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701093315642&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SparsePolynomial SparsePolynomial::Add(const SparsePolynomial&amp;amp; poly)
{
    SparsePolynomial temp;

    int polyIdx = 0;
    int thisIdx = 0;

    while (true)
    {
        int thisExp = this-&amp;gt;terms_[thisIdx].exp;
        int polyExp = poly.terms_[polyIdx].exp;
        
        if (polyIdx &amp;lt; poly.num_terms_ &amp;amp;&amp;amp; thisIdx &amp;lt; this-&amp;gt;num_terms_)
        {
            if (thisExp == polyExp)
            {
                float sumCoef = poly.terms_[polyIdx].coef + this-&amp;gt;terms_[thisIdx].coef;
                temp.NewTerm(sumCoef, polyExp);
                thisIdx++;
                polyIdx++;
            }
            else if (thisExp &amp;gt; polyExp)
            {
                temp.NewTerm(poly.terms_[polyIdx].coef, polyExp);
                polyIdx++;
            }
            else if (thisExp &amp;lt; polyExp)
            {
                temp.NewTerm(this-&amp;gt;terms_[thisIdx].coef, thisExp);
                thisIdx++;
            }
        }
        else if (polyIdx &amp;lt; poly.num_terms_)
        {
            temp.NewTerm(poly.terms_[polyIdx].coef, polyExp);
            polyIdx++;
        }
        else if (thisIdx &amp;lt; this-&amp;gt;num_terms_)
        {
            temp.NewTerm(this-&amp;gt;terms_[thisIdx].coef, thisExp);
            thisIdx++;
        }
        else
        {
            break;
        }
        
    }

    return temp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;우수구현&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701093632221&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SparsePolynomial SparsePolynomial::Add(const SparsePolynomial&amp;amp; poly)
{
    SparsePolynomial temp;

    int i = 0, j = 0;
    while ((i &amp;lt; this-&amp;gt;num_terms_) &amp;amp;&amp;amp; (j &amp;lt; poly.num_terms_))
    {
        if ((terms_[i].exp == poly.terms_[j].exp))
        {
            float sum = poly.terms_[j].coef + terms_[i].coef;
            if (sum != 0.f)
                temp.NewTerm(sum, terms_[i].exp);

            ++i;
            ++j;
        }
        else if ((terms_[i].exp &amp;gt; poly.terms_[j].exp))
        {
            temp.NewTerm(poly.terms_[j].coef, poly.terms_[j].exp);
            ++j;
        }
        else
        {
            temp.NewTerm(terms_[i].coef, terms_[i].exp);
            ++i;
        }
    }

    // i가 끝날 경우 실행되지 않음
    for (; i &amp;lt; num_terms_; i++)
        temp.NewTerm(terms_[i].coef, terms_[i].exp);

    // j가 끝날 경우 실행되지 않음
    for (; j &amp;lt; poly.num_terms_; j++)
        temp.NewTerm(poly.terms_[j].coef, poly.terms_[j].exp);

    return temp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;시간복잡도&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘의 시간복잡도는 &lt;b&gt;O(m+n)&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 메모리를 동적할당 할 때 필요한 시간복잡도는 &lt;b&gt;O( log2(N) )&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;예) 2^5를 가정할 때 0 - 1 - 2 - 4 - 8 - 16 - 32&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;메모리 크기를 100을 할당받을 때와 10000을 할당받을 때의 속도는 동일하다. 따라서 N개의&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1701094204385&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void SparsePolynomial::NewTerm(float coef, int exp)
{
	...
    if (num_terms_ &amp;gt;= capacity_)
    {
        capacity_ = capacity_ &amp;gt; 0 ? capacity_ * 2 : 1; // 2배씩 증가
        Term* new_term = new Term[capacity_];
		...
    }
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;행렬&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1차원 배열을 활용하여 2차원 배열처럼 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;참고 &lt;b&gt;const&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;함수 안에서 멤버 변수의 값을 바꾸지 않겠다는 의미&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701153086392&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;float Matrix::GetValue(int row, int col) const;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Transpose&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내구현&lt;/p&gt;
&lt;pre id=&quot;code_1701153200142&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Matrix Matrix::Transpose()
{
    Matrix temp(num_cols_, num_rows_); // num_cols_, num_rows_ 순서 주의

    for (int i = 0; i &amp;lt; num_cols_ * num_rows_; ++i)
    {
        int row = i / num_cols_;
        int col = i % num_cols_;
        temp.SetValue(col, row, this-&amp;gt;GetValue(row, col));
    }

    return temp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 구현&lt;/p&gt;
&lt;pre id=&quot;code_1701153208797&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Matrix Matrix::Transpose()
{
    Matrix temp(num_cols_, num_rows_); // num_cols_, num_rows_ 순서 주의

    for (int r = 0; r &amp;lt; num_rows_; ++r)
        for (int c = 0; c &amp;lt; num_cols_; ++c)
            temp.SetValue(c, r, GetValue(r, c));

    return temp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Add&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내구현&lt;/p&gt;
&lt;pre id=&quot;code_1701153316929&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Matrix Matrix::Add(const Matrix&amp;amp; b)
{
    assert(b.num_cols_ == num_cols_);
    assert(b.num_rows_ == num_rows_);

    Matrix temp(num_rows_, num_cols_);

    for (int i = 0; i &amp;lt; num_rows_ * num_cols_; ++i)
        temp.values_[i] = b.values_[i] + this-&amp;gt;values_[i];

    return temp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고구현&lt;/p&gt;
&lt;pre id=&quot;code_1701153325562&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Matrix Matrix::Add(const Matrix&amp;amp; b)
{
    assert(b.num_cols_ == num_cols_);
    assert(b.num_rows_ == num_rows_);

    Matrix temp(num_rows_, num_cols_);

    for (int r = 0; r &amp;lt; num_rows_; ++r)
        for (int c = 0; c &amp;lt; num_cols_; ++c)
            temp.SetValue(r, c, GetValue(r, c) + b.GetValue(r, c));

    return temp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;동적 배열의 배열&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. 동적할당으로 포인터 배열을 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. 이 때 각 포인터는 동적할당 배열을 가리킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;1차원 배열로 2차원 배열처럼 사용 VS 동적할당 포인터 배열을 활용&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1차원 배열&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아주 큰 저장공간을 OS에게 요구할 경우 연속되지 않은 메모리를 할당받을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;동적할당 포인터 배열&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 Row 별로 나누어 저장할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적할당 포인터 배열의 크기만큼 추가적인 저장공간을 차지한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;복사생성자 구현&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1701160196434&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Array2D::Array2D(const Array2D&amp;amp; b)
{
    this-&amp;gt;num_rows_ = b.num_rows_;
    this-&amp;gt;num_cols_ = b.num_cols_;

    arrays_ = new float* [b.num_rows_];

    for (int r = 0; r &amp;lt; b.num_rows_; ++r)
    {
        arrays_[r] = new float[b.num_cols_];
        for (int c = 0; c &amp;lt; b.num_cols_; ++c)
            arrays_[r][c] = b.arrays_[r][c];
    }
}

Array2D::Array2D(const Array2D&amp;amp; b)
{
    this-&amp;gt;num_rows_ = b.num_rows_;
    this-&amp;gt;num_cols_ = b.num_cols_;

    arrays_ = new float* [b.num_rows_];

    for (int r = 0; r &amp;lt; b.num_rows_; ++r)
    {
        arrays_[r] = new float[b.num_cols_];
        memcpy(arrays_[r], b.arrays_[r], sizeof(float) * num_cols_);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;C++ 정적 2차원 배열&lt;/h2&gt;
&lt;pre id=&quot;code_1701160286610&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;

using namespace std;

int main() 
{
    int arr[3][2] = {1, 2, 3, 4, 5, 6}; // 2차원 (정적) 배열

    for(int j = 0; j &amp;lt; 3; j ++)
        for(int i = 0; i &amp;lt; 2; i ++)
            cout &amp;lt;&amp;lt; arr[j][i] &amp;lt;&amp;lt; &quot; &quot;; // &amp;lt;- 정적 2차원 배열도 2차원 인덱싱 가능
    
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;희소 행렬(Sparse Matrix)&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체에서 &lt;b&gt;값이 0인 항의 비중이 큰 행렬&lt;/b&gt;을 희소행렬(Sparse Matrix)라 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;희소행렬은 값이 0인 항을 저장하지 않는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0이 아닌 값을 가지는 항이 정렬되게 구현하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;내구현&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1701177898618&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void SparseMatrix::SetValue(int row, int col, float value)
{
    if (value == 0.0f) return; // value가 0이 아닌 term만 저장

    int i;
    for (i = 0; i &amp;lt; num_terms_; ++i)
    {
        if (row &amp;lt; terms_[i].row)
        {	
            break; // row를 기준으로 새로 넣을 위치를 찾음
        }
        else if (row == terms_[i].row)
        {
            for (; i &amp;lt; num_terms_; ++i)
            {	
                if (row &amp;lt; terms_[i].row)
                    break; // i를 높였을 때 row가 변했다면 해당 위치에 넣기
                if (col &amp;lt;= terms_[i].col )
                    break; // row가 일정할 때 col을 기준으로 위치 찾기
            }
            break;
        }
    }

    // Shift
    if (col != terms_[i].col)
        for (int j = num_terms_ - 1; i &amp;lt; j; --j)
            terms_[j] = terms_[j - 1];
    
    MatrixTerm NewTerm;
    NewTerm.col = col;
    NewTerm.row = row;
    NewTerm.value = value;

    terms_[i] = NewTerm;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 아무 값이 들어가있지 않을 때도 값을 비교해야하므로&amp;nbsp;생성자에서 &lt;b&gt;col, row 초기값을 INT_MAX&lt;/b&gt;로 잡아준다.&lt;/p&gt;
&lt;pre id=&quot;code_1701178493106&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SparseMatrix::SparseMatrix(int num_rows, int num_cols, int capacity)
{
    this-&amp;gt;num_rows_ = num_rows;
    this-&amp;gt;num_cols_ = num_cols;

    this-&amp;gt;capacity_ = capacity;
    this-&amp;gt;num_terms_ = capacity;

    terms_ = new MatrixTerm[this-&amp;gt;capacity_];
    for (int i = 0; i &amp;lt; this-&amp;gt;capacity_; ++i)
    {
        MatrixTerm Term;
        Term.col = INT_MAX; // 중요
        Term.row = INT_MAX; // 중요
        Term.value = 0;

        terms_[i] = Term;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1701179470832&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;float SparseMatrix::GetValue(int row, int col) const
{
    for (int i = 0; i &amp;lt; num_terms_; ++i)
    {
        if (row &amp;lt; terms_[i].row) // 원하는 row의 범위를 지나갔음
            break;

        if (row == terms_[i].row &amp;amp;&amp;amp; col == terms_[i].col)
            return terms_[i].value;
    }
    return 0.0f;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1701179599974&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SparseMatrix SparseMatrix::Transpose()
{
	SparseMatrix temp(num_cols_, num_rows_, capacity_); // num_cols_, num_rows_ 순서 주의

	for (int i = 0; i &amp;lt; num_terms_; ++i)
		temp.SetValue(terms_[i].col, terms_[i].row, terms_[i].value);

	return temp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1701179631445&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;float SparseMatrix::GetValue(int row, int col) const
{
    for (int i = 0; i &amp;lt; num_terms_; ++i)
    {
        if (row &amp;lt; terms_[i].row) // 원하는 row의 범위를 지나갔음
            break;

        if (row == terms_[i].row &amp;amp;&amp;amp; col == terms_[i].col)
            return terms_[i].value;
    }
    return 0.0f;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;추천구현&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Key값 row * num_cols + col은 항상 유일하고 순서대로 정렬할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;terms_에 쓰레기 값이 들어있으므로 구현이 되지 않은 index에 접근 불가해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 num_cols_는 구현의 핵심이다.&lt;/p&gt;
&lt;pre id=&quot;code_1701182999574&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SparseMatrix::SparseMatrix(int num_rows, int num_cols, int capacity)
{
    terms_ = new MatrixTerm[capacity];

    this-&amp;gt;num_rows_ = num_rows;
    this-&amp;gt;num_cols_ = num_cols;
    this-&amp;gt;capacity_ = capacity;
    this-&amp;gt;num_terms_ = 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;num_cols_가 0일 때 SetValue에서 값을 할당해야한다. 따라서 else if(curKey &amp;gt; key) 내부에서 shift를 구현하면 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;num_terms_++&lt;/p&gt;
&lt;pre id=&quot;code_1701183013126&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void SparseMatrix::SetValue(int row, int col, float value)
{
    if (value == 0.0f) return; // value가 0이 아닌 term만 저장

    int key = row * num_cols_ + col;

    int i;
    for (i = 0; i &amp;lt; num_terms_; ++i)
    {
        int curKey = terms_[i].row * num_cols_ + terms_[i].col;
        if (key == curKey)
        {
            terms_[i].col = col;
            terms_[i].row = row;
            terms_[i].value = value;
            return;
        }
        else if (key &amp;lt; curKey)
            break;
    }

    // Shift
    num_terms_++;
    for (int j = num_terms_ - 1; i &amp;lt; j; --j)
        terms_[j] = terms_[j - 1];

    terms_[i].col = col;
    terms_[i].row = row;
    terms_[i].value = value;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;key 값이 유일하고 정렬되어있으므로 이를 활용할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1701183028157&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;float SparseMatrix::GetValue(int row, int col) const
{
    int key = row * num_cols_ + col;
    for (int i = 0; i &amp;lt; num_terms_; ++i)
    {
        int curKey = terms_[i].row * num_cols_ + terms_[i].col;

        if (curKey == key)
            return terms_[i].value;
        else if (key &amp;lt; curKey)
            break;
    }

    return 0.0f;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1701183035658&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SparseMatrix SparseMatrix::Transpose()
{
    SparseMatrix temp(num_cols_, num_rows_, capacity_); // num_cols_, num_rows_ 순서 주의
    
    // O(num_terms * (num_terms + num_terms))
    // = O(num_terms^2)
    for (int i = 0; i &amp;lt; num_terms_; ++i)
        temp.SetValue(terms_[i].col, terms_[i].row, terms_[i].value);

    return temp;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;참고&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1. { }를 활용하여 간단하게 구조체를 정의할 수 있다. 이 때 &lt;b&gt;멤버변수의 순서가 반드시 일치&lt;/b&gt;해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701183625672&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct MatrixTerm
{
    int row;
    int col;
    float value;
};

// 1
terms_[i].row = row;
terms_[i].col = col;
terms_[i].value = value;

// 2
terms_[i] = {row, col, value};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 동적할당 initialization&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/12694214/initialize-a-float-array-on-construction&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://stackoverflow.com/questions/12694214/initialize-a-float-array-on-construction&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;더해보기&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;더하는 두 행렬은 동일한 row과 col을 가지며 capacity = row * col으로 설정하였다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1701185439675&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SparseMatrix SparseMatrix::Add(const SparseMatrix&amp;amp; b)
{
    SparseMatrix temp(b.num_rows_, b.num_cols_, b.capacity_);

    int cur = 0;
    int pram = 0;
    while (cur &amp;lt; num_terms_ &amp;amp;&amp;amp; pram &amp;lt; b.num_terms_)
    {
        int curKey = num_cols_ * terms_[cur].row + terms_[cur].col;
        int pramKey = b.num_cols_ * b.terms_[pram].row + b.terms_[pram].col;

        if (curKey &amp;lt; pramKey)
        {
            temp.SetValue(terms_[cur].row, terms_[cur].col, terms_[cur].value);
            cur++;
        }
        else if (pramKey &amp;lt; curKey)
        {
            temp.SetValue(b.terms_[pram].row, b.terms_[pram].col, b.terms_[pram].value);
            pram++;
        }
        else
        {
            temp.SetValue(terms_[cur].row, terms_[cur].col, terms_[cur].value + b.terms_[pram].value);
            cur++;
            pram++;
        }
    }

    for (; cur &amp;lt; num_terms_; ++cur)
        temp.SetValue(terms_[cur].row, terms_[cur].col, terms_[cur].value);

    for (; pram &amp;lt; b.num_terms_; ++pram)
        temp.SetValue(b.terms_[pram].row, b.terms_[pram].col, b.terms_[pram].value);

    return temp;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>CS/Data Structure</category>
      <category>Honglab</category>
      <category>자료구조</category>
      <category>홍랩</category>
      <category>홍정모</category>
      <author>시옷지읏</author>
      <guid isPermaLink="true">https://hoplite.tistory.com/165</guid>
      <comments>https://hoplite.tistory.com/165#entry165comment</comments>
      <pubDate>Wed, 29 Nov 2023 00:31:13 +0900</pubDate>
    </item>
  </channel>
</rss>