<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>suyeon-jung.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sat, 09 Apr 2022 07:39:19 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>suyeon-jung.log</title>
            <url>https://images.velog.io/images/suyeon-jung/profile/1b8a1a5b-b2ee-443f-8059-b18e8263598a/IMG_2249.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. suyeon-jung.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/suyeon-jung" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[백준 10799] 쇠막대기 - C++]]></title>
            <link>https://velog.io/@suyeon-jung/%EB%B0%B1%EC%A4%80-10799-%EC%87%A0%EB%A7%89%EB%8C%80%EA%B8%B0-C-uv7320e7</link>
            <guid>https://velog.io/@suyeon-jung/%EB%B0%B1%EC%A4%80-10799-%EC%87%A0%EB%A7%89%EB%8C%80%EA%B8%B0-C-uv7320e7</guid>
            <pubDate>Sat, 09 Apr 2022 07:39:19 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p><a href="https://www.acmicpc.net/problem/10799">https://www.acmicpc.net/problem/10799</a></p>
<h3 id="문제-설명">문제 설명</h3>
<p>여러 개의 쇠막대기를 레이저로 절단하려고 한다. 효율적인 작업을 위해서 쇠막대기를 아래에서 위로 겹쳐 놓고, 레이저를 위에서 수직으로 발사하여 쇠막대기들을 자른다. 쇠막대기와 레이저의 배치는 다음 조건을 만족한다.</p>
<p>쇠막대기는 자신보다 긴 쇠막대기 위에만 놓일 수 있다. - 쇠막대기를 다른 쇠막대기 위에 놓는 경우 완전히 포함되도록 놓되, 끝점은 겹치지 않도록 놓는다.
각 쇠막대기를 자르는 레이저는 적어도 하나 존재한다.
레이저는 어떤 쇠막대기의 양 끝점과도 겹치지 않는다. 
아래 그림은 위 조건을 만족하는 예를 보여준다. 수평으로 그려진 굵은 실선은 쇠막대기이고, 점은 레이저의 위치, 수직으로 그려진 점선 화살표는 레이저의 발사 방향이다.</p>
<p><img src="https://velog.velcdn.com/images/suyeon-jung/post/ecee3024-2f7c-4237-8612-522d00fb5a28/image.png" alt=""></p>
<p>이러한 레이저와 쇠막대기의 배치는 다음과 같이 괄호를 이용하여 왼쪽부터 순서대로 표현할 수 있다.</p>
<p>레이저는 여는 괄호와 닫는 괄호의 인접한 쌍 ‘( ) ’ 으로 표현된다. 또한, 모든 ‘( ) ’는 반드시 레이저를 표현한다.
쇠막대기의 왼쪽 끝은 여는 괄호 ‘ ( ’ 로, 오른쪽 끝은 닫힌 괄호 ‘) ’ 로 표현된다. 
위 예의 괄호 표현은 그림 위에 주어져 있다.</p>
<p>쇠막대기는 레이저에 의해 몇 개의 조각으로 잘려지는데, 위 예에서 가장 위에 있는 두 개의 쇠막대기는 각각 3개와 2개의 조각으로 잘려지고, 이와 같은 방식으로 주어진 쇠막대기들은 총 17개의 조각으로 잘려진다. </p>
<p>쇠막대기와 레이저의 배치를 나타내는 괄호 표현이 주어졌을 때, 잘려진 쇠막대기 조각의 총 개수를 구하는 프로그램을 작성하시오.</p>
<h3 id="입출력">입출력</h3>
<ul>
<li><p><strong>입력</strong>
한 줄에 쇠막대기와 레이저의 배치를 나타내는 괄호 표현이 공백없이 주어진다. 괄호 문자의 개수는 최대 100,000이다. </p>
</li>
<li><p><strong>출력</strong>
잘려진 조각의 총 개수를 나타내는 정수를 한 줄에 출력한다.</p>
</li>
</ul>
<h2 id="풀이">풀이</h2>
<ul>
<li><strong>사용한 자료구조</strong><ul>
<li><code>stack&lt;char&gt; s</code> : 괄호의 쌍을 찾기 위해 사용하는 자료구조</li>
</ul>
</li>
<li><strong>풀이</strong>
입력한 문자열의 처음부터 끝까지 탐색<ul>
<li>문자가 여는 괄호(<code>(</code>)일 경우 스택에 <code>push</code></li>
<li>문자가 닫는 괄호(<code>)</code>)일 경우<ul>
<li>바로 이전 문자가 여는 괄호(<code>(</code>)였을 경우 ➡️ 레이저
스택에서 pop() 수행 ➡️ 현재 스택의 사이즈를 결과 값에 더하기
<span style="color: red">스택에서 pop을 수행하고 size 값을 더하는 것은 top의 괄호는 레이저의 괄호여서 제외해야 하기 때문에 위와 같은 순서로 구함</span></li>
<li>바로 이전 문자가 여는 괄호가 아닌 경우 ➡️ not 레이저
스택에서 pop() 수행 ➡️ 결과값에 1더하기
<span style="color: red">쇠막대기가 끝남으로써 조각 1개가 더해짐</span></li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li><strong>코드</strong>
처음 작성한 코드 ➡️ 괄호 쌍이 없는 괄호가 있는 문자열이 입력되는 경우를 고려<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;stack&gt;
#include &lt;string&gt;
using namespace std;
</code></pre>
</li>
</ul>
<p>int main()
{
    cin.tie(0);
    ios::sync_with_stdio(0);</p>
<pre><code>stack&lt;char&gt; s;
string str;
int ans = 0;

cin &gt;&gt; str;
for (int i = 0; i &lt; str.length(); i++)
{
    if (str[i] == &#39;(&#39;) // 여는 괄호인 경우
        s.push(&#39;(&#39;);
    else // 닫는 괄호인 경우(레이저인 경우/레이저가 아닌 경우)
    {
        if (i &gt; 0 &amp;&amp; str[i - 1] == &#39;(&#39; &amp;&amp; s.top() == &#39;(&#39;) // 레이저인 경우
        {
            s.pop();
            ans += s.size();
        }
        else // 레이저가 아닌 경우
        {
            // 스택이 비지 않은 경우
            if (!s.empty() &amp;&amp; s.top() == &#39;(&#39;)
            {
                ans += 1;
                s.pop();
            }
        }
    }
}
cout &lt;&lt; ans;</code></pre><p>}</p>
<pre><code>만약, 입력되는 문자열내 괄호가 모두 괄호쌍을 가진다고 제한된다면 아래와 같이 코드를 작성해도 된다. 
또한, 문자열 내의 문자가 여는 괄호(`(`), 닫는 괄호(`)`)로 제한되기 때문에 `else` 문 하위 문들에서 `s.top() == &#39;(&#39;` 은 제외해도 되는 조건이다. 
```cpp
#include &lt;iostream&gt;
#include &lt;stack&gt;
#include &lt;string&gt;
using namespace std;

int main()
{
    cin.tie(0);
    ios::sync_with_stdio(0);

    stack&lt;char&gt; s;
    string str;
    int ans = 0;

    cin &gt;&gt; str;
    for (int i = 0; i &lt; str.length(); i++)
    {
        if (str[i] == &#39;(&#39;) // 여는 괄호인 경우
            s.push(&#39;(&#39;);
        else // 닫는 괄호인 경우(레이저인 경우/레이저가 아닌 경우)
        {
            if (str[i - 1] == &#39;(&#39;) // 레이저인 경우
            {
                s.pop();
                ans += s.size();
            }
            else // 레이저가 아닌 경우
            {
                s.pop();
                ans++;
            }
        }
    }
    cout &lt;&lt; ans;
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[백준 4949] 균형잡힌 세상 - C++]]></title>
            <link>https://velog.io/@suyeon-jung/%EB%B0%B1%EC%A4%80-4949-%EA%B7%A0%ED%98%95%EC%9E%A1%ED%9E%8C-%EC%84%B8%EC%83%81-C</link>
            <guid>https://velog.io/@suyeon-jung/%EB%B0%B1%EC%A4%80-4949-%EA%B7%A0%ED%98%95%EC%9E%A1%ED%9E%8C-%EC%84%B8%EC%83%81-C</guid>
            <pubDate>Sat, 09 Apr 2022 05:59:53 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p><a href="https://www.acmicpc.net/problem/4949">https://www.acmicpc.net/problem/4949</a></p>
<h3 id="문제-설명">문제 설명</h3>
<p>세계는 균형이 잘 잡혀있어야 한다. 양과 음, 빛과 어둠 그리고 왼쪽 괄호와 오른쪽 괄호처럼 말이다.</p>
<p>정민이의 임무는 어떤 문자열이 주어졌을 때, 괄호들의 균형이 잘 맞춰져 있는지 판단하는 프로그램을 짜는 것이다.</p>
<p>문자열에 포함되는 괄호는 소괄호(&quot;()&quot;) 와 대괄호(&quot;[]&quot;)로 2종류이고, 문자열이 균형을 이루는 조건은 아래와 같다.</p>
<p><strong>모든 왼쪽 소괄호(&quot;(&quot;)는 오른쪽 소괄호(&quot;)&quot;)와만 짝을 이뤄야 한다.
모든 왼쪽 대괄호(&quot;[&quot;)는 오른쪽 대괄호(&quot;]&quot;)와만 짝을 이뤄야 한다.</strong>
모든 오른쪽 괄호들은 자신과 짝을 이룰 수 있는 왼쪽 괄호가 존재한다.
모든 괄호들의 짝은 1:1 매칭만 가능하다. 즉, 괄호 하나가 둘 이상의 괄호와 짝지어지지 않는다.
짝을 이루는 두 괄호가 있을 때, 그 사이에 있는 문자열도 균형이 잡혀야 한다.
정민이를 도와 문자열이 주어졌을 때 균형잡힌 문자열인지 아닌지를 판단해보자.</p>
<h3 id="입출력">입출력</h3>
<ul>
<li><strong>입력</strong>
하나 또는 여러줄에 걸쳐서 문자열이 주어진다. 각 문자열은 영문 알파벳, 공백, 소괄호(&quot;( )&quot;) 대괄호(&quot;[ ]&quot;)등으로 이루어져 있으며, 길이는 100글자보다 작거나 같다.
입력의 종료조건으로 맨 마지막에 점 하나(&quot;.&quot;)가 들어온다.
➡️ string 라이브러리에 속하는 <code>getline</code> 을 통해 문자열을 입력 받음</li>
</ul>
<ul>
<li><strong>출력</strong>
각 줄마다 해당 문자열이 균형을 이루고 있으면 &quot;yes&quot;를, 아니면 &quot;no&quot;를 출력한다.</li>
</ul>
<h2 id="풀이">풀이</h2>
<ul>
<li><strong>사용한 자료구조</strong><ul>
<li><code>stack&lt;char&gt; s</code> ➡️ 문자열내 문자를 하나씩 돌면서 여는 괄호가 나오면 저장</li>
</ul>
</li>
<li><strong>풀이 내용</strong></li>
</ul>
<ol>
<li>여는 괄호(<code>(</code>, <code>[</code>)가 나오면 스택에 추가(push)</li>
<li>닫는 괄호가 나왔을 경우,
 2-1. 스택이 비어있으면 올바르지 않은 괄호 쌍(empty)
 2-2. 스택의 top이 짝이 맞지 않는 괄호일 경우 올바르지 않은 괄호 쌍
 2-3. 스택의 top이 짝이 맞는 괄호일 경우 pop</li>
<li>모든 과정을 끝낸 후 스택에 괄호가 남아있으면 올바르지 않은 괄호 쌍, 남아있지 않으면 올바른 괄호 쌍</li>
</ol>
<ul>
<li><strong>코드</strong><pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;stack&gt;
using namespace std;
</code></pre>
</li>
</ul>
<p>bool check(string ipt)
{
    stack<char> s;
    for (auto word : ipt)
    {
        if (word == &#39;(&#39; || word == &#39;[&#39;) // 1. 여는 괄호인 경우 스택에 push
            s.push(word);
        else if (word == &#39;)&#39;) // 2. 닫는 괄호인 경우 스택에서 pop(쌍이 맞는 경우)
        {
            if (!s.empty() &amp;&amp; s.top() == &#39;(&#39;)
                s.pop();
            else
                return false;
        }
        else if (word == &#39;]&#39;)
        {
            if (!s.empty() &amp;&amp; s.top() == &#39;[&#39;)
                s.pop();
            else
                return false;
        }
    }</p>
<pre><code>if (s.empty()) // 3. 스택이 비지 않은 경우(-&gt; 짝을 짓지 못한 괄호가 있음)
    return true;
else
    return false;</code></pre><p>}
int main()
{
    cin.tie(0);
    ios::sync_with_stdio(0);</p>
<pre><code>string ipt;

while (true)
{
    getline(cin, ipt);
    if (ipt == &quot;.&quot;)
        break;
    bool ans = check(ipt);
    if (ans)
        cout &lt;&lt; &quot;yes&quot; &lt;&lt; &#39;\n&#39;;
    else
        cout &lt;&lt; &quot;no&quot; &lt;&lt; &#39;\n&#39;;
}</code></pre><p>}</p>
<pre><code>- **개선한 코드**
`check` 함수를 제외한 다른 부분은 위 코드와 동일
```cpp
bool check(string ipt)
{
    stack&lt;char&gt; s;
    for (auto word : ipt)
    {
        if (word == &#39;(&#39; || word == &#39;[&#39;) // 1. 여는 괄호인 경우 스택에 push
            s.push(word);
        else if (word == &#39;)&#39;) // 2. 닫는 괄호인 경우 스택에서 pop(쌍이 맞는 경우)
        {
            if (s.empty() || s.top() != &#39;(&#39;)
                return false;
            s.pop();
        }
        else if (word == &#39;]&#39;)
        {
            if (s.empty() || s.top() != &#39;[&#39;)
                return false;
            s.pop();
        }
    }

    if (s.empty()) // 3. 스택이 비지 않은 경우(-&gt; 짝을 짓지 못한 괄호가 있음)
        return true;
    else
        return false;
}</code></pre><p>스택이 비어있는지에 대한 여부를 먼저 검사하는 이유 </p>
<ol>
<li>스택이 비어있는데 <code>pop()</code>을 수행하면 런타임 에러가 발생하기 때문에</li>
<li>첫번째 조건의 결과에 따라 두번째 조건을 확인하지 않아도 결과가 정해지도록 선행 조건으로 스택이 비어있는지 검사 (Short-circuit evaluation)</li>
</ol>
<p>코드의 길이를 좀 더 짧게 하기 위해 기존 조건에서 드모르간 법칙을 적용하여 <code>OR(||)</code> 조건으로 변경하였다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[03. 배열]]></title>
            <link>https://velog.io/@suyeon-jung/03.-%EB%B0%B0%EC%97%B4</link>
            <guid>https://velog.io/@suyeon-jung/03.-%EB%B0%B0%EC%97%B4</guid>
            <pubDate>Mon, 04 Apr 2022 15:01:31 GMT</pubDate>
            <description><![CDATA[<h3 id="정의와-성질">정의와 성질</h3>
<hr>
<ul>
<li><p><strong>정의</strong></p>
<p>  메모리 상에 원소를 연속하게 배치한 자료구조</p>
</li>
<li><p><strong>성질</strong></p>
</li>
</ul>
<pre><code>| 동작 | 시간복잡도 |
| --- | --- |
| k번째(임의 위치) 원소 확인 및 변경 | O(1) |
| 원소를 마지막에 추가 | O(1) |
| 마지막 원소 제거 | O(1) |
| 임의 위치에 원소 추가 | O(N) |
| 임의 위치의 원소 제거 | O(N) |
- 추가적으로 소모되는 메모리의 양(=오버헤드)가 거의 없음
- Cache Hit Rate가 높음
- 메모리 상에 연속한 구간을 잡아야 해서 할당에 제약이 걸림</code></pre><h3 id="기능과-구현">기능과 구현</h3>
<hr>
<ul>
<li><p><strong>배열 선언</strong></p>
<pre><code class="language-cpp">  int test[5];</code></pre>
<p>  → 배열 요소가 5개인 배열 선언</p>
</li>
<li><p><strong>배열 값 접근</strong></p>
<pre><code class="language-cpp">  test[1] </code></pre>
<p>  → <code>[]</code> 안에 첨자(인덱스;index)를 넣어 특정 요소를 참조할 수 있다. </p>
<p>  → 배열의 인덱스는 0에서 시작해서 마지막 첨자는 <strong>요소 수 - 1</strong> 이 된다. </p>
</li>
<li><p><strong>값 대입 및 출력</strong></p>
<pre><code class="language-cpp">  배열명[첨자] = 식;</code></pre>
</li>
<li><p><strong>전체를 특정 값으로 초기화할 때</strong></p>
<pre><code class="language-cpp">  int a[21];
  int b[21][21];

  // 1. memset
  memset(a, 0, sizeof a);
  memset(b, 0, sizeof b);

  // 2. for
  for(int i = 0; i &lt; 21; i++)
      a[i] = 0;
  for(int i = 0; i &lt; 21; i++)
      for(int j = 0; j &lt; 21; j++)
          a[i][j] = 0;

  // 3. fill
  fill(a, a+21, 0);
  for(int i = 0; i &lt; 21; i++)
      fill(b[i], b[i] + 21, 0)</code></pre>
</li>
<li><p><strong>동적 배열</strong></p>
<p>  배열의 크기를 나타내는 값은 <code>const</code>로 선언된 <strong>상수 변수 혹은 리터럴 상수</strong>만 들어갈 수 있다. </p>
<pre><code class="language-cpp">  int n;
  cin &gt;&gt; n;
  int* arr = new int[n]</code></pre>
<p>  배열의 크기를 미리 알지 못할때는 배열의 크기를 너무 크게 잡기에도 메모리 낭비이고 너무 작게 잡아도 나중에 <code>indexOutOfRange</code> 예외가 발생해 쓰레기 값에 접근하게 된다. (→ vector 로 이 한계를 극복)</p>
</li>
</ul>
<h3 id="stl-vector">STL vector</h3>
<hr>
<ul>
<li>배열과 거의 동일한 기능을 수행하는 자료구조로 배열과 마찬가지로 원소가 메모리에 연속하게 저장되어 있다.</li>
<li><strong>동적으로 크기를 확장/축소 할 수 있다는 장점이 있다.</strong></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준 1935] 후위 표기식2 - C++]]></title>
            <link>https://velog.io/@suyeon-jung/%EB%B0%B1%EC%A4%80-1935-%ED%9B%84%EC%9C%84-%ED%91%9C%EA%B8%B0%EC%8B%9D2-cpp</link>
            <guid>https://velog.io/@suyeon-jung/%EB%B0%B1%EC%A4%80-1935-%ED%9B%84%EC%9C%84-%ED%91%9C%EA%B8%B0%EC%8B%9D2-cpp</guid>
            <pubDate>Mon, 17 Jan 2022 13:58:09 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p><a href="https://www.acmicpc.net/problem/1935">https://www.acmicpc.net/problem/1935</a></p>
<h3 id="문제-설명">문제 설명</h3>
<p>후위 표기식과 각 피연산자에 대응하는 값들이 주어져 있을 때, 그 식을 계산하는 프로그램을 작성하시오.</p>
<h3 id="입출력">입출력</h3>
<ul>
<li><p><strong>입력</strong>
첫째 줄에 <strong>피연산자의 개수(1 ≤ N ≤ 26)</strong> 가 주어진다. 그리고 둘째 줄에는 <strong>후위 표기식</strong>이 주어진다. (여기서 피연산자는 A~Z의 영대문자이며, A부터 순서대로 N개의 영대문자만이 사용되며, 길이는 100을 넘지 않는다) 그리고 셋째 줄부터 N+2번째 줄까지는 각 피연산자에 대응하는 값이 주어진다. 3번째 줄에는 A에 해당하는 값, 4번째 줄에는 B에 해당하는값 , 5번째 줄에는 C ...이 주어진다, 그리고 피연산자에 대응 하는 값은 100보다 작거나 같은 자연수이다.</p>
<p>후위 표기식을 앞에서부터 계산했을 때, 식의 결과와 중간 결과가 -20억보다 크거나 같고, 20억보다 작거나 같은 입력만 주어진다.</p>
</li>
<li><p><strong>출력</strong>
계산 결과를 <strong>소숫점 둘째 자리</strong>까지 출력한다.</p>
</li>
</ul>
<h2 id="풀이">풀이</h2>
<ul>
<li>사용한 자료구조<ul>
<li><code>vetor&lt;int&gt; operand(26)</code> : 입력되는 피연산자 저장</li>
<li><code>stack&lt;double&gt; st</code> : 중간 계산 결과 저장 </li>
</ul>
</li>
<li>풀이 내용</li>
</ul>
<ol>
<li>후위표기식 문자 단위로 처음부터 끝까지 탐색<ul>
<li>연산자인 경우
 스택에서 2개의 숫자를 꺼내 계산후 계산 결과를 push(두번째 pop 되는 숫자를 기준으로 연산)</li>
<li>피연산자인 경우
 스택에 추가</li>
</ul>
</li>
<li>스택의 top 출력</li>
</ol>
<ul>
<li>코드<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;vector&gt;
#include &lt;stack&gt;
using namespace std;
</code></pre>
</li>
</ul>
<p>int main(void)
{
    ios::sync_with_stdio(0);
    cin.tie(0);</p>
<pre><code>int N;          // 피연산자 개수
string postfix; // 후위 표기식

vector&lt;int&gt; operand(26); // 입력한 피연산자
stack&lt;double&gt; st;

cin &gt;&gt; N &gt;&gt; postfix;

for (int i = 0; i &lt; N; i++)
{
    cin &gt;&gt; operand[i];
}

// 후위표기식의 길이 만큼 반복
for (int i = 0; i &lt; postfix.length(); i++)
{
    // 피연산자인 경우
    if (postfix[i] &gt;= &#39;A&#39; &amp;&amp; postfix[i] &lt;= &#39;Z&#39;)
    {
        st.push(operand[postfix[i] - &#39;A&#39;]);
    }
    else // 연산자인 경우
    {
        if (!st.empty())
        {
            double temp = st.top();
            st.pop();
            switch (postfix[i])
            {
            case &#39;+&#39;:
                temp = st.top() + temp;
                break;
            case &#39;-&#39;:
                temp = st.top() - temp;
                break;
            case &#39;*&#39;:
                temp = st.top() * temp;
                break;
            case &#39;/&#39;:
                temp = st.top() / temp;
                break;
            }
            st.pop();
            st.push(temp); // 계산한 결과 push
        }
    }
}
// 소수점 둘째 자리까지 출력
cout &lt;&lt; fixed;
cout.precision(2);
cout &lt;&lt; st.top() &lt;&lt; &#39;\n&#39;;</code></pre><p>}
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준 1158] 요세푸스 문제 - C++ ]]></title>
            <link>https://velog.io/@suyeon-jung/%EB%B0%B1%EC%A4%80-1168-%EC%9A%94%EC%84%B8%ED%91%B8%EC%8A%A4-%EB%AC%B8%EC%A0%9C-cpp</link>
            <guid>https://velog.io/@suyeon-jung/%EB%B0%B1%EC%A4%80-1168-%EC%9A%94%EC%84%B8%ED%91%B8%EC%8A%A4-%EB%AC%B8%EC%A0%9C-cpp</guid>
            <pubDate>Sun, 09 Jan 2022 06:27:09 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p><a href="https://www.acmicpc.net/problem/1158">https://www.acmicpc.net/problem/1158</a></p>
<h3 id="문제-설명">문제 설명</h3>
<p>요세푸스 문제는 다음과 같다.</p>
<p>1번부터 N번까지 N명의 사람이 원을 이루면서 앉아있고, 양의 정수 K(≤ N)가 주어진다. 이제 순서대로 K번째 사람을 제거한다. 한 사람이 제거되면 남은 사람들로 이루어진 원을 따라 이 과정을 계속해 나간다. 이 과정은 <strong>N명의 사람이 모두 제거될 때까지 계속</strong>된다. 원에서 사람들이 제거되는 순서를 (N, K)-요세푸스 순열이라고 한다. 예를 들어 (7, 3)-요세푸스 순열은 &lt;3, 6, 2, 7, 5, 1, 4&gt;이다.</p>
<p>N과 K가 주어지면 (N, K)-요세푸스 순열을 구하는 프로그램을 작성하시오.</p>
<h3 id="입출력">입출력</h3>
<ul>
<li><p>입력
첫째 줄에 N과 K가 빈 칸을 사이에 두고 순서대로 주어진다. (1 ≤ K ≤ N ≤ 5,000)</p>
</li>
<li><p>출력
예제와 같이 요세푸스 순열을 출력한다.</p>
</li>
</ul>
<h2 id="풀이">풀이</h2>
<ul>
<li>사용한 자료구조 : 연결리스트</li>
<li>풀이 내용
iterator를 입력한 K-1번 만큼 이동
iterator가 end인 경우 begin으로 변경해줘야 한다. </li>
<li>코드<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;list&gt;
using namespace std;
</code></pre>
</li>
</ul>
<p>int N, K;</p>
<p>int main(void) {
  ios::sync_with_stdio(0);
  cin.tie(0);</p>
<p>  cin &gt;&gt; N &gt;&gt; K;</p>
<p>  list<int> L;</p>
<p>  // 1~N 까지의 숫자 리스트에 추가
  for (int i = 1; i &lt;= N; i++) L.push_back(i);
  list<int>::iterator t = L.begin();</p>
<p>  cout &lt;&lt; &quot;&lt;&quot;;
  int temp;
  while (L.size()) {
    for (int i = 1; i &lt; K; i++) {
      if (++t == L.end()) {
        t = L.begin();
        continue;
      }
    }
    if (L.size() == 1)
      cout &lt;&lt; *t;
    else
      cout &lt;&lt; *t &lt;&lt; &quot;, &quot;;</p>
<pre><code>t = L.erase(t);
// 삭제한 원소 자리가 이미 end인 경우 begin으로 보내줌
t = (t == L.end()) ? L.begin() : t;</code></pre><p>  }</p>
<p>  cout &lt;&lt; &quot;&gt;&quot;;
}</p>
<p>```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준 1874] 스택 수열 - C++]]></title>
            <link>https://velog.io/@suyeon-jung/%EB%B0%B1%EC%A4%80-1874-%EC%8A%A4%ED%83%9D-%EC%88%98%EC%97%B4-cpp</link>
            <guid>https://velog.io/@suyeon-jung/%EB%B0%B1%EC%A4%80-1874-%EC%8A%A4%ED%83%9D-%EC%88%98%EC%97%B4-cpp</guid>
            <pubDate>Sun, 09 Jan 2022 06:16:59 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p><a href="https://www.acmicpc.net/problem/1874">https://www.acmicpc.net/problem/1874</a></p>
<h3 id="문제-설명">문제 설명</h3>
<p>스택 (stack)은 기본적인 자료구조 중 하나로, 컴퓨터 프로그램을 작성할 때 자주 이용되는 개념이다. 스택은 자료를 넣는 (push) 입구와 자료를 뽑는 (pop) 입구가 같아 제일 나중에 들어간 자료가 제일 먼저 나오는 (LIFO, Last in First out) 특성을 가지고 있다.</p>
<p>1부터 n까지의 수를 스택에 넣었다가 뽑아 늘어놓음으로써, 하나의 수열을 만들 수 있다. 이때, 스택에 push하는 순서는 반드시 오름차순을 지키도록 한다고 하자. <strong>임의의 수열이 주어졌을 때 스택을 이용해 그 수열을 만들 수 있는지 없는지</strong>, 있다면 어떤 순서로 push와 pop 연산을 수행해야 하는지를 알아낼 수 있다. 이를 계산하는 프로그램을 작성하라.</p>
<h3 id="입출력">입출력</h3>
<ul>
<li><p>입력
첫 줄에 n (1 ≤ n ≤ 100,000)이 주어진다. 둘째 줄부터 n개의 줄에는 수열을 이루는 1이상 n이하의 정수가 하나씩 순서대로 주어진다. 물론 같은 정수가 두 번 나오는 일은 없다.</p>
</li>
<li><p>출력
입력된 수열을 만들기 위해 필요한 연산을 한 줄에 한 개씩 출력한다. push연산은 +로, pop 연산은 -로 표현하도록 한다. 불가능한 경우 NO를 출력한다.</p>
</li>
</ul>
<h2 id="풀이">풀이</h2>
<ul>
<li><p>사용한 자료구조 : 스택, 벡터</p>
<ul>
<li>스택 : 수열을 만들 수 있는지 확인하기 위해 활용하는 자료구조</li>
<li>벡터 : 수열을 만들 수 있을 때 필요한 연산들을 저장하는 자료구조</li>
</ul>
</li>
<li><p>풀이 내용</p>
<ul>
<li>초기 설정 : 스택에 0 push<blockquote>
<p><strong>초기에 스택에 0을 push 하는 이유?</strong>
while 반복문에서 스택의 top을 반복 조건으로 활용하는데 0을 push하지 않으면 스택에 아무 원소도 없는 상황이 발생한다. 이렇게 될 경우 반복 조건에서 top 함수를 사용할 때 문제가 발생하게 된다. </p>
</blockquote>
</li>
</ul>
<ol>
<li><p><strong>사용자가 입력한 수와 스택의 top이 같아질때까지 push</strong></p>
</li>
<li><p><strong>push작업을 완료한 뒤 pop작업</strong>
2-1. top = 사용자가 입력한 num 인 경우 pop 작업 수행
2-2. top != 사용자가 입력한 num 인 경우 valid를 false로 변경</p>
<blockquote>
<p>*<em>valid를 false로 변경하는 이유? *</em>
스택의 제일 위 원소가 입력한 원소보다 큰 경우에는 수열을 만들 수 없다. </p>
</blockquote>
</li>
<li><p><strong>valid 값에 따라 출력</strong></p>
<ul>
<li>valid = true
필요한 연산을 저장한 벡터 원소 출력<ul>
<li>valid = false
NO 출력</li>
</ul>
</li>
</ul>
</li>
</ol>
</li>
<li><p>코드</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;stack&gt;
#include &lt;vector&gt;
using namespace std;
</code></pre>
</li>
</ul>
<p>stack<int> sequence;
vector<char> ans;
int n;
int cur_num;</p>
<p>int main(void) {
    ios::sync_with_stdio(0);
    cin.tie(0);</p>
<pre><code>sequence.push(cur_num);
cur_num++;

int num;
bool valid = true;

cin &gt;&gt; n;


for (int i = 0; i &lt; n; i++) {
    cin &gt;&gt; num;
    // stack 의 top이 num과 같아질때까지 반복
    while (sequence.top() &lt; num) {
        sequence.push(cur_num);
        cur_num++;
        ans.push_back(&#39;+&#39;);
    }
    if (sequence.top() == num) {
        sequence.pop();
        ans.push_back(&#39;-&#39;);
    }
    else {
        valid = false;
    }
}

if (!valid) {
    cout &lt;&lt; &quot;NO&quot; &lt;&lt; &#39;\n&#39;;
}
else {
    for (auto ch : ans) {
        cout &lt;&lt; ch &lt;&lt; &#39;\n&#39;;
    }
}</code></pre><p>}
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준 10866] 덱 - C++]]></title>
            <link>https://velog.io/@suyeon-jung/%EB%B0%B1%EC%A4%80-10866-%EB%8D%B1-cpp</link>
            <guid>https://velog.io/@suyeon-jung/%EB%B0%B1%EC%A4%80-10866-%EB%8D%B1-cpp</guid>
            <pubDate>Sun, 09 Jan 2022 05:41:49 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p><a href="https://www.acmicpc.net/problem/108664">https://www.acmicpc.net/problem/108664</a></p>
<h3 id="문제-설명">문제 설명</h3>
<p>정수를 저장하는 덱(Deque)를 구현한 다음, 입력으로 주어지는 명령을 처리하는 프로그램을 작성하시오.</p>
<p>명령은 총 여덟 가지이다.</p>
<p>push_front X: 정수 X를 덱의 앞에 넣는다.
push_back X: 정수 X를 덱의 뒤에 넣는다.
pop_front: 덱의 가장 앞에 있는 수를 빼고, 그 수를 출력한다. 만약, 덱에 들어있는 정수가 없는 경우에는 -1을 출력한다.
pop_back: 덱의 가장 뒤에 있는 수를 빼고, 그 수를 출력한다. 만약, 덱에 들어있는 정수가 없는 경우에는 -1을 출력한다.
size: 덱에 들어있는 정수의 개수를 출력한다.
empty: 덱이 비어있으면 1을, 아니면 0을 출력한다.
front: 덱의 가장 앞에 있는 정수를 출력한다. 만약 덱에 들어있는 정수가 없는 경우에는 -1을 출력한다.
back: 덱의 가장 뒤에 있는 정수를 출력한다. 만약 덱에 들어있는 정수가 없는 경우에는 -1을 출력한다.</p>
<h3 id="입출력">입출력</h3>
<ul>
<li><p>입력
첫째 줄에 주어지는 명령의 수 N (1 ≤ N ≤ 10,000)이 주어진다. 둘째 줄부터 N개의 줄에는 명령이 하나씩 주어진다. 주어지는 정수는 1보다 크거나 같고, 100,000보다 작거나 같다. 문제에 나와있지 않은 명령이 주어지는 경우는 없다.</p>
</li>
<li><p>출력
출력해야하는 명령이 주어질 때마다, 한 줄에 하나씩 출력한다.</p>
</li>
</ul>
<h2 id="풀이">풀이</h2>
<ul>
<li>사용한 자료구조 : 덱</li>
<li>풀이 내용
STL deque 기본 함수를 이용하여 구현</li>
<li>코드<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;deque&gt;
using namespace std;
</code></pre>
</li>
</ul>
<p>const int MX = 100005;
int dat[MX];
int N;
int main(void) {
    ios::sync_with_stdio(0);
    cin.tie(0);</p>
<pre><code>deque&lt;int&gt; dq;


string comm;
int num;

cin &gt;&gt; N;
for (int i = 0; i &lt; N; i++) {
    cin &gt;&gt; comm;
    if (comm == &quot;push_front&quot;) {
        cin &gt;&gt; num;
        dq.push_front(num);
    }
    else if (comm == &quot;push_back&quot;) {
        cin &gt;&gt; num;
        dq.push_back(num);
    }
    else if (comm == &quot;pop_front&quot;) {
        if (!dq.size()) {
            cout &lt;&lt; -1 &lt;&lt; &#39;\n&#39;;
        }
        else {
            cout &lt;&lt; dq.front() &lt;&lt; &#39;\n&#39;;
            dq.pop_front();
        }
    }
    else if (comm == &quot;pop_back&quot;) {
        if (!dq.size()) {
            cout &lt;&lt; -1 &lt;&lt; &#39;\n&#39;;
        }
        else {
            cout &lt;&lt; dq.back() &lt;&lt; &#39;\n&#39;;
            dq.pop_back();
        }
    }
    else if (comm == &quot;size&quot;) {
        cout &lt;&lt; dq.size() &lt;&lt; &#39;\n&#39;;
    }
    else if (comm == &quot;empty&quot;) {
        if (dq.empty()) {
            cout &lt;&lt; 1 &lt;&lt; &#39;\n&#39;;
        }
        else {
            cout &lt;&lt; 0 &lt;&lt; &#39;\n&#39;;
        }
    }
    else if (comm == &quot;front&quot;) {
        if (dq.empty()) {
            cout &lt;&lt; -1 &lt;&lt; &#39;\n&#39;;
        }
        else {
            cout &lt;&lt; dq.front() &lt;&lt; &#39;\n&#39;;
        }
    }
    else if (comm == &quot;back&quot;) {
        if (dq.empty()) {
            cout &lt;&lt; -1 &lt;&lt; &#39;\n&#39;;
        }
        else {
            cout &lt;&lt; dq.back() &lt;&lt; &#39;\n&#39;;
        }
    }
}</code></pre><p>}</p>
<pre><code></code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[백준 2164] 카드2 - C++]]></title>
            <link>https://velog.io/@suyeon-jung/%EB%B0%B1%EC%A4%80-2164-%EC%B9%B4%EB%93%9C2-cpp</link>
            <guid>https://velog.io/@suyeon-jung/%EB%B0%B1%EC%A4%80-2164-%EC%B9%B4%EB%93%9C2-cpp</guid>
            <pubDate>Sun, 09 Jan 2022 05:37:41 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p><a href="https://www.acmicpc.net/problem/2164">https://www.acmicpc.net/problem/2164</a></p>
<h3 id="문제-설명">문제 설명</h3>
<p>N장의 카드가 있다. 각각의 카드는 차례로 1부터 N까지의 번호가 붙어 있으며, 1번 카드가 제일 위에, N번 카드가 제일 아래인 상태로 순서대로 카드가 놓여 있다.</p>
<p>이제 다음과 같은 동작을 카드가 한 장 남을 때까지 반복하게 된다. 우선, <strong>(1) 제일 위에 있는 카드를 바닥에 버린다.</strong> 그 다음, <strong>(2) 제일 위에 있는 카드를 제일 아래에 있는 카드 밑으로 옮긴다.</strong></p>
<p>예를 들어 N=4인 경우를 생각해 보자. 카드는 제일 위에서부터 1234 의 순서로 놓여있다. 1을 버리면 234가 남는다. 여기서 2를 제일 아래로 옮기면 342가 된다. 3을 버리면 42가 되고, 4를 밑으로 옮기면 24가 된다. 마지막으로 2를 버리고 나면, 남는 카드는 4가 된다.</p>
<p>N이 주어졌을 때, 제일 마지막에 남게 되는 카드를 구하는 프로그램을 작성하시오.</p>
<h3 id="입출력">입출력</h3>
<ul>
<li>입력
첫째 줄에 정수 N(1 ≤ N ≤ 500,000)이 주어진다.</li>
<li>출력
첫째 줄에 남게 되는 카드의 번호를 출력한다.</li>
</ul>
<h2 id="풀이">풀이</h2>
<ul>
<li>사용한 자료구조 : 큐
카드 묶음에서 위에서는 <strong>카드를 버리는 동작</strong>만, 아래에서는 <strong>카드를 추가하는 동작</strong>만 발생하므로 큐를 선택 </li>
<li>풀이 내용<ol>
<li>1부터 사용자가 입력한 N까지 큐에 추가</li>
<li>큐에 남은 원소가 1개가 될때까지 반복
동작 중에 원소가 1개가 되는 경우가 있기 때문에 동작 중간에((1), (2) 중간) 원소가 1개가 되었는지 확인</li>
</ol>
</li>
</ul>
<ul>
<li>코드<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;queue&gt;
using namespace std;
</code></pre>
</li>
</ul>
<p>int N;
int main(void) {
    ios::sync_with_stdio(0);
    cin.tie(0);</p>
<pre><code>cin &gt;&gt; N;
queue&lt;int&gt; deck;


for (int i = 1; i &lt;= N; i++) {
    deck.push(i);
}
while (deck.size() &gt; 1) {
    // 1. 제일 위 카드 버리기
    deck.pop();
    if (deck.size() == 1) break; // 제일 위의 카드 버렸는데 1장 남았으면 동작 종료
    // 2. 제일 위의 카드 제일 아래로 옮기기 
    // 2-1. 제일 위의 원소 뒤에 push
    deck.push(deck.front());
    // 2-2. 제일 위의 원소 pop
    deck.pop();
}
cout &lt;&lt; deck.front() &lt;&lt; &#39;\n&#39;;</code></pre><p>}
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준 18258] 큐 2 - C++]]></title>
            <link>https://velog.io/@suyeon-jung/%EB%B0%B1%EC%A4%80-18258-%ED%81%90-2-cpp</link>
            <guid>https://velog.io/@suyeon-jung/%EB%B0%B1%EC%A4%80-18258-%ED%81%90-2-cpp</guid>
            <pubDate>Sun, 09 Jan 2022 05:26:32 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p><a href="https://www.acmicpc.net/problem/18258">https://www.acmicpc.net/problem/18258</a></p>
<h3 id="문제-설명">문제 설명</h3>
<p>정수를 저장하는 큐를 구현한 다음, 입력으로 주어지는 명령을 처리하는 프로그램을 작성하시오.</p>
<p>명령은 총 여섯 가지이다.</p>
<p>push X: 정수 X를 큐에 넣는 연산이다.
pop: 큐에서 가장 앞에 있는 정수를 빼고, 그 수를 출력한다. 만약 큐에 들어있는 정수가 없는 경우에는 -1을 출력한다.
size: 큐에 들어있는 정수의 개수를 출력한다.
empty: 큐가 비어있으면 1, 아니면 0을 출력한다.
front: 큐의 가장 앞에 있는 정수를 출력한다. 만약 큐에 들어있는 정수가 없는 경우에는 -1을 출력한다.
back: 큐의 가장 뒤에 있는 정수를 출력한다. 만약 큐에 들어있는 정수가 없는 경우에는 -1을 출력한다.</p>
<h3 id="입출력">입출력</h3>
<ul>
<li><p>입력
첫째 줄에 주어지는 명령의 수 N (1 ≤ N ≤ 2,000,000)이 주어진다. 둘째 줄부터 N개의 줄에는 명령이 하나씩 주어진다. 주어지는 정수는 1보다 크거나 같고, 100,000보다 작거나 같다. 문제에 나와있지 않은 명령이 주어지는 경우는 없다.</p>
</li>
<li><p>출력
출력해야하는 명령이 주어질 때마다, 한 줄에 하나씩 출력한다.</p>
</li>
</ul>
<h2 id="풀이">풀이</h2>
<h3 id="1-배열로-구현">1. 배열로 구현</h3>
<ul>
<li>사용한 자료구조 : 배열</li>
<li>풀이 내용<ul>
<li>front : 큐의 제일 앞부분</li>
<li>rear : 큐의 제일 뒷부분</li>
<li>초기 상태<ul>
<li>front : 0</li>
<li>rear : 0</li>
</ul>
</li>
<li>push 하는 경우
  front는 변하지 않고 rear는 이전보다 1 증가<ul>
<li>front(t+1) : front(t)</li>
<li>rear(t+1) : rear(t) + 1</li>
</ul>
</li>
<li>pop 하는 경우
  rear는 변하지 않고 front는 이전보다 1증가<ul>
<li>front(t+1) : front(t) + 1</li>
<li>rear(t+1) : rear(t) + 1</li>
</ul>
</li>
</ul>
</li>
<li>코드<pre><code class="language-cpp">#include &lt;iostream&gt;
using namespace std;

</code></pre>
</li>
</ul>
<p>const int MX = 100005;
int dat[MX];
int front, rear;
int N;
int main(void) {
    ios::sync_with_stdio(0);
    cin.tie(0);</p>
<pre><code>string comm;


cin &gt;&gt; N;
for (int i = 0; i &lt; N; i++) {
    cin &gt;&gt; comm;
    if (comm == &quot;push&quot;) {
        int num;
        cin &gt;&gt; num;
        dat[rear++] = num;
    }
    else if (comm == &quot;pop&quot;) {
        if ((rear - front) == 0) {
            cout &lt;&lt; -1 &lt;&lt; &#39;\n&#39;;
        }
        else {
            cout &lt;&lt; dat[front++] &lt;&lt; &#39;\n&#39;;
        }
    }
    else if (comm == &quot;size&quot;) {
        cout &lt;&lt; rear - front &lt;&lt; &#39;\n&#39;;
    }
    else if (comm == &quot;empty&quot;) {
        if ((rear - front) == 0) {
            cout &lt;&lt; 1 &lt;&lt; &#39;\n&#39;;
        }
        else {
            cout &lt;&lt; 0 &lt;&lt; &#39;\n&#39;;
        }
    }
    else if (comm == &quot;front&quot;) {
        if ((rear - front) == 0) {
            cout &lt;&lt; -1 &lt;&lt; &#39;\n&#39;;
        }
        else {
            cout &lt;&lt; dat[front] &lt;&lt; &#39;\n&#39;;
        }

    }
    else if (comm == &quot;back&quot;) {
        if ((rear - front) == 0) {
            cout &lt;&lt; -1 &lt;&lt; &#39;\n&#39;;
        }
        else {
            cout &lt;&lt; dat[rear-1] &lt;&lt; &#39;\n&#39;;
        }
    }
}</code></pre><p>}</p>
<pre><code>### 2. STL queue로 구현
- 사용한 자료구조 : 큐
- 풀이 내용
    STL queue 기본 함수들을 이용하여 구현
- 코드
```cpp
#include &lt;iostream&gt;
#include &lt;queue&gt;
using namespace std;


int N;
int main(void) {
    ios::sync_with_stdio(0);
    cin.tie(0);

    queue&lt;int&gt; myqueue;
    string comm;


    cin &gt;&gt; N;
    for (int i = 0; i &lt; N; i++) {
        cin &gt;&gt; comm;
        if (comm == &quot;push&quot;) {
            int num;
            cin &gt;&gt; num;
            myqueue.push(num);
        }
        else if (comm == &quot;pop&quot;) {
            if (myqueue.empty()) {
                cout &lt;&lt; -1 &lt;&lt; &#39;\n&#39;;
            }
            else {
                cout &lt;&lt; myqueue.front() &lt;&lt; &#39;\n&#39;;
                myqueue.pop();
            }
        }
        else if (comm == &quot;size&quot;) {
            cout &lt;&lt; myqueue.size() &lt;&lt; &#39;\n&#39;;
        }
        else if (comm == &quot;empty&quot;) {
            cout &lt;&lt; (int)myqueue.empty() &lt;&lt; &#39;\n&#39;;
        }
        else if (comm == &quot;front&quot;) {
            if (myqueue.empty()) {
                cout &lt;&lt; -1 &lt;&lt; &#39;\n&#39;;
            }
            else {
                cout &lt;&lt; myqueue.front() &lt;&lt; &#39;\n&#39;;
            }
        }
        else if (comm == &quot;back&quot;) {
            if (myqueue.empty()) {
                cout &lt;&lt; -1 &lt;&lt; &#39;\n&#39;;
            }
            else {
                cout &lt;&lt; myqueue.back() &lt;&lt; &#39;\n&#39;;
            }
        }
    }
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[백준 9012] 괄호 - C++]]></title>
            <link>https://velog.io/@suyeon-jung/%EB%B0%B1%EC%A4%80-9012-%EA%B4%84%ED%98%B8-cpp</link>
            <guid>https://velog.io/@suyeon-jung/%EB%B0%B1%EC%A4%80-9012-%EA%B4%84%ED%98%B8-cpp</guid>
            <pubDate>Sun, 09 Jan 2022 05:07:33 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p><a href="https://www.acmicpc.net/problem/9012">https://www.acmicpc.net/problem/9012</a></p>
<h3 id="문제-설명">문제 설명</h3>
<p>괄호 문자열(Parenthesis String, PS)은 두 개의 괄호 기호인 ‘(’ 와 ‘)’ 만으로 구성되어 있는 문자열이다. 그 중에서 괄호의 모양이 바르게 구성된 문자열을 올바른 괄호 문자열(Valid PS, VPS)이라고 부른다. 한 쌍의 괄호 기호로 된 “( )” 문자열은 기본 VPS 이라고 부른다. 만일 x 가 VPS 라면 이것을 하나의 괄호에 넣은 새로운 문자열 “(x)”도 VPS 가 된다. 그리고 두 VPS x 와 y를 접합(concatenation)시킨 새로운 문자열 xy도 VPS 가 된다. 예를 들어 “(())()”와 “((()))” 는 VPS 이지만 “(()(”, “(())()))” , 그리고 “(()” 는 모두 VPS 가 아닌 문자열이다. </p>
<p>여러분은 입력으로 주어진 괄호 문자열이 VPS 인지 아닌지를 판단해서 그 결과를 YES 와 NO 로 나타내어야 한다. </p>
<h3 id="입출력">입출력</h3>
<ul>
<li><p><strong>입력</strong>
입력 데이터는 표준 입력을 사용한다. 입력은 T개의 테스트 데이터로 주어진다. 입력의 첫 번째 줄에는 입력 데이터의 수를 나타내는 정수 T가 주어진다. 각 테스트 데이터의 첫째 줄에는 괄호 문자열이 한 줄에 주어진다. 하나의 괄호 문자열의 길이는 2 이상 50 이하이다. </p>
</li>
<li><p><strong>출력</strong>
출력은 표준 출력을 사용한다. 만일 입력 괄호 문자열이 올바른 괄호 문자열(VPS)이면 “YES”, 아니면 “NO”를 한 줄에 하나씩 차례대로 출력해야 한다. </p>
</li>
</ul>
<h2 id="풀이">풀이</h2>
<ul>
<li>사용한 자료구조 : <code>stack</code></li>
<li>풀이 내용<ol>
<li>&#39;(&#39; 일 때 <code>stack</code>에 <strong>push</strong></li>
<li>&#39;)&#39; 일 때 <ul>
<li><code>stack</code>이 비어있지 않다면 <strong>pop</strong></li>
<li><code>stack</code>이 비어있다면 &quot;NO&quot;</li>
</ul>
</li>
<li>입력으로 온 문자열 확인 마친 경우<ul>
<li><code>stack</code>이 비어있는 경우 &quot;YES&quot;</li>
<li><code>stack</code>이 비어있지 않은 경우 &quot;NO&quot;</li>
</ul>
</li>
</ol>
</li>
<li>코드
괄호 문자열을 판단하는 것을 함수로 구현</li>
</ul>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;stack&gt;
using namespace std;


int T;

string checkVPS(string input) {
    stack&lt;char&gt; ps;
    for (int i = 0; i &lt; input.size(); i++) {
        if (input[i] == &#39;(&#39;) {
            ps.push(&#39;(&#39;);
        }
        else {
            if (ps.empty()) return &quot;NO&quot;;
            ps.pop();
        }
    }
    if (ps.empty()) {
        return &quot;YES&quot;;
    }
    else {
        return &quot;NO&quot;;
    }
}
int main(void) {
    ios::sync_with_stdio(0);
    cin.tie(0);

    string ps;

    cin &gt;&gt; T;
    for (int i = 0; i &lt; T; i++) {
        cin &gt;&gt; ps;
        cout &lt;&lt; checkVPS(ps) &lt;&lt; &#39;\n&#39;;
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준 10828] 스택 - C++]]></title>
            <link>https://velog.io/@suyeon-jung/10828-%EC%8A%A4%ED%83%9D-cpp</link>
            <guid>https://velog.io/@suyeon-jung/10828-%EC%8A%A4%ED%83%9D-cpp</guid>
            <pubDate>Sun, 09 Jan 2022 04:42:44 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p><a href="https://www.acmicpc.net/problem/10828">https://www.acmicpc.net/problem/10828</a></p>
<h3 id="문제-설명">문제 설명</h3>
<p>정수를 저장하는 스택을 구현하여 입력으로 주어지는 명령을 처리하는 프로그램을 작성</p>
<ul>
<li>push X: 정수 X를 스택에 넣는 연산이다.</li>
<li>pop: 스택에서 가장 위에 있는 정수를 빼고, 그 수를 출력한다. 만약 스택에 들어있는 정수가 없는 경우에는 -1을 출력한다.</li>
<li>size: 스택에 들어있는 정수의 개수를 출력한다.</li>
<li>empty: 스택이 비어있으면 1, 아니면 0을 출력한다.</li>
<li>top: 스택의 가장 위에 있는 정수를 출력한다. 만약 스택에 들어있는 정수가 없는 경우에는 -1을 출력한다.</li>
</ul>
<h3 id="입출력">입출력</h3>
<ul>
<li><p><strong>입력</strong>
첫째 줄에 주어지는 명령의 수 N (1 ≤ N ≤ 10,000)이 주어진다. 둘째 줄부터 N개의 줄에는 명령이 하나씩 주어진다. 주어지는 정수는 1보다 크거나 같고, 100,000보다 작거나 같다. 문제에 나와있지 않은 명령이 주어지는 경우는 없다.</p>
</li>
<li><p><strong>출력</strong>
출력해야하는 명령이 주어질 때마다, 한 줄에 하나씩 출력한다.</p>
</li>
</ul>
<h2 id="풀이">풀이</h2>
<h3 id="1-배열로-구현">1. 배열로 구현</h3>
<ul>
<li>배열로 구현한 스택에서 <code>top</code>은 <code>dat[pos-1]</code>로 조회할 수 있다.</li>
<li>스택에 담긴 아이템의 개수는 <code>pos</code>로 조회할 수 있다.<pre><code class="language-cpp">#include &lt;iostream&gt;
using namespace std;
</code></pre>
</li>
</ul>
<p>const int MX = 100005;
int dat[MX];
int pos = 0;</p>
<p>int main(void) {
  ios::sync_with_stdio(0);
  cin.tie(0);</p>
<p>  int N;
  cin &gt;&gt; N;</p>
<p>  string s;
  int x;
  for (int i = 0; i &lt; N; i++) {
    cin &gt;&gt; s;
    if (s == &quot;push&quot;) {
      cin &gt;&gt; x;
      dat[pos++] = x;
    } else if (s == &quot;pop&quot;) {
      if (!pos)
        cout &lt;&lt; -1 &lt;&lt; &#39;\n&#39;;
      else {
        pos--;
        cout &lt;&lt; dat[pos] &lt;&lt; &#39;\n&#39;;
      }
    } else if (s == &quot;size&quot;) {
      cout &lt;&lt; pos &lt;&lt; &#39;\n&#39;;
    } else if (s == &quot;empty&quot;) {
      if (pos)
        cout &lt;&lt; 0 &lt;&lt; &#39;\n&#39;;
      else
        cout &lt;&lt; 1 &lt;&lt; &#39;\n&#39;;
    } else if (s == &quot;top&quot;) {
      if (!pos)
        cout &lt;&lt; -1 &lt;&lt; &#39;\n&#39;;
      else
        cout &lt;&lt; dat[pos - 1] &lt;&lt; &#39;\n&#39;;
    }
  }
}</p>
<pre><code>### 2. STL list로 구현
```cpp
#include &lt;iostream&gt;
#include &lt;list&gt;
using namespace std;

int main(void) {
    ios::sync_with_stdio(0);
    cin.tie(0);

    list&lt;int&gt; mystack;
    int N;    // 명령의 수
    int num; // push 명령에서 입력으로 주어지는 수
    string command; // 입력으로 주어지는 명령


    cin &gt;&gt; N;

    for (int i = 0; i &lt; N; i++) {
        cin &gt;&gt; command;

        if (command == &quot;push&quot;) {
            cin &gt;&gt; num;
            mystack.push_back(num);
        }
        else if (command == &quot;pop&quot;) {
            if (mystack.empty()) {
                cout &lt;&lt; -1 &lt;&lt; &#39;\n&#39;;
            }
            else {
                cout &lt;&lt; mystack.back() &lt;&lt; &#39;\n&#39;;
                mystack.pop_back();
            }
        }
        else if (command == &quot;size&quot;) {
            cout &lt;&lt; mystack.size() &lt;&lt; &#39;\n&#39;;
        }
        else if (command == &quot;empty&quot;) {
            if (mystack.empty()) {
                cout &lt;&lt; 1 &lt;&lt; &#39;\n&#39;;
            }
            else {
                cout &lt;&lt; 0 &lt;&lt; &#39;\n&#39;;
            }
        }
        else if (command == &quot;top&quot;) {
            if (mystack.empty()) {
                cout &lt;&lt; -1 &lt;&lt; &#39;\n&#39;;
            }
            else {
                cout &lt;&lt; mystack.back() &lt;&lt; &#39;\n&#39;;
            }
        }
    }

}</code></pre><h3 id="3-stl-stack으로-구현">3. STL stack으로 구현</h3>
<ul>
<li><code>stackname.empty()</code>는 스택이 비어있으면 True, 스택이 비어있지 않다면 False를 반환 <ul>
<li>empty 명령에 대한 출력은 <code>stackname.empty()</code>를 <code>int</code>형으로 형변환하여 출력한다. <pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;stack&gt;
using namespace std;
</code></pre>
</li>
</ul>
</li>
</ul>
<p>int main(void) {
  ios::sync_with_stdio(0);
  cin.tie(0);</p>
<p>  stack<int> S;
  int N;
  cin &gt;&gt; N;</p>
<p>  string s;
  while (N--) {
    cin &gt;&gt; s;
    if (s == &quot;push&quot;) {
      int t;
      cin &gt;&gt; t;
      S.push(t);
    } else if (s == &quot;pop&quot;) {
      if (S.empty())
        cout &lt;&lt; -1 &lt;&lt; &#39;\n&#39;;
      else {
        cout &lt;&lt; S.top() &lt;&lt; &#39;\n&#39;;
        S.pop();
      }
    } else if (s == &quot;size&quot;)
      cout &lt;&lt; S.size() &lt;&lt; &#39;\n&#39;;
    else if (s == &quot;empty&quot;)
      cout &lt;&lt; (int)S.empty() &lt;&lt; &#39;\n&#39;;
    else  // top
    {
      if (S.empty())
        cout &lt;&lt; -1 &lt;&lt; &#39;\n&#39;;
      else
        cout &lt;&lt; S.top() &lt;&lt; &#39;\n&#39;;
    }
  }
}
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[제 2절 인덱스 기본]]></title>
            <link>https://velog.io/@suyeon-jung/%EC%A0%9C-2%EC%A0%88-%EC%9D%B8%EB%8D%B1%EC%8A%A4-%EA%B8%B0%EB%B3%B8</link>
            <guid>https://velog.io/@suyeon-jung/%EC%A0%9C-2%EC%A0%88-%EC%9D%B8%EB%8D%B1%EC%8A%A4-%EA%B8%B0%EB%B3%B8</guid>
            <pubDate>Mon, 15 Nov 2021 07:20:23 GMT</pubDate>
            <description><![CDATA[<h2 id="1-인덱스-특징과-종류">1. 인덱스 특징과 종류</h2>
<blockquote>
<p>인덱스는 검색 연산의 최적화를 위해 데이터베이스 내 열에 대한 정보를 구성한 데이터 구조이다. </p>
</blockquote>
<ul>
<li>인덱스를 통해 전체 데이터의 검색 없이 필요ㅛ한 정보에 대해 신속한 조회가 가능하다. </li>
<li>INSERT, UPDATE, DELETE 등과 같은 DML 작업은 테이블과 인덱스를 함께 변경해야 하기 때문에 오히려 느려질 수 있다는 단점이 존재한다. </li>
</ul>
<h3 id="11-트리-기반-인덱스">1.1 트리 기반 인덱스</h3>
<p>DBMS 에서 가장 일반적인 B-트리 인덱스</p>
<p><img src="https://images.velog.io/images/suyeon-jung/post/d7543f5f-a210-4c58-b216-59b931f97126/image.png" alt=""></p>
<ul>
<li>브랜치 블록 중에서 가장 상위에 있는 블록을 <strong>루프 블록</strong>이라고 한다. </li>
<li>브랜치 블록은 다음 단계의 블록을 가리키는 포인터를 가지고 있다.</li>
<li>리프 블록은 트리의 가장 아래 단계에 존재한다.</li>
<li>리프 블록은 (컬럼 데이터, 해당 데이터 행의 위치-RID)로 구성된다.</li>
<li>인덱스 데이터는 인덱스를 구성하는 컬럼의 값으로 정렬된다. </li>
<li>리프 블록은 양방향 링크를 가지고 있다. (오름차순/내림차순 검색을 쉽게 할 수 있다.)</li>
<li>B-트리 인덱스는 <code>=</code>로 검색하는 <strong>일치검색</strong>과 <code>BETWEEN</code>, <code>&gt;</code> 등과 같은 연산자로 검색하는 <strong>범위검색</strong>에 모두 적합하다. </li>
</ul>
<p>Oracle 에서 트리 기반 인덱스에는 B-트리 인덱스 외에도 비트맵 인덱스, 리버스 키 인덱스, 함수 기반 인덱스 등이 존재한다. </p>
<h3 id="12-클러스터형-인덱스sql-server">1.2 클러스터형 인덱스(SQL Server)</h3>
<p>SQL Server에서는 저장 구조에 따라 <strong>클러스터형 인덱스</strong>와 <strong>비클러스터형 인덱스</strong>가 있다. </p>
<h4 id="클러스터형-인덱스">클러스터형 인덱스</h4>
<ul>
<li>인덱스의 리프 페이지가 곧 데이터 페이지이다. 클러스터형 인덱스의 리프 페이지를 탐색하면 해당 테이블의 모든 컬럼 값을 곧바로 얻을 수 있다. </li>
<li>리프 페이지의 모든 로우(데이터)는 인덱스 키 컬럼 순으로 물리적으로 정렬되어 저장된다. </li>
<li>클러스터형 인덱스는 물리적으로 한가지 순서로만 정렬될 수 있다. 테이블당 한개만 생성할 수 있다. </li>
</ul>
<h2 id="2-전체-테이블-스캔과-인덱스-스캔">2. 전체 테이블 스캔과 인덱스 스캔</h2>
<h3 id="21-전체-테이블-스캔">2.1 전체 테이블 스캔</h3>
<blockquote>
<p>테이블에 존재하는 모든 데이터를 읽어 가면서 조건에 맞으면 결과로서 추출하고 조건에 맞지 않으면 버리는 방식으로 검색한다. </p>
</blockquote>
<p><img src="https://images.velog.io/images/suyeon-jung/post/3ae3c7d6-6e70-4579-b3f3-e8395928faec/image.png" alt=""></p>
<p>전체 테이블 스캔 방식은 테이블에 존재하는 모든 블록의 데이터를 읽기 때문에 시간이 오래 걸릴 수 있다. </p>
<h3 id="22-인덱스-스캔">2.2 인덱스 스캔</h3>
<ul>
<li>인덱스의 리프 블록 : 인덱스 구성 컬럼 + 레코드 식별자(RID)</li>
<li>인덱스는 인덱스 구성 컬럼의 순서로 정렬되어 있다. </li>
</ul>
<ol>
<li>인덱스 유일 스캔 : 유일 인덱스(Unique Index)를 사용하여 단 하나의 데이터를 추출하는 방식, 중복을 허락하지 않음</li>
<li>인덱스 범위 스캔 : 인덱스를 이용하여 한 건 이상의 데이터를 추출하는 방식</li>
<li>인덱스 역순 범위 스캔 : 인덱스 리프 블록의 양방향 링크를 이용하여 내림 차순으로 데이터를 읽는 방식
<img src="https://images.velog.io/images/suyeon-jung/post/55bc3e87-81ef-467b-adec-b67b076e10ba/image.png" alt=""></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[제 3절 조인 수행 원리]]></title>
            <link>https://velog.io/@suyeon-jung/%EC%A0%9C-3%EC%A0%88-%EC%A1%B0%EC%9D%B8-%EC%88%98%ED%96%89-%EC%9B%90%EB%A6%AC</link>
            <guid>https://velog.io/@suyeon-jung/%EC%A0%9C-3%EC%A0%88-%EC%A1%B0%EC%9D%B8-%EC%88%98%ED%96%89-%EC%9B%90%EB%A6%AC</guid>
            <pubDate>Sun, 14 Nov 2021 17:41:40 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>조인이란?
2개 이상의 테이블을 하나의 테이블로 만드는 연산</p>
</blockquote>
<ul>
<li>종류<ul>
<li>NL Join</li>
<li>Sort Merge Join</li>
<li>Hash Join</li>
</ul>
</li>
</ul>
<h2 id="1-nl-join">1. NL Join</h2>
<p>두개의 테이블을 중첩된 반복문처럼 조인을 수행한다.
반복문 외부에 있는 테이블을 선행 테이블 또는 외부테이블이라고 한다.
반복문 내부에 있는 테이블을 후행 테이블 또는 내부테이블이라고 한다. </p>
<pre><code>for 선행 테이블 읽음 
    for 후행 테이블 읽음
        (선행 테이블과 후행 테이블 조인)</code></pre><p>선행 결과값을 줄이기 위해 결과 행의 수가 적은 테이블을 선행 테이블로 선택한다. 
<img src="https://images.velog.io/images/suyeon-jung/post/9e0ce5c2-dc4f-4026-a7a4-a7a8b84cfd0b/image.png" alt=""></p>
<h2 id="2-sort-merge-join">2. Sort Merge Join</h2>
<p>조인 컬럼을 기준으로 데이터를 정렬하여 조인한다.
넓은 범위의 데이터를 처리할 때 주로 이용한다.
정렬 데이터가 많을 경우 성능이 떨어질 수 있다.(디스크 I/O로 인한 부하 발생)
비동등 조인에 대해서도 조인이 가능하다.
인덱스를 사용하지 않아 인덱스가 존재하지 않을 경우에 사용할 수 있다. 
<img src="https://images.velog.io/images/suyeon-jung/post/4ec908a6-8873-4a70-85e9-7d84265c7285/image.png" alt=""></p>
<h2 id="3-hash-join">3. Hash Join</h2>
<p>해싱 기법을 이용하여 조인을 수행한다. 
NL Join 의 랜덤 액세스 문제와 Sort Merge Join 의 정렬 작업의 부하를 해결하기 위한 대안으로 사용된다.
조인 컬럼의 인덱스가 존재하지 않을때에도 사용할 수 있다. 
해시 함수를 사용하기 때문에 동등 조인만 가능하다.
해시 테이블의 크기가 메모리에 적재할 수 있는 크기보다 커지면 디스크를 사용한다. 
<img src="https://images.velog.io/images/suyeon-jung/post/d19e6ac3-0bd0-4c1a-946a-e10e9afb960a/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[제 1절 옵티마이저와 실행계획]]></title>
            <link>https://velog.io/@suyeon-jung/%EC%A0%9C-1%EC%A0%88-%EC%98%B5%ED%8B%B0%EB%A7%88%EC%9D%B4%EC%A0%80%EC%99%80-%EC%8B%A4%ED%96%89%EA%B3%84%ED%9A%8D</link>
            <guid>https://velog.io/@suyeon-jung/%EC%A0%9C-1%EC%A0%88-%EC%98%B5%ED%8B%B0%EB%A7%88%EC%9D%B4%EC%A0%80%EC%99%80-%EC%8B%A4%ED%96%89%EA%B3%84%ED%9A%8D</guid>
            <pubDate>Sun, 14 Nov 2021 17:35:23 GMT</pubDate>
            <description><![CDATA[<h2 id="1-옵티마이저">1. 옵티마이저</h2>
<blockquote>
<p>SQL을 가장 빠르고 효율적으로 수행할 최적의 처리 경로를 생성해주는 DBMS 내부의 핵심 엔진</p>
</blockquote>
<p>최적의 실행 방법을 실행꼐획(Execution Plan)이라고 한다.</p>
<h3 id="11-옵티마이저-유형">1.1 옵티마이저 유형</h3>
<p><img src="https://images.velog.io/images/suyeon-jung/post/4fd9da61-9055-4ca5-9ae0-0e3743e30961/image.png" alt=""></p>
<table>
<thead>
<tr>
<th></th>
<th>규칙기반 옵티마이저(RBO)</th>
<th>비용기반 옵티마이저(CBO)</th>
</tr>
</thead>
<tbody><tr>
<td>개념</td>
<td>통계정보 없이 사전 등록된 규칙에 따라 질의 실행 계획을 선택</td>
<td>통계 정보로부터 모든 접근 경로를 고려한 질의 실행 계획을 선택</td>
</tr>
<tr>
<td>핵심</td>
<td>규칙(우선순위 기반)</td>
<td>비용(수행 시간)기반</td>
</tr>
<tr>
<td>평가 기준</td>
<td>인덱스 구조, 연산자, 조건절 형태 등</td>
<td>레코드 개수, 블록 개수, 평균 행 길이, 컬럼 값의 수,...</td>
</tr>
<tr>
<td>장점</td>
<td>사용자가 원하는 처리 경로로 유도하기 쉬움</td>
<td>옵티마이저의 이해도가 낮아도 성능보장 가능</td>
</tr>
</tbody></table>
<h4 id="111-규칙기반-옵티마이저">1.1.1 규칙기반 옵티마이저</h4>
<ul>
<li>인덱스를 이용한 액세스 방식이 전체 테이블 액세스 방식보다 우선수위가 높다.</li>
<li>조인 순서를 결정할 때 조인 컬럼의 인덱스 존재 유무가 중요한 판단의 기준이 된다.<ul>
<li>조인 컬럼에 대한 인덱스가 양쪽에 존재 : 우선순위가 높은 테이블이 선행 테이블</li>
<li>한쪽에만 인덱스 존재 : 인덱스가 없는 테이블이 선행 테이블</li>
<li>모두 인덱스 존재 안함 : FROM 절 뒤에 나열된 테이블이 선행 테이블</li>
<li>우선순위가 동일 : FROM 절에 나열된 테이블의 역순으로 선행 테이블 선택</li>
</ul>
</li>
</ul>
<h4 id="112-비용기반-옵티마이저">1.1.2 비용기반 옵티마이저</h4>
<p><img src="https://images.velog.io/images/suyeon-jung/post/9301f74b-09c7-459c-8111-af235744241c/image.png" alt=""></p>
<ul>
<li>질의 변환기 : 사용자가 작성한 SQL문을 처리하기에 보다 용이한 형태로 변환하는 모듈</li>
<li>대안 계획 생성기 : 동일한 결과를 생성하는 다양한 대안 계획을 생성하는 모듈</li>
<li><blockquote>
<p>대안 계획이 많아질수록 최적화를 수행하는데 시간이 오래 걸린다.</p>
</blockquote>
</li>
<li>비용 예측기 : 생성된 대안 계획의 비용을 예측하는 모듈</li>
</ul>
<ul>
<li>인덱스를 사용하는 비용이 전체 테이블 스캔 비용보다 크다고 판단되면 전체 테이블 스캔을 수행하는 방법으로 실행계획을 생성할 수 있다.</li>
<li>통계정보, DBMS 버전, DBMS 설정 정보등의 차이로 인해 동일 질의문도 서로 다른 실행 계획이 생성될 수 있다. </li>
</ul>
<h2 id="2-실행-계획">2. 실행 계획</h2>
<blockquote>
<p>SQL에서 요구한 사항을 처리하기 위한 절차와 방법, 실행계획마다 실행 시간(성능)은 다를 수 있음</p>
</blockquote>
<ul>
<li><strong>실행계획 구성요소</strong><ul>
<li>조인순서</li>
<li>조인기법</li>
<li>액세스 기법</li>
<li>최적화 정보</li>
<li>연산</li>
</ul>
</li>
</ul>
<h2 id="3-sql-처리-흐름도">3. SQL 처리 흐름도</h2>
<blockquote>
<p>SQL의 내부적인 처리 절차를 시각적으로 표현한 도표</p>
</blockquote>
<p><img src="https://images.velog.io/images/suyeon-jung/post/da330bca-89e7-4ab0-ac7d-441466e4356c/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[제 8절 절차형 SQL]]></title>
            <link>https://velog.io/@suyeon-jung/%EC%A0%9C-8%EC%A0%88-%EC%A0%88%EC%B0%A8%ED%98%95-SQL</link>
            <guid>https://velog.io/@suyeon-jung/%EC%A0%9C-8%EC%A0%88-%EC%A0%88%EC%B0%A8%ED%98%95-SQL</guid>
            <pubDate>Sun, 14 Nov 2021 16:18:13 GMT</pubDate>
            <description><![CDATA[<h2 id="1-절차형-sql-개요">1. 절차형 SQL 개요</h2>
<blockquote>
<p>일반적인 개발 언어처럼 SQL 언어에서도 절차 지향적인 프로그램이 가능하도록 하는 트랜잭션 언어이다. </p>
</blockquote>
<ul>
<li><p>Oracle : PL(Procedural Language)/SQL</p>
</li>
<li><p>SQL Server : T-SQL</p>
</li>
<li><p>DB2 : SQL/PL</p>
</li>
<li><p><strong>종류</strong></p>
<ol>
<li>프로시저 : 일련의 쿼리들을 마치 하나의 함수처럼 실행하기 위한 쿼리의 집합</li>
<li>사용자 정의함수 : 일련의 SQL 처리를 수행하고, 수행 결과를 단일 값으로 반환할 수 있는 절차형 SQL</li>
<li>트리거 : 데이터베이스 시스템에서 삽입, 갱신, 삭제 등의 이벤트가 발생할 때마다 관련 작업이 자동으로 수행되는 절차형 SQL</li>
</ol>
</li>
</ul>
<h2 id="2-plsql-개요">2. PL/SQL 개요</h2>
<p>블럭 구조로 되어 있고 블럭 내에는 DML문장과 Query 문장, 그리고 절차형 언어(IF, LOOP) 등을 사용할 수 있으며 절차적 프로그래밍을 가능하게 하는 트랜잭션 언어이다. </p>
<p><img src="https://images.velog.io/images/suyeon-jung/post/b57c70fc-261a-4cd0-bbf7-313abdac3931/image.png" alt=""></p>
<ul>
<li><strong>PL/SQL 구조</strong>
<img src="https://images.velog.io/images/suyeon-jung/post/1bf3ba2e-2653-405f-ae89-891c7818a9e0/image.png" alt=""></li>
<li>선언부(DECLARE) : 프로시저의 명칭, 변수와 인수 그리고 그에 대한 데이터 타입을 정의하는 부분</li>
<li>시작/종료부(BEGIN/END) : 프로시저의 시작과 종료를 표현</li>
<li>제어부(CONTROL) :</li>
<li>예외부(EXCEPTION) : BEGIN~END 절에서 실행되는 SQL 문이 실행될 때 예외 발생 시 예외 처리 방법을 정의하는 처리부</li>
</ul>
<h3 id="21-프로시저">2.1 프로시저</h3>
<ul>
<li><strong>프로시저 문법</strong><pre><code class="language-sql">CREATE [OR REPLACE] PROCEDURE 프로시저명
(파라미터명 [IN|OUT|INOUT] 데이터타입, ... ... ) 
IS 
  변수선언
BEGIN
  명령어;
[COMMIT|ROLLBACK]
END;</code></pre>
<ul>
<li>[OR REPLACE] : 기존 프로시저 존재시 현재 컴파일 하는 내용으로 덮어씀</li>
<li>[IN|OUT|INOUT] : 변수의 입출력 구분, (운영체제에서 프로시저로 값을 전달하는 모드/프로시저에서 처리된 결과를 운영체제로 전달하는 모드/두가지 기능을 동시에 수행)</li>
<li>BEGIN : 프로시저의 시작</li>
<li>COMMIT : 하나의 트랜잭션이 성공적으로 끝나고, 데이터베이스가 일관성 있는 상태에 있을 때 하나의 트랜잭션이 끝났을 때 사용하는 연산</li>
<li>ROLLBACK : 하나의 트랜잭션이 비정상적으로 종료되어 트랜잭션 원자성이 깨질 경우 처음부터 다시 시작하거나, 부분적으로 연산을 취소하는 연산</li>
<li>END : 프로시저의 끝</li>
</ul>
</li>
</ul>
<h3 id="22-사용자-정의함수">2.2 사용자 정의함수</h3>
<ul>
<li>기본적인 사항은 프로시저와 동일하고 반환에서의 부분만 프로시저와 다르다.</li>
<li><strong>사용자 정의함수 문법</strong><pre><code class="language-sql">CREATE [OR REPLACE] FUNCTION 함수명
(파라미터명 IN 데이터타입, ... ... ) 
RETURN 데이터타입
IS 
  변수선언
BEGIN
  명령어;
     RETURN 변수;
[COMMIT|ROLLBACK]
END;</code></pre>
</li>
<li>RETURN 데이터타입 : 사용자 정의함수가 반환하는 데이터 타입을 정의</li>
<li>RETURN 데이터값 : 사용자 정의함수가 종료될 때 반환하는 단일 값을 정의</li>
</ul>
<h3 id="23-트리거">2.3 트리거</h3>
<ul>
<li><p>데이터베이스 시스템에서 삽입, 갱신, 삭제 등의 이벤트가 발생할 때마다 관련 작업이 자동으로 수행되는 절차형 SQL이다.</p>
</li>
<li><p>이벤트는 전체 트랜잭션 대상과 각 행에 의해 발생하는 경우 모두를 포함할 수 있으며 테이블과 뷰, DB 작업을 대상으로 정의할 수 있다. </p>
</li>
<li><p><strong>목적</strong></p>
<ul>
<li>데이터 무결성 유지 및 로그 메시지 출력 등의 별도 처리를 위해 트리거 사용</li>
<li>이벤트와 관련된 테이블의 데이터 삽입, 추가, 삭제 작업을 DBMS가 자동적으로 실행시키는 데 활용</li>
</ul>
</li>
<li><p><strong>종류</strong></p>
<ul>
<li>행 트리거 : 데이터 변화가 생길 때마다 실행</li>
<li>문장 트리거 : 트리거에 의해 단 한 번 실행</li>
</ul>
</li>
<li><p><strong>트리거 문법</strong></p>
<pre><code class="language-sql">CREATE [OR REPLACE] TRIGGER 트리거명
[BEFORE|AFTER] 유형 ON 테이블명
[FOR EACH ROW]
BEGIN
END;</code></pre>
</li>
<li><p>[BEFORE|AFTER] : DML과 트리거가 실행되는 순서의 전후 관계를 결정</p>
</li>
<li><p>[FOR EACH ROW] : 매번 변경되는 데이터 행의 수만큼 실행을 위한 명령어</p>
</li>
</ul>
<h3 id="프로시저와-트리거의-차이점">프로시저와 트리거의 차이점</h3>
<table>
<thead>
<tr>
<th>프로시저</th>
<th>트리거</th>
</tr>
</thead>
<tbody><tr>
<td>CREATE 프로시저 문법 사용</td>
<td>CREATE 트리거 문법 사용</td>
</tr>
<tr>
<td>EXECUTE 명령어로 실행</td>
<td>생성 후 자동 실행</td>
</tr>
<tr>
<td>COMMIT, ROLLBACK 실행 가능</td>
<td>COMMIT, ROLLBACK 실행시 컴파일 에러</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[제 7절 DCL]]></title>
            <link>https://velog.io/@suyeon-jung/%EC%A0%9C-7%EC%A0%88-DCL</link>
            <guid>https://velog.io/@suyeon-jung/%EC%A0%9C-7%EC%A0%88-DCL</guid>
            <pubDate>Sun, 14 Nov 2021 15:44:51 GMT</pubDate>
            <description><![CDATA[<h2 id="1-데이터-제어어-개요">1. 데이터 제어어 개요</h2>
<ul>
<li><p>데이터 제어어는 데이터베이스 관리자가 데이터 보안, 무결성 유지, 병행 제어, 회복을 위해 관리자(DBA)가 사용하는 제어용 언어이다. </p>
</li>
<li><p><strong>DCL 유형</strong></p>
</li>
</ul>
<table>
<thead>
<tr>
<th>유형</th>
<th>동작</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>GRANT</td>
<td>권한 부여</td>
<td>관리자가 사용자에게 데이터베이스에 대한 권한을 부여하는 명령</td>
</tr>
<tr>
<td>REVOKE</td>
<td>권한 취소</td>
<td>관리자가 사용자에게 부여했던 권한을 회수하는 명령</td>
</tr>
</tbody></table>
<ul>
<li>Oracle과 SQL Server의 사용자에 대한 차이점<ul>
<li>Oracle : 유저를 통해 데이터베이스에 접속하는 형태, 아이디와 비밀번호 방식으로 인스턴스에 접속하고 그에 해당하는 스키마에 오브젝트 생성 등의 권한을 부여 받음</li>
<li>SQL Server : 인스턴스에 접속하기 위해 로그인을 생성하며 인스턴스 내에 존재하는 다수의 데이터베이스에 연결하여 작업하기 위해 유저를 생성한 후 로그인과 유저를 매핑, 특정 유저는 특정 데이터베이스 내의 특정 스키마에 대해 권한을 부여받을 수 있음</li>
</ul>
</li>
</ul>
<ul>
<li>유저 생성과 시스템 권한 부여
유저를 생성하고 데이터베이스에 접속한다. 하지만 데이터베이스에 접속했다고 해서 데이터베이스 오브젝트를 생성할 수는 없다. 사용자가 실행하는 모든 DDL문장은 그에 해당하는 적절한 권한이 있어야 실행할 수 있다. </li>
</ul>
<ul>
<li><p>GRANT</p>
<pre><code class="language-sql">GRANT 권한 ON 테이블 TO 사용자;</code></pre>
</li>
<li><p>REVOKE</p>
<pre><code class="language-sql">REVOKE 권한 ON 테이블 FROM 사용자;</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[제 6절 윈도함수]]></title>
            <link>https://velog.io/@suyeon-jung/%EC%A0%9C-6%EC%A0%88-%EC%9C%88%EB%8F%84%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@suyeon-jung/%EC%A0%9C-6%EC%A0%88-%EC%9C%88%EB%8F%84%ED%95%A8%EC%88%98</guid>
            <pubDate>Sun, 14 Nov 2021 15:30:16 GMT</pubDate>
            <description><![CDATA[<h2 id="1-윈도-함수-개요">1. 윈도 함수 개요</h2>
<ul>
<li>윈도 함수는 데이터베이스를 사용한 온라인 분석 처리 용도로 사용하기 위해서 표준 SQL에 추가된 함수이다.</li>
<li>윈도 함수를 OLAP 함수라고 한다.</li>
<li>행과 행간의 관계를 쉽게 정의하기 위해 만든 함수이다. </li>
</ul>
<h3 id="11-윈도-함수-구문">1.1 윈도 함수 구문</h3>
<pre><code class="language-sql">SELECT 함수명(파라미터)
    OVER
   ([PARTITION BY 컬럼1, ...]
   [ORDER BY 컬럼A, ...])
   FROM 테이블명</code></pre>
<ul>
<li>OVER 구문이 필수적으로 필요</li>
<li>PARTITION BY(선택 항목)은 순위를 정할 대상 범위의 컬럼을 설정(이를 통해 구분된 레코드 집합을 윈도라고 함)</li>
<li>ORDER BY 뒤에는 SORT 컬럼을 입력(어떤 열을 어떤 순서로 순위를 정할지를 지정)</li>
</ul>
<h3 id="12-윈도-함수-종류">1.2 윈도 함수 종류</h3>
<table>
<thead>
<tr>
<th>분류</th>
<th>설명</th>
<th>종류</th>
</tr>
</thead>
<tbody><tr>
<td>순위 함수</td>
<td>레코드의 순위를 계산하는 함수</td>
<td>RANK, DENSE_RANK, ROW_NUMBER</td>
</tr>
<tr>
<td>행 순서 함수</td>
<td>레코드에서 가장 먼저 나오거나 가장 뒤에 나오는 값, 이전/이후의 값들을 출력하는 함수<br/> <strong>Oracle에서만 지원</strong></td>
<td>FIRST_VALUE, LAST_VALUE, LAG, LEAD</td>
</tr>
<tr>
<td>그룹내 비율 함수</td>
<td>백분율을 보여주거나 행의 순서별 백분율 등 비율과 관련된 통계를 보여주는 함수</td>
<td>RATIO_TO_REPORT, PERCENT_RANK</td>
</tr>
</tbody></table>
<h2 id="2-순위-함수">2. 순위 함수</h2>
<table>
<thead>
<tr>
<th>순위 함수</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>RANK</td>
<td>- 특정 항목에 대한 순위를 구하는 함수<br/> <strong>- 동일 순위의 레코드 존재시 후순위 넘어감(2위가 3개인 레코드: 2위2위2위5위6위)</strong></td>
</tr>
<tr>
<td>DENSE_RANK</td>
<td>- 레코드의 순위를 계산<br/> <strong>- 동일 순위의 레코드 존재시 후순위 넘어가지 않음(2위가 3개인 레코드: 2위2위2위3위4위)</strong></td>
</tr>
<tr>
<td>ROW_NUMBER</td>
<td>- 레코드의 순위를 계산<br/> <strong>- 동일 순위의 값이 존재해도 이와 무관하게 연속 번호를 부여(2위가 3개인 레코드: 2위3위4위5위6위)</strong></td>
</tr>
</tbody></table>
<pre><code class="language-sql">SELECT NAME, SALARY,
RANK() OVER(ORDER BY SALARY DESC) A,
DENSE_RANK() OVER(ORDER BY SALARY DESC) B,
ROW_NUMBER() OVER(ORDER BY SALARY DESC) C
FROM EMP;</code></pre>
<h2 id="3-행순서-함수">3. 행순서 함수</h2>
<table>
<thead>
<tr>
<th>행순서 함수</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>FIRST_VALUE</td>
<td>- 파티션별 윈도에서 가장 먼저 나오는 값을 찾음 <br/> - 집계 함수의 MIN과 동일한 결과를 출력</td>
</tr>
<tr>
<td>LAST_VALUE</td>
<td>- 파티션별 윈도에서 가장 늦게 나오는 값을 찾음<br/> - 집계 함수의 MAX와 동일한 결과를 출력</td>
</tr>
<tr>
<td>LAG</td>
<td>- 파티션별 윈도에서 이전 로우의 값 반환<br/><strong>- SQL Server에서 지원하지 않음</strong></td>
</tr>
<tr>
<td>LEAD</td>
<td>- 파티션별 윈도에서 이후 로우의 값 반환<br/><strong>- SQL Server에서 지원하지 않음</strong></td>
</tr>
</tbody></table>
<pre><code class="language-sql">SELECT NAME, SALARY,
    FIRST_VALUE(NAME) OVER(ORDER BY SALARY) A,
    LAST_VALUE(NAME) OVER(ORDER BY SALARY) B,
    LAG(NAME) OVER(ORDER BY SALARY DESC) C,
    LEAD(NAME) OVER(ORDER BY SALARY DESC) D
FROM EMP;</code></pre>
<h2 id="4-그룹-내-비율-함수">4. 그룹 내 비율 함수</h2>
<table>
<thead>
<tr>
<th>그룹 내 비율 함수</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>RATIO_TO_REPORT</td>
<td>- 주어진 그룹에 대해 합을 기준으로 각 로우의 상대적 비율을 반환하는 함수<br/>- 결괏값은 0~1의 범위 값을 가짐<br/>- OVER 괄호 안에 컬럼 생략 시 그룹은 테이블 전체가 대상</td>
</tr>
<tr>
<td>PERCENT_RANK</td>
<td>- 주어진 그룹에 대해 제일 먼저 나오는 것을 0으로, 제일 늦게 나오는 것을 1로 하여, 값이 아닌 행의 순서별 백분율을 구하는 함수<br/>- 결괏값은 0~1의 범위값을 가짐<br/><strong>- SQL Server에서 지원하지 않음</strong></td>
</tr>
</tbody></table>
<pre><code class="language-sql">SELECT NAME, SALARY,
    RATIO_TO_REPORT(SALARY) OVER() A,
    PERCENT_RANK() OVER(ORDER BY SALARY DESC) B
FROM EMP;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[제 5절 그룹함수]]></title>
            <link>https://velog.io/@suyeon-jung/%EC%A0%9C-5%EC%A0%88-%EA%B7%B8%EB%A3%B9%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@suyeon-jung/%EC%A0%9C-5%EC%A0%88-%EA%B7%B8%EB%A3%B9%ED%95%A8%EC%88%98</guid>
            <pubDate>Sun, 14 Nov 2021 14:51:33 GMT</pubDate>
            <description><![CDATA[<h2 id="1-데이터-분석-개요">1. 데이터 분석 개요</h2>
<h4 id="데이터-분석-함수">데이터 분석 함수</h4>
<p>총합, 평균 등의 데이터 분석을 위해서는 복수 행 기준의 데이터를 모아서 처리하는 것을 목적으로 하는 <strong>다중행 함수</strong>이다.</p>
<ul>
<li><p><strong>특성</strong></p>
<ul>
<li>단일행을 기반으로 산출하지 않고 복수행을 그룹별로 모아 놓고 그룹당 단일 계산 결과를 반환</li>
<li><code>GROUP BY</code> 구문을 사용해 복수행을 그룹핑</li>
<li><code>SELECT</code>, <code>HAVING</code>, <code>ORDER BY</code> 등의 구문에 활용</li>
</ul>
</li>
<li><p>ANSI/ISO SQL 표준은 데이터 분석을 위해 다음 세가지 함수를 정의한다.</p>
</li>
</ul>
<table>
<thead>
<tr>
<th>함수</th>
<th>설명</th>
<th>종류</th>
</tr>
</thead>
<tbody><tr>
<td>집계함수(Aggregate Function)</td>
<td>여러 행 또는 테이블 전체 행으로부터 하나의 결괏값을 반환하는 함수</td>
<td>COUNT, SUM, AVG, MAX, MIN, STDDEV, VARIAN</td>
</tr>
<tr>
<td>그룹함수(Group Function)</td>
<td>소그룹 간의 소계 및 중계 등의 중간 합계 분석 데이터를 산출하는 함수</td>
<td>ROLLUP, CUBE, GROUPING SETS</td>
</tr>
<tr>
<td>윈도함수(Window Function)</td>
<td>데이터베이스를 사용한 온라인 분석 처리 용도로 사용하기 위해서 표준 SQL에 추가된 기능</td>
<td>순위함수, 행순서 함수, 그룹 내 비율 함수</td>
</tr>
</tbody></table>
<h2 id="2-집계-함수">2. 집계 함수</h2>
<blockquote>
<p>여러 행 또는 테이블 전체 행으로부터 하나의 결괏값을 반환하는 함수</p>
</blockquote>
<ul>
<li>집계 함수 구문<pre><code class="language-sql">SELECT 컬럼1, 컬럼2, ..., 집계함수
FROM 테이블명
[WHERE 조건]
GROUP BY 컬럼1, 컬럼2, ...
[HAVING 조건식(집계함수 포함)]</code></pre>
</li>
<li>GROUP BY 에서 주의할 점<ul>
<li>NULL 값은 제외하고 산출한다.</li>
<li>SELECT 절에서 처럼 ALIAS 사용이 불가하다.</li>
<li>집계함수 구문을 사용할 수 없다. </li>
</ul>
</li>
</ul>
<p><strong>집계함수는 NULL이 포함된 경우 없는 데이터로 판단한다.</strong></p>
<h2 id="3-그룹-함수">3. 그룹 함수</h2>
<blockquote>
<p>테이블의 전체 행을 하나 이상의 컬럼을 기준으로 컬럼 값에 따라 그룹화하여 그룹별로 결과를 출력하는 함수</p>
</blockquote>
<h3 id="31-rollup-함수">3.1 ROLLUP 함수</h3>
<ul>
<li>ROLLUP 에 의해 지정된 컬럼은 소계(소그룹의 합계) 등 중간 집계 값을 산출하기 위한 그룹 함수이다.</li>
<li>지정 컬럼 수보다 하나 더 큰 레벨만큼의 중간 집계 값이 생성된다. </li>
<li>ROLLUP의 지정 컬럼은 계층별로 구성되기 때문에 순서가 바뀌면 수행 결과가 바뀐다. </li>
</ul>
<pre><code class="language-sql">SELECT 컬럼1, 컬럼2, ..., 집계 함수
FROM 테이블명
[WHERE ...]
GROUP BY [컬럼...] ROLLUP 컬럼
[HAVING ...]
[ORDER BY ...]</code></pre>
<p><strong>SELECT 뒤에 포함되는 컬럼이 GROUP BY 또는 ROLLUP 뒤에 기재되어야 한다.</strong></p>
<ul>
<li><strong>예시</strong><pre><code class="language-sql">SELECT DEPT, JOB, SUM(SALARY)
FROM DEPT_SALARY
GROUP BY ROLLUP(DEPT, JOB);</code></pre>
</li>
</ul>
<h3 id="32-cube-함수">3.2 CUBE 함수</h3>
<ul>
<li>CUBE는 결합 가능한 모든 값에 대해 다차원 집계를 생성하는 그룹 함수 이다. </li>
<li>연산이 많아 시스템에 부담을 준다. </li>
</ul>
<pre><code class="language-sql">SELECT 컬럼1, 컬럼2, ..., 집계 함수
FROM 테이블명
[WHERE ...]
GROUP BY [컬럼...] CUBE(컬럼명 a, ..)
[HAVING ...]
[ORDER BY ...]</code></pre>
<h3 id="33-grouping-sets-함수">3.3 GROUPING SETS 함수</h3>
<ul>
<li>집계 대상 컬럼들에 대한 개별 집계를 구할 수 있으며, ROLLUP이나 CUBE와는 달리 컬럼 간 순서와 무관한 결과를 얻을 수 있는 그룹함수이다. </li>
<li>다양한 소계 집합을 만들 수 있다. </li>
<li>ORDER BY를 사용해서 집계 대상 그룹과의 표시 순서를 조정하여 체계적으로 보여줄 수 있다. </li>
<li>계층구조와 달리 인수들이 평등한 관계라 순서에 상관없이 동일한 결과를 볼 수 있다. <pre><code class="language-sql">SELECT 컬럼1, 컬럼2, ..., 집계 함수
FROM 테이블명
[WHERE ...]
GROUP BY [컬럼...] GROUPING SETS(컬럼명 a, ..)
[HAVING ...]
[ORDER BY ...]</code></pre>
</li>
<li>GROUPINT SETS 함수 사용시 UNION ALL을 사용한 일반 그룹함수를 사용한 SQL과 같은 결과를 얻을 수 있으며, 괄호로 묶은 집합 별로 집계를 구할 수 있다. </li>
<li>GROUPING SETS의 경우 일반 그룹함수를 이용한 SQL과 결과 데이터는 같으나 행들의 정렬 순서는 다를 수 있다. </li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[제 4절 서브쿼리(Sub-Query)]]></title>
            <link>https://velog.io/@suyeon-jung/%EC%A0%9C-4%EC%A0%88-%EC%84%9C%EB%B8%8C%EC%BF%BC%EB%A6%ACSub-Query</link>
            <guid>https://velog.io/@suyeon-jung/%EC%A0%9C-4%EC%A0%88-%EC%84%9C%EB%B8%8C%EC%BF%BC%EB%A6%ACSub-Query</guid>
            <pubDate>Sat, 13 Nov 2021 14:12:53 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>SQL 문 안에 포함된 또 다른 SQL 문이다. </p>
</blockquote>
<ul>
<li><strong>주의사항</strong><ul>
<li>서브쿼리를 괄호로 감싸서 사용한다.</li>
<li>서브쿼리는 단일 행 또는 복수 행 비교 연산자와 함께 사용 가능하다.</li>
<li>서브쿼리에서는 ORDER BY 절을 사용하지 못한다. ORDER BY 절은 SELECT 절에서 오직 한 개만 올 수 있기 때문에 ORDER BY 절은 메인 쿼리의 마지막 문장에 위치해야 한다. </li>
</ul>
</li>
</ul>
<ul>
<li><strong>서브쿼리가 SQL 문에서 사용 가능한 곳</strong><ul>
<li>SELECT 절
<strong>스칼라 서브쿼리</strong>는 한 행, 한 컬럼만을 반환하는 서브쿼리이다. 
<img src="https://images.velog.io/images/suyeon-jung/post/dc21523a-6829-42b4-b2b5-830bfab089c5/image.png" alt="">
결과가 2건 이상 반환되면 SQL 문은 오류를 반환한다. </li>
<li>FROM 절
FROM 절에서 사용되는 서브쿼리를 <strong>인라인 뷰</strong>라고 한다. 
인라인 뷰는 SQL문이 실행될 때 임시적으로 생성되는 동적인 뷰이기 때문에 데이터베이스에 해당 정보가 저장되지 않는다. 그래서 일반적인 뷰를 정적뷰라고 하고 인라인 뷰를 동적뷰라고 한다. </li>
<li>WHERE 절</li>
<li>HAVING 절
그룹함수와 함께 사용될때 그룹핑된 결과에 대해 부가적인 조건을 주기 위해 사용한다. </li>
<li>ORDER BY 절</li>
<li>INSERT 문의 VALUES 절</li>
<li>UPDATE 문의 SET 절</li>
</ul>
</li>
</ul>
<ul>
<li><strong>서브쿼리의 유형</strong><ul>
<li>동작 방식에 따른 서브쿼리의 종류 
<img src="https://images.velog.io/images/suyeon-jung/post/0efb678b-6236-4992-9d30-424e194b94f0/image.png" alt=""></li>
<li>반환되는 데이터의 형태에 따른 서브쿼리의 종류
<img src="https://images.velog.io/images/suyeon-jung/post/1ca3d641-65a7-449a-90d4-83fb33368f9f/image.png" alt=""></li>
<li>위치 기준</li>
</ul>
</li>
</ul>
<h4 id="1-단일행-서브쿼리">1. 단일행 서브쿼리</h4>
<p>서브쿼리가 단일 행 비교 연산자(=, &lt;, &lt;=, &gt;, &gt;=, &lt;&gt;)와 함께 사용할 때 서브쿼리의 결과 건수가 반드시 1건 이하여야 한다. 
<img src="https://images.velog.io/images/suyeon-jung/post/3d5584aa-d568-4e68-b983-a8242a1baef5/image.png" alt=""><img src="https://images.velog.io/images/suyeon-jung/post/d7565aaf-d73b-4895-a7a4-e9b3e05168a2/image.png" alt=""></p>
<h4 id="2-다중행-서브쿼리">2. 다중행 서브쿼리</h4>
<p><img src="https://images.velog.io/images/suyeon-jung/post/809dd1cc-6c5c-4578-a644-b9c1d1a90c62/image.png" alt=""></p>
<h4 id="3-다중-컬럼-서브쿼리">3. 다중 컬럼 서브쿼리</h4>
<p>서브쿼리의 결과로 여러 개의 컬럼이 반환되어 메인쿼리의 조건과 동시에 비교되는 것을 의미한다. </p>
<h4 id="4-연관-서브쿼리">4. 연관 서브쿼리</h4>
<p>연관 서브쿼리는 서브쿼리 내에 메인쿼리 컬럼이 사용된 서브쿼리이다. </p>
<h4 id="뷰">뷰</h4>
<p>테이블은 실제로 데이터를 가지고 있는 반면 뷰는 실제 데이터를 가지고 있지 않다. 
뷰는 단지 뷰 정의만을 가지고 있다. 질의에서 뷰가 사용되면 뷰 정의를 참조해서 DBMS 내부적으로 질의를 재작성하여 질의를 수행한다. 뷰는 실제 데이터를 가지고 있지 않지만 테이블이 수행하는 역할을 수행하기 때문에 <strong>가상 테이블</strong>이라고도 한다. </p>
<p><img src="https://images.velog.io/images/suyeon-jung/post/9a228221-c901-4aeb-a5cb-0026cd82b6d5/image.png" alt=""></p>
<ul>
<li><p>뷰 생성</p>
<pre><code class="language-sql">CREATE VIEW [뷰 이름] AS
[SELECT 문];</code></pre>
</li>
<li><p>뷰 삭제</p>
<pre><code class="language-sql">DROP VIEW [뷰 이름];</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[제 3절 계층형 질의와 셀프 조인]]></title>
            <link>https://velog.io/@suyeon-jung/%EC%A0%9C-3%EC%A0%88-%EA%B3%84%EC%B8%B5%ED%98%95-%EC%A7%88%EC%9D%98%EC%99%80-%EC%85%80%ED%94%84-%EC%A1%B0%EC%9D%B8</link>
            <guid>https://velog.io/@suyeon-jung/%EC%A0%9C-3%EC%A0%88-%EA%B3%84%EC%B8%B5%ED%98%95-%EC%A7%88%EC%9D%98%EC%99%80-%EC%85%80%ED%94%84-%EC%A1%B0%EC%9D%B8</guid>
            <pubDate>Sat, 13 Nov 2021 13:50:39 GMT</pubDate>
            <description><![CDATA[<h2 id="1-계층형-질의">1. 계층형 질의</h2>
<p>테이블에 계층형 데이터가 존재하는 경우 데이터를 조회하기 위해 계층형 질의(Hierarchical Query) 사용</p>
<h4 id="계층형-데이터">계층형 데이터</h4>
<p>동일 테이블에 계층적으로 <strong>상위와 하위 데이터</strong>가 포함된 데이터, 엔티티를 순환관계 데이터 모델로 설계할 경우 계층형 데이터 발생
<img src="https://images.velog.io/images/suyeon-jung/post/5a944b7c-dc77-44bd-9708-7c60d58a6127/image.png" alt=""></p>
<ul>
<li>루트 노드(루트 데이터)
가장 최상위의 데이터</li>
<li>리프 노드(리프 데이터)
가장 최하위의 데이터</li>
</ul>
<h4 id="기본적인-계층형-질의-형태">기본적인 계층형 질의 형태</h4>
<pre><code class="language-sql">SELECT ...
FROM ...
WHERE 조건
START WITH 조건
CONNECT BY [NOCYCLE] 조건
[ORDER SIBLINGS BY 컬럼명1, 컬럼명2...];</code></pre>
<h4 id="가-oracle-계층형-질의">가. Oracle 계층형 질의</h4>
<table>
<thead>
<tr>
<th>구문</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>START WITH 절</td>
<td>데이터의 전개가 시작될 데이터를 지정</td>
</tr>
<tr>
<td>CONNECT BY 절</td>
<td>자식 데이터 지정</td>
</tr>
<tr>
<td>PRIOR</td>
<td>- CONNECT BY 절에서 사용<br/> - PRIOR 자식=부모 형태는 부모에서 자식 방향으로 데이터 전개(순방향)<br/> - PRIOR 부모=자식 형태는 자식에서 부모 방향으로 데이터 전개(역방향)</td>
</tr>
<tr>
<td>NOCYCLE</td>
<td>데이터를 전개하는 도중 동일 데이터가 다시 나타나면 CYCLE이 발생했다고 함 <br/> CYCLE이 발생한 데이터 이후 데이터를 전개하면 런타임 오류가 발생 <br/> NOCYCLE을 추가하면 CYCLE이 발생한 이후의 데이터는 전개하지 않아 오류 발생하지 않음</td>
</tr>
<tr>
<td>WHERE 절</td>
<td>모든 데이터 전개를 수행한 후 지정된 조건을 만족하는 데이터만을 추출</td>
</tr>
</tbody></table>
<ul>
<li>계층형 질의에서 사용되는 <strong>가상 컬럼</strong></li>
</ul>
<table>
<thead>
<tr>
<th>구문</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>LEVEL</td>
<td>전개과정에서 루트 데이터이면 1, 그 하위 데이터이면 2/루트에서 리프로 내려갈때 1씩 증가</td>
</tr>
<tr>
<td>CONNECT_BY_ISLEAF</td>
<td>전개과정에서 해당 데이터가 리프 데이터이면 1, 그렇지 않으면 0</td>
</tr>
<tr>
<td>CONNECT_BY_ISCYCLE</td>
<td>전개과정에서 해당 데이터가 조상으로서 존재하면(자식이 존재하면) 1, 그렇지 않으면 0, CYCLE 옵션을 사용할때만 사용 가능</td>
</tr>
</tbody></table>
<ul>
<li>계층형 질의에서 사용되는 함수</li>
</ul>
<table>
<thead>
<tr>
<th>함수</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>SYS_CONNECT_BY_PATH</td>
<td>루트 데이터로부터 현재 위치까지 전개할 데이터의 경로 표시<br/>SYS_CONNECT_BY_PATH(컬럼명, 경로분리기호)</td>
</tr>
<tr>
<td>CONNECT_BY_ROOT</td>
<td>현재 전개할 데이터의 루트 데이터 표시<br/>CONNECT_BY_ROOT(컬럼명)</td>
</tr>
</tbody></table>
<h4 id="나-sql-server-계층형-질의">나. SQL Server 계층형 질의</h4>
<p>2000 버전 까지는 계층형 질의를 작성할 수 있는 문법을 지원하지 않았다. 
조직도처럼 계층적 구조를 가진 데이터는 저장 프로시저를 재귀 호출하거나 While 루프 문에서 임시 테이블을 사용하는 등 순수한 쿼리가 아닌 프로그램 방식으로 전개한다. 
하지만 SQL Server 2005 버전부터 하나의 질의로 원하는 결과를 얻을 수 있다. </p>
<ul>
<li>재귀적 쿼리의 처리 과정</li>
</ul>
<ol>
<li>CTE 식을 앵커 멤버와 재귀 멤버로 분할</li>
<li>앵커 멤버를 실행하여 첫 번째 호출 또는 기본 결과 집합 생성</li>
<li>Ti는 입력으로 사용하고 Ti+1은 출력으로 사용하여 재귀 멤버 실행</li>
<li>빈 집합이 반환될 때까지 3단계 반봅</li>
<li>결과 집합을 반환. 이것을 T0~Tn까지 UNION ALL</li>
</ol>
]]></description>
        </item>
    </channel>
</rss>