<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>프리니의 코드저장소</title>
    <link>https://onyodev.tistory.com/</link>
    <description>공부한 내용 정리하는 중  </description>
    <language>ko</language>
    <pubDate>Fri, 26 Jun 2026 10:45:47 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Frinee</managingEditor>
    <image>
      <title>프리니의 코드저장소</title>
      <url>https://tistory1.daumcdn.net/tistory/6851063/attach/22a67511d79246b1aac8be11936a9821</url>
      <link>https://onyodev.tistory.com</link>
    </image>
    <item>
      <title>[Java] 중첩 클래스(Nested class)</title>
      <link>https://onyodev.tistory.com/73</link>
      <description>&lt;h2&gt;1. 중첩 클래스, 내부 클래스란?&lt;/h2&gt;
&lt;p&gt;다음과 같이 클래스 안에 클래스를 중첩해서 정의한 것을 &lt;strong&gt;중첩 클래스(Nested Class)&lt;/strong&gt;라 한다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class Outer {
    ...
    // 중첩 클래스
    class Nested {
        ...
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image-20250709140533121.png&quot; data-origin-width=&quot;867&quot; data-origin-height=&quot;784&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1NasJ/btsPx1buwdH/Ef6CqdybO4IIL1Kw7SgaL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1NasJ/btsPx1buwdH/Ef6CqdybO4IIL1Kw7SgaL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1NasJ/btsPx1buwdH/Ef6CqdybO4IIL1Kw7SgaL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1NasJ%2FbtsPx1buwdH%2FEf6CqdybO4IIL1Kw7SgaL0%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;547&quot; height=&quot;495&quot; data-filename=&quot;image-20250709140533121.png&quot; data-origin-width=&quot;867&quot; data-origin-height=&quot;784&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;중첩 클래스는 총 4가지가 있고, 크게 2가지로 분류한다.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;정적 중첩 클래스&lt;/li&gt;
&lt;li&gt;내부 클래스 종류&lt;ul&gt;
&lt;li&gt;내부 클래스&lt;/li&gt;
&lt;li&gt;지역 클래스&lt;/li&gt;
&lt;li&gt;익명 클래스&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;중첩 클래스의 선언 위치&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;정적 중첩 클래스 → 정적 변수와 같은 위치&lt;/li&gt;
&lt;li&gt;내부 클래스 → 인스턴스 변수와 같은 위치&lt;/li&gt;
&lt;li&gt;지역 클래스 → 지역 변수와 같은 위치&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;class Outer {
    ...
    // 정적 중첩 클래스
    static class StaticNested {
        ...
    }

    // 내부 클래스
    class Inner {
        ...
    }

}&lt;/code&gt;&lt;/pre&gt;&lt;h4&gt;중첩 vs 내부&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;중첩(Nested)&lt;/strong&gt;: &lt;strong&gt;어떤 다른 것&lt;/strong&gt;이 내부에 위치하거나 포함되는 구조적인 관계 (엄연히 다른 관계)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;내부(Inner)&lt;/strong&gt;: 나의 내부에 있는 나를 구성하는 요소&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;2. 정적 중첩 클래스&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;public class NestedOuter {
    private static int outClassValue = 3;
    private int outInstanceValue = 2;

    static class Nested {
        private int nestedInstanceValue = 1;

        public void print() {
            // 자신의 멤버에 접근
            System.out.println(nestedInstanceValue);

            // 바깥 클래스의 인스턴스 멤버에는 접근할 수 없다.
            //System.out.println(outInstanceValue);

            // 바깥 클래스의 클래스 멤버에는 접근할 수 있다. private도 접근 가능
            System.out.println(NestedOuter.outClassValue);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;823&quot; data-origin-height=&quot;285&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7OFjY/btsPzVtPILH/rmZS0VSChrAhYMRk7y2TZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7OFjY/btsPzVtPILH/rmZS0VSChrAhYMRk7y2TZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7OFjY/btsPzVtPILH/rmZS0VSChrAhYMRk7y2TZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7OFjY%2FbtsPzVtPILH%2FrmZS0VSChrAhYMRk7y2TZ1%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;823&quot; height=&quot;285&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;823&quot; data-origin-height=&quot;285&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;정적 중첩 클래스는&lt;ul&gt;
&lt;li&gt;자신의 멤버 접근 → O&lt;/li&gt;
&lt;li&gt;바깥 클래스의 인스턴스 멤버 → X&lt;/li&gt;
&lt;li&gt;바깥 클래스의 클래스 멤버 → O&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;public class NestedOuterMain {
    public static void main(String[] args) {
        NestedOuter outer = new NestedOuter(); // (1)
        NestedOuter.Nested nested = new NestedOuter.Nested();  // (2)
        nested.print();

        System.out.println(&amp;quot;nestedClass = &amp;quot; + nested.getClass());
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;정적 중첩 클래스는 &lt;code&gt;new 외부클래스.중첩클래스()&lt;/code&gt;로 생성&lt;/li&gt;
&lt;li&gt;사실 (1) 과 (2)는 관련 없는 다른 인스턴스이다.&lt;/li&gt;
&lt;li&gt;사실 정적 중첩 클래스와 외부 클래스는 아무런 관련이 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3. 내부 클래스&lt;/h2&gt;
&lt;p&gt;정적 중첩 클래스는 바깥 클래스와 서로 관계가 없다. 하지만 내부 클래스는 바깥 클래스의 인스턴스를 이루는 요소가 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package nested.inner.ex2;

public class Car {
    private String model;
    private int chargeLevel;
    private Engine engine;

    public Car(String model, int chargeLevel) {
        this.model = model;
        this.chargeLevel = chargeLevel;
        this.engine = new Engine();
    }

    public void start() {
        engine.start();
        System.out.println(model + &amp;quot; 시작 완료&amp;quot;);
    }

    private class Engine {
        public void start() {
            System.out.println(&amp;quot;충전 레벨 확인: &amp;quot; + chargeLevel);
            System.out.println(model + &amp;quot;의 엔진을 구동합니다.&amp;quot;);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;내부 클래스는 앞에 &lt;code&gt;static&lt;/code&gt;이 붙지 않는다. 쉽게 이야기해서 인스턴스 멤버가 된다.&lt;/li&gt;
&lt;li&gt;내부 클래스는&lt;ul&gt;
&lt;li&gt;자신의 멤버 접근 → O&lt;/li&gt;
&lt;li&gt;바깥 클래스의 인스턴스 멤버 → O&lt;/li&gt;
&lt;li&gt;바깥 클래스의 클래스 멤버 → O&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;package nested.inner;

public class InnerOuterMain {
    public static void main(String[] args) {
        InnerOuter outer = new InnerOuter();
        InnerOuter.Inner inner = outer.new Inner();
        inner.print();
        System.out.println(&amp;quot;innerClass = &amp;quot; + inner.getClass());
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;내부 클래스는 바깥 클래스 인스턴스의 소속되기 때문에 바깥 인스턴스 정보를 알아야 생성 가능&lt;/li&gt;
&lt;li&gt;내부 클래스는 &lt;code&gt;바깥클래스의 인스턴스 참조.new 내부클래스()&lt;/code&gt;로 생성할 수 있음.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;outer.new Inner()&lt;/code&gt;에서 &lt;code&gt;outer&lt;/code&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;792&quot; data-origin-height=&quot;598&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bh5dbN/btsPzRSwjwj/4RGxz6tTBLQfVUb8M3lwak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bh5dbN/btsPzRSwjwj/4RGxz6tTBLQfVUb8M3lwak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bh5dbN/btsPzRSwjwj/4RGxz6tTBLQfVUb8M3lwak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbh5dbN%2FbtsPzRSwjwj%2F4RGxz6tTBLQfVUb8M3lwak%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;458&quot; height=&quot;346&quot; data-origin-width=&quot;792&quot; data-origin-height=&quot;598&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;실제로 내부 인스턴스가 바깥 인스턴스 안에 생성되지는 않지만 개념상 안에 생성된다고 이해해도 된다.&lt;/li&gt;
&lt;li&gt;내부 인스턴스는 바깥 인스턴스 참조를 보관하여 바깥 인스턴스 멤버에 접근 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;중첩 클래스 사용&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;언제 사용해야 하나?&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;중첩 클래스는 특정 클래스가 다른 하나의 클래스 안에서만 사용되거나, 둘이 아주 긴밀하게 연결되어 있는 특별한 경우에만 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;사용하는 이유&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;논리적 그룹화&lt;/strong&gt;: 특정 클래스가 다른 하나의 클래스 안에서만 사용되는 경우 해당 클래스 안에 포함하는 것이 논리적으로 그룹화가 된다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;캡슐화&lt;/strong&gt;: 중첩 클래스는 바깥 클래스의 &lt;code&gt;private&lt;/code&gt; 멤버에 접근할 수 있다. 이렇게 해서 둘을 긴밀하게 연결하고 불필요한 &lt;code&gt;public&lt;/code&gt; 메서드를 제거할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;4. 같은 이름의 바깥 변수 접근&lt;/h2&gt;
&lt;p&gt;변수의 이름이 같은 경우, 더 가깝거나 구체적인 것에 우선권을 가진다.&lt;/p&gt;
&lt;p&gt;인스턴스의 참조 &lt;code&gt;this.value&lt;/code&gt; 나 &lt;code&gt;바깥클래스이름.this&lt;/code&gt; 를 활용해서 바깥클래스 인스턴스에 접근 가능&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package nested;

public class ShadowingMain {

    public int value = 1;

    class Inner {
        public int value = 2;

        void go() {
            int value = 3;
            System.out.println(&amp;quot;value = &amp;quot; + value);
            System.out.println(&amp;quot;this.value = &amp;quot; + this.value);
            System.out.println(&amp;quot;ShadowingMain.value = &amp;quot; + ShadowingMain.this.value);
        }
    }

    public static void main(String[] args) {
        ShadowingMain main = new ShadowingMain();
        Inner inner = main.new Inner();
        inner.go();
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;5. 지역 클래스&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;지역 클래스는 내부 클래스의 특별한 종류 중 하나이며 내부 클래스의 특징을 그대로 가진다.&lt;/li&gt;
&lt;li&gt;지역 클래스는 지역 변수와 같이 코드 블럭 안에서 정의&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;class Outer {
    public void process() {
        //지역 변수
        int localVar = 0;

        //지역 클래스
        class Local {...}

        Local local = new Local();
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;지역 클래스는 지역 변수처럼 코드 블럭 안에 클래스를 선언&lt;/li&gt;
&lt;li&gt;지역 클래스는 지역 변수에 접근할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;public class LocalOuterV1 {
    private int outInstanceVar = 3;
    public void process(int paramVar) {
        int localVar = 1;

        class LocalPrinter {
            int value = 0;

            public void printData() {
                System.out.println(&amp;quot;value=&amp;quot; + value);
                System.out.println(&amp;quot;localVar=&amp;quot; + localVar);
                System.out.println(&amp;quot;paramVar=&amp;quot; + paramVar);
                System.out.println(&amp;quot;outInstanceVar=&amp;quot; + outInstanceVar);
            }
        }
        LocalPrinter printer = new LocalPrinter();
        printer.printData();
    }
    public static void main(String[] args) {
        LocalOuterV1 localOuter = new LocalOuterV1();
        localOuter.process(2);
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;h4&gt;지역 클래스의 접근 범위&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;자신의 인스턴스 변수인 &lt;code&gt;value&lt;/code&gt;에 접근 가능&lt;/li&gt;
&lt;li&gt;자신이 속한 코드 블럭의 지역변수 &lt;code&gt;localVar&lt;/code&gt;에 접근 가능&lt;/li&gt;
&lt;li&gt;자신이 속한 코드 블럭의 매개변수인 &lt;code&gt;paramVar&lt;/code&gt; 에 접근할 수 있다. 참고로 매개변수도 지역 변수의 한 종류이다.&lt;/li&gt;
&lt;li&gt;바깥 클래스의 인스턴스 멤버인 &lt;code&gt;outInstanceVar&lt;/code&gt; 에 접근할 수 있다. (지역 클래스도 내부 클래스의 한 종류이다.)&lt;/li&gt;
&lt;li&gt;지역 클래스는 지역 변수처럼 접근 제어자를 사용할 수 없음.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;6. 지역 클래스 - 지역 변수 캡처&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;클래스 변수, 인스턴스 변수, 지역 변수는 각각의 생명주기가 다르다.&lt;/li&gt;
&lt;li&gt;그렇기 때문에 메서드를 통해 지역 변수에 접근하려 할 때, 이미 생명 주기 상으로 지역변수가 제거되어 접근할 수 없는 경우도 생긴다.&lt;/li&gt;
&lt;li&gt;그렇지만 우리는 지역변수의 값들을 모두 정상적으로 출력할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;→ 이게 가능한 이유가 바로 자바의 &amp;quot;변수 캡처&amp;quot; 기능&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;지역 클래스의 인스턴스를 생성하는 시점에 필요한 지역 변수를 복사해서 생성한 인스턴스에 함께 넣어둠.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;그렇기 때문에 지역변수는 절대로 중간에 값이 변해서는 안된다.&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;지역변수는 &lt;strong&gt;&lt;code&gt;final&lt;/code&gt;&lt;/strong&gt;로 선언하거나 &lt;strong&gt;사실상 &lt;code&gt;final&lt;/code&gt;(effectively final)&lt;/strong&gt;이어야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;7. 익명 클래스&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;익명 클래스는 지역 클래스인데 클래스의 이름이 없다는 특징이 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;

public class AnonymousOuter {
    private int outInstanceVar = 3;

    public void process(int paramVar) {
        int localVar = 1;

        // 지역 클래스의 선언과 생성을 한번에 수행
        Printer printer = new Printer() {
            int value = 0;

            @Override
            public void print() {
                System.out.println(&amp;quot;value=&amp;quot; + value);
                System.out.println(&amp;quot;localVar=&amp;quot; + localVar);
                System.out.println(&amp;quot;paramVar=&amp;quot; + paramVar);
                System.out.println(&amp;quot;outInstanceVar=&amp;quot; + outInstanceVar);
            }
        };

        printer.print();
        System.out.println(&amp;quot;printer.class=&amp;quot; + printer.getClass());
    }

    public static void main(String[] args) {
        AnonymousOuter main = new AnonymousOuter();
        main.process(2);
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;익명 클래스는 부모 클래스를 상속받거나 또는 인터페이스를 구현해야 한다.&lt;ul&gt;
&lt;li&gt;익명 클래스는 상위 클래스나 인터페이스가 필요함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이름을 가지지 않기 때문에 생성자를 가질 수 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;장점&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;클래스를 별도로 정의하지 않고도 인터페이스나 추상 클래스를 즉석에서 구현할 수 있어 코드가 간결해짐.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;&lt;strong&gt;조건&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;익명 클래스는 단 한 번만 인스턴스를 생성할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;람다(lambda)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;자바8 이전 메서드에 인수로 전달할 수 있는 것은 기본형 타입이나 참조형 타입이 다였음.&lt;/li&gt;
&lt;li&gt;자바8 이후 메서드를 인수로 전달할 수 있게 되었음. 이것을 &lt;strong&gt;람다(Lambda)&lt;/strong&gt;라 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;package nested.anonymous.ex;

import java.util.Random;

// 람다 사용
public class Ex1RefMainV5 {
    public static void hello(Process process) {
        System.out.println(&amp;quot;프로그램 시작&amp;quot;);
        //코드 조각 시작
        process.run();
        //코드 조각 종료
        System.out.println(&amp;quot;프로그램 종료&amp;quot;);
    }

    public static void main(String[] args) {
        hello(() -&amp;gt; {
            int randomValue = new Random().nextInt(6) + 1;
            System.out.println(&amp;quot;주사위 = &amp;quot; + randomValue);
        });

        hello(() -&amp;gt; {
            for (int i = 1; i &amp;lt;= 3; i++) {
                System.out.println(&amp;quot;i = &amp;quot; + i);
            }
        });
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;클래스나 인스턴스를 정의하지 않고, 메서드의 코드 블럭을 직접 전달함.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Backend/Java</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/73</guid>
      <comments>https://onyodev.tistory.com/73#entry73comment</comments>
      <pubDate>Fri, 25 Jul 2025 13:24:33 +0900</pubDate>
    </item>
    <item>
      <title>[Java] Generics, Enum, Annotation</title>
      <link>https://onyodev.tistory.com/72</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 제네릭스(Generics)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.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;객체의 타입을 컴파일 시에 체크하기 때문에 객체의 타입 안정성을 높이고 형변환의 번거로움을 줄여줌.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;제네릭스의 장점&lt;/b&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;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.2. 제네릭 클래스의 선언&lt;/h3&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// 여기서 T는 임의의 참조형 타입이다. 
// T에 원하는 타입을 지정하여 사용할 수 있다.
class Box&amp;lt;T&amp;gt; {
	T item;
	
	void setItem(T item) { this.item = item; }
	T getItem() { return item;}
}

Box&amp;lt;String&amp;gt; b = new Box&amp;lt;String&amp;gt;();  // 타입 T 대신 실제 타입 지정
b.setItem(new Object());            // 에러, 지정한 String 외에는 지정불가
b.setItem(&quot;ABC&quot;);                   // OK
String item = (String)b.getItem(); // 형변환이 필요없음&lt;/code&gt;&lt;/pre&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;/li&gt;
&lt;li&gt;타입 변수 T에 Object타입을 지정하면, 경고가 발생하지 않음&lt;/li&gt;
&lt;/ul&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;865&quot; data-origin-height=&quot;383&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o3Ro7/btsMm0Fnhpj/V22aHnCm4VXG17Ha3TtyvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o3Ro7/btsMm0Fnhpj/V22aHnCm4VXG17Ha3TtyvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o3Ro7/btsMm0Fnhpj/V22aHnCm4VXG17Ha3TtyvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo3Ro7%2FbtsMm0Fnhpj%2FV22aHnCm4VXG17Ha3TtyvK%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;332&quot; height=&quot;147&quot; data-origin-width=&quot;865&quot; data-origin-height=&quot;383&quot;/&gt;&lt;/span&gt;&lt;/figure&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Box&amp;lt;T&amp;gt; : 제네릭 클래스, &amp;lsquo;T의 Box&amp;rsquo; 또는 &amp;lsquo;T Box&amp;rsquo;라고 읽는다.&lt;/li&gt;
&lt;li&gt;T : 타입 변수 또는 타입 매개변수. (T는 타입 문자)&lt;/li&gt;
&lt;li&gt;Box : 원시 타입(raw type)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;제네릭스 제한
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;T는 인스턴스변수로 간주되기 때문에 모든 객체에 대해 동일하게 동작해야 하는 static멤버에 타입 변수 T를 사용할 수 없음&lt;/li&gt;
&lt;li&gt;제네릭 타입의 배열 선언은 가능하나 배열을 생성하는 것은 허용되지 않음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;new 연산자는 컴파일 시점에 타입을 정확하게 알고 있어야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.3. 제네릭 클래스의 객체 생성과 사용&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;/li&gt;
&lt;li&gt;JDK1.7부터는 추정이 가능한 경우 타입을 생략할 수 있게 됨.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1739847941411&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Box&amp;lt;Apple&amp;gt; appleBox = new Box&amp;lt;&amp;gt;();  // JDK1.7부터 가능&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1739847930031&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Box&amp;lt;Apple&amp;gt; appleBox = new Box&amp;lt;Apple&amp;gt;();  // OK
Box&amp;lt;Apple&amp;gt; appleBox = new Box&amp;lt;Grape&amp;gt;();  // 에러
Box&amp;lt;Fruit&amp;gt; appleBox = new Box&amp;lt;Apple&amp;gt;();  // 에러&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.4. 제한된 제네릭 클래스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;타입 매개변수 T에 지정할 수 있는 타입의 종류를 제한하는 방법이 존재함.&lt;/li&gt;
&lt;li&gt;제네릭에 extends 를 사용하면 특정 타입의 자손들만 대입할 수 있게 제한할 수 있음.&lt;/li&gt;
&lt;li&gt;인터페이스를 구현하는 제약을 사용할 때에도 extends 를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;class FruitBox&amp;lt;T extends Fruit&amp;gt; {    // Fruit의 자손 타입만 지정가능
	ArrayList&amp;lt;T&amp;gt; list = new ArrayList&amp;lt;T&amp;gt;();
	...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.5. 와일드 카드&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;// 매개변수에 과일박스를 대입하면 주스를 만들어 반환하는 클래스
class Juicer { 
	static Juice makeJuice(FruitBox&amp;lt;Fruit&amp;gt; box) { 
		String tmp = &quot;&quot;;
		for(Fruit f : box.getList()) tmp += f + &quot; &quot;;
		return new Juice(tmp);
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 경우, 제네릭 타입을 FruitBox&amp;lt;Fruit&amp;gt; 로 고정해버리면 Apple 과 같은 다른 과일의 타입을 활용할 수 없는 문제가 발생&lt;/li&gt;
&lt;li&gt;이럴 때 사용하기 위해 고안된 것이 &lt;b&gt;와일드 카드&lt;/b&gt;이며 와일드 카드 기호는 &lt;b&gt;&amp;ldquo;?&amp;rdquo;&lt;/b&gt; 로 표현&lt;/li&gt;
&lt;li&gt;extends 와 super 로 제한할 수 있음.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;lt;? extends T&amp;gt; : 와일드 카드의 상한 제한. T와 그 자손들만 가능&lt;/li&gt;
&lt;li&gt;&amp;lt;? super T&amp;gt; : 와일드 카드의 하한 제한. T와 그 조상들만 가능&lt;/li&gt;
&lt;li&gt;&amp;lt;?&amp;gt; : 제한 없음. 모든 타입이 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.6. 제네릭 메서드&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;pre class=&quot;dart&quot;&gt;&lt;code&gt;// Collections.sort()
static &amp;lt;T&amp;gt; void sort(List&amp;lt;T&amp;gt; List, Comparator&amp;lt;? super T&amp;gt; c)

class FruitBox&amp;lt;T&amp;gt; {
		...
	static &amp;lt;T&amp;gt; void sort(List&amp;lt;T&amp;gt; list, Comparator&amp;lt;? super T&amp;gt; c){
		...
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 열거형(Enum)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1. 열거형(Enum)이란?&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;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;class Card {
	enum Kind { CLOVER, HEART, DIAMOND, SPADE }
	enum Value { TWO, THREE, FOUR }
	
	final Kind kind;
	final Value value;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2. 열거형의 정의와 사용&lt;/h3&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;enum 열거형이름 { 상수명1, 상수명2, ... }

enum Direction { EAST, SOUTH, WEST, NORTH }

class Unit {
	int x, y;
	Direction dir;
	
	void init() {
		dir = Driection.EAST;
	}
}
&lt;/code&gt;&lt;/pre&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;열거형의 메서드&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 135px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 39.4927%; text-align: center;&quot;&gt;메서드&lt;/td&gt;
&lt;td style=&quot;width: 60.3865%; text-align: center;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;height: 25px; width: 39.4927%;&quot;&gt;Class&amp;lt;E&amp;gt; getDeclaringClass()&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 60.3865%;&quot;&gt;열거형의 Class객체를 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;height: 25px; width: 39.4927%;&quot;&gt;String name()&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 60.3865%;&quot;&gt;열거형 상수의 이름을 문자열로 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;height: 25px; width: 39.4927%;&quot;&gt;int ordinal()&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 60.3865%;&quot;&gt;열거형 상수가 정의된 순서를 반환 (0부터 시작)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;height: 25px; width: 39.4927%;&quot;&gt;T valueOf(Class&amp;lt;T&amp;gt; enumType, String name)&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 60.3865%;&quot;&gt;지정된 열거형에서 name과 일치하는 열거형 상수를 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;height: 25px; width: 39.4927%;&quot;&gt;static E values()&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 60.3865%;&quot;&gt;열거형에 정의된 모든 상수를 출력&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;/ul&gt;
&lt;pre id=&quot;code_1739854158728&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;enum Direction { 
	EAST(1), SOUTH(5), WEST(-1), NORTH(10);
	
	private final int value;
	Direction(int value) { this.value = value; }
	public int getValue() { return value; } 
 }&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;3. 애너테이션(Annotation)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1. 애너테이션(Annotation)이란?&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;소스코드의 주석 /** ~ */ 에 소스코드에 대한 정보를 저장하고, 소스코드 주석으로부터 HTML문서를 생성하는 프로그램(javadoc.exe)을 만들어 사용함.&lt;/li&gt;
&lt;li&gt;이 기능을 응용해서 프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것이 &lt;b&gt;애너테이션&lt;/b&gt;이다.&lt;/li&gt;
&lt;li&gt;애너테이션은 주석처럼 프로그래밍 언어에 영향을 미치지 않으면서도 다른 프로그램에게 유용한 정보를 줄 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2. 표준 애너테이션&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 68px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 37.2093%; height: 17px; text-align: center;&quot;&gt;애너테이션&lt;/td&gt;
&lt;td style=&quot;width: 62.7907%; height: 17px; text-align: center;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 37.2093%; height: 17px;&quot;&gt;@Override&lt;/td&gt;
&lt;td style=&quot;width: 62.7907%; height: 17px;&quot;&gt;컴파일러에게 오버라이딩하는 메서드라는 것을 알린다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 37.2093%; height: 17px;&quot;&gt;@Deprecated&lt;/td&gt;
&lt;td style=&quot;width: 62.7907%; height: 17px;&quot;&gt;앞으로 사용하지 않을 것을 권장하는 대상에게 붙인다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 37.2093%; height: 17px;&quot;&gt;@SuppressWarnings&lt;/td&gt;
&lt;td style=&quot;width: 62.7907%; height: 17px;&quot;&gt;컴파일러의 특정 경고메시지가 나타나지 않게 해준다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 37.2093%;&quot;&gt;@SafeVarargs&lt;/td&gt;
&lt;td style=&quot;width: 62.7907%;&quot;&gt;지네릭스 타입의 가변인자에 사용한다. (JDK1.7)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 37.2093%;&quot;&gt;@FunctionalInterface&lt;/td&gt;
&lt;td style=&quot;width: 62.7907%;&quot;&gt;함수형 인터페이스라는 것을 알린다.(JDK1.8)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 37.2093%;&quot;&gt;@Native&lt;/td&gt;
&lt;td style=&quot;width: 62.7907%;&quot;&gt;native메서드에서 참조되는 상수 앞에 붙인다. (JDK1.8)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 85px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 37.5581%; height: 17px; text-align: center;&quot;&gt;&lt;span style=&quot;background-color: #2780d4; color: #ffffff; text-align: center;&quot;&gt;애너테이션&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 62.4419%; height: 17px; text-align: center;&quot;&gt;&lt;span style=&quot;background-color: #2780d4; color: #ffffff; text-align: center;&quot;&gt;설명&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 37.5581%; height: 17px;&quot;&gt;&lt;span style=&quot;background-color: #efefef; color: #333333; text-align: start;&quot;&gt;@Target&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 62.4419%; height: 17px;&quot;&gt;애너테이션이 적용가능한 대상을 지정하는데 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 37.5581%; height: 17px;&quot;&gt;&lt;span style=&quot;background-color: #efefef; color: #333333; text-align: start;&quot;&gt;@Documented&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 62.4419%; height: 17px;&quot;&gt;애너테이션 정보가 javadoc으로 작성된 문서에 포함되게 한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 37.5581%; height: 17px;&quot;&gt;@Inherited&lt;/td&gt;
&lt;td style=&quot;width: 62.4419%; height: 17px;&quot;&gt;애너테이션이 자손 클래스에 상속되도록 한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 37.5581%; height: 17px;&quot;&gt;@Retention&lt;/td&gt;
&lt;td style=&quot;width: 62.4419%; height: 17px;&quot;&gt;애너테이션이 유지되는 범위를 지정하는데 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 37.5581%;&quot;&gt;@Repeatable&lt;/td&gt;
&lt;td style=&quot;width: 62.4419%;&quot;&gt;애너테이션을 반복해서 적용할 수 있게 한다.(JDK1.8)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;애너테이션 요소 규칙&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;요소의 타입은 기본형, String, Enum, Annotation, Class만 허용&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;</description>
      <category>Backend/Java</category>
      <category>annotation</category>
      <category>Enum</category>
      <category>Generic</category>
      <category>Java</category>
      <category>프로그래밍</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/72</guid>
      <comments>https://onyodev.tistory.com/72#entry72comment</comments>
      <pubDate>Tue, 18 Feb 2025 14:08:56 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 예외 처리(exception handling)</title>
      <link>https://onyodev.tistory.com/71</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 프로그램 오류&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그램 오류(error): 프로그램 실행 중 어떤 원인에 의해서 오작동을 하거나 비정상적으로 종료되는 경우를 말함.&lt;/li&gt;
&lt;li&gt;에러의 종류
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴파일 에러(compile error): 컴파일 시 발생하는 에러&lt;/li&gt;
&lt;li&gt;런타임 에러(runtime error): 실행 시 발생하는 에러&lt;/li&gt;
&lt;li&gt;논리적 에러(logical error): 실행은 되지만, 의도와 다르게 동작하는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프로그램은 런타임 에러를 방지하기 위해 대비를 하는데 자바에서는 프로그램 오류를 에러(error)와 예외(exception)으로 구분함.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;에러(error): 프로그램 코드에 의해서 수습될 수 없는 심각한 오류&lt;/li&gt;
&lt;li&gt;예외(exception): 프로그램 코드에 의해서 수습될 수 있은 다소 미약한 오류&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 예외 클래스의 계층 구조&lt;/h2&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;Exception클래스: 사용자의 실수와 같은 외적인 요인에 의해 발생하는 예외&lt;/li&gt;
&lt;li&gt;RuntimeException클래스: 프로그래머의 실수로 발생하는 예외&lt;/li&gt;
&lt;/ul&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;1220&quot; data-origin-height=&quot;845&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beqlQZ/btsMfaA5R3R/G0pHMMkevHvMMR0n8JZqsk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beqlQZ/btsMfaA5R3R/G0pHMMkevHvMMR0n8JZqsk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beqlQZ/btsMfaA5R3R/G0pHMMkevHvMMR0n8JZqsk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeqlQZ%2FbtsMfaA5R3R%2FG0pHMMkevHvMMR0n8JZqsk%2Fimg.jpg&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;1220&quot; height=&quot;845&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;845&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IOException: 입출력 작업 중 발생하는 예외 (파일 읽기/쓰기, 네트워크 입출력 등)&lt;/li&gt;
&lt;li&gt;ClassNotFoundException: 클래스 파일을 찾을 수 없을 때 발생&lt;/li&gt;
&lt;li&gt;RuntimeException: 실행 중(Runtime)에 발생하는 예외들의 부모 클래스&lt;/li&gt;
&lt;li&gt;ArithmeticException: 수학적 연산 오류가 발생할 때 발생&lt;/li&gt;
&lt;li&gt;ClassCastException: 잘못된 형변환을 시도할 때 발생&lt;/li&gt;
&lt;li&gt;NullPointerException: null&amp;nbsp;값을 참조하려고 할 때 발생&lt;/li&gt;
&lt;li&gt;IndexOutOfBoundsException: 배열이나 리스트 등의 인덱스가 범위를 벗어날 때 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 예외 처리: try-catch&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예외처리(Exception Handling)
&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;/li&gt;
&lt;li&gt;예외를 처리하기 위해서는 try-catch문을 활용하며 그 구조는 다음과 같다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;try {
	// 예외가 발생할 가능성이 있는 문장을 넣는다.
} catch(Exception1 e1){
	// Exception1이 발생한 경우, 이를 처리하기 위한 문장을 넣는다.
} catch(Exception2 e2){
	// Exception2가 발생한 경우, 이를 처리하기 위한 문장을 적는다.
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 try블록 다음에는 여러 종류의 예외를 처리할 수 있도록 하나 이상의 catch블록이 올 수 있으며, 이 중 발생한 예외의 종류와 일치하는 단 한 개의 catch블록만 수행&lt;/li&gt;
&lt;li&gt;catch블록 안에 또 다른 try-catch블록을 사용할 경우, 변수명을 다르게 해줘야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1. try-catch문에서의 흐름&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;try블록 내에서 예외가 발생한 경우,
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;발생한 예외와 일치하는 catch블록이 있는지 확인&lt;/li&gt;
&lt;li&gt;일치하는 catch블록을 찾게 되면, 그 catch블록 내의 문장들을 수 행하고 전체 try-catch문을 빠져나가서 그 다음 문장을 계속해서 수행한다. 만일 일치하는 catch블록을 찾지 못하면, 예외는 처리되지 못한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;try블록 내에서 예외가 발생하지 않은 경우,
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;catch블록을 거치지 않고 전체 try-catch문을 빠져나가서 수행을 계속한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2. printStackTrace()와 getMessage()&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;printStackTrace(): 예외발생 당시의 호출(Call Stack)에 있었던 메서드의 정보와 예외 메시지를 화면에 출력한다.&lt;/li&gt;
&lt;li&gt;getMessage(): 발생한 예외클래스의 인스턴스에 저장된 메시지를 얻을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 예외 처리: 메서드에 예외 선언하기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메서드에 예외를 선언하려면, 메서드의 선언부에 키워드 throw를 사용해서 메서드 내에 발생할 수 있는 예외를 적어주면 됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;oxygene&quot;&gt;&lt;code&gt;void method() throws Exception1, Exception2, ... ExceptionN {
	// 메서드 내용
}
&lt;/code&gt;&lt;/pre&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;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. finally 블럭&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;finally 블럭은 예외 발생여부와 상관없이 실행되어야 할 코드를 포함시킬 목적으로 사용&lt;/li&gt;
&lt;li&gt;try-catch문의 끝에 선택적으로 덧붙여 사용할 수 있으며, try-catch-finally의 순서로 구성됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;mercury&quot;&gt;&lt;code&gt;try {
	// 예외가 발생할 가능성이 있는 문장들을 넣는다.
} catch (Exception1 e1) {
	// 예외처리를 위한 문장을 적는다.
} finally {
	// 예외의 발생 여부에 관계없이 항상 수행되어야 하는 문장들을 넣는다.
	// finally블럭은 try-catch문의 맨 마지막에 위치해야 한다.
}
&lt;/code&gt;&lt;/pre&gt;
&lt;div style=&quot;color: #37352f; text-align: start;&quot; data-block-id=&quot;19751caa-6b2d-804f-9e79-fbef53f5b3ba&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;</description>
      <category>Backend/Java</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/71</guid>
      <comments>https://onyodev.tistory.com/71#entry71comment</comments>
      <pubDate>Tue, 11 Feb 2025 21:07:30 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 컬렉션 프레임워크(Collections Framework)</title>
      <link>https://onyodev.tistory.com/70</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;컬렉션 프레임워크(Collections Framework)&lt;/b&gt;&lt;br /&gt;: 데이터 군을 저장하는 클래스들을 표준화한 설계를 뜻함. &lt;b&gt;컬렉션(Collection)&lt;/b&gt;은 다수의 데이터, 즉 데이터 그룹을, &lt;b&gt;프레임워크(Framework)&lt;/b&gt;는 표준화된 프로그래밍 방식을 말함.&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;1. 컬렉션 프레임워크의 핵심 인터페이스&lt;/h1&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;431&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBVJM5/btsMcyih4Dt/FHL1toRYJrGEJbACIiF590/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBVJM5/btsMcyih4Dt/FHL1toRYJrGEJbACIiF590/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBVJM5/btsMcyih4Dt/FHL1toRYJrGEJbACIiF590/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBVJM5%2FbtsMcyih4Dt%2FFHL1toRYJrGEJbACIiF590%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;673&quot; height=&quot;281&quot; data-origin-width=&quot;1033&quot; data-origin-height=&quot;431&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 121px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20.1163%; height: 17px; text-align: center;&quot;&gt;인터페이스&lt;/td&gt;
&lt;td style=&quot;width: 79.8837%; height: 17px;&quot;&gt;특징&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20.1163%; height: 34px; text-align: center;&quot; rowspan=&quot;2&quot;&gt;List&lt;/td&gt;
&lt;td style=&quot;width: 79.8837%; height: 17px;&quot;&gt;순서가 있는 데이터의 집합. 데이터의 중복을 허용함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 79.8837%; height: 17px;&quot;&gt;ex) ArrayList, LinkedList, Stack, Vector 등&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 20.1163%; height: 36px; text-align: center;&quot; rowspan=&quot;2&quot;&gt;Set&lt;/td&gt;
&lt;td style=&quot;width: 79.8837%; height: 19px;&quot;&gt;순서를 유지하지 않는 데이터의 집합. 데이터의 중복을 허용하지 않는다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 79.8837%; height: 17px;&quot;&gt;ex) HashSet, TreeSet 등&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20.1163%; height: 34px; text-align: center;&quot; rowspan=&quot;2&quot;&gt;Map&lt;/td&gt;
&lt;td style=&quot;width: 79.8837%; height: 17px;&quot;&gt;키(key)와 값(value)의 쌍(pair)으로 이루어진 데이터의 집합&lt;br /&gt;순서는 유지되지 않으며, 키는 중복을 허용하지 않고, 값은 중복을 허용한다.&lt;br /&gt;예) 우편번호, 지역번호(전화번호)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 79.8837%; height: 17px;&quot;&gt;ex) HashMap, TreeMap, Hashtable, Properties 등&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컬렉션 프레임워크의 모든 컬렉션 클래스들은 List, Set, Map 중 하나를 구현하고 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.1. Collection 인터페이스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;List와 Set의 조상인 Collection 인터페이스에는 다음과 같은 메서드들이 정의됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 173px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 36.6279%; text-align: center; height: 20px;&quot;&gt;메서드&lt;/td&gt;
&lt;td style=&quot;width: 63.3721%; text-align: center; height: 20px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 34px;&quot;&gt;
&lt;td style=&quot;width: 36.6279%; text-align: left; height: 34px;&quot;&gt;boolean add(Object o)&lt;br /&gt;boolean addAll(Collection c)&lt;/td&gt;
&lt;td style=&quot;width: 63.3721%; height: 34px;&quot;&gt;지정된 객체(o) 또는 Collection(c)의 객체들을 Collection에 추가한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 36.6279%; text-align: left; height: 17px;&quot;&gt;void Clear()&lt;/td&gt;
&lt;td style=&quot;width: 63.3721%; height: 17px;&quot;&gt;Collection의 모든 객체를 삭제한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 34px;&quot;&gt;
&lt;td style=&quot;width: 36.6279%; text-align: left; height: 34px;&quot;&gt;boolean contains(Object o)&lt;br /&gt;&lt;span style=&quot;background-color: #efefef; color: #333333; text-align: left;&quot;&gt;boolean containsAll(Collection c)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 63.3721%; height: 34px;&quot;&gt;지정된 객체(o) 또는 Collection(c)의 객체들이 Collection에 포함되어 있는지 확인한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 36.6279%; text-align: left; height: 17px;&quot;&gt;boolean equals(Object o)&lt;/td&gt;
&lt;td style=&quot;width: 63.3721%; height: 17px;&quot;&gt;동일한 Collection인지 비교한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 36.6279%; text-align: left; height: 17px;&quot;&gt;int hashCode()&lt;/td&gt;
&lt;td style=&quot;width: 63.3721%; height: 17px;&quot;&gt;Collection의 hash code를 반환한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 36.6279%; text-align: left; height: 17px;&quot;&gt;boolean isEmpty()&lt;/td&gt;
&lt;td style=&quot;width: 63.3721%; height: 17px;&quot;&gt;Collection이 비어있는지 확인한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 36.6279%; text-align: left; height: 17px;&quot;&gt;Iterator iterator()&lt;/td&gt;
&lt;td style=&quot;width: 63.3721%; height: 17px;&quot;&gt;Collection의 Iterator를 얻어서 반환한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 36.6279%; text-align: left;&quot;&gt;boolean remove(Object o)&lt;/td&gt;
&lt;td style=&quot;width: 63.3721%;&quot;&gt;지정된 객체를 삭제한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 36.6279%; text-align: left;&quot;&gt;boolean removeAll(Collection c)&lt;/td&gt;
&lt;td style=&quot;width: 63.3721%;&quot;&gt;지정된 Collection에 포함된 객체들을 삭제한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 36.6279%; text-align: left;&quot;&gt;int size()&lt;/td&gt;
&lt;td style=&quot;width: 63.3721%;&quot;&gt;Collection에 저장된 객체의 개수를 반환한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 36.6279%; text-align: left;&quot;&gt;Object[] toArray()&lt;/td&gt;
&lt;td style=&quot;width: 63.3721%;&quot;&gt;Collection에 저장된 객체를 객체배열(Object[])로 반환한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 36.6279%; text-align: left;&quot;&gt;Object[] toArray(Object[] a)&lt;/td&gt;
&lt;td style=&quot;width: 63.3721%;&quot;&gt;지정된 배열에 Collection의 객체를 저장해서 반환한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.2. List 인터페이스&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;986&quot; data-origin-height=&quot;565&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d3RQCi/btsMbUM1XKq/PekOaaQAVnKmPCVQe63XK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d3RQCi/btsMbUM1XKq/PekOaaQAVnKmPCVQe63XK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d3RQCi/btsMbUM1XKq/PekOaaQAVnKmPCVQe63XK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd3RQCi%2FbtsMbUM1XKq%2FPekOaaQAVnKmPCVQe63XK0%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;665&quot; height=&quot;381&quot; data-origin-width=&quot;986&quot; data-origin-height=&quot;565&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;List 인터페이스는 중복을 허용하면서 저장순서가 유지되는 컬렉션을 구현하는데 사용.&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 153px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 40.6976%; height: 17px; text-align: center;&quot;&gt;메서드&lt;/td&gt;
&lt;td style=&quot;width: 59.3024%; height: 17px; text-align: center;&quot;&gt;설명&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 40.6976%; height: 17px;&quot;&gt;void add(int index, Object element)&lt;br /&gt;boolean addAll(int index,Collection c)&lt;/td&gt;
&lt;td style=&quot;width: 59.3024%; height: 17px;&quot;&gt;지정된 위치(index)에 객체(element) 또는 컬렉션에 포함된 객체들을 추가한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 40.6976%; height: 17px;&quot;&gt;Object get(int index)&lt;/td&gt;
&lt;td style=&quot;width: 59.3024%; height: 17px;&quot;&gt;지정된 위치(index)에 있는 객체를 반환한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 40.6976%; height: 17px;&quot;&gt;int indexOf(Object o)&lt;/td&gt;
&lt;td style=&quot;width: 59.3024%; height: 17px;&quot;&gt;지정된 객체의 위치(index)를 반환한다.&lt;br /&gt;(List의 첫번째 요소로부터 순방향으로 찾는다.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 40.6976%; height: 17px;&quot;&gt;int lastIndexOf(Object o)&lt;/td&gt;
&lt;td style=&quot;width: 59.3024%; height: 17px;&quot;&gt;지정된 객체의 위치(index)를 반환한다.&lt;br /&gt;(List의 마지막 요소로부터 역방향으로 찾는다.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 40.6976%; height: 17px;&quot;&gt;ListIterator listIterator()&lt;br /&gt;ListIterator listIterator(int index)&lt;/td&gt;
&lt;td style=&quot;width: 59.3024%; height: 17px;&quot;&gt;List의 객체에 접근할 수 있는 Iterator를 반환한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 40.6976%; height: 17px;&quot;&gt;Object remove(int index)&lt;/td&gt;
&lt;td style=&quot;width: 59.3024%; height: 17px;&quot;&gt;지정된 위치(index)에 있는 객체를 삭제하고 삭제된 객체를 반환한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 40.6976%; height: 17px;&quot;&gt;void sort(Comparator c)&lt;/td&gt;
&lt;td style=&quot;width: 59.3024%; height: 17px;&quot;&gt;지정된 비교자(Comparator)로 List를 정렬한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 40.6976%; height: 17px;&quot;&gt;List subList(int fromIndex,&lt;br /&gt;int toIndex)&lt;/td&gt;
&lt;td style=&quot;width: 59.3024%; height: 17px;&quot;&gt;지정된 범위(fromIndex, toIndex)에 있는 객체를 반환한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.3. Set 인터페이스&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;385&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWRj7n/btsMcHe7Ylj/Cg6j7SQirEPoNRB4S1Bo6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWRj7n/btsMcHe7Ylj/Cg6j7SQirEPoNRB4S1Bo6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWRj7n/btsMcHe7Ylj/Cg6j7SQirEPoNRB4S1Bo6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWRj7n%2FbtsMcHe7Ylj%2FCg6j7SQirEPoNRB4S1Bo6K%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;606&quot; height=&quot;327&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;385&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Set 인터페이스는 중복을 허용하지 않고 저장순서가 유지되지 ㅇ낳는 컬렉션 클래스를 구현하는 데 사용.&lt;/li&gt;
&lt;li&gt;Set 인터페이스를 구현한 클래스로는 HashSet, TreeSet 등이 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.4. Map 인터페이스&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;789&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hvb58/btsMa5aGuye/KM8AVLdwKkKAa2HkgujZSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hvb58/btsMa5aGuye/KM8AVLdwKkKAa2HkgujZSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hvb58/btsMa5aGuye/KM8AVLdwKkKAa2HkgujZSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHvb58%2FbtsMa5aGuye%2FKM8AVLdwKkKAa2HkgujZSK%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;643&quot; height=&quot;305&quot; data-origin-width=&quot;789&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Map 인터페이스는 키와 값을 하나의 쌍으로 묶어 저장하는 컬렉션 클래스를 구현하는 데 사용&lt;/li&gt;
&lt;li&gt;키는 중복될 수 없지만 값은 중복을 허용함.&lt;/li&gt;
&lt;li&gt;기존에 저장된 데이터와 중복된 키와 값을 저장하면 기존의 값은 없어지고 마지막에 저장된 값이 남게 됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 173px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 35.3489%; text-align: center; height: 20px;&quot;&gt;메서드&lt;/td&gt;
&lt;td style=&quot;width: 64.6511%; text-align: center; height: 20px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 35.3489%; height: 17px;&quot;&gt;void clear()&lt;/td&gt;
&lt;td style=&quot;width: 64.6511%; height: 17px;&quot;&gt;Map의 모든 객체를 삭제한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 35.3489%; height: 17px;&quot;&gt;boolean containsKey(Object key)&lt;/td&gt;
&lt;td style=&quot;width: 64.6511%; height: 17px;&quot;&gt;지정된 key객체와 일치하는 Map의 key객체가 있는지 확인한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 35.3489%; height: 17px;&quot;&gt;boolean containsValue(Object value)&lt;/td&gt;
&lt;td style=&quot;width: 64.6511%; height: 17px;&quot;&gt;지정된 value 객체와 일치하는 Map의 value객체가 있는지 확인다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 35.3489%; height: 17px;&quot;&gt;Set entrySet()&lt;/td&gt;
&lt;td style=&quot;width: 64.6511%; height: 17px;&quot;&gt;Map에 저장되어 있는 key-value 쌍을 Map.Entry타입의 객체로 저장한 Set으로 반환한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 35.3489%; height: 17px;&quot;&gt;boolean equals(Object o)&lt;/td&gt;
&lt;td style=&quot;width: 64.6511%; height: 17px;&quot;&gt;동일한 Map인지 비교한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 35.3489%; height: 17px;&quot;&gt;Object get(Object key)&lt;/td&gt;
&lt;td style=&quot;width: 64.6511%; height: 17px;&quot;&gt;지정한 key객체에 대응하는 value객체를 찾아서 반환한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 35.3489%; height: 17px;&quot;&gt;int hashCode()&lt;/td&gt;
&lt;td style=&quot;width: 64.6511%; height: 17px;&quot;&gt;해시코드를 반환한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 35.3489%; height: 17px;&quot;&gt;boolean isEmpty()&lt;/td&gt;
&lt;td style=&quot;width: 64.6511%; height: 17px;&quot;&gt;Map이 비어있는지 확인한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 35.3489%; height: 17px;&quot;&gt;Set keySet()&lt;/td&gt;
&lt;td style=&quot;width: 64.6511%; height: 17px;&quot;&gt;Map에 저장된 모든 key객체를 반환한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 35.3489%;&quot;&gt;Objcect put(Object key, Object value)&lt;/td&gt;
&lt;td style=&quot;width: 64.6511%;&quot;&gt;Map에 value객체를 key객체에 연결하여 저장한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 35.3489%;&quot;&gt;void putAll(Map t)&lt;/td&gt;
&lt;td style=&quot;width: 64.6511%;&quot;&gt;지정된 Map의 모든 key-value쌍을 추가한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 35.3489%;&quot;&gt;Object remove(Object key)&lt;/td&gt;
&lt;td style=&quot;width: 64.6511%;&quot;&gt;지정한 key객체와 일치하는 key-value객체를 삭제한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 35.3489%;&quot;&gt;int size()&lt;/td&gt;
&lt;td style=&quot;width: 64.6511%;&quot;&gt;Map에 저장된 key-value쌍의 개수를 반환한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 35.3489%;&quot;&gt;Collection values()&lt;/td&gt;
&lt;td style=&quot;width: 64.6511%;&quot;&gt;Map에 저장된 모든 value객체를 반환한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Map.Entry인터페이스는 Map에 저장되어 있는 key-value 쌍을 다루기 위해 내부적으로 정의한 인터페이스이다.&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;2. 컬렉션 프레임워크의 종류&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1. ArrayList&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;h3 data-ke-size=&quot;size23&quot;&gt;2.2. LinkedList&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;li&gt;크기를 변경할 수 없고 비순차적인 데이터 추가 혹은 삭제에 시간이 많이 걸림&lt;/li&gt;
&lt;li&gt;각 요소는 다음 요소에 대한 참조값과 데이터로 구성됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.3. Stack &amp;amp; Queue&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스택(Stack)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스택(Stack)은 마지막에 저장한 데이터를 가장 먼저 꺼내는 LIFO 구조&lt;/li&gt;
&lt;li&gt;스택은 ArrayList 기반 배열기반 컬렉션 클래스가 적합함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;큐(Queue)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;큐(Queue)는 처음에 저장한 데이터를 가장 먼저 꺼내는 FIFO 구조&lt;/li&gt;
&lt;li&gt;큐는 데이터 추가/삭제가 쉬운 LinkedList로 구현하는 것이 더 적합함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.4. HashSet&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Set인터페이스를 구현한 가장 대표적인 컬렉션&lt;/li&gt;
&lt;li&gt;중복된 요소를 저장하지 않는 특징&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.5. TreeSet&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이진 검색 트리(binary search tree)라는 자료구조의 형태로 데이터를 저장하는 데이터 컬렉션 클래스&lt;/li&gt;
&lt;li&gt;중복된 데이터의 저장을 허용하지 않으며 정렬된 위치에 저장하므로 저장순서를 유지하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.6. HashMap&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Map의 특징, 키(key)와 값(value)을 묶어서 하나의 데이터로 저장하는 특징을 가짐.&lt;/li&gt;
&lt;li&gt;해싱(hashing)을 사용하기 때문에 많은 양의 데이터를 검색하는데 있어 뛰어난 성능을 보임.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.7. TreeMap&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;li&gt;특히, HashMap과 비교했을 때 범위검색이나 정렬이 필요한 경우 성능이 더 좋음.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.8. Properties&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HashMap의 구버전인 HashTable을 상속받아 구현한 것으로, (String, String)의 형태로 저장하는 보다 단순화된 컬렉션 클래스&lt;/li&gt;
&lt;li&gt;주로 애플리케이션의 환경설정과 관련된 속성을 저장하는데 사용&lt;/li&gt;
&lt;li&gt;데이터를 파일로부터 읽고 쓰는 편리한 기능을 제공함.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Backend/Java</category>
      <category>Collection</category>
      <category>Java</category>
      <category>프로그래밍</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/70</guid>
      <comments>https://onyodev.tistory.com/70#entry70comment</comments>
      <pubDate>Sun, 9 Feb 2025 20:31:55 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 객체지향 프로그래밍 (OOP)</title>
      <link>https://onyodev.tistory.com/69</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;객체지향 프로그래밍 (OOP: Object-Oriented Programming)&lt;br /&gt;&lt;/b&gt;: 실제 세계의 개념을 소프트웨어로 모델링하여 효율적이고 직관적인 프로그램을 개발할 수 있도록 하는 프로그램 패러다임&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 클래스와 객체&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;클래스(Class)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스(Class)는 객체를 정의하는 틀 또는 설계도의 의미로 사용됨.&lt;/li&gt;
&lt;li&gt;클래스는 속성 변수를 나타내는 필드(field)와 객체의 함수를 나타내는 메소드(method)로 구성됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Circle {
	// 필드(field)
	public int radius;
	public String name;
	
	// 메소드(method)
	public Circle() { // 생성자 메소드
	}
	
	public double getArea() {  // 원의 면적 메소드
		return 3.14*radius*radius;
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;객체(Object)와 인스턴스(instance)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체(Object): 물리적으로 존재하거나 개념적인 것 중에서 다른 것과 식별 가능한 것을 말함.
&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;인스턴스(instance): 클래스에 의해서 만들어진 객체를 의미함.&lt;/li&gt;
&lt;li&gt;클래스가 어떤 데이터의 구조 설계도라면, 객체는 설계도를 이용해 찍어낸 실 데이터라고 보면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// 클래스
class Animal { ... }

public class Sample {
    public static void main(String[] args) {
        // 변수 cat은 객체
        // 변수 catd은 Animal 클래스의 인스턴스
        Animal cat = new Animal(); // 클래스라는 설계도를 통해 객체 데이터를 new 생성
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;필드(field)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스에 포함된 변수(variable)을 말한다.&lt;/li&gt;
&lt;li&gt;클래스 멤버(member)라고도 불린다.&lt;/li&gt;
&lt;li&gt;클래스 필드는 선언된 위치와 선언자에 따라 다음과 같이 구분됨.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스 변수(static variable)&lt;/li&gt;
&lt;li&gt;인스턴스 변수(instance variable)&lt;/li&gt;
&lt;li&gt;지역 변수(local variable)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;class Field {
    static int classVar = 10; // 클래스/스태틱 변수 선언
    int instanceVar = 20;     // 인스턴스 변수 선언
    
    int method() {
    	int localVar = 30; // 지역 변수 선언
        return localVar;
    }
}

public class Member01 {
    public static void main(String[] args) {
        System.out.println( Field.classVar ); // 클래스/스태틱 변수 참조
        Field myField1 = new Field();   // 인스턴스 생성
        System.out.println( myField1.instanceVar ); // 인스턴스 변수 참조       
        System.out.println( myField1.method() ); // 메서드안의 지역변수 출력
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;변수&lt;/td&gt;
&lt;td&gt;생성 시기&lt;/td&gt;
&lt;td&gt;소멸 시기&lt;/td&gt;
&lt;td&gt;저장 메모리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;클래스 변수&lt;/td&gt;
&lt;td&gt;클래스가 메모리에 올라갈 때&lt;/td&gt;
&lt;td&gt;프로그램이 종료될 때&lt;/td&gt;
&lt;td&gt;메소드 영역&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;인스턴스 변수&lt;/td&gt;
&lt;td&gt;인스턴스가 생성될 때&lt;/td&gt;
&lt;td&gt;인스턴스가 소멸할 때&lt;/td&gt;
&lt;td&gt;힙 영역&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;지역 변수&lt;/td&gt;
&lt;td&gt;블록 내에서 변수의 선언문이 실행될 때&lt;/td&gt;
&lt;td&gt;블록을 벗어날 때&lt;/td&gt;
&lt;td&gt;스택 영역&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;/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;2. 메서드와 생성자&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;메서드(Method)&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;다른 프로그래밍 언어에서는 함수(function)라는 개념을 자바에서는 메소드(method)라 표현함.&lt;/li&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;/li&gt;
&lt;li&gt;반환 타입(return type): 메서드가 모든 작업을 마치고 반환하는 데이터 타입을 명시&lt;/li&gt;
&lt;li&gt;메서드명: 메서드를 호출하기 위한 이름을 명시&lt;/li&gt;
&lt;li&gt;매개변수 목록(parameters): 메서드 호출 시에 전달되는 인수의 값을 저장할 변수들을 명시&lt;/li&gt;
&lt;li&gt;구현부: 메서드의 고유 기능을 수행하는 명령문의 집합. 중괄호 { } 안에 포함&lt;/li&gt;
&lt;/ul&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;1182&quot; data-origin-height=&quot;349&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rQO1O/btsL2AAtH9b/JDoxS6AbUjq4GNR5d1GLx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rQO1O/btsL2AAtH9b/JDoxS6AbUjq4GNR5d1GLx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rQO1O/btsL2AAtH9b/JDoxS6AbUjq4GNR5d1GLx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrQO1O%2FbtsL2AAtH9b%2FJDoxS6AbUjq4GNR5d1GLx0%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;1182&quot; height=&quot;349&quot; data-origin-width=&quot;1182&quot; data-origin-height=&quot;349&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;생성자 규칙&lt;/b&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;클래스 이름과 반드시 동일&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;생성자는 new를 통해 객체를 생성할 때, 객체당 한 번 호출&lt;/li&gt;
&lt;li&gt;생성자는 객체가 생성될 때 반드시 호출됨.&lt;/li&gt;
&lt;li&gt;생성자는 return 타입을 지정하지 않음&lt;/li&gt;
&lt;li&gt;생성자는 여러 개 작성할 수 있음(Overloading)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;class Car {
    String modelName;
    int modelYear;
    String color;
    int maxSpeed;
    int currentSpeed;

	// 생성자 (인스턴스 변수 값 초기화)
    Car(String modelName, int modelYear, String color, int maxSpeed) {
        this.modelName = modelName; // 메서드의 입력값으로 인스턴스 변수의 값을 지정
        this.modelYear = modelYear;
        this.color = color;
        this.maxSpeed = maxSpeed;
        this.currentSpeed = 0; // 입력값 없이 디폴트 초기화
    }

    String getModel() {
        return this.modelYear + &quot;년식 &quot; + this.modelName + &quot; &quot; + this.color;
    }
}

public class Main {
    public static void main(String[] args) {
        Car myCar1 = new Car(&quot;아반떼&quot;, 2016, &quot;흰색&quot;, 250); // 생성자의 호출
		Car myCar2 = new Car(&quot;제네시스&quot;, 2020, &quot;검은색&quot;, 500); // 생성자의 호출
        Car myCar3 = new Car(&quot;티코&quot;, 2003, &quot;빨간색&quot;, 100); // 생성자의 호출

        System.out.println(myCar1.getModel()); // 2016년식 아반떼 흰색
        System.out.println(myCar2.getModel()); // 2020년식 제네시스 검은색
        System.out.println(myCar3.getModel()); // 2003년식 티코 빨간색
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;this 참조 변수
&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;li&gt;this() 메서드
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생성자 내부에서 같은 클래스의 다른 생성자를 호출할 때 사용.&lt;br /&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;	Car() {
		this(&quot;소나타&quot;, 2012, &quot;검정색&quot;, 160);	
        // 해당 아규먼트가 일치하는 다른 생성자를 호출함.
	}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;3. 접근 제어자와 캡슐화&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;접근 제어자(access modifier)&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;private: 해당 클래스 안에서만 접근 가능&lt;/li&gt;
&lt;li&gt;default: 접근 제어자를 별도로 설정하지 않으면 자동으로 설정되며 동일한 패키지 안에서만 접근 가능&lt;/li&gt;
&lt;li&gt;protected: 동일 패키지의 클래스 또는 해당 클래스를 상속받은 클래스에서만 접근이 가능&lt;/li&gt;
&lt;li&gt;public: 어떤 클래스에서도 접근 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;캡슐화(Encapsulation)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터를 보호하기 위해 접근을 제한하고 외부와의 상호작용은 공개된 메서드(getter, setter)를 통해서만 이루어지도록 하는 객체지향 프로그래밍의 중요한 원칙
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 은닉: 중요한 데이터는 private으로 보호&lt;/li&gt;
&lt;li&gt;인터페이스 제공: 데이터를 읽거나 수정할 때, public 메서드를 통해 제한적으로 접근 허용&lt;/li&gt;
&lt;li&gt;데이터 무결성 보장: 직접 접근을 차단해 데이터를 의도치 않게 변경하지 않도록 보호&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Student {
    private String name;  // private으로 데이터를 보호
    private int age;

    // Getter 메서드
    public String getName() {
        return name;
    }

    // Setter 메서드
    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age &amp;gt; 0) {  // 데이터 무결성을 위한 조건 추가
            this.age = age;
        } else {
            System.out.println(&quot;Invalid age!&quot;);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Main {
    public static void main(String[] args) {
        Student student = new Student();
        student.setName(&quot;Alice&quot;); // setter를 통해 이름 설정
        student.setAge(20);       // setter를 통해 나이 설정

        System.out.println(student.getName()); // &quot;Alice&quot;
        System.out.println(student.getAge());  // 20
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 상속과 다형성의 기초&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;상속(inheritance)&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;/li&gt;
&lt;li&gt;상속 시 키워드 extends 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;class Animal {
    int teethCount; 
    int legCount; 
    int tailCount; 
}

class Dog extends Animal { // 상속을 통해 중복 코드를 제거
    void bark();
}

class Cat extends Animal { // 상속을 통해 중복 코드를 제거
    void meow();
}

class Lion extends Animal { // 상속을 통해 중복 코드를 제거
    void roar();
}

&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;다형성 1 - 메서드 오버라이딩(Method Overriding)&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;class Animal {
    String name;

    void setName(String name) {
        this.name = name;
    }
}

class Dog extends Animal {
    void sleep() {
        System.out.println(this.name + &quot; zzz&quot;);
    }
}

class HouseDog extends Dog {
	// 메서드 오버라이딩(method overriding) 
    void sleep() {
        System.out.println(this.name + &quot; zzz in house&quot;);
    }
}

public class Sample {
    public static void main(String[] args) {
        HouseDog houseDog = new HouseDog();
        houseDog.setName(&quot;happy&quot;);
        houseDog.sleep();  // happy zzz in house 출력
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;다형성 2 - 메서드 오버로딩(Method Overloading)&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;class Animal {
    String name;

    void setName(String name) {
        this.name = name;
    }
}

class Dog extends Animal {
    void sleep() {
        System.out.println(this.name + &quot; zzz&quot;);
    }
}

class HouseDog extends Dog {
    void sleep() {
        System.out.println(this.name + &quot; zzz in house&quot;);
    }
		// 메서드 오버로딩(Method Overloading)
    void sleep(int hour) {
        System.out.println(this.name + &quot; zzz in house for &quot; + hour + &quot; hours&quot;);
    }
}

public class Sample {
    public static void main(String[] args) {
        HouseDog houseDog = new HouseDog();
        houseDog.setName(&quot;happy&quot;);
        houseDog.sleep();  // happy zzz in house 출력
        houseDog.sleep(3);  // happy zzz in house for 3 hours 출력
    }
}
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Backend/Java</category>
      <category>Java</category>
      <category>OOP</category>
      <category>Programming</category>
      <category>다형성</category>
      <category>캡슐화</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/69</guid>
      <comments>https://onyodev.tistory.com/69#entry69comment</comments>
      <pubDate>Mon, 27 Jan 2025 18:05:04 +0900</pubDate>
    </item>
    <item>
      <title>자바 기본 구조와 기본 문법</title>
      <link>https://onyodev.tistory.com/68</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 자바의 기본 구조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 프로그램은 클래스(Class)와 메서드(Method)로 구성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java는 객체지향 언어로, 프로그램 실행 단위는 클래스에서 시작하여 모든 실행은 main 메서드에서 이루어진다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;// 클래스 선언
public class Main {
    // main 메서드: 프로그램의 시작점
    public static void main(String[] args) {
        // 실행할 코드
        System.out.println(&quot;Hello, Java!&quot;); // 콘솔에 출력
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;구성 요소&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;클래스(Class)&lt;/b&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;code&gt;public class Main&lt;/code&gt; : 클래스 이름은 파일 이름과 동일해야 함.&lt;/li&gt;
&lt;li&gt;클래스는 서로 다른 데이터와 기능을 담아 코드 재사용성을 높이고, 객체지향적 설계를 가능하게 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;main 메서드&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바 프로그램의 시작점으로 반드시 &lt;code&gt;public static void main(String[] args)&lt;/code&gt; 형태
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;public&lt;/code&gt;: 모든 곳에서 접근할 수 있음을 의미함.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;static&lt;/code&gt;: 객체를 생성하지 않고도 메서드를 실행할 수 있도록 함. 이는 자바 실행 시 JVM이 직접 호출하기 위해 필요합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;void&lt;/code&gt;: 반환값이 없음&lt;/li&gt;
&lt;li&gt;&lt;code&gt;String[] args&lt;/code&gt;: 프로그램 실행 시 전달되는 입력값을 저장하는 매개변&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;JVM과의 연동&lt;/b&gt;: &lt;code&gt;main&lt;/code&gt; 메서드는 JVM이 프로그램을 실행할 때 가장 먼저 호출하는 진입점으로 설계&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단순성과 유연성&lt;/b&gt;: &lt;code&gt;static&lt;/code&gt; 키워드를 사용함으로써 객체 생성 없이 프로그램을 시작할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 변수와 자료형&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수는 데이터를 저장하기 위한 공간이며, 자바에서는 변수 선언 시 반드시 자료형을 명시해야 함.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;자료형 분류&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;기본형(Primitive Types)&lt;/b&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;종류&lt;/b&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;자료형&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;th&gt;메모리 사이즈&lt;/th&gt;
&lt;th&gt;범위&lt;/th&gt;
&lt;th&gt;기본값&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;byte&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;8-bit 정수&lt;/td&gt;
&lt;td&gt;1 byte&lt;/td&gt;
&lt;td&gt;-2⁷ ~ 2⁷-1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;short&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;16-bit 정수&lt;/td&gt;
&lt;td&gt;2 bytes&lt;/td&gt;
&lt;td&gt;-2&amp;sup1;⁵ ~ 2&amp;sup1;⁵-1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;int&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;32-bit 정수&lt;/td&gt;
&lt;td&gt;4 bytes&lt;/td&gt;
&lt;td&gt;-2&amp;sup3;&amp;sup1; ~ 2&amp;sup3;&amp;sup1;-1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;long&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;64-bit 정수&lt;/td&gt;
&lt;td&gt;8 bytes&lt;/td&gt;
&lt;td&gt;-2⁶&amp;sup3; ~ 2⁶&amp;sup3;-1&lt;/td&gt;
&lt;td&gt;0L&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;float&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;32-bit 부동소수점(IEEE 754)&lt;/td&gt;
&lt;td&gt;4 bytes&lt;/td&gt;
&lt;td&gt;-3.40E+38 ~ 3.40E+38&lt;/td&gt;
&lt;td&gt;0.0f&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;double&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;64-bit 부동소수점(IEEE 754)&lt;/td&gt;
&lt;td&gt;8 bytes&lt;/td&gt;
&lt;td&gt;1.79E+308 ~ 1.79E+308&lt;/td&gt;
&lt;td&gt;0.0d&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;char&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;16-bit 유니코드 문자&lt;/td&gt;
&lt;td&gt;2 bytes&lt;/td&gt;
&lt;td&gt;0 ~ 2&amp;sup1;⁶-1&lt;/td&gt;
&lt;td&gt;\u0000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;boolean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;논리형&lt;/td&gt;
&lt;td&gt;1 bit&lt;/td&gt;
&lt;td&gt;0 or 1&lt;/td&gt;
&lt;td&gt;0 (false)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;참조형(Reference Types)&lt;/b&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;Object&lt;/code&gt;: 모든 Class와 Enum의 일반화된 타입&lt;/li&gt;
&lt;li&gt;&lt;code&gt;String&lt;/code&gt;: char의 배열로 구현된 참조 자료형&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Array&lt;/code&gt;: 동일한 타입의 데이터를 순차적으로 저장하는 객체&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Class&lt;/code&gt;: Class 객체 자체를 다루는 자료형&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Wrapper&lt;/code&gt;: 기본 데이터 타입의 값을 객체로 다루기 위한 클래스&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Interface&lt;/code&gt;: 객체가 구현해야 하는 메소드의 집합을 정의한 타입&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Enum&lt;/code&gt; 고정된 상수들의 집합을 정의하는 특별한 종류의 클래스&lt;/li&gt;
&lt;li&gt;그 외에도 많은 참조형 타입들이 존재함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;구분&lt;/td&gt;
&lt;td&gt;기본형&lt;/td&gt;
&lt;td&gt;참조형&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;저장&amp;nbsp;방식&lt;/td&gt;
&lt;td&gt;값&amp;nbsp;자체를&amp;nbsp;저장&lt;/td&gt;
&lt;td&gt;메모리&amp;nbsp;주소를&amp;nbsp;저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;메모리 사용&lt;/td&gt;
&lt;td&gt;스택(Stack)&lt;/td&gt;
&lt;td&gt;힙(Heap)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;데이터 크기&lt;/td&gt;
&lt;td&gt;고정 (자료형별로 정해짐)&lt;/td&gt;
&lt;td&gt;가변 (객체 크기에 따라 다름)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;주요 예시&lt;/td&gt;
&lt;td&gt;&lt;code&gt;int&lt;/code&gt;, &lt;code&gt;double&lt;/code&gt;, &lt;code&gt;char&lt;/code&gt;, &lt;code&gt;boolean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;String&lt;/code&gt;, 배열, 사용자 정의 클래스&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class VariablesExample {
    public static void main(String[] args) {
        int age = 25; // 정수형 변수
        double height = 175.5; // 실수형 변수
        char grade = 'A'; // 문자형 변수
        String name = &quot;Alice&quot;; // 문자열 변수
        boolean isStudent = true; // 논리형 변수

        // 출력
        System.out.println(&quot;Name: &quot; + name);
        System.out.println(&quot;Age: &quot; + age);
        System.out.println(&quot;Height: &quot; + height);
        System.out.println(&quot;Grade: &quot; + grade);
        System.out.println(&quot;Is student? &quot; + isStudent);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 연산자&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연산자는 변수나 값을 조작하거나 비교하는 데 사용&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;연산자의 종류와 의미&lt;/h4&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;연산자 유형&lt;/th&gt;
&lt;th&gt;연산자&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;예시&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;산술 연산자&lt;/td&gt;
&lt;td&gt;&lt;code&gt;+&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;\*&lt;/code&gt;, &lt;code&gt;/&lt;/code&gt;, &lt;code&gt;%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;숫자 간의 덧셈, 뺄셈, 곱셈, 나눗셈, 나머지를 구함&lt;/td&gt;
&lt;td&gt;&lt;code&gt;a + b&lt;/code&gt;, &lt;code&gt;a % b&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;증감 연산자&lt;/td&gt;
&lt;td&gt;&lt;code&gt;++&lt;/code&gt;, &lt;code&gt;--&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1씩 증가 또는 감소. 접두사와 접미사로 사용 가능.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;++a&lt;/code&gt;, &lt;code&gt;b--&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;대입 연산자&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;오른쪽 값을 왼쪽 변수에 대입.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;a = 10&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;복합 대입 연산자&lt;/td&gt;
&lt;td&gt;&lt;code&gt;+=&lt;/code&gt;, &lt;code&gt;-=&lt;/code&gt;, &lt;code&gt;\*=&lt;/code&gt;, &lt;code&gt;/=&lt;/code&gt;, &lt;code&gt;%=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;대입과 동시에 산술 연산 수행.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;a += 5&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;비교 연산자&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\==&lt;/code&gt;, &lt;code&gt;!=&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;=&lt;/code&gt;, &lt;code&gt;&amp;gt;=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;값의 동등성, 크기 비교를 수행.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;a == b&lt;/code&gt;, &lt;code&gt;a &amp;gt; b&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;논리 연산자&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, &lt;code&gt;||&lt;/code&gt;, &lt;code&gt;!&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;논리적 조건을 결합하거나 부정&lt;/td&gt;
&lt;td&gt;&lt;code&gt;a &amp;amp;&amp;amp; b&lt;/code&gt;, &lt;code&gt;!a&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;비트 연산자&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;amp;&lt;/code&gt;, &lt;code&gt;|&lt;/code&gt;, &lt;code&gt;^&lt;/code&gt;, &lt;code&gt;~&lt;/code&gt;, &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;비트 단위의 연산 수행&lt;/td&gt;
&lt;td&gt;&lt;code&gt;a &amp;amp; b&lt;/code&gt;, &lt;code&gt;a &amp;lt;&amp;lt; 1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;삼항 연산자&lt;/td&gt;
&lt;td&gt;&lt;code&gt;? :&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;조건에 따라 값을 선택.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;a &amp;gt; b ? a : b&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;instanceof 연산자&lt;/td&gt;
&lt;td&gt;&lt;code&gt;instanceof&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;객체가 특정 클래스의 인스턴스인지 확인.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;obj instanceof String&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;문자열 연결 연산자&lt;/td&gt;
&lt;td&gt;&lt;code&gt;+&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;문자열을 이어 붙임.&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;Hello&quot; + name&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;String name = &quot;Alice&quot;;
if (name instanceof String) {
    System.out.println(&quot;name은 String입니다.&quot;);
}

String greeting = &quot;Hello, &quot; + &quot;World!&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 조건문과 반복문&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.1. 조건문&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;if 문&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건식이 참인 경우 명령문을 실행&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;if (조건식) {
    // 조건이 참일 때 실행할 코드
}

int score = 85;
if (score &amp;gt;= 90) {
    System.out.println(&quot;Grade: A&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;if-else 문&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건식이 참인 경우 if 문 실행, 거짓인 경우 else 문 실행&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;if (조건식) {
    // 조건이 참일 때 실행할 코드
} else {
    // 조건이 거짓일 때 실행할 코드
}

if (score &amp;gt;= 90) {
    System.out.println(&quot;Grade: A&quot;);
} else {
    System.out.println(&quot;Grade: B or lower&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;switch 문&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;/ul&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;switch (변수) {
    case 값1:
        // 값1일 때 실행할 코드
        break;
    case 값2:
        // 값2일 때 실행할 코드
        break;
    default:
        // 일치하는 값이 없을 때 실행할 코드
}

int day = 3;
switch (day) {
    case 1:
        System.out.println(&quot;Monday&quot;);
        break;
    case 2:
        System.out.println(&quot;Tuesday&quot;);
        break;
    case 3:
        System.out.println(&quot;Wednesday&quot;);
        break;
    default:
        System.out.println(&quot;Other Day&quot;);
}&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;4.2. 반복문&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;for 문&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고정된 횟수만큼 반복하여 실행&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;for (초기화; 조건식; 증감식) {
    // 반복할 코드
}

for (int i = 1; i &amp;lt;= 5; i++) {
    System.out.println(&quot;Count: &quot; + i);
}&lt;/code&gt;&lt;/pre&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;li&gt;&lt;b&gt;증감식&lt;/b&gt;: 반복 변수값을 변경&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;while 문&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건식이 true인 경우 계속해서 반복하여 실행&lt;/p&gt;
&lt;pre class=&quot;gradle&quot;&gt;&lt;code&gt;while (조건식) {
    // 반복할 코드
}

int count = 5;
while (count &amp;gt; 0) {
    System.out.println(&quot;Countdown: &quot; + count);
    count--;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;do - while 문&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건문과 반복문을 결합한 구조로 &lt;b&gt;코드를 최소 한 번은 실행한 후 조건을 검사&lt;/b&gt;하여 반복을 결정&lt;/p&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;do {
    // 실행할 코드
} while (조건식);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;do&lt;/code&gt; 블록: 조건과 관계없이 한 번은 반드시 실행되는 코드 블록&lt;/li&gt;
&lt;li&gt;&lt;code&gt;while (조건식)&lt;/code&gt;: 코드 블록을 반복할 조건을 검사함. 조건이 참이면 &lt;code&gt;do&lt;/code&gt; 블록을 다시 실행하고, 거짓인 경우 반복을 종료&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;public class DoWhileExample {
    public static void main(String[] args) {
        int number = 0;

        do {
            System.out.println(&quot;Current number: &quot; + number);
            number++;
        } while (number &amp;lt; 3);
    }
}

Current number: 0
Current number: 1
Current number: 2&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;code&gt;do-while&lt;/code&gt; 문 vs &lt;code&gt;while&lt;/code&gt; 문&lt;/h4&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;특성&lt;/th&gt;
&lt;th&gt;do-while 문&lt;/th&gt;
&lt;th&gt;while 문&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;코드 실행 순서&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;코드를 먼저 실행한 후 조건 확인&lt;/td&gt;
&lt;td&gt;조건을 먼저 확인한 후 코드 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;최소 실행 횟수&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;최소 한 번은 코드가 실행됨&lt;/td&gt;
&lt;td&gt;조건이 거짓이면 한 번도 실행되지 않을 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;사용 예시&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;사용자 입력 처리, 값 확인 등&lt;/td&gt;
&lt;td&gt;조건이 참일 때 반복을 시작해야 할 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</description>
      <category>Backend/Java</category>
      <category>Java</category>
      <category>기본문법</category>
      <category>프로그래밍</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/68</guid>
      <comments>https://onyodev.tistory.com/68#entry68comment</comments>
      <pubDate>Sat, 18 Jan 2025 22:19:53 +0900</pubDate>
    </item>
    <item>
      <title>React Native와 React 기본</title>
      <link>https://onyodev.tistory.com/67</link>
      <description>&lt;p&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/001.gif&quot; alt=&quot;&quot; width=&quot;154&quot; height=&quot;154&quot; /&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 모바일 앱 개발을 위한 React Native와 &lt;br /&gt;개발을 위해 필요한 React의 기본에 대해서 간단히 포스팅하겠습니다..! ✈&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;React Native?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;React Native는 React와 앱 플랫폼의 기본 기능을 사용하여 Android 및 iOS 애플리케이션을 빌드하기 위한 오픈 소스 프레임워크&lt;/li&gt;
&lt;li&gt;Javascript를 사용하여 플랫폼의 API를 액세스 하고 React의 Component를 사용하여 UI의 모양과 동작을 설명함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;뷰(View)와 모바일&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;뷰(View)는 UI의 기본 구성 요소이며 text, image, 사용자 input 등을 담는 직사각형 element를 말함.&lt;/li&gt;
&lt;li&gt;뷰(View)는 뷰(View) 안에 또 다른 뷰(View)를 포함할 수 있음&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;778&quot; data-origin-height=&quot;533&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UCZEI/btsLsqZOOId/XQ2oaKImkPk9NPbkcUyM50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UCZEI/btsLsqZOOId/XQ2oaKImkPk9NPbkcUyM50/img.png&quot; data-alt=&quot;&amp;amp;lt;출처&amp;amp;gt; - React Native 공식 Documentation/
 Android와 iOS 앱에서 사용되는 다양한 뷰의 일부&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UCZEI/btsLsqZOOId/XQ2oaKImkPk9NPbkcUyM50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUCZEI%2FbtsLsqZOOId%2FXQ2oaKImkPk9NPbkcUyM50%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;453&quot; height=&quot;310&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;533&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;&amp;lt;출처&amp;gt; - React Native 공식 Documentation/
 Android와 iOS 앱에서 사용되는 다양한 뷰의 일부&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;주요 컴포넌트들&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React Native에는 컨트롤부터 활동 표시기까지 다양한 컴포넌트들이 존재한다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 111px;&quot;&gt;React Native&lt;br /&gt;UI 컴포넌트&lt;/td&gt;
&lt;td style=&quot;width: 114px;&quot;&gt;Android&lt;br /&gt;View&lt;/td&gt;
&lt;td style=&quot;width: 134px;&quot;&gt;iOS View&lt;/td&gt;
&lt;td style=&quot;width: 116px;&quot;&gt;Web Analog&lt;/td&gt;
&lt;td style=&quot;width: 374px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 111px;&quot;&gt;&lt;code&gt;&amp;lt;View&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 114px;&quot;&gt;&lt;code&gt;&amp;lt;ViewGroup&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 134px;&quot;&gt;&lt;code&gt;&amp;lt;UIView&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 116px;&quot;&gt;&lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 374px;&quot;&gt;flexbox, 스타일, 일부 터치 처리, 접근성 제어 등을 제공합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 111px;&quot;&gt;&lt;code&gt;&amp;lt;Text&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 114px;&quot;&gt;&lt;code&gt;&amp;lt;TextView&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 134px;&quot;&gt;&lt;code&gt;&amp;lt;UITextView&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 116px;&quot;&gt;&lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 374px;&quot;&gt;문자열을 표시하고 스타일을 지정하며, 텍스트 내에서 터치 이벤트도 처리합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 111px;&quot;&gt;&lt;code&gt;&amp;lt;Image&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 114px;&quot;&gt;&lt;code&gt;&amp;lt;ImageView&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 134px;&quot;&gt;&lt;code&gt;&amp;lt;UIImageView&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 116px;&quot;&gt;&lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 374px;&quot;&gt;다양한 유형의 이미지를 표시합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 111px;&quot;&gt;&lt;code&gt;&amp;lt;ScrollView&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 114px;&quot;&gt;&lt;code&gt;&amp;lt;ScrollView&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 134px;&quot;&gt;&lt;code&gt;&amp;lt;UIScrollView&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 116px;&quot;&gt;&lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 374px;&quot;&gt;여러 컴포넌트와 뷰를 포함할 수 있는 일반적인 스크롤 컨테이너&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 111px;&quot;&gt;&lt;code&gt;&amp;lt;TextInput&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 114px;&quot;&gt;&lt;code&gt;&amp;lt;EditText&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 134px;&quot;&gt;&lt;code&gt;&amp;lt;UITextField&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 116px;&quot;&gt;&lt;code&gt;&amp;lt;input &lt;br /&gt;  type=&quot;text&quot;&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td style=&quot;width: 374px;&quot;&gt;사용자가 텍스트를 입력할 수 있도록 합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;React 기본 개념&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;React Native는 Javacript로 React 위에서 실행된다.&lt;/li&gt;
&lt;li&gt;필요한 React의 핵심 개념은...
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴포넌트(Components)&lt;/li&gt;
&lt;li&gt;JSX&lt;/li&gt;
&lt;li&gt;Props&lt;/li&gt;
&lt;li&gt;State&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;컴포넌트 (Components)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 모든 예제를 'Cat'을 사용해서 설명할 예정입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;Cat&lt;/code&gt; 컴포넌트 정의&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import React from 'react';
import {Text} from 'react-native';

// 컴포넌트는 함수로 정의
const Cat = () =&amp;gt; {
  return &amp;lt;Text&amp;gt;Hello, I am your cat!&amp;lt;/Text&amp;gt;;
};

// 앱 전역에서 사용하도록 export default
export default Cat;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;JSX&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;React에서 사용하는 JavaScript 확장 문법&lt;/b&gt;으로, HTML과 유사한 구문을 사용해 UI를 정의&lt;/li&gt;
&lt;li&gt;JSX는 &lt;b&gt;JavaScript 코드 안에 XML/HTML과 유사한 문법&lt;/b&gt;을 작성할 수 있도록 도와줌.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예시 코드&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import React from 'react';

const name = &quot;Munkustrap&quot;;
const Cat = () =&amp;gt; {
  return &amp;lt;Text&amp;gt;Hello, I am {name}!&amp;lt;/Text&amp;gt;;
};

const fullName = getFullName(&quot;Rum&quot;, &quot;Tum&quot;, &quot;Tugger&quot;);
return &amp;lt;Text&amp;gt;{fullName}&amp;lt;/Text&amp;gt;;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Props&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;React에서 속성(properties)을 의미하는 용어로 컴포넌트에 전달되는 데이터나 설정값을 말함.&lt;/li&gt;
&lt;li&gt;Props는 부모 컴포넌트에서 자식 컴포넌트로 전달되며, 자식 컴포넌트는 이 데이터를 활용하여 UI를 렌더링 하거나 특정 동작을 수행&lt;/li&gt;
&lt;li&gt;특징
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;읽기 전용: Props는 자식 컴포넌트에서 읽기만 할 수 있고, 변경할 수 없음&lt;/li&gt;
&lt;li&gt;부모에서 자식으로 전달&lt;/li&gt;
&lt;li&gt;컴포넌트의 커스터마이징: Props를 사용하면 컴포넌트의 동작이나 외형을 동적으로 설정할 수 있음&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예시 코드&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;const Cat = (props) =&amp;gt; {
  return &amp;lt;Text&amp;gt;Hello, I am {props.name}!&amp;lt;/Text&amp;gt;;
};

const App = () =&amp;gt; {
  return (
    &amp;lt;View&amp;gt;
      &amp;lt;Cat name=&quot;Munkustrap&quot; /&amp;gt;
      &amp;lt;Cat name=&quot;Spot&quot; /&amp;gt;
    &amp;lt;/View&amp;gt;
  );
};&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;React Native의 대부분 핵심 컴포넌트도 props로 커스터마이징이 가능하며 Image 컴포넌트도 가능하다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Image source={{uri: '[https://example.com/cat.jpg'](https://example.com/cat.jpg')}} /&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;State&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;React와 React Native에서 컴포넌트의 상태를 관리하는 방법을 말함.&lt;/li&gt;
&lt;li&gt;컴포넌트의 데이터나 상태를 저장하는 곳으로 사용자의 상호작용이나 시간에 따라 변할 수 있는 데이터를 다루는 데 사용&lt;/li&gt;
&lt;li&gt;특징
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;동적인 데이터 저장: &lt;code&gt;state&lt;/code&gt;는 시간이 지나면서 변경될 수 있는 데이터를 저장 ex) 버튼 클릭값, 입력 필드값 등&lt;/li&gt;
&lt;li&gt;컴포넌트 내에서 관리: &lt;code&gt;state&lt;/code&gt;는 해당 컴포넌트 내에서만 관리되며, 변경되면 그 컴포넌트는 다시 렌더링됨&lt;/li&gt;
&lt;li&gt;변경 시 UI 업데이트: &lt;code&gt;state&lt;/code&gt; 값이 변경되면 React는 UI를 자동으로 업데이트하여 반영&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;컴포넌트에 &lt;code&gt;state&lt;/code&gt;를 추가하기 위해서 React의 &lt;code&gt;useState&lt;/code&gt; 훅을 사용함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예시 코드&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import React, {useState} from 'react';

const Cat = () =&amp;gt; {
  const [isHungry, setIsHungry] = useState(true);

  return (
    &amp;lt;View&amp;gt;
      &amp;lt;Text&amp;gt;{isHungry ? 'I am hungry!' : 'I am full!'}&amp;lt;/Text&amp;gt;
      &amp;lt;Button
        title=&quot;Feed me&quot;
        onPress={() =&amp;gt; setIsHungry(false)}
      /&amp;gt;
    &amp;lt;/View&amp;gt;
  );
};&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;useState&lt;/code&gt;는 두 가지를 반환함.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;state&lt;/code&gt; : &lt;code&gt;isHungry&lt;/code&gt;와 같은 상태 변수를 정의&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setState&lt;/code&gt; : &lt;code&gt;setIsHungry&lt;/code&gt;와 같은 상태 변수의 값을 업데이트하는 함수&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;/ul&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;const Cafe = () =&amp;gt; {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;Cat name=&quot;Munkustrap&quot; /&amp;gt;
      &amp;lt;Cat name=&quot;Spot&quot; /&amp;gt;
    &amp;lt;/&amp;gt;
  );
};&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&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;a href=&quot;https://reactnative.dev/docs/intro-react-native-components&quot;&gt;React Native 공식 Documentation - Guides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Frontend/React Native</category>
      <category>react</category>
      <category>React Native</category>
      <category>앱개발</category>
      <category>프론트엔드</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/67</guid>
      <comments>https://onyodev.tistory.com/67#entry67comment</comments>
      <pubDate>Sun, 22 Dec 2024 15:28:13 +0900</pubDate>
    </item>
    <item>
      <title>Context API</title>
      <link>https://onyodev.tistory.com/66</link>
      <description>&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;009&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/009.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/009.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 코딩테스트에서 Context API를 사용한 문제를 마주하여 좌절하게 된 후,&lt;br /&gt;궁금증이 생겨 Context 방식에 대해서 알아보게 되었습니다.  &lt;br /&gt;&lt;br /&gt;저는 props나 Zustand를 활용해서 각자 다른 컴포넌트에 데이터를 전달하는 방식만 알고 있었습니다..&lt;br /&gt;그런데 웬 느닷없는 context 가 나왔는지 모르겠네요..&lt;br /&gt;이게 왜 나왔고 필요한지에 대해서 적어봤습니다.&amp;nbsp;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Context를 사용해 데이터를 깊게 전달하기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;보통의 경우는 부모 컴포넌트에서 자식 컴포넌트로 props를 통해 정보를 전달한다.&lt;/li&gt;
&lt;li&gt;하지만 중간에 많은 컴포넌트를 거쳐야 하거나, 많은 컴포넌트에서 동일한 정보가 필요한 경우 props를 전달하는 것이 번거롭고 불편해진다.&lt;/li&gt;
&lt;li&gt;context는 부모 컴포넌트가 트리 아래에 있는 모든 컴포넌트 깊이에 상관없이 정보를 명시적으로 props를 통해 전달하지 않고도 사용할 수 있게 해줌.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Props 전달하기의 문제점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;props는 UI 트리를 통해 해당 데이터를 사용하는 컴포넌트에 명시적으로 데이터를 전달하는 훌륭한 방법이다.&lt;/li&gt;
&lt;li&gt;하지만 이 방식은 어떤 prop을 트리를 통해 깊이 전해줘야 하거나 많은 컴포넌트에서 같은 prop이 필요한 경우에 장황하고 불편함.&lt;/li&gt;
&lt;li&gt;데이터가 필요한 여러 컴포넌트의 가장 가까운 공통 조상은 트리 상 높은 위치할 수 있고 그렇게 높게까지 state를 끌어올리는 것은 Prop drilling 현상을 초래할 수 있음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Prop drilling:&lt;/b&gt; 부모 컴포넌트가 자식 컴포넌트로 데이터를 전달하기 위해 props를 사용하는 과정에서, 직접 데이터를 필요로 하지 않는 중간 컴포넌트들도 데이터를 전달하는 역할만을 하게 되는 문제&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;1445&quot; data-origin-height=&quot;809&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgLVs4/btsLlKx42Aa/jZkjjtE1fM8FhtlcbLg3pK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgLVs4/btsLlKx42Aa/jZkjjtE1fM8FhtlcbLg3pK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgLVs4/btsLlKx42Aa/jZkjjtE1fM8FhtlcbLg3pK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgLVs4%2FbtsLlKx42Aa%2FjZkjjtE1fM8FhtlcbLg3pK%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;596&quot; height=&quot;334&quot; data-origin-width=&quot;1445&quot; data-origin-height=&quot;809&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;br /&gt;Context: Props 전달하기 대안&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Context는 부모 컴포넌트가 그 아래의 트리 전체에 데이터를 전달할 수 있도록 해줌.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시로 크기 조정을 위해 level을 받는 Heading 컴포넌트를 본다면,,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;App.js&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1734443199181&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import Heading from './Heading.js';
import Section from './Section.js';

export default function Page() {
  return (
    &amp;lt;Section&amp;gt;
      &amp;lt;Heading level={1}&amp;gt;Title&amp;lt;/Heading&amp;gt;
      &amp;lt;Heading level={2}&amp;gt;Heading&amp;lt;/Heading&amp;gt;
      &amp;lt;Heading level={3}&amp;gt;Sub-heading&amp;lt;/Heading&amp;gt;
      &amp;lt;Heading level={4}&amp;gt;Sub-sub-heading&amp;lt;/Heading&amp;gt;
      &amp;lt;Heading level={5}&amp;gt;Sub-sub-sub-heading&amp;lt;/Heading&amp;gt;
      &amp;lt;Heading level={6}&amp;gt;Sub-sub-sub-sub-heading&amp;lt;/Heading&amp;gt;
    &amp;lt;/Section&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Section.js&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1734443230582&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default function Section({ children }) {
  return (
    &amp;lt;section className=&quot;section&quot;&amp;gt;
      {children}
    &amp;lt;/section&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Heading.js&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1734443258947&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default function Heading({ level, children }) {
  switch (level) {
    case 1:
      return &amp;lt;h1&amp;gt;{children}&amp;lt;/h1&amp;gt;;
    case 2:
      return &amp;lt;h2&amp;gt;{children}&amp;lt;/h2&amp;gt;;
    case 3:
      return &amp;lt;h3&amp;gt;{children}&amp;lt;/h3&amp;gt;;
    case 4:
      return &amp;lt;h4&amp;gt;{children}&amp;lt;/h4&amp;gt;;
    case 5:
      return &amp;lt;h5&amp;gt;{children}&amp;lt;/h5&amp;gt;;
    case 6:
      return &amp;lt;h6&amp;gt;{children}&amp;lt;/h6&amp;gt;;
    default:
      throw Error('Unknown level: ' + level);
  }
}&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;같은 Section 내의 여러 제목이 항상 동일한 크기를 가져야 한다고 봤을 때 각각 &amp;lt;Heading&amp;gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;에 level prop을 전달함.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;Section&amp;gt;
  &amp;lt;Heading level={3}&amp;gt;About&amp;lt;/Heading&amp;gt;
  &amp;lt;Heading level={3}&amp;gt;Photos&amp;lt;/Heading&amp;gt;
  &amp;lt;Heading level={3}&amp;gt;Videos&amp;lt;/Heading&amp;gt;
&amp;lt;/Section&amp;gt;
&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;lt;Section&amp;gt; 컴포넌트에 level prop을 전달해 이를 &amp;lt;Heading&amp;gt;에서 제거하는 것이 가장 효율적일 것이다. 이렇게 하면 반복적인 코드를 쓰지 않아도 되고 좋을 것 같다.&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;ex) 
&amp;lt;Section level={3}&amp;gt;
  &amp;lt;Heading&amp;gt;About&amp;lt;/Heading&amp;gt;
  &amp;lt;Heading&amp;gt;Photos&amp;lt;/Heading&amp;gt;
  &amp;lt;Heading&amp;gt;Videos&amp;lt;/Heading&amp;gt;
&amp;lt;/Section&amp;gt;
&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;lt;Heading&amp;gt; 컴포넌트가 가장 가까운 &amp;lt;Section&amp;gt; 레벨을 알아야 한다.&lt;/p&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;여기서부턴 세 단계로 context를 쓰기 시작한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Context를 생성
&lt;pre id=&quot;code_1734443400215&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// LevelContext.js
import { createContext } from 'react';

export const LevelContext = createContext(1);  //  1은 가장 큰 제목 레벨&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;데이터가 필요한 컴포넌트에서 context를 사용(Heading 에서 LevelContext 사용)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;React에서 useContext Hook과 생성한 Context를 가져옴&lt;/li&gt;
&lt;li&gt;level props를 제거하고 LevelContext를 읽도록 함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// Heading.js

import { useContext } from 'react';
import { LevelContext } from './LevelContext.js';

export default function Heading({ children }) {
  const level = useContext(LevelContext);
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;Section level={4}&amp;gt;
  &amp;lt;Heading&amp;gt;Sub-sub-heading&amp;lt;/Heading&amp;gt;
  &amp;lt;Heading&amp;gt;Sub-sub-heading&amp;lt;/Heading&amp;gt;
  &amp;lt;Heading&amp;gt;Sub-sub-heading&amp;lt;/Heading&amp;gt;
&amp;lt;/Section&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;데이터를 지정하는 컴포넌트에서 context를 제공(Section 에서 LevelContext 제공)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Section 컴포넌트는 자식들을 렌더링하고 있음&lt;/li&gt;
&lt;li&gt;LevelContext 를 자식들에게 제공하기 위해 context provider로 감싸준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import { LevelContext } from './LevelContext.js';

export default function Section({ level, children }) {
  return (
    &amp;lt;section className=&quot;section&quot;&amp;gt;
      &amp;lt;LevelContext.Provider value={level}&amp;gt;
        {children}
      &amp;lt;/LevelContext.Provider&amp;gt;
    &amp;lt;/section&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Context는 부모가 트리 내부 전체에, 심지어 멀리 떨어진 컴포넌트에게도 데이터를 제공할 수 있도록 함.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;같은 컴포넌트에서 context를 사용하며 제공하기&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지금은 각각의 section에 level을 수동으로 지정하는데&lt;/li&gt;
&lt;li&gt;Context를 통해 컴포넌트에서 정보를 읽을 수 있으므로 각 Section 은 위의 Section 에서 level 을 읽고 자동으로 level + 1 을 아래로 전달할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1734443533668&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useContext } from 'react';
import { LevelContext } from './LevelContext.js';

export default function Section({ children }) {
  const level = useContext(LevelContext);
  return (
    &amp;lt;section className=&quot;section&quot;&amp;gt;
      &amp;lt;LevelContext.Provider value={level + 1}&amp;gt;
        {children}
      &amp;lt;/LevelContext.Provider&amp;gt;
    &amp;lt;/section&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최종적으로 &amp;lt;Section&amp;gt; 과 &amp;lt;Heading&amp;gt; 둘 모두 level 을 전달할 필요가 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// App.js

import Heading from './Heading.js';
import Section from './Section.js';

export default function Page() {
  return (
    &amp;lt;Section&amp;gt;
      &amp;lt;Heading&amp;gt;Title&amp;lt;/Heading&amp;gt;
      &amp;lt;Section&amp;gt;
        &amp;lt;Heading&amp;gt;Heading&amp;lt;/Heading&amp;gt;
        &amp;lt;Heading&amp;gt;Heading&amp;lt;/Heading&amp;gt;
        &amp;lt;Heading&amp;gt;Heading&amp;lt;/Heading&amp;gt;
        &amp;lt;Section&amp;gt;
          &amp;lt;Heading&amp;gt;Sub-heading&amp;lt;/Heading&amp;gt;
          &amp;lt;Heading&amp;gt;Sub-heading&amp;lt;/Heading&amp;gt;
          &amp;lt;Heading&amp;gt;Sub-heading&amp;lt;/Heading&amp;gt;
          &amp;lt;Section&amp;gt;
            &amp;lt;Heading&amp;gt;Sub-sub-heading&amp;lt;/Heading&amp;gt;
            &amp;lt;Heading&amp;gt;Sub-sub-heading&amp;lt;/Heading&amp;gt;
            &amp;lt;Heading&amp;gt;Sub-sub-heading&amp;lt;/Heading&amp;gt;
          &amp;lt;/Section&amp;gt;
        &amp;lt;/Section&amp;gt;
      &amp;lt;/Section&amp;gt;
    &amp;lt;/Section&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Context 사용 예시&lt;/h2&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;: 사용자가 모양을 변경할 수 있는 애플리케이션의 경우 context provider를 앱 최상단에 두고 시각적 조정을 통해 활용할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;라우팅&lt;/b&gt;: 대부분 라우팅 솔루션은 현재 경로를 유지하기 위해 내부적으로 context를 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상태 관리&lt;/b&gt;: reducer를 context와 함께 사용하여 복잡한 state를 관리하고 번거로운 작업 없이 멀리 떨어진 컴포넌트까지 값을 전달할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Context 사용 시 단점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Provider 컴포넌트가 재렌더링 되는 경우,모든 하위 consumer 컴포넌트가 재렌더링되는 문제가 있다.&lt;/li&gt;
&lt;li&gt;중첩된 Context를 동시에 사용하면 코드가 복잡해지고 가독성이 떨어질 수 있음. 이 경우는 Context 병합 도구나 커스텀 훅을 활용해 중첩을 줄임.&lt;/li&gt;
&lt;li&gt;Context에 의존적인 컴포넌트는 특정 상태를 제공해야만 동작하므로, 컴포넌트를 독립적으로 재사용하기 어려움.&lt;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://ko.react.dev/learn/passing-data-deeply-with-context&quot;&gt;React 공식 documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Frontend/React</category>
      <category>context</category>
      <category>frontend</category>
      <category>props</category>
      <category>react</category>
      <category>상태관리</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/66</guid>
      <comments>https://onyodev.tistory.com/66#entry66comment</comments>
      <pubDate>Tue, 17 Dec 2024 22:54:58 +0900</pubDate>
    </item>
    <item>
      <title>데이터 과학과 빅데이터</title>
      <link>https://onyodev.tistory.com/65</link>
      <description>&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;001&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/001.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/001.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 김연희 저 - &quot;데이터베이스 개론 3판&quot;을 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 데이터 과학&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;1️⃣ 데이터 과학의 필요성&lt;/span&gt;&lt;/u&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;li&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;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;2️⃣ 데이터 과학의 개념&lt;/span&gt;&lt;/u&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;b&gt;DIKW(Data-Information-Knowledge-Wisdom) 계층 구조&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&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;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;/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;2466&quot; data-origin-height=&quot;899&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzYM8R/btsLcunwP98/kUSKoZgRcENBcKXSERUkp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzYM8R/btsLcunwP98/kUSKoZgRcENBcKXSERUkp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzYM8R/btsLcunwP98/kUSKoZgRcENBcKXSERUkp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzYM8R%2FbtsLcunwP98%2FkUSKoZgRcENBcKXSERUkp1%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;739&quot; height=&quot;269&quot; data-origin-width=&quot;2466&quot; data-origin-height=&quot;899&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;컴퓨터 과학 분야의 데이터 마이닝, 기계 학습, 프로그래밍 능력&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;따라서 데이터 과학은 컴퓨터 과학과 통계학의 교집합 영역에 있으며, 적용 대상이 되는 분야에 대한 업무적 이해를 필요로 하는 복합적인 기술&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 빅데이터&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;1️⃣ 빅데이터의 개념&lt;/u&gt;&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;li&gt;그리고 엄청난 양의 데이터를 분석하여 가치 있는 정보를 추출하기 위한 정교한 분석 기술이 필요하게 되었고 이때 &lt;b&gt;빅데이터&lt;/b&gt;가 등장하게 됨.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;빅데이터(Big data)&lt;/b&gt;는 좁게는 대규모의 다양한 데이터로 정의하기도 하고 넓게는 대규모의 데이터를 저장 및 관리하는 기술과 가치 있는 정보로 만들기 위한 분석 기술도 포함하여 정의함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;빅데이터의 활용&lt;/span&gt;&lt;/u&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;li&gt;그리고 정치 분야에서도 활용되고 있는데 여론조사 기관들이 투표 결과를 더 정확히 예측하기 위해 SNS를 선거 관련 데이터로 활용하여 분석함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;2️⃣ 빅데이터의 특징&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반적으로 빅데이터의 특징을 데이터양(Volume), 속도(Velocity), 다양성(Variety) 을 의미하는 3V로 요약함.&lt;/li&gt;
&lt;li&gt;최근에는 가치(Value)과 정확성(Veracity)을 주착해 5V로 설명하는 경우가 많고 시각화(Visualization)과 가변성(Variability)를 넣어 7V로 언급하기도 함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터양&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;속도&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다양성&lt;/b&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;책, 잡지, 의료 기록, 비디오, 오디오 같은 전통적인 비정형 데이터 외에도 위치 정보, 이메일, SNS 등에서 생성되는 비정형 데이터도 포함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;❗반정형 데이터&lt;/b&gt;&lt;br /&gt;&amp;nbsp;관계 데이터베이스와 같은 정형화된 시스템에 저장되어 있지 않지만 내부적으로 스키마, 즉 구조를 어느 정도 포함하고 있는 XML, HTML 등을 의미&lt;/blockquote&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;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;수집된 빅데이터에 대한 분석으로 얻은 결과는 문제 해결을 위한 의사 결정에 활용될 만한 유용한 가치가 있어야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;정확성&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;시각화&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가변성&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;최근의 빅데이터는 생각, 의견, 감정을 자유롭게 소통하기 위해 이메일, SNS 등을 통해 생성되는 텍스트 형태의 비정형 데이터가 많음&lt;/li&gt;
&lt;li&gt;따라서 빅데이터가 맥락에 따른 가변성을 가지고 있음을 인식하고 수집과 분석 작업에서 데이터의 원래 의미가 그대로 반영될 수 있게 노력해야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;3️⃣ 빅데이터의 기술&lt;/span&gt;&lt;/u&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;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;대표적인 기술로는 하둡(Hadoop)과 NoSQL이 있음.&lt;/li&gt;
&lt;li&gt;하둡(Hadoop)
&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;하둡은 분산 파일 시스템인 HDFS에 데이터를 저장하고 분산 처리 시스템인 MapReduce를 이용해 데이터를 처리&lt;/li&gt;
&lt;li&gt;오픈 소스이기 때문에 기존 데이터베이스 시스템보다 비용이 적게 들고, 여러 대의 서버에 데이터를 저장하기 때문에 처리속도가 빠름.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;NoSQL
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;관계 데이터 모델과 SQL을 사용하지 않은 데이터베이스 시스템&lt;/li&gt;
&lt;li&gt;기존 관계 데이터베이스의 일관성보다는 가용성, 확장성에 중점을 둠.&lt;/li&gt;
&lt;li&gt;비정형 데이터를 저장하기 위해 유연한 데이터 모델을 지원&lt;/li&gt;
&lt;li&gt;관계 데이터베이스와 동일한 데이터 처리가 가능하면서도 더 저렴한 비용으로 분산 처리와 병렬 처리 가능&lt;/li&gt;
&lt;li&gt;HBase, Casandra, MongoDB, CouchDB 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;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;텍스트 마이닝&lt;/b&gt;: 반정형 또는 비정형 텍스트에서 자연어 처리 기술을 기반으로 가치 있는 정보를 추출하고 가공&lt;/li&gt;
&lt;li&gt;&lt;b&gt;오피니언 마이닝&lt;/b&gt;: SNS, 블로그, 게시판 등에 기록된 사용자들의 의견을 수집하고 분석하여, 제품이나 서비스 에 대한 긍정,부정, 중립 등의 선호도 추출&lt;/li&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;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;표현 기술
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;데이터 분석을 통해 추출한 의미와 가치를 시각적으로 표현하기 위해서 R을 주로 사용&lt;/li&gt;
&lt;li&gt;오픈 소스인 R은 통계 기반 데이터 분석과 다양한 시각화를 위한 언어와 개발 환경 제공&lt;/li&gt;
&lt;li&gt;R 언어를 이용해 기본 통계 기법부터 최신 데이터 마이닝 기법까지 적용할 수 있음&lt;/li&gt;
&lt;li&gt;R 언어는 다양한 운영체제와 프로그래밍 언어와 연동되고, 하둡 환경에서 분산 처리를 지원하는 라이브러리를 제공하기 때문에 빅데이터 분석과 시각화를 위해 주로 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;빅데이터 이전 데이터와 빅데이터 비교&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 67px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 16px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 16px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 16px;&quot;&gt;빅 데이터 이전의 데이터&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 16px;&quot;&gt;빅 데이터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;데이터 유형&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;정형화된 문자, 수치 데이터 중심&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;정형, 반정형, 비정형 데이터 모두 포함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;관련 기술&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&amp;bull; 관계 데이터베이스 &lt;br /&gt;&amp;bull;&amp;nbsp;SAS,&amp;nbsp;SPSS와 같은 통계 패키지 &lt;br /&gt;&amp;bull; 데이터 마이닝 &lt;br /&gt;&amp;bull; 기계 학습&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&amp;bull; 저장 기술 : 하둡,&amp;nbsp;NoSQL &lt;br /&gt;&amp;bull; 분석 기술 : 텍스트 마이닝, 오피니언 마이닝, 소셜 네트워크 분석, 군집 분석 &lt;br /&gt;&amp;bull; 표현 기술 : R 언어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;저장 장치&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;데이터베이스나 데이터 웨어하우스와 같은 고가의 저장 장치&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;비용이 저렴한 클라우드 컴퓨팅 장비 활용 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 빅데이터 저장 기술 : NoSQL&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;1️⃣ NoSQL의 등장&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NoSQL(Not only SQL)은 관계 데이터베이스에만 고집하지 말고 필요에 따라 다른 특성을 제공하는 데이터베이스를 사용하는 것이 좋다는 의미로 이해하면 좋다.&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;blockquote data-ke-style=&quot;style3&quot;&gt;❗&lt;b&gt;클러스터 환경&lt;/b&gt;&lt;br /&gt;&amp;nbsp;여러 대의 컴퓨터를 하나의 시스템처럼 동작하도록 구성한 환경&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그래서 웹에서의 대량의 비정형 데이터 저장 및 처리를 위해 새로운 대안으로 제시된 것이 NoSQL이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;2️⃣ NoSQL의 특징&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NoSQL은 빠른 속도로 생성되는 대량의 비정형 데이터를 저장하고 처리하기 위해 ACID를 위한 트랜잭션 기능을 제공하지 않는다.&lt;/li&gt;
&lt;li&gt;대신 저렴한 비용으로 여러 대의 컴퓨터에 데이터를 분산&amp;bull;저장&amp;bull;처리하는 것이 가능한 데이터베이스&lt;/li&gt;
&lt;li&gt;NoSQL은 스키마 없이 동작하기 때문에 데이터 구조를 미리 정의할 필요 없고, 수시로 그 구조를 바꿀 수 있어 비정형 데이터를 저장하기에 적합하며 대부분 오픈 소스로 제공&lt;/li&gt;
&lt;li&gt;관계 데이터베이스는 트랜잭션을 통해 일관성을 유지하고 외래키로 테이블 간의 관계를 표현함으로써 조인과 같은 복잡한 질의를 처리할 수 있음&lt;/li&gt;
&lt;li&gt;하지만 빠른 속도로 증가하는 대량의 비정형 데이터를 저장하기에 확장성 측면에서 비효율적&lt;/li&gt;
&lt;li&gt;NoSQL은 자유롭게 구조를 바꾸면 대량의 비정형 데이터를 빠르게 저장하고 처리할 수 있음&lt;/li&gt;
&lt;li&gt;하지만 NoSQL은 데이터 마이닝과 같은 별도의 분석 기술을 적용해 숨겨진 의미를 찾아내야 함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;관계 데이터베이스와 NoSQL 비교&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;구분 관계&lt;/td&gt;
&lt;td&gt;데이터베이스&lt;/td&gt;
&lt;td&gt;&amp;nbsp;NoSQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;처리 데이터&lt;/td&gt;
&lt;td&gt;정형 데이터&lt;/td&gt;
&lt;td&gt;정형 데이터, 비정형(반정형 포함) 데이터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;대용량 데이터&lt;/td&gt;
&lt;td&gt;대용량 처리 시 성능 저하&lt;/td&gt;
&lt;td&gt;대용량 데이터 처리 지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;스키마&lt;/td&gt;
&lt;td&gt;미리 정해진 스키마가 존재&lt;/td&gt;
&lt;td&gt;스키마가 없거나 변경이 자유로움&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;트랜잭션&lt;/td&gt;
&lt;td&gt;트랜잭션을 통해 일관성 유지 보장&lt;/td&gt;
&lt;td&gt;트랜잭션을 지원하지 않아 일관성 유지를 보장하기 어려움&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;검색 기능&lt;/td&gt;
&lt;td&gt;조인 등 복잡한 검색 기능 제공&lt;/td&gt;
&lt;td&gt;단순한 데이터 검색 기능 제공&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;확장성&lt;/td&gt;
&lt;td&gt;클러스터 환경에 부적합&lt;/td&gt;
&lt;td&gt;클러스터 환경에 적합함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;라이선스&lt;/td&gt;
&lt;td&gt;고가의 라이선스 비용&lt;/td&gt;
&lt;td&gt;오픈 소스&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;대표적 사례&lt;/td&gt;
&lt;td&gt;Oracle, MySQL, MS SQL 서버 등&lt;/td&gt;
&lt;td&gt;카산드라, 몽고DB, H베이스 등&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;background-color: #f6e199;&quot;&gt;&lt;u&gt;3️⃣ NoSQL의 종류&lt;/u&gt;&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;b&gt;키-값 데이터베이스&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NoSQL의 가장 단순한 형태, 키와 값의 쌍으로 데이터가 저장&lt;/li&gt;
&lt;li&gt;어떠한 형태의 값도 저장할 수 있고 질의 처리 속도도 빠름.&lt;/li&gt;
&lt;li&gt;키를 이용해 값 전체를 검색할 수 있지만 값의 일부를 검색하거나 값의 내용을 이용한 질의는 할 수 없음&lt;/li&gt;
&lt;li&gt;DynamoDB, Redis 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;문서 기반 데이터베이스&lt;/b&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;트리 형태의 계층적 구조가 존재하는 JSON, XML 등과 같은 반정형 형태의 문서로 데이터를 저장&lt;/li&gt;
&lt;li&gt;키를 통해 문서 전체를 검색하는 것도 가능하지만 XQuery와 같은 특별한 문서 대상 질의 언어를 이용하면 문서 내 일부를 검색하거나 질의에 활용할 수 있음&lt;/li&gt;
&lt;li&gt;MongoDB, CouchDB 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컬럼 기반 데이터베이스&lt;/b&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/W82P8/btsLa20butM/nEgkaafYrVUv1DRhyQDwg1/img.png&quot; width=&quot;698&quot; height=&quot;395&quot; data-image-src=&quot;https://blog.kakaocdn.net/dn/W82P8/btsLa20butM/nEgkaafYrVUv1DRhyQDwg1/img.png&quot; data-origin-width=&quot;1929&quot; data-origin-height=&quot;1093&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;b&gt;컬럼 패밀리&lt;/b&gt;는 관련 있는 컬럼 값들이 모여서 구성되는 데, 컬럼의 이름과 값이 모여 있는 모습이 마치 테이블에서 속성의 이름과 값이 모인 모습과 유사&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컬럼 패밀리&lt;/b&gt;는 테이블에서 1개의 튜플, 즉 1개의 행을 구성하는 속성들의 모임으로 생각할 수 있고 각 행을 구분하는 키로 각 컬럼 패밀리를 식별&lt;/li&gt;
&lt;li&gt;Google의 BigTable, HBase, Casandra 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;그래프 기반 데이터베이스&lt;/b&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;li&gt;다른 NoSQL 모델과 달리 트랜잭션을 통해 ACID를 지원하며 클러스터 환경에는 적합하지 않음&lt;/li&gt;
&lt;li&gt;연관 데이터를 추천해주거나 소셜 네트워크에서 친구 찾기 질의를 효율적으로 수행하는 데 적합한 데이터베이스&lt;/li&gt;
&lt;li&gt;Neo4J, OrientDB, AgensGraph 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 빅데이터 분석 기술: 데이터 마이닝&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;1️⃣ 데이터 분석의 개념&lt;/u&gt;&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;li&gt;빅데이터를 대상으로 한 데이터 분석 기술은 기존의 정형화된 데이터보다 다양한 형태의 비정형 데이터를 기반으로 엄청난 양의 데이터를 처리한다는 특징이 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;2️⃣ 기계 학습과 데이터 마이닝&lt;/span&gt;&lt;/u&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;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;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;3️⃣ 데이터 마이닝&lt;/span&gt;&lt;/u&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;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;데이터 마이닝의 대표적인 분석 기법&lt;/span&gt;&lt;/u&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;b&gt;분류 분석&lt;/b&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;li&gt;분류 분석에 주로 사용되는 데이터 마이닝 기법으로 로지스틱 회귀모형, 의사결정나무, K-최근접 이웃모형, 베이즈분류모형, 인공신경망, 지지벡터기계, 유전 알고리즘 등이 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;군집 분석&lt;/b&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;li&gt;형성된 군집들의 특성을 파악하여 군집들 사이의 관계를 분석하는 것도 군집의 목적&lt;/li&gt;
&lt;li&gt;&lt;b&gt;계층적 군집 분석&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;비계층 군집 분석&lt;/b&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;대표적인 방법으로는 K-중심 군집&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;연관 분석&lt;/b&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;li&gt;상품이나 서비스 간의 연관 관계를 분석하여 마케팅에 주로 활용&lt;/li&gt;
&lt;li&gt;연관 규칙을 평가하기 위해서 지지도, 신뢰도, 향상도 지표를 이용함.&lt;/li&gt;
&lt;li&gt;대표적으로 Apriori 알고리즘이 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 빅데이터 표현 기술: 데이터 시각화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;1️⃣ 데이터 시각화 개념&lt;/u&gt;&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;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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;2️⃣ 데이터 시각화 방법&lt;/span&gt;&lt;/u&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;b&gt;시간 시각화&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;분포 시각화&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;관계 시각화&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비교 시각화&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공간 시각화&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;3️⃣ 데이터 시각화 도구&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Tableau, GraphViz, Tag Cloud, Gephi, Processing, Fusion Tables 등 다양한 시각화 도구가 출시되었고 이 중 오픈소스도 많음&lt;/li&gt;
&lt;li&gt;태블로(Tableau)는 대표적인 데이터 시각화 도구로 다양한 그래프 시각화 결과물을 쉽고 빠르게 만들어낼 수 있어 많이 사용되며 빠른 그래프 변형과 실시간 공유가 큰 장점&lt;/li&gt;
&lt;li&gt;최근에는 다양한 패키지를 제공하여 시각화는 물론 데이터 분석에 특화된 도구로 평가받고 있는 R도 큰 인기를 얻고 있 음&lt;/li&gt;
&lt;li&gt;R 언어
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;1993년 뉴질랜드 오클랜드 대학교의 로버트 젠틀맨과 로스 이하카가 개발한 프로그래밍 언어이자 데이터 분석을 위한 소프트웨어&lt;/li&gt;
&lt;li&gt;함수를 이용해 명령문을 작성하면 바로 실행 결과를 확인할 수 있는 대화형 방식으로 운영되고 R 스튜디오를 추가로 설치하여 GUI에서 보다 편하게 작업을 수행할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프로그래밍 언어인 Python도 데이터 시각화 도구로 쓰임&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;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스 개론 3판 (김연희 저, 2024.1)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/데이터베이스</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/65</guid>
      <comments>https://onyodev.tistory.com/65#entry65comment</comments>
      <pubDate>Mon, 9 Dec 2024 13:45:45 +0900</pubDate>
    </item>
    <item>
      <title>그래프(Graph)</title>
      <link>https://onyodev.tistory.com/64</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 윤성우 저 - &quot;윤성우의 열혈 자료구조&quot;를 공부하고 정리하여 작성하였습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 그래프의 이해와 종류&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;그래프 이해와 종류&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dr8tuM/btsK66n7dbk/jk6nWWBEMvAuuje3bkMdB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dr8tuM/btsK66n7dbk/jk6nWWBEMvAuuje3bkMdB0/img.png&quot; data-origin-width=&quot;391&quot; data-origin-height=&quot;228&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.3106%; margin-right: 10px;&quot; data-widthpercent=&quot;48.88&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dr8tuM/btsK66n7dbk/jk6nWWBEMvAuuje3bkMdB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdr8tuM%2FbtsK66n7dbk%2Fjk6nWWBEMvAuuje3bkMdB0%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;391&quot; height=&quot;228&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bf3uNk/btsK82dojHG/C91xQFgqQxK4syKJgi06Wk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bf3uNk/btsK82dojHG/C91xQFgqQxK4syKJgi06Wk/img.png&quot; data-origin-width=&quot;391&quot; data-origin-height=&quot;218&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.5266%;&quot; data-widthpercent=&quot;51.12&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bf3uNk/btsK82dojHG/C91xQFgqQxK4syKJgi06Wk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbf3uNk%2FbtsK82dojHG%2FC91xQFgqQxK4syKJgi06Wk%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;391&quot; height=&quot;218&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;li&gt;완전 그래프(complete graph): 각각의 정점에서 다른 모든 정점을 연결한 그래프&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSsAUV/btsK68sFOcO/ccbMal36iK70QM6M80L721/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSsAUV/btsK68sFOcO/ccbMal36iK70QM6M80L721/img.png&quot; data-origin-width=&quot;292&quot; data-origin-height=&quot;273&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.5831%; margin-right: 10px;&quot; data-widthpercent=&quot;50.17&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSsAUV/btsK68sFOcO/ccbMal36iK70QM6M80L721/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSsAUV%2FbtsK68sFOcO%2FccbMal36iK70QM6M80L721%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;292&quot; height=&quot;273&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEldbM/btsK74QEeCS/cUeOrYtDseOUjntEtgyaC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEldbM/btsK74QEeCS/cUeOrYtDseOUjntEtgyaC1/img.png&quot; data-origin-width=&quot;289&quot; data-origin-height=&quot;272&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.2541%;&quot; data-widthpercent=&quot;49.83&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEldbM/btsK74QEeCS/cUeOrYtDseOUjntEtgyaC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEldbM%2FbtsK74QEeCS%2FcUeOrYtDseOUjntEtgyaC1%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;289&quot; height=&quot;272&quot;/&gt;&lt;/span&gt;&lt;/div&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;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;가중치 그래프(weight graph)와 부분 그래프(Sub graph)&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NWObT/btsK8Jd8Zkf/z2zd1ZvNhbcNawckXJYoeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NWObT/btsK8Jd8Zkf/z2zd1ZvNhbcNawckXJYoeK/img.png&quot; data-origin-width=&quot;270&quot; data-origin-height=&quot;214&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.6263%; margin-right: 10px;&quot; data-widthpercent=&quot;50.21&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NWObT/btsK8Jd8Zkf/z2zd1ZvNhbcNawckXJYoeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNWObT%2FbtsK8Jd8Zkf%2Fz2zd1ZvNhbcNawckXJYoeK%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;270&quot; height=&quot;214&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjPuVf/btsK76OpmGF/ktxOeR6rHjZ8dKUs3IpvU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjPuVf/btsK76OpmGF/ktxOeR6rHjZ8dKUs3IpvU1/img.png&quot; data-origin-width=&quot;279&quot; data-origin-height=&quot;223&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.2109%;&quot; data-widthpercent=&quot;49.79&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjPuVf/btsK76OpmGF/ktxOeR6rHjZ8dKUs3IpvU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjPuVf%2FbtsK76OpmGF%2FktxOeR6rHjZ8dKUs3IpvU1%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;279&quot; height=&quot;223&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;그래프의 집합 표현&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xq7A8/btsK74Xr181/LzTc0sCe6t5v8jJp3Da240/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xq7A8/btsK74Xr181/LzTc0sCe6t5v8jJp3Da240/img.png&quot; data-origin-width=&quot;281&quot; data-origin-height=&quot;235&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.3308%; margin-right: 10px;&quot; data-widthpercent=&quot;49.91&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xq7A8/btsK74Xr181/LzTc0sCe6t5v8jJp3Da240/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxq7A8%2FbtsK74Xr181%2FLzTc0sCe6t5v8jJp3Da240%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;281&quot; height=&quot;235&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bziJpH/btsK7fFlP9z/qulKDxVjCQh8cPmQjjkeDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bziJpH/btsK7fFlP9z/qulKDxVjCQh8cPmQjjkeDK/img.png&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;230&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.5064%;&quot; data-widthpercent=&quot;50.09&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bziJpH/btsK7fFlP9z/qulKDxVjCQh8cPmQjjkeDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbziJpH%2FbtsK7fFlP9z%2FqulKDxVjCQh8cPmQjjkeDK%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;276&quot; height=&quot;230&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IDiBY/btsK8pNKKxA/KCk736FVXZkU5qQ1kkOq9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IDiBY/btsK8pNKKxA/KCk736FVXZkU5qQ1kkOq9k/img.png&quot; data-origin-width=&quot;278&quot; data-origin-height=&quot;228&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.2226%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;50.81&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IDiBY/btsK8pNKKxA/KCk736FVXZkU5qQ1kkOq9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIDiBY%2FbtsK8pNKKxA%2FKCk736FVXZkU5qQ1kkOq9k%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;228&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QqKQV/btsK8j7OgN9/hxpKNomoFfTjaxSIvcFiGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QqKQV/btsK8j7OgN9/hxpKNomoFfTjaxSIvcFiGK/img.png&quot; data-origin-width=&quot;275&quot; data-origin-height=&quot;233&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.6146%; margin-top: 10px;&quot; data-widthpercent=&quot;49.19&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QqKQV/btsK8j7OgN9/hxpKNomoFfTjaxSIvcFiGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQqKQV%2FbtsK8j7OgN9%2FhxpKNomoFfTjaxSIvcFiGK%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;275&quot; height=&quot;233&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그래프 G의 정점 집합 &amp;rarr; V(G)&lt;/li&gt;
&lt;li&gt;그래프 G의 간선 집합 &amp;rarr; E(G)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;V(G1) = {A, B, C, D}, E(G1) = {(A,B), (A,C), (A,D), (B,C), (C,D)}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;V(G2) = {A, B, C, D}, E(G2) = {(A,C), (A,D), (B,C)}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;V(G3) = {A, B, C, D}, E(G3) = {&amp;lt;A,B&amp;gt;, &amp;lt;A,C&amp;gt;, &amp;lt;D,A&amp;gt;}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;V(G4) = {A, B, C, D}, E(G4) = {&amp;lt;A,C&amp;gt;, &amp;lt;B,C&amp;gt;, &amp;lt;D,A&amp;gt;}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;그래프의 ADT&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;pre class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;void GraphInit(UALGraph *pg, int nv);
- 그래프의 초기화를 진행
- 두 번째 인자로 정점의 수를 전달

void GraphDestroy(UALGraph *pg);
- 그래프 초기화 과정에서 할당한 리소스를 반환

void AddEdge(UALGraph *pg, int fromV, int toV);
- 매개변수 fromV와 toV로 전달된 정점을 연결하는 간선을 그래프에 추가

void ShowGraphEdgeInfo(UALGraph *pg);
- 그래프의 간선 정보를 출력&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;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;그래프 구현 방법&lt;/u&gt;&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;인접 행렬 기반 그래프 &amp;rarr; 정방 행렬을 활용&lt;/li&gt;
&lt;li&gt;인접 리스트 기반 그래프 &amp;rarr; 연결 리스트 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mCjT1/btsK8TAP92R/BCRFNxDDI60tJ8ssLvxNPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mCjT1/btsK8TAP92R/BCRFNxDDI60tJ8ssLvxNPk/img.png&quot; data-origin-width=&quot;555&quot; data-origin-height=&quot;242&quot; data-is-animation=&quot;false&quot; style=&quot;width: 45.725%; margin-right: 10px;&quot; data-widthpercent=&quot;46.26&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mCjT1/btsK8TAP92R/BCRFNxDDI60tJ8ssLvxNPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmCjT1%2FbtsK8TAP92R%2FBCRFNxDDI60tJ8ssLvxNPk%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;555&quot; height=&quot;242&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cq4ekQ/btsK78yFNfe/JI5qiqkJFdyrsr2fPIsjs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cq4ekQ/btsK78yFNfe/JI5qiqkJFdyrsr2fPIsjs0/img.png&quot; data-origin-width=&quot;642&quot; data-origin-height=&quot;241&quot; data-is-animation=&quot;false&quot; style=&quot;width: 53.1122%;&quot; data-widthpercent=&quot;53.74&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cq4ekQ/btsK78yFNfe/JI5qiqkJFdyrsr2fPIsjs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcq4ekQ%2FbtsK78yFNfe%2FJI5qiqkJFdyrsr2fPIsjs0%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;642&quot; height=&quot;241&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 인접 리스트 기반의 그래프 구현&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;헤더파일 정의&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;typedef struct _ual
{
    int numV;  // 정점의 수
    int numE;  // 간선의 수
    List * adjList;  // 간선의 정보
}

// 그래프 초기화
void GraphInit(UALGraph *pg, int nv);

// 그래프 리소스 해제
void GraphDestroy(UALGraph *pg);

// 간선의 추가
void AddEdge(UALGraph *pg, int fromV, int toV);

// 간선의 정보 출력
void ShowGraphEdgeInfo(UALGraph *pg);&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;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;그래프 구현&lt;/b&gt;&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GraphInit&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;void GraphInit(ALGraph *pg, int nv)
{
    int i;

    // 정점의 수에 해당하는 길이의 리스트 배열을 생성
    pg-&amp;gt; adjList = (List*)malloc(sizeof(List)*nv);  // 간선정보를 저장할 리스트 생성

    pg-&amp;gt;numV = nv;  // 정점의 수는 nv에 저장된 값으로 결정
    pg-&amp;gt;numE = 0;  // 초기 간선 수는 0

    // 정점의 수만큼 생성된 리스트들을 초기화
    for(i=0; i&amp;lt;nv; i++)
    {
        ListInit(&amp;amp;(pg-&amp;gt;adjList[i]));
        SetSortRule(&amp;amp;(pg-&amp;gt;adjList[i]), WhoIsPrecede);  // 리스트의 정렬기준 설정
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GraphDestroy&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;void GraphDestroy(ALGraph * pg)
{
    if(pg-&amp;gt;adjList != NULL)
        free(pq-&amp;gt;adjList);  // 동적으로 할당된 연결 리스트 소멸
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AddEdge&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;pf&quot;&gt;&lt;code&gt;void AddEdge(ALGraph *pg, int fromV, int toV)
{
    // 정점 fromV의 연결 리스트에 정점 toV의 정보 추가
    LInsert(&amp;amp;(pg-&amp;gt;adjList[fromV]), toV);
    // 정점 toV의 연결 리스트에 정점 fromV 정보 추가
    LInsert(&amp;amp;(pg-&amp;gt;adjList[toV], fromV);
    pg-&amp;gt;numE += 1;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 그래프의 탐색&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;깊이 우선 탐색(DFS)&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;438&quot; data-origin-height=&quot;293&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8Wsvk/btsK7caObMi/2ULD4E3GhD7javkFhozBk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8Wsvk/btsK7caObMi/2ULD4E3GhD7javkFhozBk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8Wsvk/btsK7caObMi/2ULD4E3GhD7javkFhozBk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8Wsvk%2FbtsK7caObMi%2F2ULD4E3GhD7javkFhozBk0%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;438&quot; height=&quot;293&quot; data-origin-width=&quot;438&quot; data-origin-height=&quot;293&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DFS의 핵심 ex) 비상연락망
&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;li&gt;처음 연락을 시작한 사람의 위치에서 연락은 끝이 난다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;너비 우선 탐색(BFS)&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d8zHbN/btsK7GJuFiF/8h79lFG43l4SwvDIPHWNZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d8zHbN/btsK7GJuFiF/8h79lFG43l4SwvDIPHWNZ1/img.png&quot; data-origin-width=&quot;391&quot; data-origin-height=&quot;339&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;47.09&quot; style=&quot;width: 46.5404%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d8zHbN/btsK7GJuFiF/8h79lFG43l4SwvDIPHWNZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd8zHbN%2FbtsK7GJuFiF%2F8h79lFG43l4SwvDIPHWNZ1%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;391&quot; height=&quot;339&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsPeut/btsK8V6s06l/33kH8BahfG0QeIzRQs7dIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsPeut/btsK8V6s06l/33kH8BahfG0QeIzRQs7dIk/img.png&quot; data-origin-width=&quot;394&quot; data-origin-height=&quot;304&quot; data-is-animation=&quot;false&quot; style=&quot;width: 52.2968%;&quot; data-widthpercent=&quot;52.91&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsPeut/btsK8V6s06l/33kH8BahfG0QeIzRQs7dIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsPeut%2FbtsK8V6s06l%2F33kH8BahfG0QeIzRQs7dIk%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;394&quot; height=&quot;304&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cd0HwE/btsK7dgoZcY/2JKRPKRXkNqwUal6PHGfN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cd0HwE/btsK7dgoZcY/2JKRPKRXkNqwUal6PHGfN1/img.png&quot; data-origin-width=&quot;388&quot; data-origin-height=&quot;298&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.802%; margin-right: 10px; margin-top: 10px;&quot; data-widthpercent=&quot;50.39&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cd0HwE/btsK7dgoZcY/2JKRPKRXkNqwUal6PHGfN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcd0HwE%2FbtsK7dgoZcY%2F2JKRPKRXkNqwUal6PHGfN1%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;388&quot; height=&quot;298&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckvVMd/btsK8Znrb51/wIgggIS7HZLG0vLi4bhxuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckvVMd/btsK8Znrb51/wIgggIS7HZLG0vLi4bhxuk/img.png&quot; data-origin-width=&quot;391&quot; data-origin-height=&quot;305&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.0352%; margin-top: 10px;&quot; data-widthpercent=&quot;49.61&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckvVMd/btsK8Znrb51/wIgggIS7HZLG0vLi4bhxuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckvVMd%2FbtsK8Znrb51%2FwIgggIS7HZLG0vLi4bhxuk%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;391&quot; height=&quot;305&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;DFS 구현&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3odvB/btsK7bQodmT/Vlrl8ULPAUKGAsLIQUtCW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3odvB/btsK7bQodmT/Vlrl8ULPAUKGAsLIQUtCW1/img.png&quot; data-origin-width=&quot;470&quot; data-origin-height=&quot;349&quot; data-is-animation=&quot;false&quot; style=&quot;width: 43.9545%; margin-right: 10px;&quot; data-widthpercent=&quot;44.47&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3odvB/btsK7bQodmT/Vlrl8ULPAUKGAsLIQUtCW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3odvB%2FbtsK7bQodmT%2FVlrl8ULPAUKGAsLIQUtCW1%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;470&quot; height=&quot;349&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctOepo/btsK7ON2sLQ/EBKyayYvACKPNu2NjFg4tK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctOepo/btsK7ON2sLQ/EBKyayYvACKPNu2NjFg4tK/img.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;314&quot; data-is-animation=&quot;false&quot; style=&quot;width: 54.8827%;&quot; data-widthpercent=&quot;55.53&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctOepo/btsK7ON2sLQ/EBKyayYvACKPNu2NjFg4tK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctOepo%2FbtsK7ON2sLQ%2FEBKyayYvACKPNu2NjFg4tK%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;528&quot; height=&quot;314&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;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;/li&gt;
&lt;li&gt;연결된 노드 중 방문하지 않은 곳이 존재할 때까지 스택에서 꺼낸다.&lt;/li&gt;
&lt;li&gt;모든 노드를 다 방문한 경우, 시작점으로 돌아간다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;BFS 구현&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zz8ZA/btsK9v0wkDU/ifYAvLanHsTWZoDiqdbkHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zz8ZA/btsK9v0wkDU/ifYAvLanHsTWZoDiqdbkHk/img.png&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;455&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4523%; margin-right: 10px;&quot; data-widthpercent=&quot;50.03&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zz8ZA/btsK9v0wkDU/ifYAvLanHsTWZoDiqdbkHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzz8ZA%2FbtsK9v0wkDU%2FifYAvLanHsTWZoDiqdbkHk%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;733&quot; height=&quot;455&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMKeWI/btsK75Pwygg/L0fW9qrvMzNkybbTTPtzj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMKeWI/btsK75Pwygg/L0fW9qrvMzNkybbTTPtzj0/img.png&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;455&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.3849%;&quot; data-widthpercent=&quot;49.97&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMKeWI/btsK75Pwygg/L0fW9qrvMzNkybbTTPtzj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMKeWI%2FbtsK75Pwygg%2FL0fW9qrvMzNkybbTTPtzj0%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;732&quot; height=&quot;455&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;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;/li&gt;
&lt;li&gt;방문하지 않은 노드가 없을 때까지 1,2를 반복함.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 최소 비용 신장 트리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;사이클을 형성하지 않는 그래프&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhYLgB/btsK8lLm2M3/unOUxs3kwUpcHcmQc5SwJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhYLgB/btsK8lLm2M3/unOUxs3kwUpcHcmQc5SwJK/img.png&quot; data-origin-width=&quot;306&quot; data-origin-height=&quot;284&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4385%; margin-right: 10px;&quot; data-widthpercent=&quot;50.02&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhYLgB/btsK8lLm2M3/unOUxs3kwUpcHcmQc5SwJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhYLgB%2FbtsK8lLm2M3%2FunOUxs3kwUpcHcmQc5SwJK%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;306&quot; height=&quot;284&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkpUyo/btsK63Zd5ok/30AHLuQVqpd3IvzXMkqjC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkpUyo/btsK63Zd5ok/30AHLuQVqpd3IvzXMkqjC1/img.png&quot; data-origin-width=&quot;253&quot; data-origin-height=&quot;235&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.3987%;&quot; data-widthpercent=&quot;49.98&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkpUyo/btsK63Zd5ok/30AHLuQVqpd3IvzXMkqjC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkpUyo%2FbtsK63Zd5ok%2F30AHLuQVqpd3IvzXMkqjC1%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;253&quot; height=&quot;235&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;b&gt;경로&lt;/b&gt;라 함.&lt;/li&gt;
&lt;li&gt;그 중 동일한 간선을 중복하여 포함하지 않는 경로를 &lt;b&gt;단순 경로&lt;/b&gt;라 함.&lt;/li&gt;
&lt;li&gt;단순 경로이면서 시작과 끝이 같은 경로를 &lt;b&gt;사이클(cycle)&lt;/b&gt;이라 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;최소 비용 신장 트리의 이해와 적용&lt;/u&gt;&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;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;/li&gt;
&lt;li&gt;신장 트리의 모든 간선의 가중치 합이 최소인 그래프를 &lt;b&gt;최소 비용 신장 트리(MST, minimum cost spanning tree)&lt;/b&gt;라 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkMSvu/btsK8t3FYWI/nBe3teDfCkZsZgGyRZOMSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkMSvu/btsK8t3FYWI/nBe3teDfCkZsZgGyRZOMSK/img.png&quot; data-origin-width=&quot;277&quot; data-origin-height=&quot;227&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.9234%; margin-right: 10px;&quot; data-widthpercent=&quot;51.52&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkMSvu/btsK8t3FYWI/nBe3teDfCkZsZgGyRZOMSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkMSvu%2FbtsK8t3FYWI%2FnBe3teDfCkZsZgGyRZOMSK%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;277&quot; height=&quot;227&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/X4KuI/btsK7GWXC8c/r74OhWO0nkwGFuxtoDTyXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/X4KuI/btsK7GWXC8c/r74OhWO0nkwGFuxtoDTyXk/img.png&quot; data-origin-width=&quot;279&quot; data-origin-height=&quot;243&quot; data-is-animation=&quot;false&quot; style=&quot;width: 47.9138%;&quot; data-widthpercent=&quot;48.48&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/X4KuI/btsK7GWXC8c/r74OhWO0nkwGFuxtoDTyXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FX4KuI%2FbtsK7GWXC8c%2Fr74OhWO0nkwGFuxtoDTyXk%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;279&quot; height=&quot;243&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;최소 비용 신장 트리의 구성을 위한 크루스칼 알고리즘&lt;/u&gt;&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;크루스칼(Kruskal) 알고리즘
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가중치를 기준으로 간선을 정렬한 후에 MST가 될 때까지 간선을 하나씩 선택 또는 삭제해 나가는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프림(Prim) 알고리즘
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 정점을 시작으로 MST가 될 때까지 트리를 확장해 나가는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzZp40/btsK7JTHqrg/XJudqjPDDY3WCEVyQQkx6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzZp40/btsK7JTHqrg/XJudqjPDDY3WCEVyQQkx6K/img.png&quot; data-origin-width=&quot;594&quot; data-origin-height=&quot;295&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;49.38&quot; style=&quot;width: 48.8024%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzZp40/btsK7JTHqrg/XJudqjPDDY3WCEVyQQkx6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzZp40%2FbtsK7JTHqrg%2FXJudqjPDDY3WCEVyQQkx6K%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;594&quot; height=&quot;295&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IBgru/btsK8jGMVgI/Wywe1eNfmnlFEDFnaBzae0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IBgru/btsK8jGMVgI/Wywe1eNfmnlFEDFnaBzae0/img.png&quot; data-origin-width=&quot;609&quot; data-origin-height=&quot;295&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.0348%;&quot; data-widthpercent=&quot;50.62&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IBgru/btsK8jGMVgI/Wywe1eNfmnlFEDFnaBzae0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIBgru%2FbtsK8jGMVgI%2FWywe1eNfmnlFEDFnaBzae0%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;609&quot; height=&quot;295&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rORDv/btsK8M9K07f/09CFy6DB3VT7fVPWtBANa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rORDv/btsK8M9K07f/09CFy6DB3VT7fVPWtBANa1/img.png&quot; data-origin-width=&quot;608&quot; data-origin-height=&quot;298&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.1973%; margin-right: 10px;&quot; data-widthpercent=&quot;49.78&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rORDv/btsK8M9K07f/09CFy6DB3VT7fVPWtBANa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrORDv%2FbtsK8M9K07f%2F09CFy6DB3VT7fVPWtBANa1%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;608&quot; height=&quot;298&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cblhvz/btsK73RFQ1S/1g0uI56ZcoMZ5Et8WgHLu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cblhvz/btsK73RFQ1S/1g0uI56ZcoMZ5Et8WgHLu0/img.png&quot; data-origin-width=&quot;597&quot; data-origin-height=&quot;290&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.6399%;&quot; data-widthpercent=&quot;50.22&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cblhvz/btsK73RFQ1S/1g0uI56ZcoMZ5Et8WgHLu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcblhvz%2FbtsK73RFQ1S%2F1g0uI56ZcoMZ5Et8WgHLu0%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;597&quot; height=&quot;290&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;b&gt;크루스칼 알고리즘의 핵심&lt;/b&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;li&gt;사이클을 형성하는 간선은 추가하지 않음&lt;/li&gt;
&lt;li&gt;간선의 수가 정점의 수보다 하나 적을 때 MST 완성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;반대로 간선을 내림차순 정렬하고 하나씩 소거하는 방법도 존재함.&lt;/li&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;/li&gt;
&lt;li&gt;높은 가중치의 간선부터 시작해서 하나씩 그래프에서 제거&lt;/li&gt;
&lt;li&gt;두 정점을 연결하는 다른 경로가 없을 경우 간선을 제거하지 않음&lt;/li&gt;
&lt;li&gt;간선의 수가 정점의 수보다 하나 적을 때 MST 완성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;윤성우의 열혈 자료구조 (윤성우 저, 2023.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/자료구조</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/64</guid>
      <comments>https://onyodev.tistory.com/64#entry64comment</comments>
      <pubDate>Thu, 5 Dec 2024 16:10:50 +0900</pubDate>
    </item>
    <item>
      <title>테이블(Table)과 해쉬(Hash)</title>
      <link>https://onyodev.tistory.com/63</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 윤성우 저 - &quot;윤성우의 열혈 자료구조&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 빠른 탐색을 보이는 해쉬 테이블&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;테이블(Table) 자료구조의 이해&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블 자료구조의 탐색 연산은 O(1)의 시간 복잡도를 보임.&lt;/li&gt;
&lt;li&gt;저장되는 데이터는 키(key)와 값(value)가 하나의 쌍을 이루며 모든 키는 중복되지 않음&lt;/li&gt;
&lt;li&gt;테이블은 사전 구조라고도 불리며 맵(map)이라고도 불림.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;352&quot; data-origin-height=&quot;226&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FbzUj/btsK8YIIMA9/fJBoTFZowzRE5MJNbgzkAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FbzUj/btsK8YIIMA9/fJBoTFZowzRE5MJNbgzkAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FbzUj/btsK8YIIMA9/fJBoTFZowzRE5MJNbgzkAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFbzUj%2FbtsK8YIIMA9%2FfJBoTFZowzRE5MJNbgzkAK%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;274&quot; height=&quot;176&quot; data-origin-width=&quot;352&quot; data-origin-height=&quot;226&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;테이블에 의미를 부여하는 해쉬 함수와 충돌 문제&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열을 기반으로 한 테이블의 문제점 ex) 직원 테이블
&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;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Psrsq/btsK8m4p0RM/ign4ncmHG4kRQRYKoZ1MP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Psrsq/btsK8m4p0RM/ign4ncmHG4kRQRYKoZ1MP0/img.png&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;325&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.2771%; margin-right: 10px;&quot; data-widthpercent=&quot;48.85&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Psrsq/btsK8m4p0RM/ign4ncmHG4kRQRYKoZ1MP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPsrsq%2FbtsK8m4p0RM%2Fign4ncmHG4kRQRYKoZ1MP0%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;574&quot; height=&quot;325&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ljouq/btsK9j6UbJu/xYukoJdR62FczAKm81VC61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ljouq/btsK9j6UbJu/xYukoJdR62FczAKm81VC61/img.png&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;306&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.5601%;&quot; data-widthpercent=&quot;51.15&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ljouq/btsK9j6UbJu/xYukoJdR62FczAKm81VC61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fljouq%2FbtsK9j6UbJu%2FxYukoJdR62FczAKm81VC61%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;566&quot; height=&quot;306&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해쉬 함수(hash function): 넓은 범위의 키를 좁은 범위의 키로 변경하는 역할을 함.&lt;/li&gt;
&lt;li&gt;8자리 고유번호를 2자리 단위로 변경함.&lt;/li&gt;
&lt;li&gt;하지만, 이 경우도 충돌 문제가 발생하기 때문에 해결책이 아닌 회피책이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;좋은 해쉬 함수의 조건&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3WRuJ/btsK8HAul6x/kzDaMb4cqJTo7JdIyZS8C1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3WRuJ/btsK8HAul6x/kzDaMb4cqJTo7JdIyZS8C1/img.png&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;140&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.2927%; margin-right: 10px;&quot; data-widthpercent=&quot;50.88&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3WRuJ/btsK8HAul6x/kzDaMb4cqJTo7JdIyZS8C1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3WRuJ%2FbtsK8HAul6x%2FkzDaMb4cqJTo7JdIyZS8C1%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;557&quot; height=&quot;140&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bntVtV/btsK7DlxvXx/oyx5QM2EjKcxmM3zH1wqbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bntVtV/btsK7DlxvXx/oyx5QM2EjKcxmM3zH1wqbk/img.png&quot; data-origin-width=&quot;553&quot; data-origin-height=&quot;144&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.5445%;&quot; data-widthpercent=&quot;49.12&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bntVtV/btsK7DlxvXx/oyx5QM2EjKcxmM3zH1wqbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbntVtV%2FbtsK7DlxvXx%2Foyx5QM2EjKcxmM3zH1wqbk%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;553&quot; height=&quot;144&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;li&gt;좋은 해쉬 함수는 키의 일부분이 아닌 전체를 참조하여 해쉬 값을 만들어 내는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;자릿수 선택(digit selection) 방법과 자릿수 폴딩(digit folding) 방법&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&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;li&gt;그리고 유사하게 탐색 키의 비트 열에서 일부를 추출 및 조합하는 비트 추출 방법도 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자릿수 폴딩(digit folding)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;344&quot; data-origin-height=&quot;93&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvtyFC/btsK7Of2xGQ/bfXydpFbbGPqlgrf8E8EGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvtyFC/btsK7Of2xGQ/bfXydpFbbGPqlgrf8E8EGk/img.png&quot; data-alt=&quot;27 + 34 + 19 = 80&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvtyFC/btsK7Of2xGQ/bfXydpFbbGPqlgrf8E8EGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvtyFC%2FbtsK7Of2xGQ%2FbfXydpFbbGPqlgrf8E8EGk%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;344&quot; height=&quot;93&quot; data-origin-width=&quot;344&quot; data-origin-height=&quot;93&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;27 + 34 + 19 = 80&lt;/figcaption&gt;
&lt;/figure&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;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 충돌(Collision) 문제의 해결책&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;선형 조사법(Linear Probing)과 이차 조사법(Quadratic Probing)&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y7v7U/btsK6MiTSJc/LWqbn83DSCld17DJcnM121/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y7v7U/btsK6MiTSJc/LWqbn83DSCld17DJcnM121/img.png&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;120&quot; data-is-animation=&quot;false&quot; style=&quot;width: 47.6794%; margin-right: 10px;&quot; data-widthpercent=&quot;48.24&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y7v7U/btsK6MiTSJc/LWqbn83DSCld17DJcnM121/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy7v7U%2FbtsK6MiTSJc%2FLWqbn83DSCld17DJcnM121%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;532&quot; height=&quot;120&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EG92E/btsK8qsdvPF/D4mJrAk0JX1qVBttFBp4m1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EG92E/btsK8qsdvPF/D4mJrAk0JX1qVBttFBp4m1/img.png&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;111&quot; data-is-animation=&quot;false&quot; style=&quot;width: 51.1578%;&quot; data-widthpercent=&quot;51.76&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EG92E/btsK8qsdvPF/D4mJrAk0JX1qVBttFBp4m1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEG92E%2FbtsK8qsdvPF%2FD4mJrAk0JX1qVBttFBp4m1%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;528&quot; height=&quot;111&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;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;k의 키에서 충돌 발생시 선형 조사법의 조사 순서&lt;/li&gt;
&lt;/ul&gt;
$$ f(k)+1 &amp;rarr; f(k)+2 &amp;rarr; f(k)+3 &amp;rarr; f(k)+4 ... $$
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이러한 방법은 충돌 횟수가 증가함에 따라 특정 영역에 데이터가 집중적으로 몰리는 클러스터(cluster) 현상이 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이차 조사법
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이러한 단점을 극복하기 위해 충돌 발생 시 $n^2$칸 옆 슬롯을 검사한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;슬롯의 상태
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;EMPTY : 이 슬롯에는 데이터에 저장된 바 없다.&lt;/li&gt;
&lt;li&gt;DELETED : 이 슬롯에는 데이터가 저장된 바 있으나 현재는 비워진 상태&lt;/li&gt;
&lt;li&gt;INUSE : 이 슬롯에는 현재 유효한 데이터가 저장되어 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;만약 키가 9인 데이터를 삭제한 경우의 슬롯 상태이다.&lt;/li&gt;
&lt;li&gt;해쉬 값이 2인 데이터는 DELETED 상태&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;525&quot; data-origin-height=&quot;110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/T95F2/btsK86NvSug/Hau3pbPVFQzTeLuD7y49vk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/T95F2/btsK86NvSug/Hau3pbPVFQzTeLuD7y49vk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/T95F2/btsK86NvSug/Hau3pbPVFQzTeLuD7y49vk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FT95F2%2FbtsK86NvSug%2FHau3pbPVFQzTeLuD7y49vk%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;525&quot; height=&quot;110&quot; data-origin-width=&quot;525&quot; data-origin-height=&quot;110&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이전 키가 2인 데이터가 충돌로 밀려났기 때문에 해쉬 값이 3으로 저장된 상황.&lt;/li&gt;
&lt;li&gt;키가 2인 데이터 탐색을 위해 해쉬 함수를 거치면서 2를 인덱스로 하여 탐색을 진행&lt;/li&gt;
&lt;li&gt;만약, DELETED 상태가 없이 EMPTY였다면 존재하지 않는다고 판단하여 탐색을 종료함.&lt;/li&gt;
&lt;li&gt;하지만 DELETED 상태였기 때문에 충돌이 발생했었음을 의심할 수 있고 선형 조사법에 근거하여 탐색을 진행함.&lt;/li&gt;
&lt;li&gt;결론
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;선형, 이차 조사법과 같은 충돌 해결책을 적용하기 위해선 DELETED 상태가 존재해야 함.&lt;/li&gt;
&lt;li&gt;선형, 이차 조사법을 적용했다면, 탐색 과정에서도 이를 근거로 충돌을 의심하는 탐색의 과정을 포함해야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이중 해쉬(Double Hash)&lt;/b&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;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;1차 해쉬 함수: 키를 근거로 저장위치를 결정하기 위한 것, $h1(k)=k\%15$&lt;/li&gt;
&lt;li&gt;2차 해쉬 함수: 충돌 발생시 몇 칸 뒤를 살필지 결정하기 위한 것, $h2(k)=1+(k\%c)$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;해쉬 함수를 이중으로 두면 1차 해쉬 함수 값이 같더라도 2차 해쉬 함수 값이 달라져 클러스터 현상을 낮출 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;⛓️체이닝(chaining)&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;열린 어드레싱 방법(open addressing method): 충돌이 발생하면 다른 자리에 대신 저장한다는 의미&lt;/li&gt;
&lt;li&gt;닫힌 어드레싱 방법(closed addressing method): 충돌이 발생해도 자신의 자리에 저장을 한다는 의미&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rZBaQ/btsK7R4TDEi/R6UvYlbdOKxXKXK1a4poO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rZBaQ/btsK7R4TDEi/R6UvYlbdOKxXKXK1a4poO1/img.png&quot; data-origin-width=&quot;434&quot; data-origin-height=&quot;280&quot; data-is-animation=&quot;false&quot; style=&quot;width: 51.3048%; margin-right: 10px;&quot; data-widthpercent=&quot;51.91&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rZBaQ/btsK7R4TDEi/R6UvYlbdOKxXKXK1a4poO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrZBaQ%2FbtsK7R4TDEi%2FR6UvYlbdOKxXKXK1a4poO1%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;434&quot; height=&quot;280&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y3wUk/btsK9eEzGOG/Qtnq1k2kK7FC6aS8JhYO80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y3wUk/btsK9eEzGOG/Qtnq1k2kK7FC6aS8JhYO80/img.png&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;383&quot; data-is-animation=&quot;false&quot; style=&quot;width: 47.5324%;&quot; data-widthpercent=&quot;48.09&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y3wUk/btsK9eEzGOG/Qtnq1k2kK7FC6aS8JhYO80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy3wUk%2FbtsK9eEzGOG%2FQtnq1k2kK7FC6aS8JhYO80%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;550&quot; height=&quot;383&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;li&gt;&lt;b&gt;&lt;b&gt;체이닝을 구현하면 슬롯의 상태 정보를 표시할 필요가 없어짐&lt;/b&gt;&lt;/b&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;402&quot; data-origin-height=&quot;79&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bavjAg/btsK7Taw4pO/haPZNPAckkCt20HRRyRkAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bavjAg/btsK7Taw4pO/haPZNPAckkCt20HRRyRkAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bavjAg/btsK7Taw4pO/haPZNPAckkCt20HRRyRkAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbavjAg%2FbtsK7Taw4pO%2FhaPZNPAckkCt20HRRyRkAK%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;402&quot; height=&quot;79&quot; data-origin-width=&quot;402&quot; data-origin-height=&quot;79&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;typedef int Key;
typedef Person * Value;

typedef struct _slot
{
	Key key;
	Value val;
} Slot;

#define MAX_TBL 100

typedef int HashFunc(Key k);

typedef struct _table
{
	List tbl[MAX_TBL];
	HashFunc * hf;
} Table;

void TBLInit(Table * pt, HashFunc *f);
void TBLInsert(Table * pt, Key k, Value v);
void TBLDelete(Table * pt, Key k);
void TBLSearch(Table * pt, Key k);
&lt;/code&gt;&lt;/pre&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;연결 리스트 노드의 data가 slot형 변수의 주소 값이 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;typedef Slot * Data;

typedef struct _node
{
	Data data;
	struct _node * next;
} Node;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;그 외의 코드는 연결리스트 구현과 동일하게 진행됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 id=&quot;head52&quot; data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;윤성우의 열혈 자료구조 (윤성우 저, 2023.10)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>[컴퓨터 과학자 스터디]/자료구조</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/63</guid>
      <comments>https://onyodev.tistory.com/63#entry63comment</comments>
      <pubDate>Thu, 5 Dec 2024 14:43:40 +0900</pubDate>
    </item>
    <item>
      <title>데이터베이스 응용 기술</title>
      <link>https://onyodev.tistory.com/62</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 김연희 저 - &quot;데이터베이스 개론 3판&quot;을 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 객체지향 데이터베이스&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 객체지향 데이터 모델&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;/li&gt;
&lt;li&gt;의미상 관계가 있는 데이터베이스 구조를 표현할 때의 강력한 설계 기능 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;객체와 식별자&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체(object): 현실 세계에 존재하는 개체를 추상적으로 표현한 것&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;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;속성과 메서드&lt;/span&gt;&lt;/u&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;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;u&gt;속성(attribute)&lt;/u&gt;&lt;/span&gt;은 데이터 모델의 속성과 같은 의미로 볼 수 있음&lt;/li&gt;
&lt;li&gt;하지만 객체지향 데이터 모델의 속성은 값을 여러 개 가질 수 있고 사용자가 정의한 클래스뿐 아니라 해당 클래스의 하위 클래스도 도메인으로 정의할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;u&gt;메서드(method)&lt;/u&gt;&lt;/span&gt;는 객체에 수행할 수 있는 연산이고 객체의 속성 값을 검색&amp;bull;추가&amp;bull;삭제&amp;bull;수정하는 데 주로 사용 (프로그래밍의 함수 기능)&lt;/li&gt;
&lt;li&gt;특정 객체의 속성과 메서드에 접근하려면 &lt;u&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;메시지(message)&lt;/span&gt;&lt;/u&gt;를 사용해야 함.&lt;/li&gt;
&lt;li&gt;한 객체의 속성 값을 수정하기 위해 이 역할을 담당하는 메서드를 실행시키는 메시지를 해당 객체에 보내야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;클래스&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스(class)는 속성과 메서드를 공유하는 유사한 성질의 객체들을 하나로 그룹화한 것&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;&lt;u&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;클래스 계층과 상속&lt;/span&gt;&lt;/u&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;li&gt;상위클래스와 하위클래스는 일반적으로 IS-A가 성립한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;IS-A는 A is B라는 의미&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u4JTC/btsK7KqQ0kY/adF6C7LSL4DvplEulA0D00/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u4JTC/btsK7KqQ0kY/adF6C7LSL4DvplEulA0D00/img.jpg&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;178&quot; data-is-animation=&quot;false&quot; style=&quot;width: 41.8173%; margin-right: 10px;&quot; data-widthpercent=&quot;42.31&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u4JTC/btsK7KqQ0kY/adF6C7LSL4DvplEulA0D00/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu4JTC%2FbtsK7KqQ0kY%2FadF6C7LSL4DvplEulA0D00%2Fimg.jpg&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;530&quot; height=&quot;178&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/onPt4/btsK6oPT8r9/mW8KWp4zGTAIaFdSU4RRGk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/onPt4/btsK6oPT8r9/mW8KWp4zGTAIaFdSU4RRGk/img.jpg&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;100&quot; data-is-animation=&quot;false&quot; style=&quot;width: 57.0199%;&quot; data-widthpercent=&quot;57.69&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/onPt4/btsK6oPT8r9/mW8KWp4zGTAIaFdSU4RRGk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FonPt4%2FbtsK6oPT8r9%2FmW8KWp4zGTAIaFdSU4RRGk%2Fimg.jpg&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;406&quot; height=&quot;100&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;u&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;상속(inheritance)&lt;/span&gt;&lt;/u&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;u&gt;복합 객체&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;220&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lv6Uw/btsK6nKcJYA/HzamumKcTWvdwKObO5r290/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lv6Uw/btsK6nKcJYA/HzamumKcTWvdwKObO5r290/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lv6Uw/btsK6nKcJYA/HzamumKcTWvdwKObO5r290/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flv6Uw%2FbtsK6nKcJYA%2FHzamumKcTWvdwKObO5r290%2Fimg.jpg&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;536&quot; height=&quot;171&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;220&quot;/&gt;&lt;/span&gt;&lt;/figure&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;u&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;복합 객체(composite object)&lt;/span&gt;&lt;/u&gt;라 한다.&lt;/li&gt;
&lt;li&gt;복합 객체에서 사용자 정의 클래스를 도메인으로 하는 속성은 해당 클래스에 속하는 객체 인스턴스의 객체 식별자를 값으로 가지게 됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 객체지향 질의 모델&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;/li&gt;
&lt;li&gt;클래스 하나 또는 클래스 하나와 해당 클래스의 하위 클래스 전체를 대상으로 하는 질의를 단일 오퍼랜드(single operand)라고 한다.&lt;/li&gt;
&lt;li&gt;여러 클래스를 대상으로 하는 질의를 다중 오퍼랜드(multiple operand)라 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;tp&quot;&gt;&lt;code&gt;(예) 
SELECT P
FROM P : 운동선수
WHERE P.키 〉= 180 AND P.소속팀.연고지 = '서울';
&amp;rarr; 키가 180이상이고, 소속팀의 연고지가 서울인 모든 운동선수 검색
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 객체관계 데이터베이스&lt;/h2&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;u&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;관계 데이터 모델에 객체지향 개념을 적용&lt;/span&gt;&lt;/u&gt;한 객체관계 데이터 모델을 사용하는 객체관계 데이터베이스가 나타남.&lt;/li&gt;
&lt;li&gt;객체관계 데이터 모델은 객체지향 개념과 관계 데이터 모델의 개념을 통합한 것&lt;/li&gt;
&lt;li&gt;릴레이션, 객체, 메서드, 클래스, 상속, 캡슐화, 복합 객체 등 모두 지원함.&lt;/li&gt;
&lt;li&gt;관계 데이터베이스 표준 질의어 SQL을 표준으로 채택하여 발전 중&lt;/li&gt;
&lt;li&gt;객체관계 데이터베이스를 위한 SQL은 기본 질의어 기능과 사용자 정의 타입, 객체, 객체 식별자, 메서드 등과 같은 객체지향 특성도 갖고 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;객체지향 데이터베이스 vs 객체관계 데이터베이스&lt;/span&gt;&lt;/u&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;u&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;객체지향 데이터베이스&lt;/span&gt;&lt;/u&gt;는 객체지향 프로그래밍 기반에서 데이터베이스의 기능을 추가하는 데에 목적&lt;/li&gt;
&lt;li&gt;반면, &lt;u&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;객체관계 데이터베이스&lt;/span&gt;&lt;/u&gt;는 관계 데이터베이스에 기반을 두고 사용자가 더 풍부한 데이터 타입을 추가할 수 있도록 한 것이 목적&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 분산 데이터베이스 시스템&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스 시스템을 물리적으로 한 장소에 설치하여 운영하는 것을 &lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;중앙 집중식 데이터베이스 시스템&lt;/span&gt;&lt;/u&gt;이라 함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 물리적으로 분산된 데이터베이스 시스템을 네트워크로 연결해, 사용자가 논리적으로 하나의 집중식 데이터베이스 시스템처럼 사용할 수 있도록 한 것을 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;분산 데이터베이스 시스템&lt;/u&gt;&lt;/span&gt;이라 함.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 분산 데이터베이스 시스템의 구성&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dCctfP/btsK77Tqkcx/NuiEqXE5QxkRgulY5ZKPhk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dCctfP/btsK77Tqkcx/NuiEqXE5QxkRgulY5ZKPhk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dCctfP/btsK77Tqkcx/NuiEqXE5QxkRgulY5ZKPhk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdCctfP%2FbtsK77Tqkcx%2FNuiEqXE5QxkRgulY5ZKPhk%2Fimg.jpg&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;406&quot; height=&quot;287&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;분산 처리기&lt;/span&gt;&lt;/u&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;분산 처리기는 지역에서 운영하는 데이터베이스를 자체적으로 관리할 수 있는 DBMS를 갖고 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;분산 데이터베이스&lt;/span&gt;&lt;/u&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;보통 해당 지역에서 가장 많이 사용하는 데이터를 저장하며 각 지역 분산 처리기에 설치된 DBMS가 관리함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;통신 네트워크&lt;/u&gt;&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;h4 data-ke-size=&quot;size20&quot;&gt;2. 분산 데이터베이스 시스템의 주요 목표&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;분산 데이터 독립성&lt;/span&gt;&lt;/u&gt;은 데이터베이스가 분산되지 않은 것처럼 사용할 수 있다는 의미로 분산 데이터베이스 시스템의 주요 목표이다.&lt;/li&gt;
&lt;li&gt;그리고 분산 데이터 독립성을 지원하기 위해서는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;분산 투명성&lt;/u&gt;&lt;/span&gt;을 보장해야 함.&lt;/li&gt;
&lt;li&gt;분산 투명성에는 위치 투명성, 중복 투명성, 단편화 투명성, 병행 투명성, 장애 투명성이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;위치 투명성&lt;/span&gt;&lt;/u&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;li&gt;&lt;b&gt;다른 지역에 있는 데이터 접근 요청의 경우 처리 방법&lt;/b&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;li&gt;이 두 가지 방법을 모두 사용해 처리&lt;/li&gt;
&lt;/ul&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;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;중복 투명성&lt;/span&gt;&lt;/u&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;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;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;데이터 중복의 장단점&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.0465%;&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;/td&gt;
&lt;td style=&quot;width: 88.8372%;&quot;&gt;내용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.0465%;&quot;&gt;장점&lt;/td&gt;
&lt;td style=&quot;width: 88.8372%;&quot;&gt;1. 한 지역에서 문제가 발생해도 다른 지역에서 작업 수행이 가능하므로 신뢰성, 가용성이 높아짐&lt;br /&gt;2. &lt;span&gt;동일한 데이터가 저장된 여저 지역에서 병렬 처리가 가능하여 데이터 처리 성능 향상&lt;br /&gt;&lt;/span&gt;&lt;span&gt;3. 데이터 처리 요청이 여러 지역에 분산되어 처리 부담을 줄일 수 있음&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 11.0465%;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;단점&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 88.8372%;&quot;&gt;&lt;span&gt;&lt;span&gt;1. 저장 공간을 많이 사용함.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;2. 데이터 변경 시 중복 저장된 데이터를 모두 같이 변경해야 하므로 비용 증가 및 데이터 불일치 발생&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;b&gt;완전 중복&lt;/b&gt;: 동일한 데이터를 둘 이상의 지역에 있는 분산 데이터베이스에 저장하는 방법&lt;/li&gt;
&lt;li&gt;&lt;b&gt;부분 중복&lt;/b&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;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;단편화 투명성&lt;/span&gt;&lt;/u&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;u&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;단편화&lt;/span&gt;&lt;/u&gt;는 하나의 릴레이션을 더 작은 조각(단편)으로 나누고 각 조각을 별개의 릴레이션으로 처리하는 것&lt;/li&gt;
&lt;li&gt;단편화를 하면 각 조각이 전체 릴레이션의 일부가 되기 때문에 저장 공간을 적게 사용하고 관리할 데이터 수도 줄어듦&lt;/li&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;/li&gt;
&lt;li&gt;회복성: 단편화된 조각들로부터 원래의 전체 릴레이션을 회복할 수 있어야 한다.&lt;/li&gt;
&lt;li&gt;분리성: 전체 릴레이션의 모든 조각을 서로 중복되지 않게 분리해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;병행 투명성&lt;/span&gt;&lt;/u&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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;장애 투명성&lt;/u&gt;&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;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 분산 데이터베이스의 구조&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;368&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWTO3y/btsK79DIhUb/8klxJjctR5wES47G2m01e0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWTO3y/btsK79DIhUb/8klxJjctR5wES47G2m01e0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWTO3y/btsK79DIhUb/8klxJjctR5wES47G2m01e0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWTO3y%2FbtsK79DIhUb%2F8klxJjctR5wES47G2m01e0%2Fimg.jpg&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;530&quot; height=&quot;368&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;368&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;전역 개념 스키마&lt;/span&gt;&lt;/u&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;단편화 스키마&lt;/u&gt;&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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;할당 스키마&lt;/span&gt;&lt;/u&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;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;지역 스키마&lt;/span&gt;&lt;/u&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;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. 분산 데이터베이스의 질의 처리&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;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5. 분산 데이터베이스 시스템의 장&amp;bull;단점&lt;/h4&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: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;신뢰성과 가용성 증대&lt;/li&gt;
&lt;li&gt;지역 자치성과 효율성 증대&lt;/li&gt;
&lt;li&gt;확장성 증대&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;li&gt;추가 통신 비용과 처리 비용 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 멀티미디어 데이터베이스 시스템&lt;/h2&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;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 멀티미디어 데이터의 특성&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;멀티미디어 데이터의 유형&amp;nbsp;&amp;nbsp;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;유형&lt;/td&gt;
&lt;td&gt;의미&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;텍스트&lt;/td&gt;
&lt;td&gt;문자로 구성된 데이터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;그래픽&lt;/td&gt;
&lt;td&gt;수학 공식을 기반으로 제작된 벡터 이미지 데이터&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이미지&lt;/td&gt;
&lt;td&gt;정적 이미지나 사진과 같이 픽셀 단위로 표현되는 비트맵 이미지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;비디오&lt;/td&gt;
&lt;td&gt;동영상, 애니메이션&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;오디오&lt;/td&gt;
&lt;td&gt;음성, 소리, 음악&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;대용량 데이터&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;검색 방법이 복잡한 데이터&lt;/b&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: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;초기의 멀티미디어 시스템에서 많이 사용한 방법&lt;/li&gt;
&lt;li&gt;멀티미디어의 특성을 나타내는 키워드나 자세한 설명을 멀티미디어 데이터와 함께 저장했다가 검색에 이용&lt;/li&gt;
&lt;li&gt;많은 양의 데이터를 처리하기에 적합하지 않고 주관적 관점이 포함되어 설명이 달라질 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;li&gt;멀티미디어 데이터가 포함한 내용의 정보를 추출하여 데이터베이스에 저장하는 기술과 이 정보를 이용해 사용자 질의를 처리하는 멀티미디어 데이터용 질의 처리 기법이 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구조가 복잡한 데이터&lt;/b&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;li&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;등록 데이터는 원시 데이터를 처리하는 데 도움이 됨&lt;/li&gt;
&lt;li&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;멀티미디어 데이터들은 공간이나 시간적으로 관련 있는 경우가 많으므로 복잡한 관계성을 표현하고 관리할 수 있는 기술이 필요함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 멀티미디어 데이터베이스의 발전 과정&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;/li&gt;
&lt;/ol&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;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;관계 데이터베이스에서의 멀티미디어 데이터 처리&lt;/span&gt;&lt;/u&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;p data-ke-size=&quot;size16&quot;&gt;EX) GENESIS, STAIRS 등&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이미지, 그래픽 등 대용량 멀티미디어 데이터를 처리하기 위해 이진 대형 객체(BLOB)라는 새로운 데이터 타입을 지원&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;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;객체지향 데이터베이스에서의 멀티미디어 데이터 처리&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1980년대 후반부터 객체지향 데이터베이스를 활용한 방법을 시도하기 시작함.&lt;/li&gt;
&lt;li&gt;다양한 관계의 표현, 데이터 추상화와 캡슐화, 상속 등 멀티미디어 데이터를 처리하는 데 필요한 다양한 기능을 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EX) ORION, MULTOS, MINOS 등&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;h4 data-ke-size=&quot;size20&quot;&gt;3. 멀티미디어 데이터베이스 관리 시스템의 구성&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;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;데이터를 제공할 때 중간에 끊겨서는 안 됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;멀티미디어 데이터를 관리하는 데이터베이스 관리 시스템
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;UniSQL, 오라클, 인포믹스 ,O2, DB2 UDB 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;미디어 데이터 유형에 따라 멀티미디어 데이터베이스 관리 시스템의 구성이 달라짐&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;  파일 시스템을 이용하는 방식&lt;/span&gt;&lt;/u&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;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;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;⛓️ 관계 데이터베이스 관리 시스템을 이용하는 방식&lt;/span&gt;&lt;/u&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;지리 정보 시스템(Geographical Information Systems) 등에서 많이 사용함.&lt;/li&gt;
&lt;li&gt;파일에 저장된 데이터에 대한 처리 요청을 프로그래밍 언어로 작성하고, 관계 데이터베이스에 저장된 데이터에 대한 처리 요청을 SQL 로 작성&lt;/li&gt;
&lt;li&gt;데이터 처리 요청을 위해 두 가지 방법을 모두 지원해야 한다는 부담이 있고 멀티미디어 데이터에 데이터베이스 관리시스템의 고급 기능을 제공할 수 없는 문제가 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;확장된 관계 데이터베이스 관리 시스템을 이용하는 방식&lt;/span&gt;&lt;/u&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;기존 관계 데이터베이스 관리 시스템에 BLOB 객체 데이터 타입을 추가하는 방식&lt;/li&gt;
&lt;li&gt;모든 멀티미디어 데이터에 데이터베이스 관리 시스템의 고급 기능을 제공할 수 있지만 완벽히 지원하기 어려움&lt;/li&gt;
&lt;li&gt;멀티미디어 데이터의 특성을 반영한 처리 요청을 SQL로 표현하기 어려움&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;  객체지향 데이터베이스 관리 시스템을 이용하는 방식&lt;/span&gt;&lt;/u&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;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. 멀티미디어 데이터의 질의&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;멀티미디어 데이터 검색 요청을 SQL로 표현하기 어려워 멀티미디어 데이터베이스 관리 시스템만의 질의 처리 기법이 필요함.&lt;/li&gt;
&lt;li&gt;데이터 자체의 질의보다는 데이터에 포함된 특정 객체, 설명, 키워드를 이용한 질의를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;멀티미디어 데이터 질의 유형&lt;/span&gt;&lt;/u&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;li&gt;비디오 질의: 비디오는 장면을 대상으로 하는 검색 질의&lt;/li&gt;
&lt;li&gt;공간 질의: 주어진 범위 조건에 맞는 특정 위치를 검색하는 질의&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;멀티미디어 데이터 질의 처리&lt;/span&gt;&lt;/u&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;b&gt;매칭(matching) 기법&lt;/b&gt;: 수학 함수로 저장된 데이터와 질의 조건으로 주어진 데이터 간의 유사도를 수학 함수로 계산하여, 유사도가 높은 데이터를 검색&lt;/li&gt;
&lt;li&gt;&lt;b&gt;랭킹(ranking) 기법&lt;/b&gt;: 검색 결과를 질의 조건과의 관련 정도에 따라 정렬하여 관련성이 높은 결과부터 제공&lt;/li&gt;
&lt;li&gt;&lt;b&gt;필터링(filtering) 기법&lt;/b&gt;: 질의 조건과 관련성이 적은 데이터를 단계적으로 제거하여 검색 범위를 줄임&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인덱스(index) 기법&lt;/b&gt;: 인덱스 구조를 이용해 질의 조건에 적합한 데이터 검색&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 기타 데이터베이스 시스템&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 웹 데이터베이스&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WWW(world wide web) 서비스, 즉 인터넷 서비스는 누구나 쉽게 사용할 수 있다는 장점이 있어 대중화에 성공함.&lt;/li&gt;
&lt;li&gt;초기 인터넷 서비스는 단순한 정보 검색 기능만 제공했지만 이후 전자 상거래, 디지털 라이브러리 등 다양한 분야에서 대량의 데이터를 관리하는 새로운 유형의 웹 서비스가 등장.&lt;/li&gt;
&lt;li&gt;새로운 유형의 웹 서비스를 관리하기 위한 웹 서비스와 데이터베이스를 통합한 웹 데이터베이스가 등장함.&lt;/li&gt;
&lt;li&gt;웹 데이터베이스에는 웹 서비스와 데이터베이스 시스템을 연결해주는 &lt;u&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;미들웨어&lt;/span&gt;&lt;/u&gt;가 필요함.&lt;/li&gt;
&lt;li&gt;웹 서비스는 미들웨어를 통해 데이터베이스 시스템의 기능을 제공받기 때문에 미들웨어는 데이터베이스 통로라고도 함.&lt;/li&gt;
&lt;li&gt;미들웨어 구현 방법
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;미들웨어를 통해 데이터베이스에 접근하는 프로그램을 웹 서버 쪽에 두는 서버 확장 방법&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;클라이언트 쪽에 두는 클라이언트 확장 방법&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 데이터 웨어하우스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기업과 같은 대규모 조직에서는 정보 시스템에 저장된 데이터를 분석하고 요약하여 추출한 유용한 정보를 &lt;u&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;의사 결정 지원 시스템&lt;/span&gt;&lt;/u&gt;을 통해 의사 결정에 이용함.&lt;/li&gt;
&lt;li&gt;이 때문에 의사 결정에 도움이 되는 데이터를 빠르고 정확히 추출할 수 있는 방법을 연구하는 데 그 중에 하나가 &lt;u&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;데이터 웨어하우스&lt;/span&gt;&lt;/u&gt;이다.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;데이터 웨어하우스&lt;/span&gt;&lt;/u&gt;는 데이터베이스 시스템에서 의사 결정에 필요한 데이터를 미리 추출하여, 이를 원하는 형태로 변환하고 통합한 읽기 전용의 데이터 저장소이다.&lt;/li&gt;
&lt;li&gt;트랜잭션 처리 중심의 일반 데이터베이스와는 다르게 데이터 웨어하우스는 의사결정을 위한 정보의 집합으로 검색 위주의 의사 결정 업무를 위한 것&lt;/li&gt;
&lt;li&gt;그리고 데이터 웨어하우스는 올바른 의사 결정을 위해 과거와 현재 데이터를 함께 유지함.&amp;nbsp;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8M3ni/btsK7dUoEUG/4R0ZN9fTPcCL8S4SKwekfk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8M3ni/btsK7dUoEUG/4R0ZN9fTPcCL8S4SKwekfk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8M3ni/btsK7dUoEUG/4R0ZN9fTPcCL8S4SKwekfk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8M3ni%2FbtsK7dUoEUG%2F4R0ZN9fTPcCL8S4SKwekfk%2Fimg.jpg&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;530&quot; height=&quot;196&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;196&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;주제 지향적(subject-oriented) 내용&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;div&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;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;통합된(integrated) 내용&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;div&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;li&gt;데이터 웨어하우스는 내부적으로 데이터가 항상 일관된 상태를 유지하도록 여러 데이터베이스에서 추출한 데이터를 통합하여 저장하는 특징&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;시간에 따라 변하는(time-variant) 내용&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;div&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;li&gt;데이터 웨어하우스가 저장하고 있는 각 시점의 데이터를 스냅샷이라 함.&lt;/li&gt;
&lt;li&gt;데이터 간의 시간적 관계나 동향을 분석하여 의사결정을 하기 위해 과거와 현재 데이터를 동시에 유지함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;비소멸성(nonvoatile)을 가진 내용&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 웨어하우스는 검색 작업만 수행되는 읽기 전용의 데이터를 유지하기 때문에 삽입&amp;bull;삭제&amp;bull;갱신 이상이 발생할 염려가 없음&lt;/li&gt;
&lt;/ul&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스 개론 3판 (김연희 저, 2024.1)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/데이터베이스</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/62</guid>
      <comments>https://onyodev.tistory.com/62#entry62comment</comments>
      <pubDate>Thu, 5 Dec 2024 10:49:25 +0900</pubDate>
    </item>
    <item>
      <title>보안과 권한 관리</title>
      <link>https://onyodev.tistory.com/61</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 김연희 저 - &quot;데이터베이스 개론 3판&quot;을 공부하고 정리하여 작성하였습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 보안&lt;/h2&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;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;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;운영 관리를 통한 보안&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 권한 관리&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. 권한 관리의 개념&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;229&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9fw71/btsK6iPIxJb/ZgWYA3CRY8atfRpT3O89yK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9fw71/btsK6iPIxJb/ZgWYA3CRY8atfRpT3O89yK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9fw71/btsK6iPIxJb/ZgWYA3CRY8atfRpT3O89yK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9fw71%2FbtsK6iPIxJb%2FZgWYA3CRY8atfRpT3O89yK%2Fimg.jpg&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;530&quot; height=&quot;229&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;229&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;접근 제어 기능&lt;/b&gt;을 제공&lt;/li&gt;
&lt;li&gt;기존 사용자의 계정 관리는 데이터베이스 관리 시스템의 데이터베이스 관리자가 담당&lt;/li&gt;
&lt;li&gt;데이터베이스 관리자는 데이터베이스 전체 보안 관리를 위한 모든 권한을 갖고 있음&lt;/li&gt;
&lt;li&gt;테이블이나 뷰와 같이 데이터베이스에 존재하는 모든 객체는 기본적으로 생성한 사용자만 사용 권한을 가짐&lt;/li&gt;
&lt;li&gt;데이터베이스 객체 소유자는 필요에 따라 SQL문을 이용해 다른 사용자에게 사용 권한을 부여할 수 있다.&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;690&quot; data-origin-height=&quot;251&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYXlGT/btsK6xlvJVZ/yDse5btSYJU4dzgqEaRNq0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYXlGT/btsK6xlvJVZ/yDse5btSYJU4dzgqEaRNq0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYXlGT/btsK6xlvJVZ/yDse5btSYJU4dzgqEaRNq0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYXlGT%2FbtsK6xlvJVZ%2FyDse5btSYJU4dzgqEaRNq0%2Fimg.jpg&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;690&quot; height=&quot;251&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;251&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. 권한의 부여&lt;/h4&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;GRANT 권한 ON 객체 TO 사용자 [WITH GRANT OPTION];&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GRANT 명령어를 활용해 데이터베이스에 존재하는 모든 유형의 객체에 다른 사용자 권한을 부여할 수 있음&lt;/li&gt;
&lt;li&gt;부여할 수 있는 권한은 &lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;SELECT&lt;/code&gt;, &lt;code&gt;REFERENCES&lt;/code&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;REFERENCES&lt;/code&gt; : 외래키 제약조건을 정의할 수 있는 권한&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;REFERENCES&lt;/code&gt; 권한을 부여받은 사용자는 권한 부여 대상인 테이블의 기본키를 참조하는 외래키를 자신이 생성하는 테이블에 포함할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GRANT&lt;/code&gt;는 테이블을 구성하는 모든 속성에 권한을 부여&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UPDATE&lt;/code&gt; 와 &lt;code&gt;SELECT&lt;/code&gt; 는 테이블을 구성하는 속성들 중 일부 속성만 수정 또는 검색하는 권한을 부여할 수도 있음&lt;/li&gt;
&lt;li&gt;모든 사용자에게 권한을 똑같이 부여하고 싶으면 &lt;code&gt;PUBLIC&lt;/code&gt; 키워드를 사용&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WITH GRANT OPTION&lt;/code&gt; 을 포함하면 권한을 부여받은 사용자가 자신이 부여받은 권한을 다른 사용자에게도 부여할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시스템 권한&lt;/b&gt;은 데이터베이스 관리와 관련된 작업에 대한 권한
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;CREATE TABLE&lt;/code&gt;, &lt;code&gt;CREATE VIEW&lt;/code&gt; 등 데이터 정의어와 관련된 작업&lt;/li&gt;
&lt;li&gt;EX) &lt;code&gt;GRANT CREATE TABLE TO Song;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3. 권한의 취소&lt;/h4&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;REVOKE 권한 ON 객체 FROM 사용자 CASCADE | RESTRICT;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;REVOKE 문을 활용하여 다른 사용자에게 부여했던 권한을 취소할 수도 있음.&lt;img src=&quot;https://blog.kakaocdn.net/dn/bps7cc/btsK8pzx0Tk/Z40WIrMbyMCftavoHaqa81/img.jpg&quot; data-image-src=&quot;https://blog.kakaocdn.net/dn/bps7cc/btsK8pzx0Tk/Z40WIrMbyMCftavoHaqa81/img.jpg&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;470&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;권한을 취소할 사용자 A가 사용자 B에게, 사용자 B는 사용자 C에게 권한을 부여한 경우 처리하는 방법이 각각 존재함.&lt;/li&gt;
&lt;li&gt;사용자 A 가 사용자 B 뿐만 아니라 사용자 C도 권한을 취소하려면 &lt;code&gt;CASCADE&lt;/code&gt; 옵션을 사용&lt;/li&gt;
&lt;li&gt;사용자 A가 사용자 C의 권한은 유지시킬 경우 &lt;code&gt;RESTRICT&lt;/code&gt; 옵션을 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.4. 역할의 부여와 취소&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;239&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dTreQS/btsK7ImiFx2/Ha6KjVAvjTHUUXXa5doA00/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dTreQS/btsK7ImiFx2/Ha6KjVAvjTHUUXXa5doA00/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dTreQS/btsK7ImiFx2/Ha6KjVAvjTHUUXXa5doA00/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdTreQS%2FbtsK7ImiFx2%2FHa6KjVAvjTHUUXXa5doA00%2Fimg.jpg&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;530&quot; height=&quot;239&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;239&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 사용자에게 동일한 권한들을 부여하고 취소하는 번거로운 작업을 편리하게 수행할 수 있도록 도움을 주는 것이 역할(ROLE)이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;CREATE ROLE 롤이름;  // 역할 생성
GRANT 권한 ON 객체 TO 롤이름;  // 역할에 필요한 권한들을 넣는 작업
GRANT 롤이름 TO 사용자;  // 사용자에게 역할 부여

EX)
CREATE ROLE role_1;
GRANT SELECT,INSERT,DELETE ON 고객 TO role_1;
GRANT role_1 TO Hong;&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;530&quot; data-origin-height=&quot;248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2zWtF/btsK8GOAlGF/6JTLkkkPV8FEXNeIPlEEA0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2zWtF/btsK8GOAlGF/6JTLkkkPV8FEXNeIPlEEA0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2zWtF/btsK8GOAlGF/6JTLkkkPV8FEXNeIPlEEA0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2zWtF%2FbtsK8GOAlGF%2F6JTLkkkPV8FEXNeIPlEEA0%2Fimg.jpg&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;530&quot; height=&quot;248&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;/figure&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;code&gt;REVOKE 롤이름 FROM 사용자;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;역할 제거 명령어는 &lt;code&gt;DROP ROLE&lt;/code&gt;문을 사용한다.&lt;/li&gt;
&lt;li&gt;역할을 제거는 데이터베이스 관리자가 담당하며 역할을 제거하면 해당 역할을 부여 받았던 모든 사용자도 역할에 속해 있던 권한을 더는 가지지 못함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스 개론 3판 (김연희 저, 2024.1)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/데이터베이스</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/61</guid>
      <comments>https://onyodev.tistory.com/61#entry61comment</comments>
      <pubDate>Thu, 5 Dec 2024 10:31:05 +0900</pubDate>
    </item>
    <item>
      <title>탐색(Search) 2</title>
      <link>https://onyodev.tistory.com/60</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 윤성우 저 - &quot;윤성우의 열혈 자료구조&quot;를 공부하고 정리하여 작성하였습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 균형 잡힌 이진 탐색 트리: AVL 트리의 이해&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;⚠️ 이진탐색 트리의 문제점과 AVL 트리&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LHbXJ/btsK31GBQ5j/PowbzRLt7I4tMov2imx6UK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LHbXJ/btsK31GBQ5j/PowbzRLt7I4tMov2imx6UK/img.png&quot; data-origin-width=&quot;323&quot; data-origin-height=&quot;361&quot; data-is-animation=&quot;false&quot; style=&quot;width: 37.781%; margin-right: 10px;&quot; data-widthpercent=&quot;38.23&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LHbXJ/btsK31GBQ5j/PowbzRLt7I4tMov2imx6UK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLHbXJ%2FbtsK31GBQ5j%2FPowbzRLt7I4tMov2imx6UK%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;323&quot; height=&quot;361&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dZjN2w/btsK5nuYyyo/hGRYPwOx1ypUxW27P6JnY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dZjN2w/btsK5nuYyyo/hGRYPwOx1ypUxW27P6JnY0/img.png&quot; data-origin-width=&quot;321&quot; data-origin-height=&quot;222&quot; data-is-animation=&quot;false&quot; style=&quot;width: 61.0562%;&quot; data-widthpercent=&quot;61.77&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dZjN2w/btsK5nuYyyo/hGRYPwOx1ypUxW27P6JnY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdZjN2w%2FbtsK5nuYyyo%2FhGRYPwOx1ypUxW27P6JnY0%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;321&quot; height=&quot;222&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이진 탐색 트리의 탐색 연산은 O(logn)의 시간 복잡도를 가짐&lt;/li&gt;
&lt;li&gt;하지만 균형이 맞지 않을수록 O(n)에 가까운 시간 복잡도를 보임.&lt;/li&gt;
&lt;li&gt;이진 탐색 트리의 단점을 해결한 트리를 &amp;lsquo;균형 잡힌 이진 트리&amp;rsquo;라 하며 그 종류는 대략 이렇다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;AVL 트리&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;2-3 트리&lt;/li&gt;
&lt;li&gt;2-3-4 트리&lt;/li&gt;
&lt;li&gt;Red-Black 트리&lt;/li&gt;
&lt;li&gt;B 트리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;⚖️ 자동으로 균형을 잡는 AVL 트리와 균형 인수(Balance Factor)&lt;/span&gt;&lt;/u&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Adelson-Velskii와 Landis에 의해 고안되어 이름도 이들의 이름을 땄음.&lt;/li&gt;
&lt;li&gt;노드가 추가될 때, 그리고 삭제될 때 트리의 균형상태를 파악해서 스스로 그 구조를 변경하여 균형을 잡는 트리&lt;/li&gt;
&lt;li&gt;&lt;code&gt;균형 인수 = 왼쪽 서브 트리의 높이 - 오른쪽 서브 트리의 높이&lt;/code&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;629&quot; data-origin-height=&quot;319&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkXEdo/btsK4ig2sog/0wzVbJZlC5GmOL9DgOOLsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkXEdo/btsK4ig2sog/0wzVbJZlC5GmOL9DgOOLsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkXEdo/btsK4ig2sog/0wzVbJZlC5GmOL9DgOOLsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkXEdo%2FbtsK4ig2sog%2F0wzVbJZlC5GmOL9DgOOLsk%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;629&quot; height=&quot;319&quot; data-origin-width=&quot;629&quot; data-origin-height=&quot;319&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;  리밸런싱이 필요한 첫 번째 상태와 LL 회전&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTeNE2/btsK4YPI69G/xhNo2MN2jLQTSEkqLKnjI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTeNE2/btsK4YPI69G/xhNo2MN2jLQTSEkqLKnjI1/img.png&quot; data-origin-width=&quot;783&quot; data-origin-height=&quot;378&quot; data-is-animation=&quot;false&quot; style=&quot;width: 42.5945%; margin-right: 10px;&quot; data-widthpercent=&quot;43.1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTeNE2/btsK4YPI69G/xhNo2MN2jLQTSEkqLKnjI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTeNE2%2FbtsK4YPI69G%2FxhNo2MN2jLQTSEkqLKnjI1%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;783&quot; height=&quot;378&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7RoD7/btsK3N9uDfJ/mbVB1PW6cBQkGJY1s2jdO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7RoD7/btsK3N9uDfJ/mbVB1PW6cBQkGJY1s2jdO0/img.png&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;219&quot; data-is-animation=&quot;false&quot; style=&quot;width: 56.2427%;&quot; data-widthpercent=&quot;56.9&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7RoD7/btsK3N9uDfJ/mbVB1PW6cBQkGJY1s2jdO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7RoD7%2FbtsK3N9uDfJ%2FmbVB1PW6cBQkGJY1s2jdO0%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;599&quot; height=&quot;219&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ChangeRightSubTree(sNode, pNode)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;일반화&lt;/b&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;820&quot; data-origin-height=&quot;347&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfFm5m/btsK5ugr8gg/1Iz7ZXjIqcLP9wCGnam8ik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfFm5m/btsK5ugr8gg/1Iz7ZXjIqcLP9wCGnam8ik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfFm5m/btsK5ugr8gg/1Iz7ZXjIqcLP9wCGnam8ik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfFm5m%2FbtsK5ugr8gg%2F1Iz7ZXjIqcLP9wCGnam8ik%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;820&quot; height=&quot;347&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;347&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1733125897590&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ChangeLeftSubTree(pNode, GetRightSubTree(cNode));
ChangeRightSubTree(cNode, pNode);&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;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;  리밸런싱이 필요한 두 번째 상태와 RR 회전&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tLXus/btsK24qmR8L/k50i9zZbpxmmlqKDyIaZk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tLXus/btsK24qmR8L/k50i9zZbpxmmlqKDyIaZk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tLXus/btsK24qmR8L/k50i9zZbpxmmlqKDyIaZk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtLXus%2FbtsK24qmR8L%2Fk50i9zZbpxmmlqKDyIaZk0%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;822&quot; height=&quot;366&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;ChangeRightSubTree(pNode, GetLeftSubTree(cNode));
ChangeLeftSubTree(cNode, pNode);
&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;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;  리밸런싱이 필요한 세 번째 상태와 LR 회전&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnlALx/btsK5abtq2H/4QiWn1DnJqDd33eZaZqDIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnlALx/btsK5abtq2H/4QiWn1DnJqDd33eZaZqDIK/img.png&quot; data-origin-width=&quot;713&quot; data-origin-height=&quot;340&quot; data-is-animation=&quot;false&quot; style=&quot;width: 43.1808%; margin-right: 10px;&quot; data-widthpercent=&quot;43.69&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnlALx/btsK5abtq2H/4QiWn1DnJqDd33eZaZqDIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdnlALx%2FbtsK5abtq2H%2F4QiWn1DnJqDd33eZaZqDIK%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;713&quot; height=&quot;340&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kYypy/btsK34cgNrM/kxMU5SPy1M76Ty8eciZQ3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kYypy/btsK34cgNrM/kxMU5SPy1M76Ty8eciZQ3K/img.png&quot; data-origin-width=&quot;646&quot; data-origin-height=&quot;239&quot; data-is-animation=&quot;false&quot; style=&quot;width: 55.6564%;&quot; data-widthpercent=&quot;56.31&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kYypy/btsK34cgNrM/kxMU5SPy1M76Ty8eciZQ3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkYypy%2FbtsK34cgNrM%2FkxMU5SPy1M76Ty8eciZQ3K%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;646&quot; height=&quot;239&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DeFnI/btsK31fwQuS/QTHroqEPenKE0HbZc2QsJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DeFnI/btsK31fwQuS/QTHroqEPenKE0HbZc2QsJ1/img.png&quot; data-origin-width=&quot;630&quot; data-origin-height=&quot;233&quot; data-is-animation=&quot;false&quot; style=&quot;width: 45.0043%; margin-right: 10px;&quot; data-widthpercent=&quot;45.53&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DeFnI/btsK31fwQuS/QTHroqEPenKE0HbZc2QsJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDeFnI%2FbtsK31fwQuS%2FQTHroqEPenKE0HbZc2QsJ1%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;630&quot; height=&quot;233&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNGgha/btsK4XXCpDo/pS31RKX2vD26OH3x4lf0V1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNGgha/btsK4XXCpDo/pS31RKX2vD26OH3x4lf0V1/img.png&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;175&quot; data-is-animation=&quot;false&quot; style=&quot;width: 53.8329%;&quot; data-widthpercent=&quot;54.47&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNGgha/btsK4XXCpDo/pS31RKX2vD26OH3x4lf0V1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNGgha%2FbtsK4XXCpDo%2FpS31RKX2vD26OH3x4lf0V1%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;566&quot; height=&quot;175&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LR 상태는 RR회전을 통해서 LL 상태가 되게 할 수 있음&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;682&quot; data-origin-height=&quot;245&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpmCfg/btsK326yVns/D4NdjTbpGc9zo8beGYb38K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpmCfg/btsK326yVns/D4NdjTbpGc9zo8beGYb38K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpmCfg/btsK326yVns/D4NdjTbpGc9zo8beGYb38K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpmCfg%2FbtsK326yVns%2FD4NdjTbpGc9zo8beGYb38K%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;682&quot; height=&quot;245&quot; data-origin-width=&quot;682&quot; data-origin-height=&quot;245&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;686&quot; data-origin-height=&quot;201&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwX8Sk/btsK2TvRnwh/9WgzB91irSxBQONf9MCTq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwX8Sk/btsK2TvRnwh/9WgzB91irSxBQONf9MCTq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwX8Sk/btsK2TvRnwh/9WgzB91irSxBQONf9MCTq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwX8Sk%2FbtsK2TvRnwh%2F9WgzB91irSxBQONf9MCTq1%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;686&quot; height=&quot;201&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;201&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;  리밸런싱이 필요한 네 번째 상태와 RL 회전&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;229&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brT0gI/btsK3j8FlDW/JT2a4vCBlEFGWc3NzDHA9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brT0gI/btsK3j8FlDW/JT2a4vCBlEFGWc3NzDHA9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brT0gI/btsK3j8FlDW/JT2a4vCBlEFGWc3NzDHA9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrT0gI%2FbtsK3j8FlDW%2FJT2a4vCBlEFGWc3NzDHA9k%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;676&quot; height=&quot;229&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;229&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;669&quot; data-origin-height=&quot;206&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nz3rq/btsK5spppr7/KPVl6izTn7RNdTmktkRQTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nz3rq/btsK5spppr7/KPVl6izTn7RNdTmktkRQTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nz3rq/btsK5spppr7/KPVl6izTn7RNdTmktkRQTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnz3rq%2FbtsK5spppr7%2FKPVl6izTn7RNdTmktkRQTK%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;669&quot; height=&quot;206&quot; data-origin-width=&quot;669&quot; data-origin-height=&quot;206&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자식 노드와 연결된 방향이 LR 상태와 반대인 것 외에는 차이가 없음&lt;/li&gt;
&lt;li&gt;부분적 LL 회전에 이어서 RR 회전을 진행&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 균형 잡힌 이진 탐색 트리: AVL 트리의 구현&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;➕ 확장 포인트&lt;/u&gt;&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BSTInsert 함수 : 트리에 노드를 추가&lt;/li&gt;
&lt;li&gt;BSTRemove 함수: 트리에서 노드를 제거&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;void BSTInsert(BTreeNode ** pRoot, BSTData data)
{
	...
	Rebalance(Root);
}

BTreeNode * BSTRemove(BTreeNode ** pRoot, BSTData target)
{
	...
	Rebalance(pRoot);
	return dNode;
}
&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;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;  추가적인 도구들 1: 트리가 균형을 이루는지를 확인&lt;/span&gt;&lt;/u&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;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;// 트리의 높이를 계산하여 반환
int GetHeight(BTreeNode *bst)
{
	int leftH;
	int rightH;
	
	if(bst == NULL)
		return 0;
	
	leftH = GetHeight(GetLeftSubTree(bst));
	rightH = GetHeight(GetRightSubTree(bst));
	
	// 큰 값의 높이를 반환
	if(leftH &amp;gt; rightH)
		return leftH + 1;
	else
		return rightH + 1;
}

int GetHeightDiff(BTreeNode *bst)
{
	int lsh;
	int rsh;
	
	if(bst == NULL)
		return 0;
	
	lsh = GetHeight(GetLeftSubTree(bst));
	rsh = GetHeight(GetRightSubTree(bst));
	return lsh - rsh;
}
&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;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;  추가적인 도구들 2: LL 회전, RR 회전&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LL 회전&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;531&quot; data-origin-height=&quot;227&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3SgU5/btsK4JrOCcH/5Gz2cjO3nIYwt2rkUkAKJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3SgU5/btsK4JrOCcH/5Gz2cjO3nIYwt2rkUkAKJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3SgU5/btsK4JrOCcH/5Gz2cjO3nIYwt2rkUkAKJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3SgU5%2FbtsK4JrOCcH%2F5Gz2cjO3nIYwt2rkUkAKJk%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;531&quot; height=&quot;227&quot; data-origin-width=&quot;531&quot; data-origin-height=&quot;227&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;BTreeNode * RotateLL(BTreeNode * bst)
{
	BTreeNode * pNode;
	BTreeNode * cNode;
	
	// pNode와 cNode가 LL회전을 위해 적절한 위치를 가리키게 한다.
	pNode = bst;
	cNode = GetLeftSubTree(pNode);
	
	// 실제 LL회전을 담당하는 두 개의 문장
	ChangeLeftSubTree(pNode, GetRightSubTree(cNode));
	ChangeRightSubTree(cNode, pNode);
	
	// LL회전으로 인해서 변경된 루트 노드의 주소 값 반환
	return cNode;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RR 회전&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;BTreeNode * RotateRR(BTreeNode * bst)
{
	BTreeNode * pNode;
	BTreeNode * cNode;
	
	// pNode와 cNode가 RR회전을 위해 적절한 위치를 가리키게 한다.
	pNode = bst;
	cNode = GetRightSubTree(pNode);
	
	// 실제 RR회전을 담당하는 두 개의 문장
	ChangeRightSubTree(pNode, GetLeftSubTree(cNode));
	ChangeLeftSubTree(cNode, pNode);
	
	// RR회전으로 인해서 변경된 루트 노드의 주소 값 반환
	return cNode;
}
&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;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;  추가적인 도구들 3: LR 회전, RL 회전&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LR 회전 &amp;amp; RL 회전&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dhySwd/btsK2WzjrSb/DLOoSvlQyfbnFoI2P3wMV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dhySwd/btsK2WzjrSb/DLOoSvlQyfbnFoI2P3wMV1/img.png&quot; data-origin-width=&quot;554&quot; data-origin-height=&quot;225&quot; data-is-animation=&quot;false&quot; style=&quot;width: 51.6746%; margin-right: 10px;&quot; data-widthpercent=&quot;52.28&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dhySwd/btsK2WzjrSb/DLOoSvlQyfbnFoI2P3wMV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdhySwd%2FbtsK2WzjrSb%2FDLOoSvlQyfbnFoI2P3wMV1%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;554&quot; height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R09It/btsK2YYcljT/5Aa2tRHu8ilo4E8COaUQpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R09It/btsK2YYcljT/5Aa2tRHu8ilo4E8COaUQpk/img.png&quot; data-origin-width=&quot;609&quot; data-origin-height=&quot;271&quot; data-is-animation=&quot;false&quot; style=&quot;width: 47.1626%;&quot; data-widthpercent=&quot;47.72&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R09It/btsK2YYcljT/5Aa2tRHu8ilo4E8COaUQpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR09It%2FbtsK2YYcljT%2F5Aa2tRHu8ilo4E8COaUQpk%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;609&quot; height=&quot;271&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;BTreeNode * RotateLR(BTreeNode * bst)
{
	BTreeNode * pNode;
	BTreeNode * cNode;
	
	// pNode와 cNode가 LR 회전을 위해 적절한 위치를 가리키게 한다.
	pNode = bst;
	cNode = GetLeftSubTree(pNode);
	
	// 실제 LR 회전을 담당하는 두 개의 문장
	ChangeLeftSubTree(pNode, RotateRR(cNode)); // 부분적 RR 회전
	return RotateLL(pNode);  // LL 회전
}

BTreeNode * RotateRL(BTreeNode * bst)
{
	BTreeNode * pNode;
	BTreeNode * cNode;
	
	// pNode와 cNode가 RL 회전을 위해 적절한 위치를 가리키게 한다.
	pNode = bst;
	cNode = GetRightSubTree(pNode);
	
	// 실제 RL 회전을 담당하는 두 개의 문장
	ChangeRightSubTree(pNode, RotateLL(cNode)); // 부분적 LL 회전
	return RotateRR(pNode);  // RR 회전
}
&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;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;  추가적인 도구들 4: Rebalance 함수&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;577&quot; data-origin-height=&quot;254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjwzS7/btsK253SJQT/3hKPGQbk9ect0Py5361NT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjwzS7/btsK253SJQT/3hKPGQbk9ect0Py5361NT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjwzS7/btsK253SJQT/3hKPGQbk9ect0Py5361NT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjwzS7%2FbtsK253SJQT%2F3hKPGQbk9ect0Py5361NT0%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;577&quot; height=&quot;254&quot; data-origin-width=&quot;577&quot; data-origin-height=&quot;254&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;575&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CQp72/btsK4QxzpdZ/dYFo5myFa9KLP1vBn3pAo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CQp72/btsK4QxzpdZ/dYFo5myFa9KLP1vBn3pAo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CQp72/btsK4QxzpdZ/dYFo5myFa9KLP1vBn3pAo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCQp72%2FbtsK4QxzpdZ%2FdYFo5myFa9KLP1vBn3pAo1%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;575&quot; height=&quot;252&quot; data-origin-width=&quot;575&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;BTreeNode * Rebalance(BTreeNode ** pRoot)
{
	int hDiff = GetHeightDiff(*pRoot);  // 균형 인수 계산
	
	// LL or LR 상태
	if(hDiff &amp;gt; 1)
	{
		if(GetHeightDiff(GetLeftSubTree(*pRoot)) &amp;gt; 0) // 왼쪽 서브트리가 왼쪽으로 치우쳐 있다면
			*pRoot = RotateLL(*pRoot);
		else
			*pRoot = RotateLR(*pRoot);
	}
	// RR or RL 상태
	if(hDiff &amp;lt; -1)
	{
		if(GetHeightDiff(GetRightSubTree(*pRoot)) &amp;lt; 0) // 오른쪽 서브트리가 오른쪽으로 치우쳐 있다면
			*pRoot = RotateRR(*pRoot);
		else
			*pRoot = RotateRL(*pRoot);
	}
	
	return *pRoot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;윤성우의 열혈 자료구조 (윤성우 저, 2023.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/자료구조</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/60</guid>
      <comments>https://onyodev.tistory.com/60#entry60comment</comments>
      <pubDate>Mon, 2 Dec 2024 16:55:58 +0900</pubDate>
    </item>
    <item>
      <title>탐색(Search) 1</title>
      <link>https://onyodev.tistory.com/59</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 윤성우 저 - &quot;윤성우의 열혈 자료구조&quot;를 공부하고 정리하여 작성하였습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 탐색의 이해와 보간 탐색&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;❓ 탐색의 이해&lt;/span&gt;&lt;/u&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;  보간 탐색(interpolation Search)&lt;/u&gt;&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;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;이진 탐색처럼 그냥 중앙에서 시작하지 말고, 탐색대상이 앞쪽에 위치해 있으면 앞쪽에서 탐색을 시작하자!&amp;rdquo;&lt;/p&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;205&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hnfr0/btsK5qrs2k7/9CTMKp8lOHHHzRLsalTpHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hnfr0/btsK5qrs2k7/9CTMKp8lOHHHzRLsalTpHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hnfr0/btsK5qrs2k7/9CTMKp8lOHHHzRLsalTpHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHnfr0%2FbtsK5qrs2k7%2F9CTMKp8lOHHHzRLsalTpHK%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;205&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;205&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d0vJKt/btsK44oGwzH/d7afA7wTfRfPDZYpbQO400/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d0vJKt/btsK44oGwzH/d7afA7wTfRfPDZYpbQO400/img.png&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;43&quot; data-is-animation=&quot;false&quot; style=&quot;width: 64.9655%; margin-right: 10px;&quot; data-widthpercent=&quot;65.73&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d0vJKt/btsK44oGwzH/d7afA7wTfRfPDZYpbQO400/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd0vJKt%2FbtsK44oGwzH%2Fd7afA7wTfRfPDZYpbQO400%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;404&quot; height=&quot;43&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bagce4/btsK5bORhMK/U5E0lh8mlcWKHP7SlnS5I1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bagce4/btsK5bORhMK/U5E0lh8mlcWKHP7SlnS5I1/img.png&quot; data-origin-width=&quot;338&quot; data-origin-height=&quot;69&quot; data-is-animation=&quot;false&quot; style=&quot;width: 33.8717%;&quot; data-widthpercent=&quot;34.27&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bagce4/btsK5bORhMK/U5E0lh8mlcWKHP7SlnS5I1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbagce4%2FbtsK5bORhMK%2FU5E0lh8mlcWKHP7SlnS5I1%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;338&quot; height=&quot;69&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;591&quot; data-origin-height=&quot;104&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nTtxr/btsK47Z0DV2/FnUBhdM6DJiPYldMIweU9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nTtxr/btsK47Z0DV2/FnUBhdM6DJiPYldMIweU9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nTtxr/btsK47Z0DV2/FnUBhdM6DJiPYldMIweU9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnTtxr%2FbtsK47Z0DV2%2FFnUBhdM6DJiPYldMIweU9k%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;591&quot; height=&quot;104&quot; data-origin-width=&quot;591&quot; data-origin-height=&quot;104&quot;/&gt;&lt;/span&gt;&lt;/figure&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;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;  탐색 키(Search Key)와 탐색 데이터(Search Data)&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;typedef int Key;  // 탐색 키에 대한 typedef 선언

typedef double Data; // 탐색 데이터에 대한 typedef 선언

typedef struct item
{
    Key searchKey;    // 탐색 키(search key)
    Data searchData;  // 탐색 데이터(search data)
} Item;&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;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt; &amp;zwj;  보간 탐색의 구현&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;int ISearch(int ar[], int first, int last, int target)
{
    int mid;

    if(ar[first] &amp;gt; target || ar[last] &amp;lt; target)
        return -1;  // 탐색 실패

    // 이진 탐색과의 차이점
    mid = ((double)(target - ar[first]) / (ar[last] - ar[first]) * (last - first)) + first;

    if(ar[mid] == target)
        return mid;
    else if(target &amp;lt; ar[mid])
        return ISearch(ar, first, mid-1, target);
    else
        return ISearch(ar, mid+1, last, target);
}&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;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;⚠️ 탈출조건을 만족하지 않는 이유&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;int arr\[\] = {1,3,5,7,9};&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;ISearch(arr,1,4,2);&lt;/code&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mid = 0 이 저장됨.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그래서 &lt;code&gt;return ISearch(ar, mid+1, last, target)&lt;/code&gt; 이 실행이 되버리고 이는 &lt;code&gt;ISearch(arr, 1, 4, 2)&lt;/code&gt; 가 되어 탈출할 수 없음&lt;/li&gt;
&lt;li&gt;그래서 &lt;code&gt;if(ar\[first\] &amp;gt; target || ar\[last\] &amp;lt; target) return -1;&lt;/code&gt; // 탐색 실패를 설정해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 이진 탐색 트리&lt;/h2&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;이진 탐색 트리의 노드에 저장된 키(key)는 유일하다.&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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽 자식 노드의 키 &amp;lt; 부모 노드의 키 &amp;lt; 오른쪽 자식 노드의 키&lt;/p&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;/li&gt;
&lt;li&gt;루트 노드와 비교했을 때, 값이 작으면 왼쪽 자식 노드로 이동&lt;/li&gt;
&lt;li&gt;왼쪽/오른쪽 노드가 없으면 그 위치에 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;  이진 탐색 트리 헤더 파일&lt;/u&gt;&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;BinaryTree2.h&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;BTreeNode * MakeBTreeNode(void);
- 노드를 동적으로 할당해서 그 노드의 주소 값을 반환한다.
BTData GetData(BTreeNode * bt);
- 노드에 저장된 데이터를 반환한다.
void SetData(BTreeNode *bt, BTData data);
- 인자로 전달된 데이터를 노드에 저장한다.
BTreeNode * GetLeftSubTree(BTreeNode * bt);
- 인자로 전달된 노드의 왼쪽 자식 노드의 주소 값을 반환
BTreeNode * GetRightSubTree(BTreeNode * bt);
- 인자로 전달된 노드의 오른쪽 자식 노드의 주소 값을 반환
void MakeLeftSubTree(BTreeNode *main, BTreeNode *sub);
- 인자로 전달된 노드의 왼쪽 자식 노드를 교체
void MakeRightSubTree(BTreeNode *main, BTreeNode *sub);
- 인자로 전달된 노드의 오른쪽 자식 노드를 교체&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BinarySearchTree.h&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;#include &quot;BinaryTree2.h&quot;

typedef BTData BSTData;

// BST의 생성 및 초기화
void BSTMakeAndInit(BTreeNode ** pRoot);

// 노드에 저장된 데이터 반환
BSTData BSTGetNodeData(BTreeNode *bst);

// BST를 대상으로 데이터 저장(노드의 생성과정 포함)
void BSTInsert(BTreeNode ** pRoot, BSTData data);

// BST를 대상으로 데이터 탐색
BTreeNode * BSTSearch(BTreeNode *bst, BSTData target);&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;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;  이진 탐색 트리: 삽입과 탐색&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;548&quot; data-origin-height=&quot;307&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ShBAI/btsK23rkkMZ/YimdG2KvkSkFIwPIzyIdI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ShBAI/btsK23rkkMZ/YimdG2KvkSkFIwPIzyIdI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ShBAI/btsK23rkkMZ/YimdG2KvkSkFIwPIzyIdI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FShBAI%2FbtsK23rkkMZ%2FYimdG2KvkSkFIwPIzyIdI0%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;548&quot; height=&quot;307&quot; data-origin-width=&quot;548&quot; data-origin-height=&quot;307&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;void BSTInsert(BTreeNode ** pRoot, BSTData data)
{
	BTreeNode * pNode = NULL;    // parent Node
	BTreeNode * cNode = *pRoot;  // current Node
	BTreeNode * nNode = NULL;    // new Node
	
	// 새로운 노드가 추가될 위치를 찾는다.
	while(cNode != NULL)
	{
		if(data == GetData(cNode))
			return;   // 키의 중복 허용하지 않음
		
		pNode = cNode;
		if(GetData(cNode) &amp;gt; data)
			cNode = GetLeftSubTree(cNode);
		else
			cNode = GetRightSubTree(cNode);
	}
	
	//pNode의 자식노드로 추가할 새 노드의 생성
	nNode = MakeBTreeNode();  // 새 노드 생성
	SetData(nNode, data);     // 새 노드에 데이터 저장
	
	//pNode의 자식 노드로 새 노드를 추가
	if(pNode != NULL)   // 새 노드가 루트 노드가 아니라면,
	{
		if(data &amp;lt; GetData(pNode))
			MakeLeftSubTree(pNode, nNode);
		else
			MakeRightSubTree(pNode, nNode);
	}
	else
	{
		*pRoot = nNode;
	}
}

&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;BTreeNode * BSTSearch(BTreeNode *bst, BSTData target)
{
	BTreeNode * cNode = bst;  // current node
	BSTData cd;               // current data
	
	while(cNode != NULL)
	{
		cd = GetData(cNode);
		
		if(target == cd)
			return cNode;
		else if(target &amp;lt; cd)
			cNode = GetLeftSubTree(cNode);
		else
			cNode = GetRightSubTree(cNode);
	}
	
	return NULL;
}

&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;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt; ❌ 이진 탐색 트리: 삭제&lt;/u&gt;&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;상황 1 : 삭제할 노드가 단말 노드인 경우&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;648&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wmzXL/btsK4hvwHJH/nUW63H7kyhg4sdfnPVOES0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wmzXL/btsK4hvwHJH/nUW63H7kyhg4sdfnPVOES0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wmzXL/btsK4hvwHJH/nUW63H7kyhg4sdfnPVOES0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwmzXL%2FbtsK4hvwHJH%2FnUW63H7kyhg4sdfnPVOES0%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;648&quot; height=&quot;222&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;222&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;if(삭제할 노드가 단말 노드이면)
{
	if(GetLeftSubTree(pNode) == dNode)  // 삭제할 노드가 왼쪽 자식 노드라면
		RemoveLeftSubTree(pNode);
	else
		RemoveRightSubTree(pNode);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상황 2: 삭제할 노드가 하나의 자식 노드를 갖는 경우&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;659&quot; data-origin-height=&quot;202&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsxAte/btsK33K39Ul/x6ORaialPKWnsKjEFc8tuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsxAte/btsK33K39Ul/x6ORaialPKWnsKjEFc8tuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsxAte/btsK33K39Ul/x6ORaialPKWnsKjEFc8tuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsxAte%2FbtsK33K39Ul%2Fx6ORaialPKWnsKjEFc8tuK%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;659&quot; height=&quot;202&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;202&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;if(삭제할 노드가 하나의 자식 노드를 갖고 있다면)
{
	BTreeNode * dcNode;
	
	// 삭제 대상의 자식 노드를 찾는다.
	if(GetLeftSubTree(dNode) != NULL)  // 자식 노드가 왼쪽이라면
		dcNode = GetLeftSubTree(dNode);
	else
		dcNode = GetRightSubTree(dNode);
		
	// 삭제 대상의 부모 노드와 자식 노드를 연결한다.
	if(GetLeftSubTree(pNode) == dNode)  // 삭제 대상이 왼쪽 자식 노드이면
		ChangeLeftSubTree(pNode, dcNode); // 왼쪽 연결
	else
		ChangeRightSubTree(pNode, dcNode);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상황 3: 삭제할 노드가 두 개의 자식 노드를 갖는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JP9Cu/btsK3lrFfH2/CqaK0bFEBLgh4zXVkpTCS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JP9Cu/btsK3lrFfH2/CqaK0bFEBLgh4zXVkpTCS1/img.png&quot; data-origin-width=&quot;407&quot; data-origin-height=&quot;275&quot; data-is-animation=&quot;false&quot; style=&quot;width: 39.0416%; margin-right: 10px;&quot; data-widthpercent=&quot;39.97&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JP9Cu/btsK3lrFfH2/CqaK0bFEBLgh4zXVkpTCS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJP9Cu%2FbtsK3lrFfH2%2FCqaK0bFEBLgh4zXVkpTCS1%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;407&quot; height=&quot;275&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cY9dC7/btsK24jsiyJ/YSBwInHfo4P7tUf2zQxY9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cY9dC7/btsK24jsiyJ/YSBwInHfo4P7tUf2zQxY9K/img.png&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;247&quot; data-is-animation=&quot;false&quot; style=&quot;width: 29.4766%; margin-right: 10px;&quot; data-widthpercent=&quot;30.18&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cY9dC7/btsK24jsiyJ/YSBwInHfo4P7tUf2zQxY9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcY9dC7%2FbtsK24jsiyJ%2FYSBwInHfo4P7tUf2zQxY9K%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;276&quot; height=&quot;247&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pvPsi/btsK47yWKGy/XpkZMTKlRjbm4Op16BBVR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pvPsi/btsK47yWKGy/XpkZMTKlRjbm4Op16BBVR0/img.png&quot; data-origin-width=&quot;273&quot; data-origin-height=&quot;247&quot; data-is-animation=&quot;false&quot; style=&quot;width: 29.1562%;&quot; data-widthpercent=&quot;29.85&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pvPsi/btsK47yWKGy/XpkZMTKlRjbm4Op16BBVR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpvPsi%2FbtsK47yWKGy%2FXpkZMTKlRjbm4Op16BBVR0%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;273&quot; height=&quot;247&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;447&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YVt8U/btsK2EyG1cQ/oPKTiwdfhoxKWFw6jKL3rK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YVt8U/btsK2EyG1cQ/oPKTiwdfhoxKWFw6jKL3rK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YVt8U/btsK2EyG1cQ/oPKTiwdfhoxKWFw6jKL3rK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYVt8U%2FbtsK2EyG1cQ%2FoPKTiwdfhoxKWFw6jKL3rK%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;447&quot; height=&quot;222&quot; data-origin-width=&quot;447&quot; data-origin-height=&quot;222&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 큰 값을 찾을 때는 NULL을 만날 때까지 계속 오른쪽 자식 노드로 이동&lt;/li&gt;
&lt;li&gt;가장 작은 값을 찾을 때는 NULL을 만날 때까지 계속해서 왼쪽 자식 노드로 이동&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&amp;ldquo;삭제할 노드의 오른쪽 서브 트리에서 가장 작은 값을 지니는 노드를 찾아서 이것으로 삭제할 노드를 대체한다.&amp;rdquo;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;171&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bggtxu/btsK5cNOJqI/kAo6STyuk7XokpesHpiWlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bggtxu/btsK5cNOJqI/kAo6STyuk7XokpesHpiWlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bggtxu/btsK5cNOJqI/kAo6STyuk7XokpesHpiWlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbggtxu%2FbtsK5cNOJqI%2FkAo6STyuk7XokpesHpiWlk%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;530&quot; height=&quot;171&quot; data-origin-width=&quot;530&quot; data-origin-height=&quot;171&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단계 1 : 삭제할 노드를 대체할 노드를 찾는다.&lt;/li&gt;
&lt;li&gt;단계 2 : 대체할 노드에 저장된 값을 삭제할 노드에 대입한다.&lt;/li&gt;
&lt;li&gt;단계 3 : 대체할 노드의 부모 노드와 자식 노드를 연결한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;if(삭제할 노드가 두 개의 자식 노드를 지닌다.)
{
	BTreeNode * mNode = GetRightSubTree(dNode);  // 대체 노드
	BTreeNode * mpNode = dNode;  // 대체 노드의 부모 노드
	
	// 단계 1. 삭제 대상의 대체 노드를 찾는다.
	while(GetLeftSubTree(mNode) != NULL)
	{
		mpNode = mNode;
		mNode = GetLeftSubTree(mNode);
	}
	
	// 단계 2. 대체할 노드에 저장된 값을 삭제할 노드에 대입한다.
	SetData(dNode, GetData(mNode));
	
	// 단계 3. 대체할 노드의 부모 노드와 자식 노드를 연결한다.
	if(GetLeftSubTree(mpNode) == mNode)
	{
		// 대체할 노드의 자식 노드를 부모 노드의 왼쪽에 연결
		ChangeLeftSubTree(mpNode, GetRightSubTree(mNode));
	}
	else
	{
		ChangeRightSubTree(mpNode, GetRightSubTree(mNode));
	}
}
&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;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt; ❌ 이진 탐색 트리: 삭제를 위한 이진 트리 확장&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;perl&quot;&gt;&lt;code&gt;// 왼쪽 자식 노드를 트리에서 제거, 제거된 노드의 주소 값이 반환된다.
BTreeNode * RemoveLeftSubTree(BTreeNode *bt)
{
	BTreeNode * delNode;
	
	if(bt != NULL){
		delNode = bt-&amp;gt;left;
		bt-&amp;gt;left = NULL;
	}
	return delNode;
}

// 오른쪽 자식 노드를 트리에서 제거, 제거된 노드의 주소 값이 반환된다.
BTreeNode * RemoveRightSubTree(BTreeNode *bt)
{
	BTreeNode * delNode;
	
	if(bt != NULL){
		delNode = bt-&amp;gt;right;
		bt-&amp;gt;right = NULL;
	}
	return delNode;
}

// 메모리 소멸을 수반하지 않고 main의 왼쪽 자식 노드를 변경
void ChangeLeftSubTree(BTreeNode *main, BTreeNode * sub)
{
	main-&amp;gt;left = sub;
}

// 메모리 소멸을 수반하지 않고 main의 오른쪽 자식 노드를 변경
void ChangeRightSubTree(BTreeNode *main, BTreeNode * sub)
{
	main-&amp;gt;right = sub;
}
&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;span style=&quot;color: #000000; background-color: #f6e199;&quot;&gt;&lt;u&gt; 이진 탐색 트리: 완전한 구현  &lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;BTreeNode * BSTRemove(BTreeNode ** pRoot, BSTData target)
{
	BTreeNode *pVRoot = MakeBTreeNode();
	BTreeNode *pNode = pVRoot;
	BTreeNode *cNode = *pRoot;
	BTreeNode *dNode;
	
	// 루트 노드를 pVRoot가 가리키는 노드의 오른쪽 자식 노드가 되게 한다.
	ChangeRightSubTree(pVRoot, *pRoot);
	
	// 삭제 대상인 노드를 탐색
	while(cNode != NULL &amp;amp;&amp;amp; GetData(cNode) != target)
	{
		pNode = cNode;
		if(target &amp;lt; GetData(cNode))
			cNode = GetLeftSubTree(cNode);
		else
			cNode = GetRightSubTree(cNode);
	}
	
	if(cNode == NULL)
		return NULL;
		
	dNode = cNode;
	
	// 1. 삭제할 노드가 단말 노드이면
	if(GetLeftSubTree(dNode) == NULL &amp;amp;&amp;amp; GetRightSubTree(dNode) == NULL)
	{
		if(GetLeftSubTree(pNode) == dNode)  // 삭제할 노드가 왼쪽 자식 노드라면
			RemoveLeftSubTree(pNode);
		else
			RemoveRightSubTree(pNode);
	}
	// 2. 삭제할 노드가 하나의 자식 노드를 갖고 있다면
	else if(GetLeftSubTree(dNode) == NULL || GetRightSubTree(dNode) == NULL)
	{
		BTreeNode * dcNode;
		
		// 삭제 대상의 자식 노드를 찾는다.
		if(GetLeftSubTree(dNode) != NULL)  // 자식 노드가 왼쪽이라면
			dcNode = GetLeftSubTree(dNode);
		else
			dcNode = GetRightSubTree(dNode);
			
		// 삭제 대상의 부모 노드와 자식 노드를 연결한다.
		if(GetLeftSubTree(pNode) == dNode)  // 삭제 대상이 왼쪽 자식 노드이면
			ChangeLeftSubTree(pNode, dcNode); // 왼쪽 연결
		else
			ChangeRightSubTree(pNode, dcNode);
	}
	// 3. 삭제할 노드가 두 개의 자식 노드를 지닌다.
	else
	{
		BTreeNode * mNode = GetRightSubTree(dNode);  // 대체 노드
		BTreeNode * mpNode = dNode;  // 대체 노드의 부모 노드
		int delData;
		
		// 단계 1. 삭제 대상의 대체 노드를 찾는다.
		while(GetLeftSubTree(mNode) != NULL)
		{
			mpNode = mNode;
			mNode = GetLeftSubTree(mNode);
		}
		
		// 단계 2. 대체할 노드에 저장된 값을 삭제할 노드에 대입한다.
		delData = GetData(dNode);  // 대입 전 데이터 백업
		SetData(dNode, GetData(mNode));
		
		// 단계 3. 대체할 노드의 부모 노드와 자식 노드를 연결한다.
		if(GetLeftSubTree(mpNode) == mNode)
			// 대체할 노드의 자식 노드를 부모 노드의 왼쪽에 연결
			ChangeLeftSubTree(mpNode, GetRightSubTree(mNode));
		else
			ChangeRightSubTree(mpNode, GetRightSubTree(mNode));
		
		dNode = mNode;
		SetData(dNode, delData);
	}
	
	// 삭제된 노드가 루트노드라면
	if(GetRightSubTree(pVRoot) != *pRoot)
		*pRoot = GetRightSubTree(pVRoot);  // 루트 노드 변경
	 	
	free(pVRoot);  // 가상 루트 노드 소멸
	return dNode;
}
&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;468&quot; data-origin-height=&quot;302&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dihMju/btsK4I7kWlQ/OV1KLYxWozuRh3DpjpyjE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dihMju/btsK4I7kWlQ/OV1KLYxWozuRh3DpjpyjE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dihMju/btsK4I7kWlQ/OV1KLYxWozuRh3DpjpyjE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdihMju%2FbtsK4I7kWlQ%2FOV1KLYxWozuRh3DpjpyjE0%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;468&quot; height=&quot;302&quot; data-origin-width=&quot;468&quot; data-origin-height=&quot;302&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;윤성우의 열혈 자료구조 (윤성우 저, 2023.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/자료구조</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/59</guid>
      <comments>https://onyodev.tistory.com/59#entry59comment</comments>
      <pubDate>Mon, 2 Dec 2024 15:26:33 +0900</pubDate>
    </item>
    <item>
      <title>회복과 병행 제어</title>
      <link>https://onyodev.tistory.com/58</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 김연희 저 - &quot;데이터베이스 개론 3판&quot;을 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 트랜잭션&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1. 트랜잭션의 개념&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;/li&gt;
&lt;li&gt;예시)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;순서는 상관없지만 두 UPDATE 문이 정상적으로 실행되어야 함.&lt;/li&gt;
&lt;li&gt;시스템이 정상적으로 작동하게 되어 두 번째 UPDATE 문을 실행해 트랜잭션의 모든 UPDATE문이 정상적으로 실행되거나, 첫 번째 UPDATE문을 취소하여 트랜잭션 작업 전으로 돌려 놓는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;계좌이체 작업
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;성호 계좌에서 5,000원 인출
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;UPDATE 계좌
SET 잔액 = 잔액 - 5000
WHERE 계좌번호 = 100;
​&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;은경 계좌에 5,000원 입금
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;UPDATE 계좌
SET 잔액 = 잔액 + 5000
WHERE 계좌번호 = 200;
​&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;상품주문 작업
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;새로운 주문 내역 추가
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;INSERT
INTO 주문(주문번호, 주문고객, 주문제품, 주문수량, 주문날짜)
VALUES ('o11', 'apple', 'p01', 10, '2022-10-10');
​&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;주문제품의 재고량 수정
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;UPDATE 제품
SET 재고량 = 재고량 - 10
WHERE 제품번호 = 'p01';
​&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2. 트랜잭션의 특성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;⚛️ 원자성&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;b&gt;all-or-nothing&lt;/b&gt; 방식을 의미함.&lt;/li&gt;
&lt;li&gt;트랜잭션을 수행하다 장애가 발생하여 완료되지 못할 경우, 지금까지 실행한 연산 처리를 모두 취소하고 트랜잭션 작업 전 상태로 되돌려 넣는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt; &amp;zwj;♀️ 일관성&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt; ️ 격리성&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;⏳&amp;nbsp;지속성&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;⚙️ 트랜잭션의 특성을 지원하는 DBMS의 기능&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 97px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;트랜잭션의 특성&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;&amp;nbsp;DBMS의 기능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;원자성&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;회복 기능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;일관성&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;병행 제어 기능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;격리성&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;병행 제어 기능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;지속성&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;회복 기능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3. 트랜잭션의 연산&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;COMMIT 연산
&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;COMMIT 연산이 실행된 후에야 트랜잭션 수행 결과가 데이터베이스에 반영됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ROLLBACK 연산
&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;ROLLBACK 연산이 실행되면 트랜잭션이 지금까지 실행한 연산의 결과가 취소되고 트랜잭션이 수행되기 전의 상태로 돌아감.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.4. 트랜잭션의 상태&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;685&quot; data-origin-height=&quot;616&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/H0v6u/btsK2bDj5tS/vGXKhHVN2xJPidBPmfm2u0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H0v6u/btsK2bDj5tS/vGXKhHVN2xJPidBPmfm2u0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H0v6u/btsK2bDj5tS/vGXKhHVN2xJPidBPmfm2u0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FH0v6u%2FbtsK2bDj5tS%2FvGXKhHVN2xJPidBPmfm2u0%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;358&quot; height=&quot;322&quot; data-origin-width=&quot;685&quot; data-origin-height=&quot;616&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;활동 상태&lt;/span&gt;&lt;/u&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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;부분 완료 상태&lt;/span&gt;&lt;/u&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;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;완료 상태&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션이 성공적으로 완료되어 commit 연산을 실행한 상태&lt;/li&gt;
&lt;li&gt;트랜잭션이 수행한 최종 결과를 데이터베이스에 반영하고 데이터베이스가 새로운 일관된 상태가 되면서 트랜잭션이 종료됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;실패 상태&lt;/span&gt;&lt;/u&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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;철회 상태&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션을 수행하는 데 실패하여 rollback 연산을 실행한 상태&lt;/li&gt;
&lt;li&gt;지금까지 실행한 트랜잭션의 연산을 모두 취소하고 트랜잭션이 수행되기 전의 데이터베이스 상태로 되돌리면서 트랜잭션이 종료&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;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;2. 장애와 회복&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;회복(recovery):&lt;/b&gt; 장애가 발생했을 때 데이터베이스에 장애가 발생하기 전의 일관된 상태로 복구시키는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1. 장애의 유형&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템이 제대로 동작하지 않는 상태를 장애(failure)라 함.&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;1232&quot; data-origin-height=&quot;649&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Qe1vU/btsK2zjj1eI/iQLmKKwaJqPuIcAcaslfr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Qe1vU/btsK2zjj1eI/iQLmKKwaJqPuIcAcaslfr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Qe1vU/btsK2zjj1eI/iQLmKKwaJqPuIcAcaslfr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQe1vU%2FbtsK2zjj1eI%2FiQLmKKwaJqPuIcAcaslfr1%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;1232&quot; height=&quot;649&quot; data-origin-width=&quot;1232&quot; data-origin-height=&quot;649&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;br /&gt;2.2. 데이터베이스의 저장 연산&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1114&quot; data-origin-height=&quot;581&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgp3pb/btsK3wlQSdD/OJPLl0dL9DBDPtzYnkgVXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgp3pb/btsK3wlQSdD/OJPLl0dL9DBDPtzYnkgVXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgp3pb/btsK3wlQSdD/OJPLl0dL9DBDPtzYnkgVXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbgp3pb%2FbtsK3wlQSdD%2FOJPLl0dL9DBDPtzYnkgVXk%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;1114&quot; height=&quot;581&quot; data-origin-width=&quot;1114&quot; data-origin-height=&quot;581&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;  디스크 - 메인 메모리 간 데이터 이동 연산&lt;/span&gt;&lt;/u&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;li&gt;디스크와 메인 메모리 간의 데이터 이동은 대개 블록 단위로 수행됨&lt;/li&gt;
&lt;li&gt;디스크에 있는 블록을 &lt;b&gt;디스크 블록&lt;/b&gt;이라 하고 메인 메모리에 있는 블록 은 &lt;b&gt;버퍼 블록&lt;/b&gt;이라 함.&lt;/li&gt;
&lt;li&gt;input(X) : 디스크 블록에 저장되어 있는 데이터 X를 메인 메모리 버퍼 블록으로 이동시키는 연산&lt;/li&gt;
&lt;li&gt;output(X) : 메인 메모리 버퍼 블록에 있는 데이터 X를 디스크 블록으로 이동시키는 연산&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;  메인 메모리 버퍼 블록과 프로그램 변수 간의 데이터 이동 연산&lt;/u&gt;&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;li&gt;read(X) : 메인 메모리 버퍼 블록에 저장되어 있는 데이터 X를 프로그램의 변수로 읽어오는 연산&lt;/li&gt;
&lt;li&gt;write(X) : 프로그램의 변수 값을 메인 메모리 버퍼 블록에 있는 데이터 X에 기록하는 연산&lt;/li&gt;
&lt;li&gt;응용 프로그램에 의해 수행된 트랜잭션이 데이터베이스에 접근하여 데이터를 처리할 때 read(X) 연산이 실행됨.&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;898&quot; data-origin-height=&quot;307&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0rt7m/btsK4yQMsuM/KM1lQPDokNKKUSvTgn60v1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0rt7m/btsK4yQMsuM/KM1lQPDokNKKUSvTgn60v1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0rt7m/btsK4yQMsuM/KM1lQPDokNKKUSvTgn60v1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0rt7m%2FbtsK4yQMsuM%2FKM1lQPDokNKKUSvTgn60v1%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;898&quot; height=&quot;307&quot; data-origin-width=&quot;898&quot; data-origin-height=&quot;307&quot;/&gt;&lt;/span&gt;&lt;/figure&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;pre class=&quot;sas&quot;&gt;&lt;code&gt;// 성호 계좌에서 5,000원 인출

read(X);
X = X-5000;
write(X);
​&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3. 회복 기법&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;/li&gt;
&lt;li&gt;회복 관리자는 장애 발생을 탐지하고, 장애가 탐지되면 데이터베이스 복구 기능을 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;  회복을 위한 연산&lt;/span&gt;&lt;/u&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;li&gt;덤프 또는 로그 방법을 사용해 데이터를 복사해두었다가 회복시킬 때 복사본을 사용&lt;/li&gt;
&lt;li&gt;dump : 데이터베이스 전체를 다른 저장 장치에 주기적으로 복사하는 방법
&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;log : 데이터베이스에서 변경 연산이 실행될 때마다 데이터를 변경하기 이전 값과 변경한 이후의 값을 별도의 파일에 기록하는 방법&lt;/li&gt;
&lt;li&gt;장애가 발생했을 때, 중복 저장한 데이터를 이용해 데이터베이스를 복구하는 가장 기본적인 방법은 redo나 undo 연산을 실행하는 것&lt;/li&gt;
&lt;li&gt;redo(재실행) : 가장 최근에 저장한 데이터베이스 복사본을 가져온 후 로그를 이용해 복사본이 만들어진 이후에 실행된 모든 변경 연산을 재실행하여 장애가 발생하기 직전의 데이터베이스 상태로 복구
&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;undo(취소) : 로그를 이용해 지금까지 실행된 모든 변경 연산을 취소하여 데이터베이스를 원상태로 복구
&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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt; 로그를 기록하는 방법&lt;/span&gt;&lt;/u&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;li&gt;로그는 데이터 손실이 발생하지 않는 저장 장치에 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt; 로그 레코드의 종류&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1793&quot; data-origin-height=&quot;1141&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tJLrs/btsK32SjoEG/5lp58Fvxocw4iE2L7xO10k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tJLrs/btsK32SjoEG/5lp58Fvxocw4iE2L7xO10k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tJLrs/btsK32SjoEG/5lp58Fvxocw4iE2L7xO10k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtJLrs%2FbtsK32SjoEG%2F5lp58Fvxocw4iE2L7xO10k%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;1793&quot; height=&quot;1141&quot; data-origin-width=&quot;1793&quot; data-origin-height=&quot;1141&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3.1. 데이터베이스 회복 기법의 종류&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2664&quot; data-origin-height=&quot;819&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvJNKx/btsK21s4XFf/lXbzwK3QEhSODPmpq3AIRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvJNKx/btsK21s4XFf/lXbzwK3QEhSODPmpq3AIRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvJNKx/btsK21s4XFf/lXbzwK3QEhSODPmpq3AIRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvJNKx%2FbtsK21s4XFf%2FlXbzwK3QEhSODPmpq3AIRk%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;2664&quot; height=&quot;819&quot; data-origin-width=&quot;2664&quot; data-origin-height=&quot;819&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt; 로그 회복 기법&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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;즉시 갱신 회복 기법&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;li&gt;로그 파일에 로그 레코드를 먼저 기록한 후 데이터베이스에 변경 연산 반영&lt;/li&gt;
&lt;li&gt;장애가 발생하면 로그 파일에 기록된 내용을 참조하여 장애 발생 시점에 따라 redo나 undo 연산을 실행하여 복구함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트랜잭션 완료 전 장애 발생&lt;/b&gt; &amp;rarr; &amp;lt;Ti, commit&amp;gt; 는 없는 상태이고 undo 연산 실행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트랜잭션 완료 후 장애 발생&lt;/b&gt; &amp;rarr; &amp;lt;Ti, commit&amp;gt; 존재하고 redo 연산 실행&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;2036&quot; data-origin-height=&quot;1039&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XIhyF/btsK3un2xry/QYGItDo6HOqTzcdGhsI5G1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XIhyF/btsK3un2xry/QYGItDo6HOqTzcdGhsI5G1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XIhyF/btsK3un2xry/QYGItDo6HOqTzcdGhsI5G1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXIhyF%2FbtsK3un2xry%2FQYGItDo6HOqTzcdGhsI5G1%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;2036&quot; height=&quot;1039&quot; data-origin-width=&quot;2036&quot; data-origin-height=&quot;1039&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;1번 시점에서 장애가 발생한 경우&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;T1 트랜잭션 수행이 완료되기 전이므로 로그 파일에 &amp;lt;T1, start&amp;gt; 로그 레코드만 존재함.&lt;/li&gt;
&lt;li&gt;그러므로 T1 트랜잭션에서 undo(T1) 연산을 실행해야 함&lt;/li&gt;
&lt;li&gt;지금까지 변경한 데이터 값을 변경 연산 이전의 값으로 되돌려야 함.&lt;/li&gt;
&lt;li&gt;이전 값으로 되돌려야 하는 데이터가 여러 개인 경우 로그에 기록된 순서 반대로 undo 연산 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;2번 시점에서 장애가 발생한 경우&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;T1 트랜잭션 수행이 완료되었으므로 &amp;lt;T1, start&amp;gt; 와 &amp;lt;T1, commit&amp;gt; 레코드가 모두 존재함.&lt;/li&gt;
&lt;li&gt;T2 트랜잭션은 완료 전이므로 &amp;lt;T2,start&amp;gt; 만 존재함.&lt;/li&gt;
&lt;li&gt;T1 트랜잭션은 redo 연산을, T2 트랜잭션은 undo 연산을 실행함.&lt;/li&gt;
&lt;li&gt;둘 다 실행해야 할 땐, T2 undo를 먼저 실행하고 T1 redo를 실행함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;지연 갱신 회복 기법&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;li&gt;지연 갱신 회복 기법에서는 undo 연산은 필요 없고 redo 연산만 필요하므로 변경 이전 값을 기록할 필요가 없음.&lt;/li&gt;
&lt;li&gt;그래서 변경 연산 실행에 대한 로그 레코드는 &amp;lt;T1, X, new_value&amp;gt; 형식으로 기록됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트랜잭션 완료 전 장애 발생&lt;/b&gt; &amp;rarr; 로그 내용 무시하고 버림&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트랜잭션 완료 후 장애 발생&lt;/b&gt; &amp;rarr; redo 연산 실행&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;2059&quot; data-origin-height=&quot;1107&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJrTBo/btsK4aQaWbA/mBekPXyOzxhKeCVkQ46mrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJrTBo/btsK4aQaWbA/mBekPXyOzxhKeCVkQ46mrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJrTBo/btsK4aQaWbA/mBekPXyOzxhKeCVkQ46mrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJrTBo%2FbtsK4aQaWbA%2FmBekPXyOzxhKeCVkQ46mrk%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;2059&quot; height=&quot;1107&quot; data-origin-width=&quot;2059&quot; data-origin-height=&quot;1107&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;1번 시점에서 장애가 발생한 경우&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;2번 시점에서 장애가 발생한 경우&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;완료되지 않은 T2 트랜잭션에 대한 로그 레코드를 무시하고, T1 트랜잭션은 redo(T1) 연산 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;  검사 시점 회복 기법&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로그를 이용한 회복 기법은 로그 전체를 분석해서 redo나 undo 회복 연산을 결정해야 함.&lt;/li&gt;
&lt;li&gt;로그 회복 기법을 적용할 경우, 회복에 너무 많은 시간이 걸리고 비효율적임.&lt;/li&gt;
&lt;li&gt;검사 시점 회복 기법은 로그 기록을 이용하되, 일정 시간 간격으로 검사 시점을 만들어 둠.&lt;/li&gt;
&lt;li&gt;그리고 장애가 발생하면 가장 최근 검사 시점 이전의 트랜잭션에는 회복 작업을 수행하지 않고, 이후의 트랜잭션에만 회복 작업을 수행&lt;/li&gt;
&lt;li&gt;불필요한 회복 작업을 수행하지 않아 데이터베이스의 회복 시간이 단축된다는 장점이 있음&lt;/li&gt;
&lt;li&gt;일정 시간 간격으로 검사 시점에 메인 메모리에 있는 모든 로그 레코드를 안정 저장 장치에 있는 로그 파일에 기록하고 트랜잭션 데이터 변경 내용을 데이터베이스에 반영&lt;/li&gt;
&lt;li&gt;그 다음, &amp;lt;checkpoint L&amp;gt; 형식의 로그 레코드를 로그 파일에 기록하고 장애 발생 시 가장 최근의 &amp;lt;checkpoint L&amp;gt; 를 찾아 이후의 로그 기록만 회복 작업 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;  미디어 회복 기법&lt;/span&gt;&lt;/u&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;li&gt;디스크 장애가 발생하면 가장 최근에 복사해둔 덤프를 이용해 복구하고 필요에 따라 로그 내용을 토대로 redo 연산 실행&lt;/li&gt;
&lt;li&gt;비용이 많이 들고 복사하는 동안 다른 트랜잭션은 중단되야 하므로 CPU가 낭비되는 단점이 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 병행 제어&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1. 병행 수행과 병행 제어&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;여러 개의 트랜잭션이 동시에 수행&lt;/b&gt;되는 &lt;b&gt;병행 수행&lt;/b&gt;이 지원됨.&lt;/li&gt;
&lt;li&gt;병행 수행은 실제로 여러 트랜잭션이 차례로 번갈아 수행되는 인터리빙 방식으로 진행&lt;/li&gt;
&lt;li&gt;병행 수행되는 트랜잭션들이 같은 데이터에 동시에 접근하면 문제가 생길 수 있음&lt;/li&gt;
&lt;li&gt;여러 개의 트랜잭션이 병행 수행을 하더라도 문제가 발생하지 않고 정확한 수행 결과를 얻을 수 있도록 트랜잭션의 수행을 제어하는 것을 &lt;b&gt;병행 제어&lt;/b&gt; 또는 동시성 제어라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.2. 병행 수행의 문제&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;❗갱신 분실&lt;/span&gt;&lt;/u&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;예) 3000에 1000을 더하는 연산과 반으로 나누는 연산이 병행 수행되면서 뒤에 오는 연산이 덮어서 1500이 되버리는 문제&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;  모순성&lt;/u&gt;&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;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;⛓️ 연쇄 복귀&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션이 완료되기 전에 장애가 발생하여 rollback을 수행하면, 이 트랜잭션이 장애 발생 전에 변경한 데이터를 가져가 변경 연산을 실행한 또 다른 트랜잭션에도 rollback을 수행해야 함.&lt;/li&gt;
&lt;li&gt;장애가 발생한 트랜잭션이 rollback 연산을 실행하기 전, 변경한 데이터를 가져가 사용하는 다른 트랜잭션이 수행을 완료해버리면 rollback이 불가능해짐.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.3. 트랜잭션 스케줄&amp;nbsp;&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;/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;2236&quot; data-origin-height=&quot;725&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cifsbI/btsK4gbLqyW/Dor0Yoh202xR9BQiHyqKR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cifsbI/btsK4gbLqyW/Dor0Yoh202xR9BQiHyqKR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cifsbI/btsK4gbLqyW/Dor0Yoh202xR9BQiHyqKR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcifsbI%2FbtsK4gbLqyW%2FDor0Yoh202xR9BQiHyqKR1%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;2236&quot; height=&quot;725&quot; data-origin-width=&quot;2236&quot; data-origin-height=&quot;725&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;인터리빙 방식을 사용하지 않고 트랜잭션별로 연산들을 순차적으로 실행시키는 것&lt;/li&gt;
&lt;li&gt;모든 트랜잭션이 완료될 때까지 다른 트랜잭션의 방해를 받지 않고 독립적으로 수행됨&lt;/li&gt;
&lt;li&gt;직렬 스케줄에 따라 여러 트랜잭션을 수행하면 정확한 결과를 얻을 수 있지만, 각 트랜잭션을 독립적으로 수행하기 때문에 트랜잭션들이 동시에 수행되는 병행 수행이라 할 수 없음.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&amp;rarr; 결론적으로 잘 안써요.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&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;인터리빙 방식을 이용하여 트랜잭션을 병행해서 수행시키는 것&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;직렬 가능 스케줄&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;li&gt;대부분의 데이터베이스 관리 시스템에서는 직렬 가능 스케줄인지를 검사하기보다는 직렬 가능성을 보장하는 병행 제어 기법을 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.4. 병행 제어 기법&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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;u&gt;  로킹 기법의 개념&lt;/u&gt;&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;로킹 기법은 병행 수행되는 트랜잭션들이 동일한 데이터에 동시에 접근하지 못하도록 lock과 unlock이라는 2개의 연산을 이용해 제어함.&lt;/li&gt;
&lt;li&gt;로킹 기법의 기본 원리는 한 트랜잭션이 먼저 접근한 데이터에 대한 연산을 모두 마칠 때까지, 해당 데이터에 다른 트랜잭션이 접근하지 못하도록 상호 배제하여 직렬 가능성을 보장함.&lt;/li&gt;
&lt;li&gt;lock 연산: 트랜잭션이 사용할 데이터에 대한 독점권을 가짐.&lt;/li&gt;
&lt;li&gt;unlock 연산: 트랜잭션이 데이터에 대한 독점권을 반납함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기본 로킹 규약&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터에 접근하는 연산을 실행하려면 lock 연산을 통해 독점권을 획득해야 함.&lt;/li&gt;
&lt;li&gt;그러므로 트랜잭션이 데이터에 read 또는 write 연산 실행 전 반드시 lock 연산 실행&lt;/li&gt;
&lt;li&gt;lock 연산을 통해 독점권을 획득한 데이터에 대한 모든 연산이 끝난 후 unlock 연산을 통해 독점권을 반납해야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;lock 연산은 데이터베이스를 구성하는 속성부터 데이터베이스 전체까지 다양한 크기의 데이터를 대상으로 수행 가능함.&lt;/li&gt;
&lt;li&gt;로킹 단위가 커질수록 병행성은 낮아지지만 제어가 쉽고, 로킹 단위가 작을수록 병행성은 높아지고 제어가 어려워진다.&lt;/li&gt;
&lt;li&gt;기본 로킹 기법을 사용하면 병행 수행을 제어하는 목표는 이루지만 어떤 순간이든 데이터에 대한 독점권을 하나의 트랜잭션만 가지게 됨.&lt;/li&gt;
&lt;li&gt;생각해보면 read 연산의 경우, 여러 트랜잭션이 동시에 실행해도 문제가 없음. 그래서 허용하는 것이 효율성을 높일 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공용 lock&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션이 데이터에 대해 공용 lock 연산을 실행하면, 해당 데이터에 read 연산을 실행할 수 있지만 write 연산은 실행할 수 없음&lt;/li&gt;
&lt;li&gt;해당 데이터에 다른 트랜잭션도 공용 lock 연산을 동시에 실행할 수 있음&lt;/li&gt;
&lt;li&gt;데이터에 대한 사용권을 여러 트랜잭션이 함께 가질 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;전용 lock&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션이 데이터에 전용 lock 연산을 실행하면 해당 데이터에 read 연산과 write 연산을 모두 실행할 수 있음&lt;/li&gt;
&lt;li&gt;해당 데이터에 다른 트랜잭션은 어떤 lock 연산도 실행할 수 없음&lt;/li&gt;
&lt;li&gt;전용 lock 연산을 실행한 트랜잭션만 해당 데이터에 대한 독점권을 가질 수 있음&lt;/li&gt;
&lt;/ul&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;1970&quot; data-origin-height=&quot;709&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/be6Q7U/btsK4NAbeeC/yRVoicntJOk4zAG43Piu6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/be6Q7U/btsK4NAbeeC/yRVoicntJOk4zAG43Piu6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/be6Q7U/btsK4NAbeeC/yRVoicntJOk4zAG43Piu6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbe6Q7U%2FbtsK4NAbeeC%2FyRVoicntJOk4zAG43Piu6K%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;649&quot; height=&quot;234&quot; data-origin-width=&quot;1970&quot; data-origin-height=&quot;709&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt; 2단계 로킹 규약&lt;/span&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2단계 로킹 규약을 따르려면 모든 트랜잭션이 lock과 unlock 연산을 2단계로 나누어 실행해야 한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;확장 단계: 트랜잭션이 lock 연산만 실행할 수 있고, unlock 연산은 실행할 수 없는 단계&lt;/li&gt;
&lt;li&gt;축소 단계: 트랜잭션이 unlock 연산만 실행할 수 있고, lock 연산을 실행할 수 없는 단계&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;트랜잭션이 처음에 수행되면 확장 단계로 들어가 lock 연산만 수행할 수 있음&lt;/li&gt;
&lt;li&gt;이후 unlock 연산을 실행하면 축소 단계로 들어가 그때부터는 unlock 연산만 실행할 수 있음&lt;/li&gt;
&lt;li&gt;2단계 로킹 규약을 준수하는 트랜잭션은 첫 번째 unlock 연산을 수행하기 전 필요한 모든 lock 연산을 실행해야 함.&lt;/li&gt;
&lt;li&gt;2단계 로킹 규약을 적용하면 트랜잭션의 스케줄 직렬 가능성을 보장할 수 있음&lt;/li&gt;
&lt;li&gt;하지만 교착(deadlock) 상태가 발생할 수 있어 해결책이 필요함&lt;/li&gt;
&lt;li&gt;교착 상태는 트랜잭션들이 상대가 독점하고 있는 데이터에 unlock 연산이 실행되기를 서로 기다리면서 수행을 중단하고 있는 상태&lt;/li&gt;
&lt;li&gt;교착 상태에 빠지면 상대 트랜잭션이 먼저 unlock 연산을 실행해주기를 한없이 기다리게 됨.&lt;/li&gt;
&lt;li&gt;교착 상태는 처음부터 발생하지 않도록 예방하거나, 발생했을 때 빨리 탐지하여 필요한 조치를 취하는 방법으로 해결함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스 개론 3판 (김연희 저, 2024.1)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/데이터베이스</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/58</guid>
      <comments>https://onyodev.tistory.com/58#entry58comment</comments>
      <pubDate>Mon, 2 Dec 2024 11:43:01 +0900</pubDate>
    </item>
    <item>
      <title>정규화</title>
      <link>https://onyodev.tistory.com/57</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 김연희 저 - &quot;데이터베이스 개론 3판&quot;을 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 정규화의 개념과 이상 현상&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1️⃣ 정규화의 개념&lt;/b&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;데이터베이스를 잘못 설계하면 불필요한 데이터 중복이 발생하여 삽입&amp;bull;수정&amp;bull;삭제 연산을 수행할 때 &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;b&gt;2️⃣ 이상 현상의 종류&lt;/b&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;li&gt;삭제 이상: 튜플을 삭제하면 꼭 필요한 데이터까지 함께 삭제되는 데이터 손실의 문제&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3️⃣ 정규화의 필요성&lt;/b&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;li&gt;정규화는 이상 현상이 발생하지 않도록 릴레이션을 관련이 있는 속성들로만 구성하기 위해 릴레이션을 분해하는 과정&lt;/li&gt;
&lt;li&gt;정규화 과정에선 먼저 릴레이션을 구성하는 속성들 간의 관련성을 판단해야 함.&lt;/li&gt;
&lt;li&gt;이를 &lt;b&gt;함수적 종속성&lt;/b&gt;이라 하고 &lt;b&gt;릴레이션에 함수적 종속성이 하나 존재&lt;/b&gt;하도록 정규화를 통해 릴레이션을 분해함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 함수 종속&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 릴레이션을 구성하는 속성들의 부분 집합을 X와 Y라 할 때, 어느 시점에서든 릴레이션 내의 모든 튜플에서 X 값에 대한 Y 값이 항상 하나인 경우&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&amp;ldquo;X가 Y를 함수적으로 결정한다&amp;rdquo;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&amp;ldquo;Y가 X에 함수적으로 종속되어 있다&amp;rdquo;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라 표현하고 &lt;b&gt;X를 결정자&lt;/b&gt;, &lt;b&gt;Y를 종속자&lt;/b&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;b&gt;완전 함수 종속(FFD: Full Functional Dependency)&lt;/b&gt;: 릴레이션에서 속성 집합 Y가 속성 집합 X에 함수적으로 종속되어 있지만, 속성 집합 X 전체에 종속되어 있는 경우&lt;/li&gt;
&lt;li&gt;&lt;b&gt;부분 함수 종속(PFD: Partial Functional Dependency)&lt;/b&gt;: 속성 집합 Y가 속성 집합 X의 전체가 아닌 일부분에 함수적으로 종속됨을 의미, 이 경우 결정자가 여러 개여야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 기본 정규형과 정규화 과정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1️⃣ 정규화의 개념과 정규형의 종류&lt;/b&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;b&gt;연관성이 있는 속성들로만 분해해 이상현상이 발생하지 않는 올바른 릴레이션으로 만들어가는 과정&lt;/b&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;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제1정규형&lt;/li&gt;
&lt;li&gt;제2정규형&lt;/li&gt;
&lt;li&gt;제3정규형&lt;/li&gt;
&lt;li&gt;보이스/코드 정규형&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;고급 정규형&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제4정규형&lt;/li&gt;
&lt;li&gt;제5정규형&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;정규형의 차수가 높아질수록 요구되는 제약조건이 많아지고 엄격해짐&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2️⃣ 제1정규형&lt;/b&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;b&gt;릴레이션에 속한 모든 속성의 도메인이 원자 값으로만 구성되어 있으면 제 1 정규형에 속한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;각 속성값을 하나씩만 포함하도록 분해하여 모든 속성이 원자 값을 가지도록 해야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 73.0233%; height: 156px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 18.3721%; height: 20px;&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;/td&gt;
&lt;td style=&quot;width: 15.2326%; height: 20px;&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;/td&gt;
&lt;td style=&quot;width: 15.2325%; height: 20px;&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;/td&gt;
&lt;td style=&quot;width: 11.0465%; height: 20px;&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;/td&gt;
&lt;td style=&quot;width: 13.0233%; height: 20px;&quot;&gt;할인율&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 18.3721%; height: 17px;&quot;&gt;apple&lt;/td&gt;
&lt;td style=&quot;width: 15.2326%; height: 17px;&quot;&gt;E001&lt;/td&gt;
&lt;td style=&quot;width: 15.2325%; height: 17px;&quot;&gt;Y&lt;/td&gt;
&lt;td style=&quot;width: 11.0465%; height: 17px;&quot;&gt;gold&lt;/td&gt;
&lt;td style=&quot;width: 13.0233%; height: 17px;&quot;&gt;10%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 18.3721%; height: 17px;&quot;&gt;apple&lt;/td&gt;
&lt;td style=&quot;width: 15.2326%; height: 17px;&quot;&gt;E005&lt;/td&gt;
&lt;td style=&quot;width: 15.2325%; height: 17px;&quot;&gt;N&lt;/td&gt;
&lt;td style=&quot;width: 11.0465%; height: 17px;&quot;&gt;gold&lt;/td&gt;
&lt;td style=&quot;width: 13.0233%; height: 17px;&quot;&gt;10%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 18.3721%; height: 17px;&quot;&gt;apple&lt;/td&gt;
&lt;td style=&quot;width: 15.2326%; height: 17px;&quot;&gt;E010&lt;/td&gt;
&lt;td style=&quot;width: 15.2325%; height: 17px;&quot;&gt;Y&lt;/td&gt;
&lt;td style=&quot;width: 11.0465%; height: 17px;&quot;&gt;gold&lt;/td&gt;
&lt;td style=&quot;width: 13.0233%; height: 17px;&quot;&gt;10%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 18.3721%; height: 17px;&quot;&gt;banana&lt;/td&gt;
&lt;td style=&quot;width: 15.2326%; height: 17px;&quot;&gt;E002&lt;/td&gt;
&lt;td style=&quot;width: 15.2325%; height: 17px;&quot;&gt;N&lt;/td&gt;
&lt;td style=&quot;width: 11.0465%; height: 17px;&quot;&gt;vip&lt;/td&gt;
&lt;td style=&quot;width: 13.0233%; height: 17px;&quot;&gt;20%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 18.3721%; height: 17px;&quot;&gt;banana&lt;/td&gt;
&lt;td style=&quot;width: 15.2326%; height: 17px;&quot;&gt;E005&lt;/td&gt;
&lt;td style=&quot;width: 15.2325%; height: 17px;&quot;&gt;Y&lt;/td&gt;
&lt;td style=&quot;width: 11.0465%; height: 17px;&quot;&gt;vip&lt;/td&gt;
&lt;td style=&quot;width: 13.0233%; height: 17px;&quot;&gt;20%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 18.3721%; height: 17px;&quot;&gt;carrot&lt;/td&gt;
&lt;td style=&quot;width: 15.2326%; height: 17px;&quot;&gt;E003&lt;/td&gt;
&lt;td style=&quot;width: 15.2325%; height: 17px;&quot;&gt;Y&lt;/td&gt;
&lt;td style=&quot;width: 11.0465%; height: 17px;&quot;&gt;gold&lt;/td&gt;
&lt;td style=&quot;width: 13.0233%; height: 17px;&quot;&gt;10%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 18.3721%; height: 17px;&quot;&gt;carrot&lt;/td&gt;
&lt;td style=&quot;width: 15.2326%; height: 17px;&quot;&gt;E007&lt;/td&gt;
&lt;td style=&quot;width: 15.2325%; height: 17px;&quot;&gt;Y&lt;/td&gt;
&lt;td style=&quot;width: 11.0465%; height: 17px;&quot;&gt;gold&lt;/td&gt;
&lt;td style=&quot;width: 13.0233%; height: 17px;&quot;&gt;10%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 18.3721%; height: 17px;&quot;&gt;orange&lt;/td&gt;
&lt;td style=&quot;width: 15.2326%; height: 17px;&quot;&gt;E004&lt;/td&gt;
&lt;td style=&quot;width: 15.2325%; height: 17px;&quot;&gt;N&lt;/td&gt;
&lt;td style=&quot;width: 11.0465%; height: 17px;&quot;&gt;silver&lt;/td&gt;
&lt;td style=&quot;width: 13.0233%; height: 17px;&quot;&gt;5%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;❗함수 종속 관계&amp;nbsp;&lt;/b&gt;&lt;br /&gt;고객아이디 &amp;rarr; 등급&lt;br /&gt;고객아이디 &amp;rarr; 할인율&lt;br /&gt;등급 &amp;rarr; 할인율&lt;br /&gt;{고객아이디, 이벤트번호} &amp;rarr; 당첨여부&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;불필요한 데이터 중복되어 삽입 &amp;bull; 갱신 &amp;bull; 삭제 이상 현상이 발생&lt;/li&gt;
&lt;li&gt;&lt;b&gt;삽입 이상&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;갱신 이상&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이벤트참여 릴레이션에는 고객아이디가 apple인 고객의 튜플이 3개이므로 이 고객의 등급과 할인율 속성 값이 중복되어 있음&lt;/li&gt;
&lt;li&gt;고객의 등급이 gold &amp;rarr; vip로 변경되면 세 튜플의 속성값을 모두 변경해야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;삭제 이상&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;고객아이디가 orange인 튜플은 단 하나인데 이벤트를 취소하게 되면 orange 고객에 대한 모든 정보가 날아감&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3️⃣ 제2정규형&lt;/b&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;b&gt;릴레이션이 제 1정규형에 속하고, 기본키가 아닌 모든 속성이 기본키에 완전 함수 종속되면 제2정규형에 속한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;제2정규형을 만족하게 하려면 부분 함수 종속을 제거하고 모든 속성이 기본키에 완전 함수 종속되도록 릴레이션을 분해하는 정규화 과정을 거쳐야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 43.7209%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.8605%;&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;/td&gt;
&lt;td style=&quot;width: 13.8373%;&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;/td&gt;
&lt;td style=&quot;width: 12.9069%;&quot;&gt;할인율&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.8605%;&quot;&gt;apple&lt;/td&gt;
&lt;td style=&quot;width: 13.8373%;&quot;&gt;gold&lt;/td&gt;
&lt;td style=&quot;width: 12.9069%;&quot;&gt;10%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.8605%;&quot;&gt;banana&lt;/td&gt;
&lt;td style=&quot;width: 13.8373%;&quot;&gt;vip&lt;/td&gt;
&lt;td style=&quot;width: 12.9069%;&quot;&gt;20%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.8605%;&quot;&gt;carrot&lt;/td&gt;
&lt;td style=&quot;width: 13.8373%;&quot;&gt;gold&lt;/td&gt;
&lt;td style=&quot;width: 12.9069%;&quot;&gt;10%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 16.8605%;&quot;&gt;orange&lt;/td&gt;
&lt;td style=&quot;width: 13.8373%;&quot;&gt;silver&lt;/td&gt;
&lt;td style=&quot;width: 12.9069%;&quot;&gt;5%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 47.2093%; height: 156px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 16.2791%; height: 20px;&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;/td&gt;
&lt;td style=&quot;width: 19.3023%; height: 20px;&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;/td&gt;
&lt;td style=&quot;width: 11.628%; height: 20px;&quot;&gt;당첨여부&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 16.2791%; height: 17px;&quot;&gt;apple&lt;/td&gt;
&lt;td style=&quot;width: 19.3023%; height: 17px;&quot;&gt;E001&lt;/td&gt;
&lt;td style=&quot;width: 11.628%; height: 17px;&quot;&gt;Y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 16.2791%; height: 17px;&quot;&gt;apple&lt;/td&gt;
&lt;td style=&quot;width: 19.3023%; height: 17px;&quot;&gt;E005&lt;/td&gt;
&lt;td style=&quot;width: 11.628%; height: 17px;&quot;&gt;N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 16.2791%; height: 17px;&quot;&gt;apple&lt;/td&gt;
&lt;td style=&quot;width: 19.3023%; height: 17px;&quot;&gt;E010&lt;/td&gt;
&lt;td style=&quot;width: 11.628%; height: 17px;&quot;&gt;Y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 16.2791%; height: 17px;&quot;&gt;banana&lt;/td&gt;
&lt;td style=&quot;width: 19.3023%; height: 17px;&quot;&gt;E002&lt;/td&gt;
&lt;td style=&quot;width: 11.628%; height: 17px;&quot;&gt;N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 16.2791%; height: 17px;&quot;&gt;banana&lt;/td&gt;
&lt;td style=&quot;width: 19.3023%; height: 17px;&quot;&gt;E005&lt;/td&gt;
&lt;td style=&quot;width: 11.628%; height: 17px;&quot;&gt;Y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 16.2791%; height: 17px;&quot;&gt;carrot&lt;/td&gt;
&lt;td style=&quot;width: 19.3023%; height: 17px;&quot;&gt;E003&lt;/td&gt;
&lt;td style=&quot;width: 11.628%; height: 17px;&quot;&gt;Y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 16.2791%; height: 17px;&quot;&gt;carrot&lt;/td&gt;
&lt;td style=&quot;width: 19.3023%; height: 17px;&quot;&gt;E007&lt;/td&gt;
&lt;td style=&quot;width: 11.628%; height: 17px;&quot;&gt;Y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 16.2791%; height: 17px;&quot;&gt;orange&lt;/td&gt;
&lt;td style=&quot;width: 19.3023%; height: 17px;&quot;&gt;E004&lt;/td&gt;
&lt;td style=&quot;width: 11.628%; height: 17px;&quot;&gt;N&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;{고객아이디, 이벤트번호}에 완전히 종속되지 않는 등급&amp;bull;할인율 속성이 관련 없는 이벤트번호&amp;bull;당첨여부 속성과 같은 릴레이션이 존재하지 않도록 분해함.&lt;/li&gt;
&lt;li&gt;정규화 과정에서 릴레이션을 분해할 때, 분해된 릴레이션들을 자연조인하여 분해 전 릴레이션으로 복원할 수 있어야 함.&lt;/li&gt;
&lt;li&gt;정보의 손실 없이 릴레이션을 분해하는 것을 &lt;b&gt;무손실 분해&lt;/b&gt;라 함.&lt;/li&gt;
&lt;li&gt;그럼에도 발생할 수 있는 이상 현상이 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;삽입 이상&lt;/b&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;고객아이디를 NULL 값으로 두며 개체 무결성 제약조건을 위반&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;갱신 이상&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;삭제 이상&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4️⃣ 제3정규형&lt;/b&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;b&gt;릴레이션이 제 2 정규형에 속하고, 기본키가 아닌 모든 속성이 기본키에 이행적 함수 종속이 되지 않으면 제3정규형이 된다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;릴레이션을 구성하는 3개의 속성 집합 X,Y,Z 에 대해 함수 종속 관계 X&amp;rarr;Y이면 Y&amp;rarr;Z가 존재하면 논리적으로 X&amp;rarr;Z가 성립한다.&lt;/li&gt;
&lt;li&gt;이때 속성 집합 Z가 속성 집합 X에 이행적으로 함수 종속되었다고 함.&lt;/li&gt;
&lt;li&gt;제2정규형을 만족했더라도 하나의 릴레이션에 함수 종속 관계가 여러 개 존재하고 논리적으로 이행적 함수 종속 관계가 유도되면 이상 현상이 발생할 수 있음&lt;/li&gt;
&lt;li&gt;릴레이션에서 &lt;b&gt;이행적 함수 종속을 제거&lt;/b&gt;해서 &lt;b&gt;모든 속성이 기본키에 이행적 함수 종속이 되지 않도록 릴레이션을 분해&lt;/b&gt;하는 과정을 거쳐야 제 3정규형을 만족할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 51.6279%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.1628%;&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;/td&gt;
&lt;td style=&quot;width: 13.9535%;&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;/td&gt;
&lt;td style=&quot;width: 16.3953%;&quot;&gt;할인율&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.1628%;&quot;&gt;apple&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%;&quot;&gt;gold&lt;/td&gt;
&lt;td style=&quot;width: 16.3953%;&quot;&gt;10%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.1628%;&quot;&gt;banana&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%;&quot;&gt;vip&lt;/td&gt;
&lt;td style=&quot;width: 16.3953%;&quot;&gt;20%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.1628%;&quot;&gt;carrot&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%;&quot;&gt;gold&lt;/td&gt;
&lt;td style=&quot;width: 16.3953%;&quot;&gt;10%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.1628%;&quot;&gt;orange&lt;/td&gt;
&lt;td style=&quot;width: 13.9535%;&quot;&gt;silver&lt;/td&gt;
&lt;td style=&quot;width: 16.3953%;&quot;&gt;5%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;li&gt;고객 릴레이션에서 이상 현상이 발생하지 않도록 2개의 릴레이션으로 분해&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 34.186%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style7&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.6512%;&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;/td&gt;
&lt;td style=&quot;width: 14.4186%;&quot;&gt;등급&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.6512%;&quot;&gt;apple&lt;/td&gt;
&lt;td style=&quot;width: 14.4186%;&quot;&gt;gold&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.6512%;&quot;&gt;banana&lt;/td&gt;
&lt;td style=&quot;width: 14.4186%;&quot;&gt;vip&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.6512%;&quot;&gt;carrot&lt;/td&gt;
&lt;td style=&quot;width: 14.4186%;&quot;&gt;gold&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.6512%;&quot;&gt;orange&lt;/td&gt;
&lt;td style=&quot;width: 14.4186%;&quot;&gt;silver&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 26.2791%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.093%;&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;/td&gt;
&lt;td style=&quot;width: 14.0698%;&quot;&gt;할인율&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.093%;&quot;&gt;gold&lt;/td&gt;
&lt;td style=&quot;width: 14.0698%;&quot;&gt;10%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.093%;&quot;&gt;vip&lt;/td&gt;
&lt;td style=&quot;width: 14.0698%;&quot;&gt;20%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.093%;&quot;&gt;silver&lt;/td&gt;
&lt;td style=&quot;width: 14.0698%;&quot;&gt;5%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;5️⃣ 보이스/코드 정규형&lt;/b&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;b&gt;릴레이션의 함수 종속 관계에서 모든 결정자가 후보키이면 보이스/코드 정규형에 속한다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;하나의 릴레이션에 여러 개의 후보키가 존재할 수 있는데 이 경우에 제3정규형까지 만족해도 이상 현상이 발생할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;후보키를 여러 개 갖고 있는 릴레이션에서 발생할 수 있는 이상 현상을 해결&lt;/b&gt;하기 위해 제3정규형보다 좀 더 엄격한 제약조건이 보이스/코드 정규형이다.&lt;/li&gt;
&lt;li&gt;보이스/코드 정규형은 제3정규형의 조건을 다 갖추면서도 좀 더 강한 제약조건을 갖고 있어 강한 제3정규형이라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 59.6512%; height: 120px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.093%;&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;/td&gt;
&lt;td style=&quot;width: 19.5349%;&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;/td&gt;
&lt;td style=&quot;width: 22.907%;&quot;&gt;담당강사번호&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 17.093%;&quot;&gt;apple&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 19.5349%;&quot;&gt;영어회화&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 22.907%;&quot;&gt;P001&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 17.093%;&quot;&gt;banana&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 19.5349%;&quot;&gt;기초토익&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 22.907%;&quot;&gt;P002&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 17.093%;&quot;&gt;carrot&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 19.5349%;&quot;&gt;영어회화&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 22.907%;&quot;&gt;P001&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 17.093%;&quot;&gt;carrot&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 19.5349%;&quot;&gt;기초토익&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 22.907%;&quot;&gt;P004&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 17.093%;&quot;&gt;orange&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 19.5349%;&quot;&gt;영어회화&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 22.907%;&quot;&gt;P003&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 17.093%;&quot;&gt;orange&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 19.5349%;&quot;&gt;기초토익&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 22.907%;&quot;&gt;P004&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;/li&gt;
&lt;li&gt;강사 한 명이 인터넷강좌 하나만 담당할 수 있고, 하나의 인터넷강좌는 여러 강사가 담당할 수 있다.&lt;/li&gt;
&lt;/ul&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;620&quot; data-origin-height=&quot;274&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZ2dO3/btsK2xkV2tw/IxxxBYGBDyNoxbK8eK1sf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZ2dO3/btsK2xkV2tw/IxxxBYGBDyNoxbK8eK1sf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZ2dO3/btsK2xkV2tw/IxxxBYGBDyNoxbK8eK1sf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZ2dO3%2FbtsK2xkV2tw%2FIxxxBYGBDyNoxbK8eK1sf1%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;448&quot; height=&quot;198&quot; data-origin-width=&quot;620&quot; data-origin-height=&quot;274&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;강좌신청 릴레이션은 모든 속성이 원자 값으로만 구성 (제1정규형)&lt;/li&gt;
&lt;li&gt;기본키가 아닌 속성이 담당강사번호와 기본키에 완전 함수 종속되는 것은 물론, 이행적 함수 종속도 없음 (제2,3정규형)&lt;/li&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;
&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;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;삭제 이상&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;고객아이디가 banana인 고객이 강좌를 취소하면 해당 강사가 강좌를 맡고 있다는 정보도 삭제되버림.&lt;/li&gt;
&lt;li&gt;이는 후보키가 아니면서 함수 종속 관계에서 다른 속성을 결정하는 담당강사번호 속성이 존재하기 때문&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 2개의 릴레이션으로 분해가 필요함&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 40.7035%; height: 169px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style6&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 20.603%; height: 25px;&quot;&gt;고객아이디&lt;/td&gt;
&lt;td style=&quot;width: 19.9749%; height: 25px;&quot;&gt;담당강사번호&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 20.603%; height: 25px;&quot;&gt;apple&lt;/td&gt;
&lt;td style=&quot;width: 19.9749%; height: 25px;&quot;&gt;P001&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 20.603%; height: 25px;&quot;&gt;banana&lt;/td&gt;
&lt;td style=&quot;width: 19.9749%; height: 25px;&quot;&gt;P002&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 20.603%; height: 25px;&quot;&gt;carrot&lt;/td&gt;
&lt;td style=&quot;width: 19.9749%; height: 25px;&quot;&gt;P001&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 20.603%; height: 19px;&quot;&gt;carrot&lt;/td&gt;
&lt;td style=&quot;width: 19.9749%; height: 19px;&quot;&gt;P004&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 20.603%; height: 25px;&quot;&gt;orange&lt;/td&gt;
&lt;td style=&quot;width: 19.9749%; height: 25px;&quot;&gt;P003&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 20.603%; height: 25px;&quot;&gt;orange&lt;/td&gt;
&lt;td style=&quot;width: 19.9749%; height: 25px;&quot;&gt;P004&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style5&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;담당강사번호&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;인터넷강좌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P001&lt;/td&gt;
&lt;td&gt;영어회화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P002&lt;/td&gt;
&lt;td&gt;기초토익&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P003&lt;/td&gt;
&lt;td&gt;영어회화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P004&lt;/td&gt;
&lt;td&gt;기초토익&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;6️⃣ 제4정규형과 제5정규형&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;고급 정규형으로 분류되는 제4정규형은 릴레이션이 보이스/코드 정규형을 만족하면서, 함수 종속이 아닌 &lt;b&gt;다치 종속&lt;/b&gt;을 제거해야 만족할 수 있음&lt;/li&gt;
&lt;li&gt;제5정규형은 릴레이션이 제4정규형을 만족하면서 &lt;b&gt;후보키를 통하지 않는 조인 종속을 제거&lt;/b&gt;해야 만족할 수 있음&lt;/li&gt;
&lt;li&gt;일반적으로는 제3정규형이나 보이스/코드 정규형에 속하도록 릴레이션을 분해하여 데이터 중복을 줄이고 이상 현상 문제를 해결함.&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;747&quot; data-origin-height=&quot;762&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOQF2u/btsK22Lh0VY/sgcpzKuBWy8XHCmI2Mjkm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOQF2u/btsK22Lh0VY/sgcpzKuBWy8XHCmI2Mjkm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOQF2u/btsK22Lh0VY/sgcpzKuBWy8XHCmI2Mjkm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOQF2u%2FbtsK22Lh0VY%2FsgcpzKuBWy8XHCmI2Mjkm0%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;747&quot; height=&quot;762&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;762&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스 개론 3판 (김연희 저, 2024.1)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/데이터베이스</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/57</guid>
      <comments>https://onyodev.tistory.com/57#entry57comment</comments>
      <pubDate>Fri, 29 Nov 2024 21:42:34 +0900</pubDate>
    </item>
    <item>
      <title>데이터베이스 설계</title>
      <link>https://onyodev.tistory.com/56</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 김연희 저 - &quot;데이터베이스 개론 3판&quot;을 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 데이터베이스 설계 단계&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1️⃣ 1단계: 요구 사항 분석&lt;/b&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;li&gt;수집한 요구 사항을 분석하여 그 결과를 요구 사항 명세서로 작성함.&lt;/li&gt;
&lt;li&gt;요구 사항 분석 단계에서 구축된 데이터베이스의 품질이 결정됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2️⃣ &lt;b&gt;2단계: 개념적 설계&lt;/b&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;개념적 데이터 모델은 개발에 사용할 DBMS의 종류에 독립적이면서, 중요한 데이터 요소 간 관계를 표현할 때 사용&lt;/li&gt;
&lt;li&gt;개념적 데이터 모델은 &lt;b&gt;E-R 모델&lt;/b&gt;을 많이 사용하고 중요한 데이터 요소 간 관계를 &lt;b&gt;E-R 다이어그램&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;3️⃣ &lt;b&gt;3단계: 논리적 설계&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개발에 사용할 DBMS에 적합한 논리적 데이터 모델을 이용해 &lt;b&gt;개념적 구조를 기반으로 논리적 구조를 설계함&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;DBMS의 종류에 따라 다양한 논리적 데이터 모델을 사용할 수 있지만, 일반적으로 &lt;b&gt;관계 데이터 모델&lt;/b&gt;을 가장 많이 사용함&lt;/li&gt;
&lt;li&gt;관계 데이터 모델을 사용할 경우, &lt;b&gt;E-R 다이어그램을 릴레이션(테이블) 스키마로 변환&lt;/b&gt;하여 DBMS가 처리할 수 있도록 하는 것이 주요 작업이고 &lt;b&gt;논리적 모델링&lt;/b&gt; 또는 &lt;b&gt;데이터 모델링&lt;/b&gt;이라 함.&lt;/li&gt;
&lt;li&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;4️⃣ &lt;b&gt;4단계: 물리적 설계&lt;/b&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;b&gt;내부 저장 구조와 접근 경로 등을 의미&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;그러므로 물리적 설계 단계에서는 저장 장치에 적합한 저장 레코드와 인덱스의 구조 등을 설계하고 탐색 기법 등을 정의함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터베이스를 컴퓨터 시스템의 저장 장치와 운영체제의 특성을 고려해 효율적이면서 구현 가능한 물리적 구조를 설계&lt;/b&gt;하는 것이 주요 작업&lt;/li&gt;
&lt;li&gt;응답 시간을 최소화하고 저장 공간을 효율적으로 활용하면서 데이터베이스 시스템의 처리 능력을 향상시킬 수 있도록 물리적 구조를 설계해야 함&lt;/li&gt;
&lt;li&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;5️⃣ &lt;b&gt;5단계: 구현&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이전 설계 단계의 결과물을 기반으로 DBMS에서 SQL로 작성한 명령문을 실행하여 데이터베이스를 실제로 생성&lt;/li&gt;
&lt;li&gt;이 때 사용하는 SQL문은 테이블이나 인덱스 등을 생성할 때 쓰이는 &lt;b&gt;데이터 정의어(DDL)&lt;/b&gt;이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 요구 사항 분석&lt;/h2&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;/li&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;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;요구 사항 분석이 잘못된 경우, 사용자가 원치 않는 쓸모없는 데이터베이스가 개발되어 후에 수정해야 되는 문제가 생기기 때문에 중요한 과정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;  &lt;span style=&quot;letter-spacing: 0px; color: #000000;&quot; data-token-index=&quot;1&quot;&gt;예시) 요구 사항 명세서&lt;/span&gt;&lt;/span&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;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;444&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dLsWix/btsKYh3EpvL/MGNHtrzUPH6ZJuK80toOuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dLsWix/btsKYh3EpvL/MGNHtrzUPH6ZJuK80toOuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dLsWix/btsKYh3EpvL/MGNHtrzUPH6ZJuK80toOuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdLsWix%2FbtsKYh3EpvL%2FMGNHtrzUPH6ZJuK80toOuk%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;681&quot; height=&quot;444&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;444&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 개념적 설계&lt;/h2&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;li&gt;일반적으로 개념 데이터 모델은 E-R 모델을 많이 이용함.&lt;/li&gt;
&lt;li&gt;개념적 설계는 &lt;b&gt;요구 사항 분석 결과 기반&lt;/b&gt;으로 현실 세계에서 중요한 데이터 요소인 &lt;b&gt;개체를 추출&lt;/b&gt;한 후 &lt;b&gt;개체 간 관계를 결정&lt;/b&gt;하여 &lt;b&gt;E-R 다이어그램으로 표현&lt;/b&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; 또는 &lt;b&gt;개념적 스키마&lt;/b&gt;라 함.&lt;/li&gt;
&lt;li&gt;개념적 모델링 과정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개체와 속성 추출&lt;/b&gt; &amp;rarr; &lt;b&gt;관계 추출&lt;/b&gt; &amp;rarr; &lt;b&gt;E-R 다이어그램 작성&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.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;즉, &lt;b&gt;개체&lt;/b&gt;는 &lt;b&gt;저장할 만한 가치가 있는 중요 데이터를 지닌 사람이나 사물 등&lt;/b&gt;이며, 개념적 모델링의 가장 중요한 요소&lt;/li&gt;
&lt;li&gt;개체를 추출하는 방법은 일반적으로 요구 사항 명세서의 문장들에서 명사를 추출함.&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;162&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCawwk/btsKZb9vWJe/AqTxIF0CPjCZIWKIlMdS00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCawwk/btsKZb9vWJe/AqTxIF0CPjCZIWKIlMdS00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCawwk/btsKZb9vWJe/AqTxIF0CPjCZIWKIlMdS00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCawwk%2FbtsKZb9vWJe%2FAqTxIF0CPjCZIWKIlMdS00%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;692&quot; height=&quot;162&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;162&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;회원 &amp;rarr; 개체&lt;/li&gt;
&lt;li&gt;회원아이디, 비밀번호, 이름, 나이, 직업, 등급, 적립금 &amp;rarr; 회원의 속성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&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;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;443&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NsEZ2/btsKYX4KEjD/iYcqyFPGBU0hYH4TK0oxaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NsEZ2/btsKYX4KEjD/iYcqyFPGBU0hYH4TK0oxaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NsEZ2/btsKYX4KEjD/iYcqyFPGBU0hYH4TK0oxaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNsEZ2%2FbtsKYX4KEjD%2FiYcqyFPGBU0hYH4TK0oxaK%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;693&quot; height=&quot;443&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;443&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;485&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ebCRBf/btsKX1mAxsP/8suLrH720gDVKxgYhYcNn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ebCRBf/btsKX1mAxsP/8suLrH720gDVKxgYhYcNn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ebCRBf/btsKX1mAxsP/8suLrH720gDVKxgYhYcNn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FebCRBf%2FbtsKX1mAxsP%2F8suLrH720gDVKxgYhYcNn0%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;485&quot; height=&quot;222&quot; data-origin-width=&quot;485&quot; data-origin-height=&quot;222&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개념적 설계의 최종 결과물을 E-R 다이어그램으로 작성해야 함&lt;/li&gt;
&lt;li&gt;그래서 요구 사항 명세서에서 추출한 개체와 속성을 E-R 다이어그램으로 표현해 둔다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개체&lt;/b&gt;: 사각형, &lt;b&gt;속성&lt;/b&gt;: 타원형&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2. 관계 추출&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;b&gt;매핑 카디널리티&lt;/b&gt;와 &lt;b&gt;참여 특성&lt;/b&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;을 결정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #fbf3db; color: #000000;&quot; data-token-index=&quot;0&quot;&gt;&lt;span style=&quot;background-color: #fbf3db; color: #000000;&quot; data-token-index=&quot;0&quot;&gt;동사 추출 예시&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;130&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjwA0E/btsKYiat7MQ/lOQaxcmYynwyuL8kki1hA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjwA0E/btsKYiat7MQ/lOQaxcmYynwyuL8kki1hA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjwA0E/btsKYiat7MQ/lOQaxcmYynwyuL8kki1hA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcjwA0E%2FbtsKYiat7MQ%2FlOQaxcmYynwyuL8kki1hA0%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;681&quot; height=&quot;130&quot; data-origin-width=&quot;681&quot; data-origin-height=&quot;130&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;span style=&quot;background-color: #fbf3db; color: #000000;&quot; data-token-index=&quot;0&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주문할 수 있다. &amp;rarr; 주문 관계/다대다 관계&lt;/p&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 style=&quot;background-color: #fbf3db; color: #000000;&quot; data-token-index=&quot;0&quot;&gt;관계와 관계 속성을 추출한 최종결과&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMgdRd/btsKYaqapoN/Eu2lvKCdXMs7Xe7fR8bk6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMgdRd/btsKYaqapoN/Eu2lvKCdXMs7Xe7fR8bk6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMgdRd/btsKYaqapoN/Eu2lvKCdXMs7Xe7fR8bk6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMgdRd%2FbtsKYaqapoN%2FEu2lvKCdXMs7Xe7fR8bk6K%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;599&quot; height=&quot;250&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;250&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. E-R 다이어그램 작성&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;685&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCLtGC/btsKZsiYZjE/GB6DemZdKzjNUrmOncebn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCLtGC/btsKZsiYZjE/GB6DemZdKzjNUrmOncebn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCLtGC/btsKZsiYZjE/GB6DemZdKzjNUrmOncebn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCLtGC%2FbtsKZsiYZjE%2FGB6DemZdKzjNUrmOncebn1%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;708&quot; height=&quot;685&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;685&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 논리적 설계&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DBMS에 적합한 논리적 데이터 모델을 이용해 개념적 스키마를 기반으로 논리적 스키마를 설계&lt;/li&gt;
&lt;li&gt;DBMS에 독립적인 개념적 스키마를 기반으로 &lt;b&gt;개발에 사용할 DBMS가 처리할 수 있는 데이터베이스 논리적 구조를 설계하는 것&lt;/b&gt;이 논리적 설계 단계의 목표&lt;/li&gt;
&lt;li&gt;일반적으로 관계 데이터 모델을 많이 사용하며 관계 데이터 모델을 이용해 &lt;b&gt;E-R 다이어그램을 관계 데이터 모델의 릴레이션 스키마, 즉 테이블 스키마로 변환&lt;/b&gt;하는 작업을 수행&lt;/li&gt;
&lt;li&gt;E-R 다이어그램을 논리적 데이터 모델로 변환하는 작업을 &lt;b&gt;논리적 모델링&lt;/b&gt; 또는 &lt;b&gt;데이터 모델링&lt;/b&gt;이라 함.&lt;/li&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;4.1. 릴레이션 스키마 변환 규칙&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;1️⃣ 규칙 1: 모든 개체는 릴레이션으로 변환한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;673&quot; data-origin-height=&quot;481&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eAOLS6/btsKYy5asza/O32BZF8pKWj8k9m2skBzZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eAOLS6/btsKYy5asza/O32BZF8pKWj8k9m2skBzZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eAOLS6/btsKYy5asza/O32BZF8pKWj8k9m2skBzZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeAOLS6%2FbtsKYy5asza%2FO32BZF8pKWj8k9m2skBzZK%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;673&quot; height=&quot;481&quot; data-origin-width=&quot;673&quot; data-origin-height=&quot;481&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;E-R 다이어그램의 각 개체를 하나의 릴레이션으로 변환&lt;/li&gt;
&lt;li&gt;개체의 이름을 릴레이션의 이름으로 하고 개체가 가진 속성도 릴레이션의 속성으로 그대로 변환&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;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;2️⃣ 규칙 2: 다대다 관계는 릴레이션으로 변환한다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;483&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ooT1b/btsKYp1BipU/nUplw3WrHHq9LyMHfEfbpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ooT1b/btsKYp1BipU/nUplw3WrHHq9LyMHfEfbpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ooT1b/btsKYp1BipU/nUplw3WrHHq9LyMHfEfbpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FooT1b%2FbtsKYp1BipU%2FnUplw3WrHHq9LyMHfEfbpK%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;734&quot; height=&quot;483&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;483&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;E-R 다이어그램에 있는 다대다 관계를 하나의 릴레이션으로 변환한다.&lt;/li&gt;
&lt;li&gt;관계의 이름을 릴레이션의 이름으로 하고, 관계의 속성도 릴레이션의 속성으로 그대로 변환&lt;/li&gt;
&lt;li&gt;관계를 맺고 있는 개체들은 규칙 1에 따라 변환한 후 이 릴레이션들의 기본키를 관계 릴레이션에 포함시키고 외래키로 지정&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;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;3️⃣ 규칙 3: 일대다 관계는 외래키로 표현한다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;E-R 다이어그램에 있는 일대다 관계는 릴레이션으로 변환하지 않고 외래키로만 표현함&lt;/li&gt;
&lt;li&gt;단, 약한 개체가 참여하는 일대다 관게는 일반 개체가 참여하는 경우와 다르게 처리함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;3️⃣1️⃣규칙 3-1: 일반적인 일대다 관계는 외래키로 표현한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;741&quot; data-origin-height=&quot;377&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hy2RZ/btsKXKrH8E9/KF6EkDJCQhxIIGpwv1K6p0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hy2RZ/btsKXKrH8E9/KF6EkDJCQhxIIGpwv1K6p0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hy2RZ/btsKXKrH8E9/KF6EkDJCQhxIIGpwv1K6p0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHy2RZ%2FbtsKXKrH8E9%2FKF6EkDJCQhxIIGpwv1K6p0%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;741&quot; height=&quot;377&quot; data-origin-width=&quot;741&quot; data-origin-height=&quot;377&quot;/&gt;&lt;/span&gt;&lt;/figure&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;관계를 맺고 있는 개체들을 변환한 릴레이션 중, 일대다 관계의 1측 개체 릴레이션의 기본키를 가져와 N측 개체의 릴레이션에 포함시키고 외래키로 지정함.&lt;/li&gt;
&lt;li&gt;N측 개체 릴레이션의 기본키를 가져와 1측 개체 릴레이션에 외래키로 포함시키면 다중값을 가져 릴레이션의 특성을 위반함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;3️⃣2️⃣규칙 3-2: 약한 개체가 참여하는 일대다 관계는 외래키를 포함해서 기본키로 지정한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;409&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Thlc0/btsKX3Sbe0A/B6lSEgInbbMbklSJ869HU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Thlc0/btsKX3Sbe0A/B6lSEgInbbMbklSJ869HU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Thlc0/btsKX3Sbe0A/B6lSEgInbbMbklSJ869HU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FThlc0%2FbtsKX3Sbe0A%2FB6lSEgInbbMbklSJ869HU1%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;700&quot; height=&quot;409&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;409&quot;/&gt;&lt;/span&gt;&lt;/figure&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;li&gt;다른 점은 외래키가 포함된 릴레이션에서 이 외래키를 포함하여 기본키를 지정해야 한다는 점&lt;/li&gt;
&lt;li&gt;&lt;b&gt;즉, N측 개체 릴레이션이 가지고 있던 키 속성과 외래키 속성을 조합하여 기본키를 구성&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;약한 개체는 강한 개체에 따라 존재 여부가 결정되기 때문에 강한 개체의 기본키를 이용해 식별&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;4️⃣ 규칙 4: 일대일 관계를 외래키로 표현한다.&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;E-R 다이어그램에 있는 일대일 관계도 일대다 관계처럼 릴레이션으로 변환하지 않고 외래키로만 표현&lt;/li&gt;
&lt;li&gt;데이터 중복을 피하려면 개체가 관게에 참여하는 특성에 따라 다르게 처리해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;4️⃣1️⃣규칙 4-1: 일반적인 일대일 관계는 외래키를 서로 주고 받는다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;705&quot; data-origin-height=&quot;424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpsNqI/btsKYEK6pMY/erH3b7BBtZKcDkOCWPvb61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpsNqI/btsKYEK6pMY/erH3b7BBtZKcDkOCWPvb61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpsNqI/btsKYEK6pMY/erH3b7BBtZKcDkOCWPvb61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpsNqI%2FbtsKYEK6pMY%2FerH3b7BBtZKcDkOCWPvb61%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;705&quot; height=&quot;424&quot; data-origin-width=&quot;705&quot; data-origin-height=&quot;424&quot;/&gt;&lt;/span&gt;&lt;/figure&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;li&gt;사실 그림처럼 남자 릴레이션, 여자 릴레이션 모두 외래키를 가지는 건 불필요한 데이터 중복&lt;/li&gt;
&lt;li&gt;릴레이션의 활용도에 따라 외래키와 관계의 속성을 포함시킬 릴레이션을 선택하는 방법&lt;/li&gt;
&lt;li&gt;&amp;rarr; &lt;b&gt;4-2, 4-3&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;4️⃣2️⃣규칙 4-2: 일대일 관계에 필수적으로 참여하는 개체의 릴레이션만 외래키를 받는다.&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;li&gt;이때, 관계가 가지고 있는 속성들도 관계에 필수적으로 참여하는 릴레이션에 포함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;4️⃣3️⃣규칙 4-3: 모든 개체가 일대일 관계에 필수적으로 참여하면 릴레이션 하나로 합친다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;380&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r2NQS/btsKXH9EhHs/j3Sh7Qw4tZec2k2gKawfEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r2NQS/btsKXH9EhHs/j3Sh7Qw4tZec2k2gKawfEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r2NQS/btsKXH9EhHs/j3Sh7Qw4tZec2k2gKawfEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr2NQS%2FbtsKXH9EhHs%2Fj3Sh7Qw4tZec2k2gKawfEk%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;736&quot; height=&quot;380&quot; data-origin-width=&quot;736&quot; data-origin-height=&quot;380&quot;/&gt;&lt;/span&gt;&lt;/figure&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;li&gt;관계의 이름을 릴레이션의 이름으로 사용하고, 관계에 참여하는 두 개체의 속성들로 관계 릴레이션에 포함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;5️⃣ 규칙 5: 다중 값 속성은 릴레이션으로 변환한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;628&quot; data-origin-height=&quot;414&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8vlow/btsKZJ5I5t1/l8KjzvSCMyqKoKZuHYfkM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8vlow/btsKZJ5I5t1/l8KjzvSCMyqKoKZuHYfkM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8vlow/btsKZJ5I5t1/l8KjzvSCMyqKoKZuHYfkM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8vlow%2FbtsKZJ5I5t1%2Fl8KjzvSCMyqKoKZuHYfkM1%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;628&quot; height=&quot;414&quot; data-origin-width=&quot;628&quot; data-origin-height=&quot;414&quot;/&gt;&lt;/span&gt;&lt;/figure&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;E-R 다이어그램에 있는 다중 값 속성은 그 속성을 가지고 있는 개체에 해당하는 릴레이션이 아닌 별도의 릴레이션을 만들어 포함함&lt;/li&gt;
&lt;li&gt;새로 만들어진 릴레이션에는 다중 값 속성 뿐만 아니라 그 속성을 가지고 있는 개체 릴레이션의 기본키를 가져와 포함시키고 이를 외래키로 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;  기타 고려 사항&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;449&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cz04pa/btsKZrxD1Uo/8MaVaEM6BiIAbtKqpTuvQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cz04pa/btsKZrxD1Uo/8MaVaEM6BiIAbtKqpTuvQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cz04pa/btsKZrxD1Uo/8MaVaEM6BiIAbtKqpTuvQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcz04pa%2FbtsKZrxD1Uo%2F8MaVaEM6BiIAbtKqpTuvQ1%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;720&quot; height=&quot;449&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;449&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&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;li&gt;다만 다대다 외 관계 릴레이션 변환이 많아질 경우, 릴레이션을 관리하는 DBMS의 부담이 커짐&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;663&quot; data-origin-height=&quot;393&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b80Eb8/btsKYDFrcKh/MG0jcTAxZsNth6GNUS1TdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b80Eb8/btsKYDFrcKh/MG0jcTAxZsNth6GNUS1TdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b80Eb8/btsKYDFrcKh/MG0jcTAxZsNth6GNUS1TdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb80Eb8%2FbtsKYDFrcKh%2FMG0jcTAxZsNth6GNUS1TdK%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;663&quot; height=&quot;393&quot; data-origin-width=&quot;663&quot; data-origin-height=&quot;393&quot;/&gt;&lt;/span&gt;&lt;/figure&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;figure data-ke-type=&quot;image&quot; data-ke-style=&quot;alignCenter&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.2. 릴레이션 스키마 변환 규칙을 이용한 논리적 설계&lt;/h3&gt;
&lt;figure data-ke-type=&quot;image&quot; data-ke-style=&quot;alignCenter&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;675&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NURRs/btsKYNBd5mM/4AkarvrEri6rXvJV9Zqbg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NURRs/btsKYNBd5mM/4AkarvrEri6rXvJV9Zqbg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NURRs/btsKYNBd5mM/4AkarvrEri6rXvJV9Zqbg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNURRs%2FbtsKYNBd5mM%2F4AkarvrEri6rXvJV9Zqbg0%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;714&quot; height=&quot;675&quot; data-origin-width=&quot;714&quot; data-origin-height=&quot;675&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;682&quot; data-origin-height=&quot;247&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbAm5o/btsKZbIrRKm/0W9hOdwDiA7VPKJ15kEvRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbAm5o/btsKZbIrRKm/0W9hOdwDiA7VPKJ15kEvRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbAm5o/btsKZbIrRKm/0W9hOdwDiA7VPKJ15kEvRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbAm5o%2FbtsKZbIrRKm%2F0W9hOdwDiA7VPKJ15kEvRk%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;682&quot; height=&quot;247&quot; data-origin-width=&quot;682&quot; data-origin-height=&quot;247&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;746&quot; data-origin-height=&quot;1032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R0S94/btsKXjuwnwE/6bZqvYKtzxPebECKok3MHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R0S94/btsKXjuwnwE/6bZqvYKtzxPebECKok3MHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R0S94/btsKXjuwnwE/6bZqvYKtzxPebECKok3MHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR0S94%2FbtsKXjuwnwE%2F6bZqvYKtzxPebECKok3MHK%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;746&quot; height=&quot;1032&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;1032&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;678&quot; data-origin-height=&quot;302&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBNiwd/btsKZCeB0KA/33QjhabV5xpPW4H0fbqGB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBNiwd/btsKZCeB0KA/33QjhabV5xpPW4H0fbqGB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBNiwd/btsKZCeB0KA/33QjhabV5xpPW4H0fbqGB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBNiwd%2FbtsKZCeB0KA%2F33QjhabV5xpPW4H0fbqGB0%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;678&quot; height=&quot;302&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;302&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;680&quot; data-origin-height=&quot;333&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MtyiE/btsKYDMcbCw/zuTnJUJMCYrTmRVHlDKyf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MtyiE/btsKYDMcbCw/zuTnJUJMCYrTmRVHlDKyf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MtyiE/btsKYDMcbCw/zuTnJUJMCYrTmRVHlDKyf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMtyiE%2FbtsKYDMcbCw%2FzuTnJUJMCYrTmRVHlDKyf1%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;680&quot; height=&quot;333&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;333&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 물리적 설계와 구현&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;529&quot; data-origin-height=&quot;335&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cciojG/btsKXpnSnSk/CkPg34ZDeDxS41YUnBoQF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cciojG/btsKXpnSnSk/CkPg34ZDeDxS41YUnBoQF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cciojG/btsKXpnSnSk/CkPg34ZDeDxS41YUnBoQF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcciojG%2FbtsKXpnSnSk%2FCkPg34ZDeDxS41YUnBoQF1%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;529&quot; height=&quot;335&quot; data-origin-width=&quot;529&quot; data-origin-height=&quot;335&quot;/&gt;&lt;/span&gt;&lt;/figure&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;DBMS를 이용해 SQL 문을 작성하고 이를 실행시켜 데이터베이스를 실제 생성하면 데이터베이스 개발 완료&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;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스 개론 3판 (김연희 저, 2024.1)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/데이터베이스</category>
      <category>computer science</category>
      <category>데이터베이스</category>
      <category>데이터베이스 설계</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/56</guid>
      <comments>https://onyodev.tistory.com/56#entry56comment</comments>
      <pubDate>Wed, 27 Nov 2024 15:34:16 +0900</pubDate>
    </item>
    <item>
      <title>정렬(Sorting)</title>
      <link>https://onyodev.tistory.com/55</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 윤성우 저 - &quot;윤성우의 열혈 자료구조&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 단순한 정렬 알고리즘&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  &lt;b&gt;버블 정렬(Bubble Sort)&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 이해와 구현&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;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dh8gj7/btsKY0f2lDi/fpnttCyqkcisoZY98QFR70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dh8gj7/btsKY0f2lDi/fpnttCyqkcisoZY98QFR70/img.png&quot; data-origin-width=&quot;421&quot; data-origin-height=&quot;490&quot; data-is-animation=&quot;false&quot; style=&quot;width: 25.2723%; margin-right: 10px;&quot; data-widthpercent=&quot;25.87&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dh8gj7/btsKY0f2lDi/fpnttCyqkcisoZY98QFR70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdh8gj7%2FbtsKY0f2lDi%2FfpnttCyqkcisoZY98QFR70%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;421&quot; height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9YAIq/btsKZrK6L1t/TszKgVCOGKkHbzHhP1zwkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9YAIq/btsKZrK6L1t/TszKgVCOGKkHbzHhP1zwkk/img.png&quot; data-origin-width=&quot;421&quot; data-origin-height=&quot;490&quot; data-is-animation=&quot;false&quot; style=&quot;width: 25.2723%; margin-right: 10px;&quot; data-widthpercent=&quot;25.87&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9YAIq/btsKZrK6L1t/TszKgVCOGKkHbzHhP1zwkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9YAIq%2FbtsKZrK6L1t%2FTszKgVCOGKkHbzHhP1zwkk%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;421&quot; height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz8MH4/btsKYxkTikc/YuLNsRXlGBLBqhi1cnKXMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz8MH4/btsKYxkTikc/YuLNsRXlGBLBqhi1cnKXMK/img.png&quot; data-origin-width=&quot;423&quot; data-origin-height=&quot;264&quot; data-is-animation=&quot;false&quot; style=&quot;width: 47.1298%;&quot; data-widthpercent=&quot;48.26&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz8MH4/btsKYxkTikc/YuLNsRXlGBLBqhi1cnKXMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz8MH4%2FbtsKYxkTikc%2FYuLNsRXlGBLBqhi1cnKXMK%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;423&quot; height=&quot;264&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;li&gt;앞에서부터 순서대로 비교하고 교환하는 일련의 과정이 거품이 일어나는 모습에 비유되어 이름이 지어짐&lt;/li&gt;
&lt;li&gt; &amp;zwj;  &lt;b&gt;코드&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732687442422&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void BubbleSort(int arr[], int n)
{
	int i,j;
	int temp;
	
	for(i=0; i&amp;lt;n-1; i++)
	{
		for(j=0; j&amp;lt;(n-i)-1; j++)
		{
			if(arr[j] &amp;gt; arr[j+1])
			{
				// 데이터 교환
				temp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = temp;
			}
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 성능평가&lt;/h4&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;비교의 횟수:&lt;/b&gt; 두 데이터간의 비교연산의 횟수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이동의 횟수:&lt;/b&gt; 위치의 변경을 위한 데이터의 이동횟수&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;비교연산 횟수 : (n-1) + (n-2) + &amp;hellip; + 2 + 1 = &lt;b&gt;n^2 + &amp;hellip;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;이동연산 횟수: 정렬이 역순으로 된 상태면 &lt;b&gt;비교연산 횟수 = 이동연산 횟수&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;시간 복잡도: &lt;b&gt;O(n^2)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  선택 정렬(Selection Sort)&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 이해와 구현&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cm30NH/btsKXA3RfUX/ONxmfcWGwTIMdvpmoqj6T1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cm30NH/btsKXA3RfUX/ONxmfcWGwTIMdvpmoqj6T1/img.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;439&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.5485%; margin-right: 10px;&quot; data-widthpercent=&quot;49.12&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cm30NH/btsKXA3RfUX/ONxmfcWGwTIMdvpmoqj6T1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcm30NH%2FbtsKXA3RfUX%2FONxmfcWGwTIMdvpmoqj6T1%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;500&quot; height=&quot;439&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kyaG8/btsKZbaACNj/fLcjWS1atHPzvKA9pgu650/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kyaG8/btsKZbaACNj/fLcjWS1atHPzvKA9pgu650/img.png&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;356&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.2887%;&quot; data-widthpercent=&quot;50.88&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kyaG8/btsKZbaACNj/fLcjWS1atHPzvKA9pgu650/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkyaG8%2FbtsKZbaACNj%2FfLcjWS1atHPzvKA9pgu650%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;420&quot; height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;li&gt;정렬 순서상 가장 앞서는 것을 선택해 가장 왼쪽으로 이동시키고 , 원래 그 자리에 있던 데이터는 빈 자리에 가져다 놓는 방식&lt;/li&gt;
&lt;li&gt;&lt;span&gt; &amp;zwj; &lt;/span&gt; &lt;span data-token-index=&quot;1&quot;&gt;코드&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732687510543&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void SelSort(int arr[], int n)
{
	int i,j;
	int maxIdx;
	int temp;
	
	for(i=0; i&amp;lt;n-1; i++)
	{
		maxIdx = i;
		for(j=i+1; j&amp;lt;n; j++)  // 최솟값 탐색
		{
			if(arr[j] &amp;lt; arr[maxIdx])
				maxIdx = j;
		}
			// 데이터 교환
			temp = arr[i];
			arr[i] = arr[maxIdx];
			arr[maxIdx] = temp;
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 성능평가&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;바깥쪽 for 문의 i 가 0일 때 안쪽 for 문의 j는 1~ n-1까지 증가하기 때문에 n-1회 연산 실행&lt;/li&gt;
&lt;li&gt;비교연산 횟수: (n-1) + (n-2) + &amp;hellip; + 2 + 1 = &lt;b&gt;n^2 + &amp;hellip; = O(n^2)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;이동연산 횟수: 데이터 교환이 바깥쪽 for문에서 일어나기 때문에 &lt;b&gt;O(n)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;최악의 경우를 놓고 보면 버블 정렬보다 선택 정렬이 좋을 수 있지만 우열을 가리긴 힘들다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  삽입 정렬(Insertion Sort)&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 이해와 구현&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;259&quot; data-origin-height=&quot;117&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kR0aB/btsKYXjkCIH/sKMBiY15XofEltkdpjEjk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kR0aB/btsKYXjkCIH/sKMBiY15XofEltkdpjEjk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kR0aB/btsKYXjkCIH/sKMBiY15XofEltkdpjEjk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkR0aB%2FbtsKYXjkCIH%2FsKMBiY15XofEltkdpjEjk0%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;259&quot; height=&quot;117&quot; data-origin-width=&quot;259&quot; data-origin-height=&quot;117&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mMs5w/btsKX9xVoaX/NmK4vUUAXHK3605KKOm9L1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mMs5w/btsKX9xVoaX/NmK4vUUAXHK3605KKOm9L1/img.png&quot; data-origin-width=&quot;327&quot; data-origin-height=&quot;454&quot; data-is-animation=&quot;false&quot; style=&quot;width: 56.2439%; margin-right: 10px;&quot; data-widthpercent=&quot;56.91&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mMs5w/btsKX9xVoaX/NmK4vUUAXHK3605KKOm9L1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmMs5w%2FbtsKX9xVoaX%2FNmK4vUUAXHK3605KKOm9L1%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;327&quot; height=&quot;454&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dn7aH/btsKYiuJRrB/GcJDtrQXm811yUYM2lu6E0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dn7aH/btsKYiuJRrB/GcJDtrQXm811yUYM2lu6E0/img.png&quot; data-origin-width=&quot;252&quot; data-origin-height=&quot;462&quot; data-is-animation=&quot;false&quot; style=&quot;width: 42.5933%;&quot; data-widthpercent=&quot;43.09&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dn7aH/btsKYiuJRrB/GcJDtrQXm811yUYM2lu6E0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDn7aH%2FbtsKYiuJRrB%2FGcJDtrQXm811yUYM2lu6E0%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;252&quot; height=&quot;462&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;li&gt;&lt;b&gt; &lt;span&gt; &amp;zwj; &lt;/span&gt; &lt;span data-token-index=&quot;1&quot;&gt;코드&lt;/span&gt; &lt;/b&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;void InsertSort(int arr[], int n)
{
	int i,j;
	int insData;
	
	for(i=0; i&amp;lt;n; i++)
	{
		insData = arr[i];  // 정렬대상을 insData에 저장
		
		for(j=i-1; j&amp;gt;=0; j--)
		{
			if(arr[j] &amp;gt; insData)  
				arr[j+1] = arr[j];  // 비교대상 한 칸 뒤로 밀기
			else
				break;  // 삽입 위치 찾은 경우 탈출
		}
		
		arr[j+1] = insData;  // 찾은 위치에 정렬대상 삽입
	}
}
​&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 성능평가&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정렬 대상이 완전히 정렬된 상태이면 조건이 항상 거짓이 되어 break 문을 실행&lt;/li&gt;
&lt;li&gt;최악의 경우는 버블정렬, 선택 정렬과 다르지 않고 항상 if 절의 true인 경우를 실행하여 이중 for문 만큼 비교와 이동연산이 실행&lt;/li&gt;
&lt;li&gt;비교연산 횟수: &lt;b&gt;O(n^2)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;이동연산 횟수: &lt;b&gt;O(n^2)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;정확한 실행 횟수는 1부터 n-1까지의 등차수열의 합&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h1&gt;2. 복잡하지만 효율적인 정렬 알고리즘&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  힙 정렬(heap)&lt;/h2&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;힙의 루트 노드에 저장된 값이 정렬 순서상 가장 앞선다.&lt;/li&gt;
&lt;li&gt;&lt;span&gt; &amp;zwj; &lt;/span&gt; &lt;span data-token-index=&quot;1&quot;&gt;&lt;span data-token-index=&quot;1&quot;&gt;코드&lt;/span&gt;&lt;/span&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;int PriComp(int n1, int n2)
{
	return n2-n1; // 오름차순 정렬
	// return n1-n2 // 내림차순 정렬
}

void HeapSort(int arr[], int n, PriorityComp pc)
{
	Heap heap;
	int i;
	
	HeapInit(&amp;amp;heap, pc);
	
	// 정렬대상을 가지고 힙을 구성한다.
	for(i=0; i&amp;lt;n; i++)
		HInsert(&amp;amp;heap, arr[i]);
	
	// 순서대로 하나씩 꺼내서 정렬을 완성
	for(i=0; i&amp;lt;n; i++)
		arr[i] = HDelete(&amp;amp;heap);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&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;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 성능평가&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;O(logn)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;힙의 데이터 삭제 시간 복잡도: &lt;b&gt;O(logn)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;정렬 대상의 수가 n 인 경우의 시간 복잡도: &lt;b&gt;O(nlogn)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;➕병합 정렬(Merge Sort)&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 이해와 구현&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;병합 정렬은 &amp;ldquo;분할 정복&amp;rdquo; 알고리즘 디자인 기법에 근거하여 만들어진 정렬 방법&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;✂️ 분할 정복(divide and conpuer)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복잡한 문제를 복잡하지 않도록 분할하여 정복하는 방법
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;분할(divide): 해결이 용이한 단계까지 문제를 분할&lt;/li&gt;
&lt;li&gt;정복(conquer): 해결이 용이한 수준까지 분할된 문제 해결&lt;/li&gt;
&lt;li&gt;결합(combine): 분할해서 해결한 결과 결합하여 마무리&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PtOP0/btsKYNum7SP/Nb2N56G3jt5ml0a0Eatzvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PtOP0/btsKYNum7SP/Nb2N56G3jt5ml0a0Eatzvk/img.png&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;522&quot; data-is-animation=&quot;false&quot; style=&quot;width: 42.4074%; margin-right: 10px;&quot; data-widthpercent=&quot;42.91&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PtOP0/btsKYNum7SP/Nb2N56G3jt5ml0a0Eatzvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPtOP0%2FbtsKYNum7SP%2FNb2N56G3jt5ml0a0Eatzvk%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;498&quot; height=&quot;522&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JRx9G/btsKYon459W/5Zn42J0X8u0jIZSh8Mnzxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JRx9G/btsKYon459W/5Zn42J0X8u0jIZSh8Mnzxk/img.png&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;616&quot; data-is-animation=&quot;false&quot; style=&quot;width: 56.4298%;&quot; data-widthpercent=&quot;57.09&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JRx9G/btsKYon459W/5Zn42J0X8u0jIZSh8Mnzxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJRx9G%2FbtsKYon459W%2F5Zn42J0X8u0jIZSh8Mnzxk%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;782&quot; height=&quot;616&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;병합 정렬은 데이터가 1개만 남을 때까지 분할을 해나가고 데이터가 1개만 남는 경우, 정렬도 할 필요가 없어짐.&lt;/li&gt;
&lt;li&gt;전체 데이터를 둘로 나누는 과정을 데이터가 하나씩 구분이 될 때까지 진행&lt;/li&gt;
&lt;li&gt;분할을 완료한 후에는 정렬순서를 고려하여 둘을 하나로 묶는다.&lt;/li&gt;
&lt;li&gt;재귀적인 구현을 위해 하나씩 구분이 될 때까지 둘로 나누는 과정을 반복&lt;/li&gt;
&lt;li&gt;MergeSort &lt;b&gt;함수 코드&lt;/b&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;void MergeSort(int arr[], int left, int right)
{
	int mid;
	
	if(left &amp;lt; right)
	{
		mid = (left + right) / 2;
		
		MergeSort(arr, left, mid);
		MergeSort(arr, mid+1, right);

		// 정렬된 두 배열을 병합
		MergeTwoArea(arr, left, mid, right)
	}
}

​&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;left 와 right 는 정렬대상의 범위정보를 인덱스 값의 형태로 전달하는 역할&lt;/li&gt;
&lt;li&gt;MergeTwoArea &lt;b&gt;&lt;b&gt;함수 코드&lt;/b&gt;&lt;/b&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;void MergeTwoArea(int arr[], int left, int mid, int right)
{
	int fIdx = left;  // 왼쪽 영역의 첫번째 위치 정보
	int rIdx = right; // 오른쪽 영역의 첫번째 위치 정보
	int i;
	
	int * sortArr = (int*)malloc(sizeof(int)*(right+1));  // 병합 결과를 담을 메모리 공간 할당
	int sIdx = left;
	
	// 병합할 두 영역의 데이터들을 비교하여 
	// 정렬순서대로 sortArr에 하나씩 옮겨 담는다.
	// 두 영역 중 하나의 영역이라도 모두 다 담길 때까지
	while(fIdx &amp;lt;= mid &amp;amp;&amp;amp; rIdx &amp;lt;= right) {
		if(arr[fIdx] &amp;lt;= arr[rIdx])  
			sortArr[sIdx] = arr[fIdx++];
		else
			sortArr[sIdx] = arr[rIdx++];
			
		sIdx++;
	}
	
	// 앞 부분이 모두 sortArr로 갔다면 남은 뒷부분은 자동으로 sortArr 뒤로 다 처리
	if(fIdx &amp;gt; mid) {
		for(i=rIdx; i &amp;lt;= right; i++, sIdx++)
			sortArr[sIdx] = arr[i];
	}
	// 뒷 부분이 모두 sortArr로 갔다면 남은 앞부분은 자동으로 sortArr 뒤로 다 처리
	else {
		for(i=fIdx; i &amp;lt;= mid; i++, sIdx++)
			sortArr[sIdx] = arr[i];
	}
	
	// 병합결과를 옮겨 담기
	for(i=left; i &amp;lt;= right; i++)
		arr[i] = sortArr[i];
		
	free(sortArr);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L1eDs/btsKXxTz348/5LSe1blcYFiqEFVoaOLOS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L1eDs/btsKXxTz348/5LSe1blcYFiqEFVoaOLOS1/img.png&quot; data-origin-width=&quot;454&quot; data-origin-height=&quot;194&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;62.99&quot; style=&quot;width: 62.2575%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L1eDs/btsKXxTz348/5LSe1blcYFiqEFVoaOLOS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL1eDs%2FbtsKXxTz348%2F5LSe1blcYFiqEFVoaOLOS1%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;454&quot; height=&quot;194&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UMsGD/btsKZsDhH7x/CCRZk3gpCVCvlcQKWaz7PK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UMsGD/btsKZsDhH7x/CCRZk3gpCVCvlcQKWaz7PK/img.png&quot; data-origin-width=&quot;506&quot; data-origin-height=&quot;368&quot; data-is-animation=&quot;false&quot; style=&quot;width: 36.5797%;&quot; data-widthpercent=&quot;37.01&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UMsGD/btsKZsDhH7x/CCRZk3gpCVCvlcQKWaz7PK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUMsGD%2FbtsKZsDhH7x%2FCCRZk3gpCVCvlcQKWaz7PK%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;506&quot; height=&quot;368&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;2. 성능평가&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;671&quot; data-origin-height=&quot;329&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lYdDZ/btsKYCmctD5/SJV2CoySNHrrH9jJElKln0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lYdDZ/btsKYCmctD5/SJV2CoySNHrrH9jJElKln0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lYdDZ/btsKYCmctD5/SJV2CoySNHrrH9jJElKln0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlYdDZ%2FbtsKYCmctD5%2FSJV2CoySNHrrH9jJElKln0%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;671&quot; height=&quot;329&quot; data-origin-width=&quot;671&quot; data-origin-height=&quot;329&quot;/&gt;&lt;/span&gt;&lt;/figure&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;정렬의 대상인 데이터 수가 n일 때, 각 병합단계마다 최대 n번의 비교연산이 진행&lt;/li&gt;
&lt;li&gt;최대 비교연산 횟수: &lt;b&gt;n(단계별 비교연산)&lt;/b&gt; x &lt;b&gt;logn(병합 단계수)&lt;/b&gt; = &lt;b&gt;nlogn = O(nlogn)&lt;/b&gt;&lt;/li&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;/li&gt;
&lt;li&gt;임시 배열에 저장된 데이터 전부를 원위치하는 과정에서 한 번 발생&lt;/li&gt;
&lt;li&gt;그러므로 비교연산 횟수의 2배인 &lt;b&gt;2n*logn = O(nlogn)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt; 퀵 정렬(Quick Sort)&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 이해와 구현&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;퀵 정렬도 &amp;lsquo;분할 정복&amp;rsquo;에 근거하여 만들어진 정렬 방법&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;522&quot; data-origin-height=&quot;255&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XRtf5/btsKW6aZ8vD/YkTZtE3QzfM03EyneHHTXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XRtf5/btsKW6aZ8vD/YkTZtE3QzfM03EyneHHTXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XRtf5/btsKW6aZ8vD/YkTZtE3QzfM03EyneHHTXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXRtf5%2FbtsKW6aZ8vD%2FYkTZtE3QzfM03EyneHHTXk%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;522&quot; height=&quot;255&quot; data-origin-width=&quot;522&quot; data-origin-height=&quot;255&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;left : 정렬대상의 가장 왼쪽 지점&lt;/li&gt;
&lt;li&gt;right: 정렬대상의 가장 오른쪽 지점&lt;/li&gt;
&lt;li&gt;pivot: 중심점, 중심축의 의미
&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;high: 피벗을 제외한 가장 오른쪽에 위치한 지점&lt;/li&gt;
&lt;li&gt;low: 피벗을 제외한 가장 왼쪽에 위치한 지점&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n0jcH/btsKXYDq0Gy/iQJD7CSBMolWgDilsKGRKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n0jcH/btsKXYDq0Gy/iQJD7CSBMolWgDilsKGRKk/img.png&quot; data-origin-width=&quot;392&quot; data-origin-height=&quot;139&quot; data-is-animation=&quot;false&quot; style=&quot;width: 58.1242%; margin-right: 10px;&quot; data-widthpercent=&quot;58.81&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n0jcH/btsKXYDq0Gy/iQJD7CSBMolWgDilsKGRKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn0jcH%2FbtsKXYDq0Gy%2FiQJD7CSBMolWgDilsKGRKk%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;392&quot; height=&quot;139&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/W8xSe/btsKX6nE8Bc/OSXillkhWuAmHfCG7DZGG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/W8xSe/btsKX6nE8Bc/OSXillkhWuAmHfCG7DZGG1/img.png&quot; data-origin-width=&quot;401&quot; data-origin-height=&quot;203&quot; data-is-animation=&quot;false&quot; style=&quot;width: 40.7131%;&quot; data-widthpercent=&quot;41.19&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/W8xSe/btsKX6nE8Bc/OSXillkhWuAmHfCG7DZGG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FW8xSe%2FbtsKX6nE8Bc%2FOSXillkhWuAmHfCG7DZGG1%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;401&quot; height=&quot;203&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;피벗보다 큰 값을 만날 때까지 low는 오른쪽으로 이동&lt;/li&gt;
&lt;li&gt;피벗보다 작은 값을 만날 때까지 high는 왼쪽으로 이동&lt;/li&gt;
&lt;li&gt;이동을 완료한 후에는 high와 low가 가리키는 데이터를 서로 교환함&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1eYO6/btsKXzcP0KI/KZZqyXEiSwPqFkfxQEOWiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1eYO6/btsKXzcP0KI/KZZqyXEiSwPqFkfxQEOWiK/img.png&quot; data-origin-width=&quot;395&quot; data-origin-height=&quot;181&quot; data-is-animation=&quot;false&quot; style=&quot;width: 45.6285%; margin-right: 10px;&quot; data-widthpercent=&quot;46.17&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1eYO6/btsKXzcP0KI/KZZqyXEiSwPqFkfxQEOWiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1eYO6%2FbtsKXzcP0KI%2FKZZqyXEiSwPqFkfxQEOWiK%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;395&quot; height=&quot;181&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tpct0/btsKX8eIBvw/k339ZJgfacw2grCU5943nK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tpct0/btsKX8eIBvw/k339ZJgfacw2grCU5943nK/img.png&quot; data-origin-width=&quot;397&quot; data-origin-height=&quot;156&quot; data-is-animation=&quot;false&quot; style=&quot;width: 53.2088%;&quot; data-widthpercent=&quot;53.83&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tpct0/btsKX8eIBvw/k339ZJgfacw2grCU5943nK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ftpct0%2FbtsKX8eIBvw%2Fk339ZJgfacw2grCU5943nK%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;397&quot; height=&quot;156&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;교환을 계속하다 보면 high와 low가 역전되는 상황이 발생함&lt;/li&gt;
&lt;li&gt;이때에는 high와 pivot을 교환함.&lt;/li&gt;
&lt;li&gt;마무리 했을 때, 피벗보다 작은 값들/피벗/피벗보다 큰 값들로 분류가 된 것을 알 수 있음&lt;/li&gt;
&lt;li&gt; &amp;zwj;  &lt;b&gt;코드&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732688018360&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Swap(int arr[], int idx1, int idx2)
{
	int temp = arr[idx1];
	arr[idx1] = arr[idx2];
	arr[idx2] = temp;
}

int Partition(int arr[], int left, int right)
{
	int pivot = arr[left]; // 피벗의 위치는 가장 왼쪽!
	int low = left+1;
	int high = right;
	
	while(low &amp;lt;= high) // 교차되지 않을 때까지 반복
	{
		// 피벗보다 큰 값을 찾는 과정
		while(pivot &amp;gt; arr[low])
			low++; // low를 오른쪽으로 이동
			
		// 피벗보다 작은 값을 찾는 과정
		while(pivot &amp;lt; arr[high])
			high--; // high를 왼쪽으로 이동
			
		// 교차되지 않은 상태라면 Swap 실행
		if(low &amp;lt;= high)
			Swap(arr, low, high);
	}
	
	Swap(arr, left, high); // 피벗과 high가 가리키는 대상 교환
	return high; // 옮겨진 피벗의 위치정보 반환
}

void QuickSort(int arr[], int left, int right)
{
	if(left &amp;lt;= right)
	{
		int pivot = Partition(arr, left, right);  // 둘로 나누고
		QuickSort(arr, left, pivot-1);  // 왼쪽 영역 정렬 
		QuickSort(arr, pivot+1, right);  // 오른쪽 영역 정렬
	}
}&lt;/code&gt;&lt;/pre&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;/li&gt;
&lt;li&gt;그래서 피벗과 low, high를 비교하는 로직의 수정이 필요함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732688095661&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;		// 피벗보다 크거나 같은 값을 찾고 맨 오른쪽 범위를 넘지 못하게
		while(pivot &amp;gt;= arr[low] &amp;amp;&amp;amp; low &amp;lt;= right)
			low++;
			
		// 피벗보다 작거나 같은 값을 찾고 pivot보다 왼쪽으로 가지 못하게
		while(pivot &amp;lt;= arr[high] &amp;amp;&amp;amp; hight &amp;gt;= (left+1))
			high--;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pivot이 중간값에 해당하는 경우 가장 좋은 성능을 보임&lt;/li&gt;
&lt;li&gt;반면, 정렬이 이미 된 경우, pivot이 제일 작은 값이므로 영역이 나뉘지 않고 새로운 pivot을 지정하여 다시 불필요하게 정렬하게 됨&lt;/li&gt;
&lt;li&gt;그래서 정렬 대상에서 임의로 세 개의 데이터를 추출한 후, 중간 값을 pivot으로 선택하여 시작하기도 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 성능평가&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 피벗이 제자리를 찾아가는 과정은 배열 안의 데이터 수만큼인 n&lt;/li&gt;
&lt;li&gt;영역이 정확히 같은 비율로 나뉘는 경우 둘로 나뉘는 횟수는 logn&lt;/li&gt;
&lt;li&gt;최상의 퀵정렬의 비교연산 횟수: &lt;b&gt;nlogn = O(nlogn)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;pivot이 잘못 설정되어 영역이 최악으로 나뉘는 경우 영역이 둘로 나뉘는 횟수는 n&lt;/li&gt;
&lt;li&gt;최악의 퀵정렬 비교연산 횟수: &lt;b&gt;n^2 = O(n^2)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;하지만 퀵정렬은 실제로 평균적으로 최선에 가까운 O(nlogn)의 성능을 보여줌&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;별도의 메모리 공간도 소모하지 않기 때문에 동일한 빅-오 알고리즘 중 평균적으로 가장 빠른 정렬속도를 보임&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  기수 정렬(Radix Sort)&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 이해 1&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;정렬 알고리즘의 한계로 알려진 O(nlogn)을 뛰어 넘을 수 있음&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;773&quot; data-origin-height=&quot;445&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZbue1/btsKXp2ucEP/nbtkTArt4Qcf23kqWfswRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZbue1/btsKXp2ucEP/nbtkTArt4Qcf23kqWfswRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZbue1/btsKXp2ucEP/nbtkTArt4Qcf23kqWfswRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZbue1%2FbtsKXp2ucEP%2FnbtkTArt4Qcf23kqWfswRk%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;773&quot; height=&quot;445&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;445&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기수(radix)는 주어진 데이터를 구성하는 기본 요소를 뜻함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기수 정렬은 데이터를 구성하는 기본 요소, 즉 기수를 이용해서 정렬을 진행하는 방식&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 이해 2&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UiH3r/btsKXYjaQeF/O5LpZQrn28KRMb9OSays4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UiH3r/btsKXYjaQeF/O5LpZQrn28KRMb9OSays4k/img.png&quot; data-origin-width=&quot;668&quot; data-origin-height=&quot;273&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.1574%; margin-right: 10px;&quot; data-widthpercent=&quot;32.92&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UiH3r/btsKXYjaQeF/O5LpZQrn28KRMb9OSays4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUiH3r%2FbtsKXYjaQeF%2FO5LpZQrn28KRMb9OSays4k%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;668&quot; height=&quot;273&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baA59o/btsKZJYVJQV/A2G8V9jnalr7akHOn1mNE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baA59o/btsKZJYVJQV/A2G8V9jnalr7akHOn1mNE1/img.png&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;263&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.9304%; margin-right: 10px;&quot; data-widthpercent=&quot;33.71&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baA59o/btsKZJYVJQV/A2G8V9jnalr7akHOn1mNE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaA59o%2FbtsKZJYVJQV%2FA2G8V9jnalr7akHOn1mNE1%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;659&quot; height=&quot;263&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIojst/btsKY4pbNLD/1Zk0k435vLW2HIXgW9zSLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIojst/btsKY4pbNLD/1Zk0k435vLW2HIXgW9zSLk/img.png&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;269&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5867%;&quot; data-widthpercent=&quot;33.37&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIojst/btsKY4pbNLD/1Zk0k435vLW2HIXgW9zSLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIojst%2FbtsKY4pbNLD%2F1Zk0k435vLW2HIXgW9zSLk%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;667&quot; height=&quot;269&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;b&gt;❓LSD 기수 정렬&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LSD(Least Significant Digit): 덜 중요한 자릿수&lt;/li&gt;
&lt;li&gt;첫번째 자릿수 기준으로 버킷에 넣음&lt;/li&gt;
&lt;li&gt;하나의 버킷에 둘 이상의 데이터가 존재하는 경우 들어간 순서대로 꺼냄&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;/li&gt;
&lt;li&gt;&lt;b&gt;❓MSD 기수 정렬&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MSD(Most Significant Digit): 가장 중요한 자릿수&lt;/li&gt;
&lt;li&gt;가장 큰 자릿수 기준으로 버킷에 넣음&lt;/li&gt;
&lt;li&gt;하지만 마지막까지 비교를 할 필요가 없고 중간에 정렬이 완료될 수 있음&lt;/li&gt;
&lt;li&gt;대신에 MSD 방식에서는 중간에 데이터를 점검해야 하므로 성능이 반감될 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. LSD 기준 구현&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LSD와 MSD의 빅-오는 동일함&lt;/li&gt;
&lt;li&gt;MSD의 경우 정렬의 과정이 단축될 수 있지만 모든 데이터에 일괄적인 과정을 거쳐야 하기 때문에 추가 연산과 별도의 메모리가 필요함&lt;/li&gt;
&lt;li&gt; &amp;zwj; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;b&gt;코드&lt;/b&gt;&lt;/b&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;void RadixSort(int arr[], int num, int maxLen)
{
	// 매개변수 maxLen은 정렬대상 중 가장 긴 데이터 길이 정보
	Queue buckets[BUCKET_NUM];
	int bi;
	int pos;
	int di;
	int divfac = 1;
	int radix;
	
	// 총 10개의 버킷 초기화
	for(bi=0; bi&amp;lt;BUCKET_NUM; bi++)
		QueueInit(&amp;amp;buckets[bi]);
	
	// 가장 긴 데이터의 길이만큼 반복
	for(pos=0; pos&amp;lt;maxLen; pos++)
	{
		// 정렬대상의 수만큼 반복
		for(di=0; di&amp;lt;num; di++)
		{
			// N번째 자리의 숫자 추출
			radix = (arr[di]/ divfac) % 10;
			
			// 추출한 숫자 근거로 버킷에 저장
			Enqueue(&amp;amp;buckets[radix], arr[di]);
		}
		
		// 버킷 수만큼 반복
		for(bi=0, di=0; bi&amp;lt;BUCKET_NUM; bi++)
		{
			// 버킷에 저장된 것 순서대로 다 꺼내서 다시 arr에 저장
			while(!QIsEmpty(&amp;amp;buckets[bi]))
				arr[di++] = Dequeue(&amp;amp;buckets[bi]);
		}
		
		// N번째 자리의 숫자 추출을 위한 피제수의 증가
		divfac *= 10;	
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4. 성능평가&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;버킷을 대상으로 하는 데이터의 삽입과 추출을 한 쌍의 연산으로 볼 때 한 쌍의 연산 수행 횟수는 maxLen x num&lt;/li&gt;
&lt;li&gt;정렬대상의 수가 n이고, 정렬대상의 길이가 l일 때 시간 복잡도는 &lt;b&gt;O(ln)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 id=&quot;head52&quot; data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;윤성우의 열혈 자료구조 (윤성우 저, 2023.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/자료구조</category>
      <category>computer science</category>
      <category>알고리즘</category>
      <category>오블완</category>
      <category>자료구조</category>
      <category>정렬</category>
      <category>티스토리챌린지</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/55</guid>
      <comments>https://onyodev.tistory.com/55#entry55comment</comments>
      <pubDate>Wed, 27 Nov 2024 15:19:16 +0900</pubDate>
    </item>
    <item>
      <title>데이터베이스 언어 SQL</title>
      <link>https://onyodev.tistory.com/54</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 김연희 저 - &quot;데이터베이스 개론 3판&quot;을 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. SQL의 소개&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SQL(Structured Query Language)은 관계 데이터베이스를 위한 표준 질의어로 많이 사용하는 언어&lt;/li&gt;
&lt;li&gt;SQL은 사용자가 처리를 원하는 데이터가 무엇인지만 제시하고 데이터를 처리하는 방법은 필요가 없어 비절차적 데이터 언어의 특징이 있음&lt;/li&gt;
&lt;li&gt;1974년에 개발된 SEQUEL(Structured English QUEry Language)에서 유래됨&lt;/li&gt;
&lt;li&gt;SEQUEL은 IBM 연구소에서 개발한 연구용 관계 데이터베이스 관리 시스템 SYSTEM R 언어였는데 회사에 따라 여러 형태로 존재하여 불편한 점이 더 많았음&lt;/li&gt;
&lt;li&gt;그래서 1986년 ANSI와 ISO에서 SQL을 관계 데이터베이스 표준 질의어로 채택하고 표준화 작업 진행&lt;/li&gt;
&lt;li&gt;SQL의 분류
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;데이터 정의어(DDL): 테이블을 생성하고 변경&amp;bull;삭제하는 기능을 제공&lt;/li&gt;
&lt;li&gt;데이터 조작어(DML): 테이블에 새 데이터를 삽입하거나 테이블에 저장된 데이터를 수정&amp;bull;삭제&amp;bull;검색하는 기능 제공&lt;/li&gt;
&lt;li&gt;데이터 제어어(DCL): 보안을 위해 데이터에 대한 접근 및 사용 권한을 사용자별로 부여하거나 취소하는 기능을 하는 언어, 주로 데이터베이스 관리자가 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. SQL을 이용한 데이터 정의&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SQL의 데이터 정의 기능
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;테이블 생성: CREATE TABLE&lt;/li&gt;
&lt;li&gt;테이블 변경: ALTER TABLE&lt;/li&gt;
&lt;li&gt;테이블 삭제: DROP TABLE&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.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;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;li&gt;데이터 타입 및 제약사항에 대한 정의&lt;/li&gt;
&lt;li&gt;기본키&amp;bull;대체키&amp;bull;외래키의 정의&lt;/li&gt;
&lt;li&gt;데이터 무결성을 위한 제약조건 정의 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;SQL 명령어: CREATE TABLE&lt;/li&gt;
&lt;li&gt;CREATE TABLE 문의 기본 형식&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;CREATE TABLE 테이블_이름 (
	1. 속성_이름 데이터_타입 [NOT NULL] [DEFAULT 기본_값]
	2. [PRIMARY KEY (속성_리스트)]
	3. [UNIQUE (속성_리스트)]
	4. [FOREIGN KEY (속성_리스트) REFERENCES 테이블_이름(속성_리스트)]
			[ON DELETE 옵션] [ON UPDATE 옵션]
	5. [CONSTRAINT 이름] [CHECK(조건)]
);
&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;테이블을 구성하는 각 속성의 이름과 데이터 타입, 기본적인 제약 사항 정의&lt;/li&gt;
&lt;li&gt;기본키로 테이블에 하나만 존재&lt;/li&gt;
&lt;li&gt;대체키로 테이블에 여러 개 존재할 수 있음&lt;/li&gt;
&lt;li&gt;외래키로 테이블에 여러개 존재할 수 있음&lt;/li&gt;
&lt;li&gt;데이터 무결성을 위한 제약조건으로 테이블에 여러 개 존재할 수 있음&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1.1. 속성의 정의&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;널 값 허용 여부&lt;/b&gt;와 &lt;b&gt;기본값 필요 여부&lt;/b&gt;를 결정해야 함&lt;/li&gt;
&lt;li&gt;기본적으로는 null 값이 허용되고 허용하지 않으려면 NOT NULL 키워드를 포함해야 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특히, 기본키를 구성하는 모든 속성은 널 값을 가질 수 없도록 반드시 NOT NULL 키워드를 표기&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;속성의 데이터 타입&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 240px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 39.186%;&quot;&gt;&lt;b&gt;데이터 타입&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 60.6977%;&quot;&gt;&lt;b&gt;의미&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 39.186%;&quot;&gt;INT 또는 INTEGER&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 60.6977%;&quot;&gt;정수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 39.186%;&quot;&gt;SMALLINT&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 60.6977%;&quot;&gt;INT보다 작은 정수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 39.186%;&quot;&gt;CHAR(n) 또는 CHARACTER(n)&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 60.6977%;&quot;&gt;길이가 n인 고정 길이의 문자열&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 39.186%;&quot;&gt;VARCHAR(n) 또는 CHARACTER VARYING(n)&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 60.6977%;&quot;&gt;최대 길이가 n인 가변 길이의 문자열&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 39.186%;&quot;&gt;NUMERIC(p, s) 또는 DECIMAL(p, s)&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 60.6977%;&quot;&gt;고정 소수점 실수&lt;br /&gt;p는 소수점을 제외한 전체 숫자 길이, s는 소수점 이하 숫자 길이 &lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 39.186%;&quot;&gt;FLOAT(n)&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 60.6977%;&quot;&gt;길이가 n인 부동 소수점 실수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 39.186%;&quot;&gt;REAL&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 60.6977%;&quot;&gt;부동 소수점 실수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 39.186%;&quot;&gt;DATE&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 60.6977%;&quot;&gt;연, 월, 일로 표현되는 날짜&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 39.186%;&quot;&gt;TIME&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 60.6977%;&quot;&gt;시, 분, 초로 표현되는 시간&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px; width: 39.186%;&quot;&gt;DATETIME&lt;/td&gt;
&lt;td style=&quot;height: 20px; width: 60.6977%;&quot;&gt;날짜와 시간&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ex)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732501827785&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;고객아이디 VARCHAR(20) NOT NULL
적립금 INT DEFAULT 0
담당자 VARCHAR(10) DEFAULT '방경아'&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1.2. 키의 정의&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CREATE TABLE 문으로 테이블을 정의할 때는 기본키, 대체키, 외래키로 지정할 수 있음&lt;/li&gt;
&lt;li&gt;기본키는 PRIMARY KEY 키워드를 사용해 지정&lt;/li&gt;
&lt;li&gt;기본키는 하나만 지정할 수 있고 여러 개의 속성으로 구성할 수도 있음&lt;/li&gt;
&lt;li&gt;외래키는 FOREIGN KEY 키워드를 사용해 지정&lt;/li&gt;
&lt;li&gt;외래키를 지정할 때는 참조 무결성 제약조건을 유지하기 위해 어떤 테이블의 무슨 속성을 참조하는지 REFERENCES 키워드 다음에 명확히 제시해야 함&lt;/li&gt;
&lt;li&gt;튜플을 삭제할 때 처리하는 방법 (ON DELETE)
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;ON DELETE NO ACTION : 튜플을 삭제하지 못하게 함&lt;/li&gt;
&lt;li&gt;ON DELETE CASCADE : 관련 튜플을 함께 삭제함&lt;/li&gt;
&lt;li&gt;ON DELETE SET NULL : 관련 튜플의 외래키 값을 NULL로 변경함.&lt;/li&gt;
&lt;li&gt;ON DELETE SET DEFAULT : 관련 튜플의 외래키 값을 미리 지정한 기본 값으로 변경함.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;튜플을 변경할 때 처리하는 방법 (ON UPDATE)
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;ON UPDATE NO ACTION : 튜플을 변경하지 못하게 함&lt;/li&gt;
&lt;li&gt;ON UPDATE CASCADE : 관련 튜플에서 외래키 값을 함께 변경함&lt;/li&gt;
&lt;li&gt;ON UPDATE SET NULL : 관련 튜플의 외래키 값을 NULL로 변경함.&lt;/li&gt;
&lt;li&gt;ON UPDATE SET DEFAULT : 관련 튜플의 외래키 값을 미리 지정한 기본 값으로 변경함.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1.3. 테이블 무결성 제약조건의 정의&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CREATE TABLE 문으로 테이블을 정의할 때는 CHECK 키워드를 사용해 특정 속성에 대한 제약조건을 지정할 수 있음&lt;/li&gt;
&lt;li&gt;테이블에는 CHECK 키워드로 지정한 제약조건을 만족하는 튜플만 존재하게 됨.&lt;/li&gt;
&lt;li&gt;테이블에서 항상 정확하고 유효한 데이터를 유지하기 위해 데이터 무결성을 위한 제약조건을 표현하는 방법&lt;/li&gt;
&lt;/ul&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;&lt;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;CHECK(재고량&amp;gt;=0 AND 재고량&amp;lt;=10000) &lt;/span&gt;: 모든 제품의 재고량은 항상 0개 이상, 10000개 이하로 유지&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;CONSTRAINT CHK_CPY CHECK(제조업체='한빛제과') &lt;/span&gt;: 모든 제품의 제조업체로 한빛제과만 허용된다는 데이터 무결성 제약조건에 CHK_CPY라는 고유의 이름을 부여&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.3. 테이블의 변경&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블은 ALTER TABLE 문으로 변경할 수 있음&lt;/li&gt;
&lt;li&gt;ALTER TABLE을 통해 새로운 속성 추가, 기존 속성 삭제, 새로운 제약조건 추가, 기존 제약조건 삭제 등이 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;b&gt;새로운 속성의 추가&lt;/b&gt;&lt;/b&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;ALTER TABLE 테이블_이름
	ADD 속성_이름 데이터_타입 [NOT NULL] [DEFAULT 기본_값];
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;b&gt;기존 속성의 삭제&lt;/b&gt;&lt;/b&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;ALTER TABLE 테이블_이름 DROP COLUMN 속성_이름;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;b&gt;새로운 제약조건의 추가&lt;/b&gt;&lt;/b&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;ALTER TABLE 테이블_이름 ADD CONSTRAINT 제약조건_이름 제약조건_내용;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;b&gt;기존 제약조건의 삭제&lt;/b&gt;&lt;/b&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;ALTER TABLE 테이블_이름 DROP CONSTRAINT 제약조건_이름;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.4. 테이블의 삭제&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DROP TABLE 명령어로 삭제할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;DROP TABLE 테이블_이름
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. SQL을 이용한 데이터 조작&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SQL의 데이터 조작 기능
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;데이터 검색: SELECT&lt;/li&gt;
&lt;li&gt;데이터 삽입: INSERT&lt;/li&gt;
&lt;li&gt;데이터 수정: UPDATE&lt;/li&gt;
&lt;li&gt;데이터 삭제: DELETE&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1. 데이터 검색&lt;/h3&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT [ ALL | DISTINCT ] 속성_리스트
FROM  테이블_리스트;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SELECT 키워드와 함께 검색하고 싶은 속성의 이름을 콤마(,)로 구분하여 차례로 나열&lt;/li&gt;
&lt;li&gt;*를 사용하면 결과 테이블의 모든 속성을 검색하며 원본 테이블의 속성 순서와 같게 나열됨&lt;/li&gt;
&lt;li&gt;동일한 튜플을 허용하지 않을 경우 DISTINCT 키워드를 사용하여 한 번씩만 출력되도록 함.&lt;/li&gt;
&lt;li&gt;AS 키워드를 사용하여 출력되는 속성의 이름을 다른 이름으로 변경할 수 있음.&lt;/li&gt;
&lt;li&gt;그리고 AS 키워드는 생략이 가능함.&lt;/li&gt;
&lt;li&gt;만약에 지정한 이름에 공백이 포함된 경우, 오라클에선 큰따옴표로 묶고 MS SQL에선 작은 따옴표로 묶는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;산술식을 이용한 검색&lt;/b&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;SELECT 제품명, 단가 + 500 AS &quot;조정 단가&quot; FROM 제품;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1.1. 조건 검색&lt;/h4&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT [ ALL | DISTINCT ] 속성_리스트
FROM  테이블_리스트;
[WHERE 조건 ];
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WHERE 키워드와 함께 비교 연산자와 논리 연산자를 이용한 검색 조건을 제시하면 됨.&lt;/li&gt;
&lt;li&gt;조건은 숫자 뿐만 아니라 문자, 날짜 값도 비교할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;LIKE를 이용한 검색&lt;/b&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;LIKE 키워드는 문자열을 이용하는 조건에서만 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 75px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;height: 25px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;기호&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 25px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;height: 25px;&quot;&gt;%&lt;/td&gt;
&lt;td style=&quot;height: 25px;&quot;&gt;0개 이상의 문자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;height: 25px;&quot;&gt;_&lt;/td&gt;
&lt;td style=&quot;height: 25px;&quot;&gt;1개의 문자&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;사용 예&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LIKE &amp;lsquo;데이터%&amp;rsquo;&lt;/td&gt;
&lt;td&gt;데이터로 시작하는 문자열&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LIKE &amp;lsquo;%데이터&amp;rsquo;&lt;/td&gt;
&lt;td&gt;데이터로 끝나는 문자열&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LIKE &amp;lsquo;%데이터%&amp;rsquo;&lt;/td&gt;
&lt;td&gt;데이터가 포함된 문자열&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LIKE &amp;lsquo;데이터___&amp;rsquo;&lt;/td&gt;
&lt;td&gt;데이터로 시작하는 6자 길이의 문자열&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LIKE &amp;lsquo;___한%&amp;rsquo;&lt;/td&gt;
&lt;td&gt;세번째 글자가 &amp;lsquo;한&amp;rsquo;인 문자열&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;NULL을 이용한 검색&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 속성의 값이 널 값인지를 비교하기 위해 IS NULL 키워드를 사용&lt;/li&gt;
&lt;li&gt;WHERE 나이 IS NULL , WHERE 나이 IS NOT NULL&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;정렬 검색&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;검색 결과 테이블은 일반적으로 DBMS가 정한 순서로 출력되지만 사용자가 원하는 순서대로 출력하려면 ORDER BY 키워드를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;SELECT [ ALL | DISTINCT ] 속성_리스트
FROM  테이블_리스트;
[WHERE 조건 ]
[ORDER BY 속성_리스트 [ASC | DESC]];
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지정하지 않는 경우 오름차순(ASC)로 기본정렬함.&lt;/li&gt;
&lt;li&gt;정렬기준이 여러 개인 경우 정렬이 기준이 되는 속성을 차례대로 제시함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;집계 함수를 이용한 검색&lt;/b&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;li&gt;SUM, AVG는 숫자 데이터에서만 적용할 수 있고 나머지는 모든 데이터에 사용 가능함.&lt;/li&gt;
&lt;li&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;집계 함수는 WHERE 절을 사용할 수 없고 SELECT 절이나 HAVING 절에서만 사용 가능&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;그룹별 검색&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블에서 특정 속성의 값이 같은 튜플을 모아 그룹을 만들고, 그룹별로 검색을 하기 위해 GROUP BY 키워드를 사용함.&lt;/li&gt;
&lt;li&gt;그룹에 대한 조건을 추가하려면 GROUP BY 절과 HAVING 절을 같이 사용함.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;SELECT [ ALL | DISTINCT ] 속성_리스트
FROM  테이블_리스트;
[WHERE 조건 ]
[GROUP BY 속성_리스트 [HAVING 조건]]
[ORDER BY 속성_리스트 [ASC | DESC]];
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;여러 테이블에 대한 조인 검색&lt;/b&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;조인 속성&lt;/b&gt;이라 함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;일반적으로 테이블의 외래키를 조인속성으로 사용함&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;SELECT 제품.제품명
FROM 제품, 주문
WHERE 주문.주문고객 = 'banana' AND 제품.제품번호 = 주문.주문제품;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;표준 SQL에서는 INNER JOIN과 ON을 이용해 작성하기도 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;SELECT 속성_리스트
FROM 테이블1
INNER|LEFT|RIGHT|FULL JOIN 테이블2
ON 조인조건
[WHERE 검색조건]
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;부속 질의문(서브쿼리)을 이용한 검색&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SELECT 문 안에 또 다른 SELECT 문을 포함할 수도 있음&lt;/li&gt;
&lt;li&gt;다른 SELECT 문 안에 들어 있는 SELECT 문을 &lt;b&gt;부속 질의문&lt;/b&gt; 또는 &lt;b&gt;서브 쿼리&lt;/b&gt;라 함.&lt;/li&gt;
&lt;li&gt;그리고 다른 SELECT 문을 포함하는 SELECT 문을 &lt;b&gt;상위 질의문&lt;/b&gt; 또는 &lt;b&gt;메인 쿼리&lt;/b&gt;라 함.&lt;/li&gt;
&lt;li&gt;서브쿼리는 괄호로 묶어 작성하고 &lt;b&gt;ORDER BY 절을 사용할 수 없으며 먼저 수행됨.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;SELECT 제품명, 단가
FROM 제품
WHERE 제조업체 = (
	SELECT 제조업체
	FROM 제품
	WHERE 제품명 = '달콤비스킷'
);
&lt;/code&gt;&lt;/pre&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;부속 질의문의 결과값을 여러 개 반환하는 경우, IN 연산자를 함께 사용함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;SELECT 제품명, 단가
FROM 제품
WHERE 제조업체 IN (
	SELECT 주문제품
	FROM 주문
	WHERE 주문고객 = 'banana'
);
&lt;/code&gt;&lt;/pre&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;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;연산자&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IN&lt;/td&gt;
&lt;td&gt;서브쿼리 결과 중 일치하는 것이 있으면 검색 조건이 참&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NOT IN&lt;/td&gt;
&lt;td&gt;서브쿼리 결과 중 일치하는 것이 없으면 검색 조건이 참&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EXISTS&lt;/td&gt;
&lt;td&gt;서브쿼리 결과 값이 하나라도 존재하면 검색 조건이 참&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NOT EXISTS&lt;/td&gt;
&lt;td&gt;서브쿼리 결과 값이 하나도 존재하지 않으면 검색 조건이 참&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ALL&lt;/td&gt;
&lt;td&gt;서브쿼리 결과 값 모두와 비교한 결과가 참이면 검색 조건을 만족&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ANY 또는 SOME&lt;/td&gt;
&lt;td&gt;서브쿼리 결과 값 하나라도 비교한 결과가 참이면 검색 조건을 만족&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2. 데이터의 삽입&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블에 새로운 튜플을 삽입하기 위해 필요한 SQL문은 INSERT다.&lt;/li&gt;
&lt;li&gt;INSERT 문을 이용해 삽입하는 방법은 두가지다.
&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;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;데이터 직접 삽입
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;INTO 절의 속성 이름과 VALUES 절의 속성 값은 순서대로 일대일 대응되고 개수도 같아야 함.&lt;/li&gt;
&lt;li&gt;INTO 절의 속성 이름의 리스트는 생략할 수 있고 생략한 경우 지정한 순서대로 VALUES 절의 속성 값이 삽입됨.&lt;/li&gt;
&lt;li&gt;VALUES 절에 나열되는 속성 값은 문자나 날짜 타입의 데이터인 경우 &lt;b&gt;작은 따옴표&lt;/b&gt;로 묶어야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;INSERT INTO 테이블_이름[(속성_리스트)] VALUES(속성값_리스트);&lt;/li&gt;
&lt;li&gt;서브쿼리를 이용한 데이터 삽입&lt;/li&gt;
&lt;li&gt;INSERT INTO 테이블_이름[(속성_리스트)] SELECT 문; INSERT INTO 한빛제품(제품명, 재고량, 단가) SELECT 제품명, 재고량, 단가 FROM 제품 WHERE 제조업체 = '한빛제과'&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.3. 데이터의 수정&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블에 저장된 데이터를 수정하기 위해 필요한 SQL 명령어는 UPDATE&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;UPDATE 테이블_이름
SET 속성_이름1 = 값1, 속성_이름2 = 값2, ...
[WHERE 조건];
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UPDATE 문은 테이블에 저장된 튜플에 서 특정 속성의 값을 수정함.&lt;/li&gt;
&lt;li&gt;WHERE 절을 생략하면 모든 튜플을 대상으로 속성 값을 수정함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.4. 데이터의 삭제&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테이블에 저장된 데이터를 수정하기 위해 필요한 SQL 명령어는 DELETE&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;DELETE
FROM 테이블_이름
[WHERE 조건];
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WHERE 절에 제시한 조건을 만족하는 튜플만 삭제&lt;/li&gt;
&lt;li&gt;WHERE 절을 생략하면 테이블에 존재하는 모든 튜플을 삭제하여 빈 테이블이 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 뷰&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.1. 뷰의 개념&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;뷰(view)는 다른 테이블을 기반으로 만들어진 가상 테이블&lt;/li&gt;
&lt;li&gt;논리적으로만 존재하면서도 일반 테입르과 동일한 방법으로 사용할 수 있음&lt;/li&gt;
&lt;li&gt;뷰를 만드는 데 기반이 되는 물리적 테이블을 기본 테이블이라 함.&lt;/li&gt;
&lt;li&gt;뷰의 생성과 삭제도 SQL의 데이터 정의 기능에 해당함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.2. 뷰의 생성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;뷰를 생성하기 위해 필요한 SQL 명령어는 CREATE VIEW&lt;/li&gt;
&lt;li&gt;CREATE VIEW 뷰_이름[(속성_리스트)] AS SELECT 문 [WITH CHECK OPTION];&lt;/li&gt;
&lt;li&gt;새로 생성할 뷰 이름을 제시한 후, 뷰를 구성하는 속성의 이름을 괄호 안에 나열함.&lt;/li&gt;
&lt;li&gt;AS 키워드와 함께 기본 테이블에 대한 SELECT 문을 제시함.&lt;/li&gt;
&lt;li&gt;SELECT 문은 생성하고자 하는 뷰의 정의를 담고 있고 ORDER BY를 사용할 수 없단 점만 제외하면 일반 SELECT 문과 동일함.&lt;/li&gt;
&lt;li&gt;WITH CHECK OPTION은 생성한 뷰에 삽입이나 수정 연산을 할 때 SELECT 문에서 WHERE 키워드와 함께 제시한 뷰의 정의 조건을 위반하면 수행되지 않도록 하는 제약조건을 의미&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;CREATE VIEW 우수고객(고객아이디, 고객이름, 나이, 등급)
AS SELECT 고객아이디, 고객이름, 나이, 등급
	FROM 고객
	WHERE 등급='vip'
WITH CHECK OPTION;

SEECT * FROM 우수고객;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.3. 뷰의 활용&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CREATE VIEW 문으로 생성된 뷰에서도 일반 테이블처럼 원하는 데이터를 검색할 수 있음&lt;/li&gt;
&lt;li&gt;뷰에 대한 SELECT 문은 내부적으로 기본 테이블에 대한 SELECT 문으로 변환되어 수행됨&lt;/li&gt;
&lt;li&gt;뷰에 대한 INSERT, DELETE, UPDATE도 가능하지만 제한적.&lt;/li&gt;
&lt;li&gt;기본 테이블의 기본키 속성을 포함한 수정과 삭제 연산은 실행이 되지만 그렇지 않은 경우 실행되지 않음&lt;/li&gt;
&lt;li&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;li&gt;DISTINCT 키워드를 포함하여 정의한 뷰&lt;/li&gt;
&lt;li&gt;GROUP BY 절을 포함하여 정의한 뷰&lt;/li&gt;
&lt;li&gt;여러 개의 테이블을 조인하여 정의한 뷰는 안되는 경우가 많음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;뷰의 대표적인 장점&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&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;뷰를 미리 만들면 사용자가 WHERE 절 없이 뷰를 검색해도 특정 조건을 만족하는 데이터를 검색할 수 있음&lt;/li&gt;
&lt;li&gt;복잡한 SQL 문 작성 없이 원하는 데이터를 검색할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;데이터 보안 유지에 도움이 됨&lt;/li&gt;
&lt;li&gt;데이터를 좀 더 편리하게 관리 할 수 있음&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.4. 뷰의 삭제&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;뷰를 삭제하기 위해 필요한 SQL 명령어는 DROP VIEW&lt;/li&gt;
&lt;li&gt;DROP VIEW 뷰_이름&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 삽입 SQL&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.1. 삽입 SQL의 개념과 특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C, C++, JAVA 등과 같은 프로그래밍 언어로 작성된 응용 프로그램 안에 삽입하여 사용하는 SQL 문&lt;/li&gt;
&lt;li&gt;초보 사용자도 삽입 SQL을 통해 데이터베이스 기능을 쉽게 이용할 수 있음&lt;/li&gt;
&lt;li&gt;삽입 SQL 사용할 때의 특징
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;삽입 SQL 문은 프로그램 안에서 일반 명령문이 위치할 수 있는 곳이면 어디든 삽입 가능&lt;/li&gt;
&lt;li&gt;일반 명령문과 구분하기 위해 삽입 SQL문 앞에 EXEC SQL을 붙임&lt;/li&gt;
&lt;li&gt;프로그램에 선언된 일반 변수를 삽입 SQL 문에서 사용할 수 있음, 앞에 콜론(:)을 붙여 테이블 이름이나 속성의 이름과 구분함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;수행 결과로 여러 개의 행을 반환하는 SELECT 문을 삽입 SQL 문으로 사용하는 경우 커서(cursor)라는 도구를 이용해 한 번에 한 행씩 차례로 처리함&lt;/li&gt;
&lt;li&gt;커서는 수행 결과로 반환된 여러 행을 한 번에 하나씩 가리키는 포인터 역할&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.2. 커서가 필요없는 삽입 SQL&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;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;pre class=&quot;gauss&quot;&gt;&lt;code&gt;int main(){
	
	// 1. 삽입 SQL에 사용할 변수 미리 선언
	EXEC SQL BEGIN DECLARE SECTION;
				char p_no[4], p_name[21];
				int price;
	EXEC SQL END DECLARE SECTION;
	
	...
	// 2. 제품번호 입력(p.no)(생략)
	
	// 3. 삽입 SQL을 통해 변수 저장
	EXEC SQL SELECT 제품명, 단가 INTO :p_name, :price
			FROM 제품
			WHERE 제품번호 = :p.no;
	
	...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BEGIN DECLARE SECTION 과 END DECLARE SECTION 사이에 삽입 SQL 문에 사용할 변수를 미리 선언&lt;/li&gt;
&lt;li&gt;삽입 SQL에서 사용할 변수를 선언할 때는 데이터 타입에 주의해야 함.&lt;/li&gt;
&lt;li&gt;제품번호 속성 길이 최대 3자 + &amp;lsquo;\0&amp;rsquo;을 마지막에 저장할 수 있도록 최대 4자로 제한&lt;/li&gt;
&lt;li&gt;사용자 입력을 받은 후, 제품 테이블에서 사용자가 입력한 제품번호에 해당하는 제품 이름과 단가를 검색하여 p_name, price 변수에 값을 저장하는 삽입 SQL 문이다.&lt;/li&gt;
&lt;li&gt;저장할 변수를 INTO 키워드 다음에 차례로 나열하는 것이 차이점&lt;/li&gt;
&lt;li&gt;이 SELECT 문은 하나의 행을 결과로 반환하여 커서가 필요 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.3. 커서가 필요한 삽입 SQL&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SELECT 문의 실행 결과로 여러 행이 검색되는 경우, 한번에 한 행씩 차례로 접근할 수 있게 해주는 커서가 필요함.&lt;/li&gt;
&lt;li&gt;우선 커서의 이름과 커서가 필요한 SELECT 문 선언&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;EXEC SQL DECLARE 커서_이름 CURSOR FOR SELECT 문;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커서를 선언한 후 SELECT 문을 실행하는 명령&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;EXEC SQL OPEN 커서_이름;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;OPEN 명령어를 이용해 실행하면 검색된 행들이 반환되고 커서는 검색된 행들 중 첫번째 행의 바로 앞에 위치함&lt;/li&gt;
&lt;li&gt;검색된 행들을 차례로 처리하기 위해 이동시키는 명령어는 FETCH&lt;/li&gt;
&lt;li&gt;커서를 이동하여 처리할 다음 행을 가리키게 하고, 커서가 가리키는 행으로부터 속성 값들을 가져와 변수에 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;EXEC SQL FETCH 커서_이름 INTO 변수_리스트;

EX)
EXEC SQL FETCH product_cursor INTO :p_name, :price;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반적으로 FETCH는 여러번 수행되기 때문에 반복문과 함께 사용&lt;/li&gt;
&lt;li&gt;커서를 사용하지 않으면 CLOSE 명령어를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;EXEC SQL CLOSE 커서_이름;
&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;h4 data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스 개론 3판 (김연희 저, 2024.1)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/데이터베이스</category>
      <category>computer science</category>
      <category>sql</category>
      <category>데이터베이스</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/54</guid>
      <comments>https://onyodev.tistory.com/54#entry54comment</comments>
      <pubDate>Mon, 25 Nov 2024 11:37:58 +0900</pubDate>
    </item>
    <item>
      <title>우선순위 큐(Priority Queue)와 힙(Heap)</title>
      <link>https://onyodev.tistory.com/53</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 윤성우 저 - &quot;윤성우의 열혈 자료구조&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 우선순위 큐의 이해&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1. 우선순위 큐와 우선순위의 이해&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;우선순위 큐도 enqueue와 dequeue가 일반 큐와 같음&lt;/li&gt;
&lt;li&gt;하지만 우선순위 큐의 결과는 들어간 순서에 상관없이 우선순위가 높은 데이터가 먼저 나옴&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2. 우선순위 큐의 구현 방법&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;/li&gt;
&lt;li&gt;힙(heap)을 이용하는 방법&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;557&quot; data-origin-height=&quot;249&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uRs2k/btsKS8GEXZG/8Hc1ltDHZJ6aVuNqrKmI41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uRs2k/btsKS8GEXZG/8Hc1ltDHZJ6aVuNqrKmI41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uRs2k/btsKS8GEXZG/8Hc1ltDHZJ6aVuNqrKmI41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuRs2k%2FbtsKS8GEXZG%2F8Hc1ltDHZJ6aVuNqrKmI41%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;557&quot; height=&quot;249&quot; data-origin-width=&quot;557&quot; data-origin-height=&quot;249&quot;/&gt;&lt;/span&gt;&lt;/figure&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;li&gt;삽입의 위치를 찾기 위해 배열에 저장된 모든 데이터와 우선순위 비교를 진행해야 할 수 있음&lt;/li&gt;
&lt;li&gt;연결 리스트의 경우, 삽입의 위치를 찾기 위해서 첫 번째 노드에서부터 시작하여 마지막 노드에 저장된 데이터와 비교해야 할 수도 있는 문제가 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3. 힙(heap)의 소개&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ukHyi/btsKT7tkz6W/PPXvSe98Zii0KFLtswa8K1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ukHyi/btsKT7tkz6W/PPXvSe98Zii0KFLtswa8K1/img.png&quot; data-origin-width=&quot;654&quot; data-origin-height=&quot;265&quot; data-is-animation=&quot;false&quot; style=&quot;width: 50.8169%; margin-right: 10px;&quot; data-widthpercent=&quot;51.41&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ukHyi/btsKT7tkz6W/PPXvSe98Zii0KFLtswa8K1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FukHyi%2FbtsKT7tkz6W%2FPPXvSe98Zii0KFLtswa8K1%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;654&quot; height=&quot;265&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WfhFr/btsKUERQYjx/Clkzq6YJoV9dN8wZjjCuv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WfhFr/btsKUERQYjx/Clkzq6YJoV9dN8wZjjCuv0/img.png&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;271&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.0203%;&quot; data-widthpercent=&quot;48.59&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WfhFr/btsKUERQYjx/Clkzq6YJoV9dN8wZjjCuv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWfhFr%2FbtsKUERQYjx%2FClkzq6YJoV9dN8wZjjCuv0%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;632&quot; height=&quot;271&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;li&gt;즉, 루트 노드가 가장 커야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 힙의 구현과 우선순위 큐의 완성&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. 힙에서의 데이터 저장과정&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;/li&gt;
&lt;li&gt;제대로 된 위치를 찾을 때까지 계속 진행&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bohcV8/btsKU5hf9fL/W7XKg9YYXpUFkuDtvXOWWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bohcV8/btsKU5hf9fL/W7XKg9YYXpUFkuDtvXOWWK/img.png&quot; data-origin-width=&quot;346&quot; data-origin-height=&quot;259&quot; data-is-animation=&quot;false&quot; style=&quot;width: 31.6597%; margin-right: 10px;&quot; data-widthpercent=&quot;32.41&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bohcV8/btsKU5hf9fL/W7XKg9YYXpUFkuDtvXOWWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbohcV8%2FbtsKU5hf9fL%2FW7XKg9YYXpUFkuDtvXOWWK%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;346&quot; height=&quot;259&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biJkpV/btsKU5VPfHp/noho2HCqVuy0lEQ69tjcC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biJkpV/btsKU5VPfHp/noho2HCqVuy0lEQ69tjcC0/img.png&quot; data-origin-width=&quot;353&quot; data-origin-height=&quot;250&quot; data-is-animation=&quot;false&quot; style=&quot;width: 33.4631%; margin-right: 10px;&quot; data-widthpercent=&quot;34.26&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biJkpV/btsKU5VPfHp/noho2HCqVuy0lEQ69tjcC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiJkpV%2FbtsKU5VPfHp%2Fnoho2HCqVuy0lEQ69tjcC0%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;353&quot; height=&quot;250&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brtnTy/btsKVb9IWtw/FMOkkzAgMrTUFUkh5DhJw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brtnTy/btsKVb9IWtw/FMOkkzAgMrTUFUkh5DhJw1/img.png&quot; data-origin-width=&quot;353&quot; data-origin-height=&quot;257&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5516%;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brtnTy/btsKVb9IWtw/FMOkkzAgMrTUFUkh5DhJw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrtnTy%2FbtsKVb9IWtw%2FFMOkkzAgMrTUFUkh5DhJw1%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;353&quot; height=&quot;257&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. 힙에서의 데이터 삭제과정&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;/li&gt;
&lt;li&gt;이때 루트 노드와 왼쪽 자식과 오른쪽 자식 중 우선순위가 더 높은 노드를 먼저 비교해야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oxCJk/btsKVwMrXxi/B99DL8h3NKrTjDoNk4Nja0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oxCJk/btsKVwMrXxi/B99DL8h3NKrTjDoNk4Nja0/img.png&quot; data-origin-width=&quot;356&quot; data-origin-height=&quot;250&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.6819%; margin-right: 10px;&quot; data-widthpercent=&quot;50.27&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oxCJk/btsKVwMrXxi/B99DL8h3NKrTjDoNk4Nja0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoxCJk%2FbtsKVwMrXxi%2FB99DL8h3NKrTjDoNk4Nja0%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;356&quot; height=&quot;250&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wlXJD/btsKU4Jojm5/ifqqvFHY743lYZHi6iHiM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wlXJD/btsKU4Jojm5/ifqqvFHY743lYZHi6iHiM0/img.png&quot; data-origin-width=&quot;348&quot; data-origin-height=&quot;247&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.1553%;&quot; data-widthpercent=&quot;49.73&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wlXJD/btsKU4Jojm5/ifqqvFHY743lYZHi6iHiM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwlXJD%2FbtsKU4Jojm5%2FifqqvFHY743lYZHi6iHiM0%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;348&quot; height=&quot;247&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cumGZ5/btsKT4cjkyZ/Wm8B9mcqibRMWcYBK8cvqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cumGZ5/btsKT4cjkyZ/Wm8B9mcqibRMWcYBK8cvqk/img.png&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;260&quot; data-is-animation=&quot;false&quot; style=&quot;width: 48.8512%; margin-right: 10px;&quot; data-widthpercent=&quot;49.43&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cumGZ5/btsKT4cjkyZ/Wm8B9mcqibRMWcYBK8cvqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcumGZ5%2FbtsKT4cjkyZ%2FWm8B9mcqibRMWcYBK8cvqk%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;358&quot; height=&quot;260&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QS0nb/btsKTToHGSV/4zkjMMo1CVqffhYsSqABpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QS0nb/btsKTToHGSV/4zkjMMo1CVqffhYsSqABpk/img.png&quot; data-origin-width=&quot;348&quot; data-origin-height=&quot;247&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.986%;&quot; data-widthpercent=&quot;50.57&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QS0nb/btsKTToHGSV/4zkjMMo1CVqffhYsSqABpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQS0nb%2FbtsKTToHGSV%2F4zkjMMo1CVqffhYsSqABpk%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;348&quot; height=&quot;247&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3. 삽입/삭제 성능 평가 및 힙 구현 자료구조&lt;/h4&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: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;데이터 저장 시간 복잡도: O(n)&lt;/li&gt;
&lt;li&gt;데이터 삭제 시간 복잡도: O(1)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;연결리스트
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;데이터 저장 시간 복잡도: O(n)&lt;/li&gt;
&lt;li&gt;데이터 삭제 시간 복잡도: O(1)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;힙
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;데이터 저장 시간 복잡도: O(logn)&lt;/li&gt;
&lt;li&gt;데이터 삭제 시간 복잡도: O(logn)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;의외로 힙은 &lt;b&gt;배열을 기반으로 구현&lt;/b&gt;해야 함.&lt;/li&gt;
&lt;li&gt;연결리스트 기반으로 힙을 구현할 경우, 새로운 노드를 힙의 마지막 위치에 추가하는 것이 어려움&lt;/li&gt;
&lt;li&gt;부모 노드의 인덱스 값: n&lt;/li&gt;
&lt;li&gt;왼쪽 자식 노드의 인덱스 값: 2*n&lt;/li&gt;
&lt;li&gt;오른쪽 자식 노드의 인덱스 값: 2*n + 1&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;521&quot; data-origin-height=&quot;239&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLNgPw/btsKVc8HiYK/njinFEMhs2Ases4cEEInk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLNgPw/btsKVc8HiYK/njinFEMhs2Ases4cEEInk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLNgPw/btsKVc8HiYK/njinFEMhs2Ases4cEEInk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLNgPw%2FbtsKVc8HiYK%2FnjinFEMhs2Ases4cEEInk1%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;521&quot; height=&quot;239&quot; data-origin-width=&quot;521&quot; data-origin-height=&quot;239&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.4. 힙의 구현&lt;/h4&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: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;힙은 완전 이진 트리이다.&lt;/li&gt;
&lt;li&gt;힙의 구현은 배열을 기반으로 하며 &lt;b&gt;인덱스가 0인 요소는 비워둔다.&lt;/b&gt;&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;/li&gt;
&lt;li&gt;헤더 파일&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;typedef char HData;
typedef int Priority;

typedef struct _heapElem
{
	Priority pr; // 값이 작을수록 높은 우선순위
	HData data;
} HeapElem;

typedef struct _heap
{
	int numOfData;
	HeapElem heapArr[HEAP_LEN];
} Heap;

void HeapInit(Heap * ph);
int HIsEmpty(Heap * ph);

void HInsert(Heap * ph, HData data, Priority pr);
HData HDelete(Heap * ph);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;/ul&gt;
&lt;pre class=&quot;zephir&quot;&gt;&lt;code&gt;void HeapInit(Heap *ph)
{
	ph-&amp;gt;numOfData = 0;  // 힙의 초기화
}

int HIsEmpty(Heap *ph)  // 힙이 비어있는지 확인
{
	if(ph-&amp;gt;numOfData == 0)
		return TRUE;
	else
		return FALSE;
}

int GetParentIDX(int idx)  // 부모 노드의 인덱스 값 반환
{
	return idx/2;
}

int GetLChildIDX(int idx)
{
	return idx*2;
}

int GetRChildIDX(int idx)
{
	return idx*2 + 1;
}

// 두 개의 자식 노드 중 높은 우선순위의 자식 노드 인덱스 값 반환
int GetHiPriChildIdx(Heap *ph, int idx)
{
	// 자식 노드가 존재하지 않는다면
	if(GetLChildIDX(idx) &amp;gt; ph-&amp;gt;numOfData)
		return 0;
	
	// 자식 노드가 왼쪽 자식 노드 하나만 존재한다면
	else if(GetLChildIDX(idx) == ph-&amp;gt;numOfData)
		return GetLChildIDX(idx);
	
	// 자식 노드 둘 다 존재한다면
	else
	{
		// 오른쪽 자식 노드의 우선순위가 높다면
		if(ph-&amp;gt;heapArr[GetLChildIDX(idx)].pr &amp;gt; ph-&amp;gt;heapArr[GetRChildIDX(idx)].pr)
			return GetRChildIDX(idx);   // 오른쪽 자식 노드 인덱스 값 반환
		else
			return GetLChildIDX(idx);   // 왼쪽 자식 노드의 인덱스 값 반환
	}
}

// 힙에 데이터 저장
void HInsert(Heap *ph, HData data, Priority pr)
{
// 새 노드가 우선순위가 가장 낮다는 가정하에 마지막 위치에서 시작
	int idx = ph-&amp;gt;numOfData+1;
	HeapElem nelem = {pr, data};
	
	while(idx != 1)
	{
		if(pr &amp;lt; (ph-&amp;gt;heapArr[GetParentIDX(idx)].pr);
			ph-&amp;gt;heapArr[idx] = heapArr[GetParentIDX(idx)];
			idx = GetParentIDX(idx);
	}
	
	ph-&amp;gt;heapArr[idx] = nelem;
	ph-&amp;gt;numOfData += 1; 
}

// 힙에서 데이터 삭제
HData HDelete(Heap *ph)
{
	HData retData = (ph-&amp;gt;heapArr[1]).data;  // 반환을 위해서 삭제할 데이터 저장
	HeapElem lastElem = ph-&amp;gt;heapArr[ph-&amp;gt;numOfData];  // 힙의 마지막 노드 저장
	
	// 아래의 변수 parentIdx에는 마지막 노드가 저장될 위치정보가 담긴다.
	int parentIdx = 1;  // 루트 노드가 위치해야 할 인덱스 값 저장
	int childIdx;
	
	// 루트 노드의 우선순위가 높은 자식 노드를 시작으로 반복문 시작
	while(childIdx == GetHiPriChildIDX(ph, parentIdx))
	{
		if(lastElem.pr &amp;lt;= ph-&amp;gt;heapArr[childIdx].pr)  // 마지막 노드와 우선순위 비교
			break;  // 마지막 노드의 우선순위가 높으면 반복문 탈출
			
		ph-&amp;gt;heapArr[parentIdx] = ph-&amp;gt;heapArr[childIdx];  
		parentIdx = childIdx;  // 마지막 노드가 저장될 위치 정보를 한 레벨 내림
	}
	
	ph-&amp;gt;heapArr[parentIdx] = lastElem;  // 마지막 노드 최종 저장
	ph-&amp;gt;numOfData -= 1;
	return retData;
}
&lt;/code&gt;&lt;/pre&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;/li&gt;
&lt;li&gt;우선순위의 판단 기준을 힙에 설정할 수 있어야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;수정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;heapElem의 역할이 없어져 삭제됨&lt;/li&gt;
&lt;li&gt;heap 구조에 두 개의 데이터를 대상으로 우선순위가 낮고 높음을 판단하는 함수를 등록하기 위한 포인터 변수 comp 등록&lt;/li&gt;
&lt;/ul&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: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;변경점만 정리한 코드&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot;&gt;&lt;code&gt;// heapElem 삭제
//  typedef struct _heapElem
// {
//	 Priority pr; // 값이 작을수록 높은 우선순위
//	 HData data;
// } HeapElem;  

typedef char HData;
typedef int (*PriorityComp)(HData d1, HData d2);

typedef struct _heap
{
	PriorityComp *comp; // 추가
	int numOfData;
	HeapElem heapArr[HEAP_LEN];
} Heap;

void HeapInit(Heap *ph, PriorityComp pc)
{
	ph-&amp;gt;numOfData = 0;  // 힙의 초기화
	ph-&amp;gt;comp = pc;
}

... 나머지 동일

// 두 개의 자식 노드 중 높은 우선순위의 자식 노드 인덱스 값 반환
int GetHiPriChildIdx(Heap *ph, int idx)
{
	// 자식 노드가 존재하지 않는다면
	if(GetLChildIDX(idx) &amp;gt; ph-&amp;gt;numOfData)
		return 0;
	
	// 자식 노드가 왼쪽 자식 노드 하나만 존재한다면
	else if(GetLChildIDX(idx) == ph-&amp;gt;numOfData)
		return GetLChildIDX(idx);
	
	// 자식 노드 둘 다 존재한다면
	else
	{
		// 오른쪽 자식 노드의 우선순위가 높다면
	// if(ph-&amp;gt;heapArr[GetLChildIDX(idx)].pr &amp;gt; ph-&amp;gt;heapArr[GetRChildIDX(idx)].pr)
		if(ph-&amp;gt;comp(ph-&amp;gt;heapArr[GetLChildIDX(idx)], ph-&amp;gt;heapArr[GetRChildIDX(idx)]) &amp;lt; 0) // 대체
			return GetRChildIDX(idx);   // 오른쪽 자식 노드 인덱스 값 반환
		else
			return GetLChildIDX(idx);   // 왼쪽 자식 노드의 인덱스 값 반환
	}
}

// 힙에 데이터 저장
void HInsert(Heap *ph, HData data, Priority pr)
{
// 새 노드가 우선순위가 가장 낮다는 가정하에 마지막 위치에서 시작
	int idx = ph-&amp;gt;numOfData+1;
//	HeapElem nelem = {pr, data};
	
	while(idx != 1)
	{
	// if(pr &amp;lt; (ph-&amp;gt;heapArr[GetParentIDX(idx)].pr);
		if(ph-&amp;gt;comp(data, ph-&amp;gt;heapArr[GetParentIDX(idx)]) &amp;gt; 0) // 대체
			ph-&amp;gt;heapArr[idx] = heapArr[GetParentIDX(idx)];
			idx = GetParentIDX(idx);
	}
	
	ph-&amp;gt;heapArr[idx] = nelem;
	ph-&amp;gt;numOfData += 1; 
}

// 힙에서 데이터 삭제
HData HDelete(Heap *ph)
{
	HData retData = (ph-&amp;gt;heapArr[1]).data;  // 반환을 위해서 삭제할 데이터 저장
	HeapElem lastElem = ph-&amp;gt;heapArr[ph-&amp;gt;numOfData];  // 힙의 마지막 노드 저장
	
	// 아래의 변수 parentIdx에는 마지막 노드가 저장될 위치정보가 담긴다.
	int parentIdx = 1;  // 루트 노드가 위치해야 할 인덱스 값 저장
	int childIdx;
	
	// 루트 노드의 우선순위가 높은 자식 노드를 시작으로 반복문 시작
	while(childIdx == GetHiPriChildIDX(ph, parentIdx))
	{
	// if(lastElem.pr &amp;lt;= ph-&amp;gt;heapArr[childIdx].pr)  // 마지막 노드와 우선순위 비교
	   if(ph-&amp;gt;comp(lastElem, ph-&amp;gt;heapArr[childIdx]) &amp;gt;= 0)  // 대체
			break;  // 마지막 노드의 우선순위가 높으면 반복문 탈출
			
		ph-&amp;gt;heapArr[parentIdx] = ph-&amp;gt;heapArr[childIdx];  
		parentIdx = childIdx;  // 마지막 노드가 저장될 위치 정보를 한 레벨 내림
	}
	
	ph-&amp;gt;heapArr[parentIdx] = lastElem;  // 마지막 노드 최종 저장
	ph-&amp;gt;numOfData -= 1;
	return retData;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;head52&quot; data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;윤성우의 열혈 자료구조 (윤성우 저, 2023.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/자료구조</category>
      <category>computer science</category>
      <category>오블완</category>
      <category>우선순위큐</category>
      <category>자료구조</category>
      <category>티스토리챌린지</category>
      <category>힙</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/53</guid>
      <comments>https://onyodev.tistory.com/53#entry53comment</comments>
      <pubDate>Sun, 24 Nov 2024 15:43:47 +0900</pubDate>
    </item>
    <item>
      <title>트리(tree)</title>
      <link>https://onyodev.tistory.com/52</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 윤성우 저 - &quot;윤성우의 열혈 자료구조&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 트리(Tree)의 개요&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1. 트리의 개념&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;ldquo;트리는 &lt;b&gt;계층적 관계를 표현&lt;/b&gt;하는 자료구조이다.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;트리의 구조와 용어
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;노드: node
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트리 구성 요소에 해당하는 A, B, C, D, E, F와 같은 요소&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;간선: edge
&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;루트 노드: root node
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트리 구조 최상위에 존재하는 A와 같은 노드&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단말 노드: terminal node or leaf node
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래로 또 다른 노드가 연결되어 있지 않은 E, F, C, D와 같은 노드&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;내부 노드: internal node
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단말 노드를 제외한 모든 노드로 A, B와 같은 노드&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;655&quot; data-origin-height=&quot;468&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmtrTs/btsKTnKrrGq/NifnoalKwZMzZEm9Nl75PK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmtrTs/btsKTnKrrGq/NifnoalKwZMzZEm9Nl75PK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmtrTs/btsKTnKrrGq/NifnoalKwZMzZEm9Nl75PK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmtrTs%2FbtsKTnKrrGq%2FNifnoalKwZMzZEm9Nl75PK%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;655&quot; height=&quot;468&quot; data-origin-width=&quot;655&quot; data-origin-height=&quot;468&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2. 이진 트리와 서브 트리&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서브 트리(sub tree): 큰 트리에 속하는 작은 트리&lt;/li&gt;
&lt;li&gt;이진 트리(binary tree)
&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;li&gt;&lt;b&gt;*노드가 위치할 수 있는 곳에 노드가 존재하지 않는다면, 공집합 노드가 존재하는 것으로 간주한다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3. 포화 이진 트리와 완전 이진 트리&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;레벨(level): 트리에서의 각 층&lt;/li&gt;
&lt;li&gt;높이(height): 트리의 최고 레벨&lt;/li&gt;
&lt;li&gt;포화 이진 트리(full binary tree): 모든 레벨이 꽉 찬 이진 트리&lt;/li&gt;
&lt;li&gt;완전 이진 트리(complete binary tree): 모든 레벨이 꽉 찬 상태가 아니지만 빈 틈 없이 노드가 채워진 이진 트리&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 이진 트리의 구현&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. 이진 트리 구현 방법: 배열/연결 리스트 기반&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;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;539&quot; data-origin-height=&quot;287&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tGSjj/btsKU9KBW5v/cAI0yTwOMPt3mQK6HoqfFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tGSjj/btsKU9KBW5v/cAI0yTwOMPt3mQK6HoqfFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tGSjj/btsKU9KBW5v/cAI0yTwOMPt3mQK6HoqfFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtGSjj%2FbtsKU9KBW5v%2FcAI0yTwOMPt3mQK6HoqfFK%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;539&quot; height=&quot;287&quot; data-origin-width=&quot;539&quot; data-origin-height=&quot;287&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;675&quot; data-origin-height=&quot;211&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0XtKX/btsKS4xsLSv/CRWZ7kBVVLdTuuz0c7TCK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0XtKX/btsKS4xsLSv/CRWZ7kBVVLdTuuz0c7TCK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0XtKX/btsKS4xsLSv/CRWZ7kBVVLdTuuz0c7TCK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0XtKX%2FbtsKS4xsLSv%2FCRWZ7kBVVLdTuuz0c7TCK0%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;675&quot; height=&quot;211&quot; data-origin-width=&quot;675&quot; data-origin-height=&quot;211&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. 헤더파일에 정의된 구조체와 함수의 기능&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이진 트리 자료구조 ADT&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;274&quot; data-origin-height=&quot;189&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rsySD/btsKUIfrpbP/MyE1vuE5akQgr9xGTwf360/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rsySD/btsKUIfrpbP/MyE1vuE5akQgr9xGTwf360/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rsySD/btsKUIfrpbP/MyE1vuE5akQgr9xGTwf360/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrsySD%2FbtsKUIfrpbP%2FMyE1vuE5akQgr9xGTwf360%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;274&quot; height=&quot;189&quot; data-origin-width=&quot;274&quot; data-origin-height=&quot;189&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1732346721034&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typedef struct _bTreeNode
{
	BTData data;
	struct _bTreeNode *left;
	struct _bTreeNode *right;
} BTreeNode;

BTreeNode * MakeBTreeNode(void);
- 이진 트리 노드를 생성하여 그 주소값을 반환

BTData GetData(BTreeNode *bt);
- 노드에 저장된 데이터를 반환

void SetData(BTreeNode*bt, BTData data);  
- 노드에 데이터를 저장, data로 전달된 값을 저장

BTreeNode * GetLeftSubTree(BTreeNode *bt);  
- 왼쪽 서브 트리 주소 값 반환
BTreeNode * GetRightSubTree(BTreeNode *bt);  
- 오른쪽 서브 트리 주소 값 반환

void MakeLeftSubTree(BTreeNode *main, BTreeNode *sub);  
- 왼쪽 서브 트리 연결

void MakeRightSubTree(BTreeNode *main, BTreeNode *sub);
- 오른쪽 서브 트리 연결&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;2.3. 이진 트리의 구현&lt;/h4&gt;
&lt;pre id=&quot;code_1732346777689&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;BTreeNode * MakeBTreeNode(void)
{
	BTreeNode * nd = (BTreeNode*)malloc(sizeof(BTreeNode));
	nd-&amp;gt;left = NULL;
	nd-&amp;gt;right = NULL;
	return nd;
}

BTData GetData(BTreeNode *bt)
{
	return bt-&amp;gt;data;
}

void SetData(BTreeNode*bt, BTData data)
{
	bt-&amp;gt;data = data;
}  

BTreeNode * GetLeftSubTree(BTreeNode *bt)
{
	return bt-&amp;gt;left;
}

BTreeNode * GetRightSubTree(BTreeNode *bt)
{
	return bt-&amp;gt;right;
}


void MakeLeftSubTree(BTreeNode *main, BTreeNode *sub)
{
	if(main-&amp;gt;left != NULL)
		free(main-&amp;gt;left);
	
	main-&amp;gt;left = sub;
}

void MakeRightSubTree(BTreeNode *main, BTreeNode *sub)
{
	if(main-&amp;gt;right != NULL)
		free(main-&amp;gt;right);
	
	main-&amp;gt;right - sub;
}&lt;/code&gt;&lt;/pre&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;한 번의 free 함수 호출이 전부이기 때문에 삭제할 서브 트리가 여러 개의 노드로 이뤄질 경우 메모리 누수가 발생&lt;/li&gt;
&lt;li&gt;그래서 순회의 방법이 필요함&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 이진 트리의 순회(Traversal)&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1. 순회의 세 가지 방법&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전위 순회(Preorder Traversal): 루트 &amp;rarr; 왼쪽 &amp;rarr; 오른쪽&lt;/li&gt;
&lt;li&gt;중위 순회(Inorder Traversal): 왼쪽 &amp;rarr; 루트 &amp;rarr; 오른쪽&lt;/li&gt;
&lt;li&gt;후위 순회(Postorder Traversal): 왼쪽 &amp;rarr; 오른쪽 &amp;rarr; 루트&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R5Ix8/btsKTSQAS7N/QG7A3XLVYmK3LfVsDXj0xK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R5Ix8/btsKTSQAS7N/QG7A3XLVYmK3LfVsDXj0xK/img.png&quot; data-origin-width=&quot;467&quot; data-origin-height=&quot;137&quot; data-is-animation=&quot;false&quot; style=&quot;width: 33.7651%; margin-right: 10px;&quot; data-widthpercent=&quot;34.57&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R5Ix8/btsKTSQAS7N/QG7A3XLVYmK3LfVsDXj0xK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR5Ix8%2FbtsKTSQAS7N%2FQG7A3XLVYmK3LfVsDXj0xK%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;467&quot; height=&quot;137&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q01Sx/btsKSQML1ig/Zw4UtVKq6jEyIkHAwDpbDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q01Sx/btsKSQML1ig/Zw4UtVKq6jEyIkHAwDpbDK/img.png&quot; data-origin-width=&quot;468&quot; data-origin-height=&quot;146&quot; data-is-animation=&quot;false&quot; style=&quot;width: 31.7516%; margin-right: 10px;&quot; data-widthpercent=&quot;32.51&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q01Sx/btsKSQML1ig/Zw4UtVKq6jEyIkHAwDpbDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq01Sx%2FbtsKSQML1ig%2FZw4UtVKq6jEyIkHAwDpbDK%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;468&quot; height=&quot;146&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ryg5S/btsKTmkrQp2/kzCuMK9mzPPs071z7IxOE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ryg5S/btsKTmkrQp2/kzCuMK9mzPPs071z7IxOE1/img.png&quot; data-origin-width=&quot;461&quot; data-origin-height=&quot;142&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.1577%;&quot; data-widthpercent=&quot;32.92&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ryg5S/btsKTmkrQp2/kzCuMK9mzPPs071z7IxOE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRyg5S%2FbtsKTmkrQp2%2FkzCuMK9mzPPs071z7IxOE1%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;461&quot; height=&quot;142&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1732346992711&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void InorderTranverse(BTreeNode * bt)
{
	if(bt == NULL)  // bt가 NULL이면 탈출
		return;
	
	InorderTranverse(bt-&amp;gt;left);
	printf(&quot;%d \n&quot;, bt-&amp;gt;data);
	InorderTranverse(bt-&amp;gt;right);


void PreorderTranverse(BTreeNode * bt)
{
	if(bt == NULL)  // bt가 NULL이면 탈출
	return;
	
	printf(&quot;%d \n&quot;, bt-&amp;gt;data);
	PreorderTranverse(bt-&amp;gt;left);
	PreorderTranverse(bt-&amp;gt;left);
}

void PostorderTranverse(BTreeNode * bt)
{
	if(bt == NULL)  // bt가 NULL이면 탈출
	return;
	
	PostorderTranverse(bt-&amp;gt;left);
	PostorderTranverse(bt-&amp;gt;right);
	printf(&quot;%d \n&quot;, bt-&amp;gt;data);
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-level=&quot;2&quot;&gt;printf를 저장하는 action 함수로만 변경하면 완성&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 수식 트리(Expression Tree)의 구현&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.1. 수식 트리의 이해와 헤더파일 정의&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;235&quot; data-origin-height=&quot;268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ruhDI/btsKTpgQCcW/RCBmdYWXrpt3Q3Fsr579d0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ruhDI/btsKTpgQCcW/RCBmdYWXrpt3Q3Fsr579d0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ruhDI/btsKTpgQCcW/RCBmdYWXrpt3Q3Fsr579d0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FruhDI%2FbtsKTpgQCcW%2FRCBmdYWXrpt3Q3Fsr579d0%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;235&quot; height=&quot;268&quot; data-origin-width=&quot;235&quot; data-origin-height=&quot;268&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;중위 표기법의 수식 &amp;rarr; 후위 표기법의 수식 &amp;rarr; 수식 트리&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;BTreeNode * MakeExpTree(char exp[]); // 수식 트리 구성
int EvalutateExpTree(BTreeNode *bt); // 수식 트리 계산

void ShowPrefixTypeExp(BTreeNode * bt);  // 전위 표기법 기반 출력
void ShowInfixTypeExp(BTreeNode * bt);   // 중위 표기법 기반 출력
void ShowPostfixTypeExp(BTreeNode * bt); // 후위 표기법 기반 출력
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.2. 후위 표기법 기반 수식 트리 구성&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;후위 표기법 수식&lt;br /&gt;1 2 + 7 *&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;235&quot; data-origin-height=&quot;268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q33jF/btsKTjOKuZr/BQjipUCJu02gyShKQYq7OK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q33jF/btsKTjOKuZr/BQjipUCJu02gyShKQYq7OK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q33jF/btsKTjOKuZr/BQjipUCJu02gyShKQYq7OK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ33jF%2FbtsKTjOKuZr%2FBQjipUCJu02gyShKQYq7OK%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;235&quot; height=&quot;268&quot; data-origin-width=&quot;235&quot; data-origin-height=&quot;268&quot;/&gt;&lt;/span&gt;&lt;/figure&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;li&gt;후위 표기법 수식의 앞쪽에 등장하는 피연산자와 연산자를 이용해 트리의 하단을 구성&lt;/li&gt;
&lt;li&gt;이를 바탕으로 점진적으로 수식 트리의 윗부분을 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dVsP0n/btsKUABCWwN/JkVVp5xDFN4ukuGjDSbBVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dVsP0n/btsKUABCWwN/JkVVp5xDFN4ukuGjDSbBVk/img.png&quot; data-origin-width=&quot;383&quot; data-origin-height=&quot;152&quot; data-is-animation=&quot;false&quot; style=&quot;width: 46.3363%; margin-right: 10px;&quot; data-widthpercent=&quot;46.88&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dVsP0n/btsKUABCWwN/JkVVp5xDFN4ukuGjDSbBVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdVsP0n%2FbtsKUABCWwN%2FJkVVp5xDFN4ukuGjDSbBVk%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;383&quot; height=&quot;152&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cG5i6C/btsKT8MlA2i/4aTe1OWDn59P3vprk18Hg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cG5i6C/btsKT8MlA2i/4aTe1OWDn59P3vprk18Hg1/img.png&quot; data-origin-width=&quot;374&quot; data-origin-height=&quot;131&quot; data-is-animation=&quot;false&quot; style=&quot;width: 52.5009%;&quot; data-widthpercent=&quot;53.12&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cG5i6C/btsKT8MlA2i/4aTe1OWDn59P3vprk18Hg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcG5i6C%2FbtsKT8MlA2i%2F4aTe1OWDn59P3vprk18Hg1%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;374&quot; height=&quot;131&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m7LZo/btsKUDrvIhc/XmjOe8rGFegBMuFVfZMOLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m7LZo/btsKUDrvIhc/XmjOe8rGFegBMuFVfZMOLk/img.png&quot; data-origin-width=&quot;371&quot; data-origin-height=&quot;186&quot; data-is-animation=&quot;false&quot; style=&quot;width: 37.458%; margin-right: 10px;&quot; data-widthpercent=&quot;37.9&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m7LZo/btsKUDrvIhc/XmjOe8rGFegBMuFVfZMOLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm7LZo%2FbtsKUDrvIhc%2FXmjOe8rGFegBMuFVfZMOLk%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;371&quot; height=&quot;186&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKzz1N/btsKTnXGxxJ/x0d7ZZ2q3Im8B4j4pFY3m0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKzz1N/btsKTnXGxxJ/x0d7ZZ2q3Im8B4j4pFY3m0/img.png&quot; data-origin-width=&quot;621&quot; data-origin-height=&quot;190&quot; data-is-animation=&quot;false&quot; style=&quot;width: 61.3792%;&quot; data-widthpercent=&quot;62.1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKzz1N/btsKTnXGxxJ/x0d7ZZ2q3Im8B4j4pFY3m0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKzz1N%2FbtsKTnXGxxJ%2Fx0d7ZZ2q3Im8B4j4pFY3m0%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;621&quot; height=&quot;190&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TzSp3/btsKVrEfRYe/L2otQc3FrN10KzFUXEK0gK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TzSp3/btsKVrEfRYe/L2otQc3FrN10KzFUXEK0gK/img.png&quot; data-origin-width=&quot;561&quot; data-origin-height=&quot;233&quot; data-is-animation=&quot;false&quot; style=&quot;width: 56.8565%; margin-right: 10px;&quot; data-widthpercent=&quot;57.53&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TzSp3/btsKVrEfRYe/L2otQc3FrN10KzFUXEK0gK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTzSp3%2FbtsKVrEfRYe%2FL2otQc3FrN10KzFUXEK0gK%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;561&quot; height=&quot;233&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oId2z/btsKUEKQqrF/vA4Z55Iu0tE8DRHkEKVLzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oId2z/btsKUEKQqrF/vA4Z55Iu0tE8DRHkEKVLzK/img.png&quot; data-origin-width=&quot;384&quot; data-origin-height=&quot;216&quot; data-is-animation=&quot;false&quot; style=&quot;width: 41.9808%;&quot; data-widthpercent=&quot;42.47&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oId2z/btsKUEKQqrF/vA4Z55Iu0tE8DRHkEKVLzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoId2z%2FbtsKUEKQqrF%2FvA4Z55Iu0tE8DRHkEKVLzK%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;384&quot; height=&quot;216&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;615&quot; data-origin-height=&quot;230&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUGyMh/btsKU5H6cDr/YUJPAZNTix2kkonvEOGIik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUGyMh/btsKU5H6cDr/YUJPAZNTix2kkonvEOGIik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUGyMh/btsKU5H6cDr/YUJPAZNTix2kkonvEOGIik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUGyMh%2FbtsKU5H6cDr%2FYUJPAZNTix2kkonvEOGIik%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;615&quot; height=&quot;230&quot; data-origin-width=&quot;615&quot; data-origin-height=&quot;230&quot;/&gt;&lt;/span&gt;&lt;/figure&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;li&gt;자식 노드를 연결해서 만들어진 트리는 다시 스택에 옮긴다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;BTreeNode * MakeExpTree(char exp[])
{
	Stack stack;
	BTreeNode * pnode;
	int expLen = strlen(exp);
	int i;
	
	for(i=0; i&amp;lt;expLen; i++)
	{
		pnode = MakeBTreeNode();
		if(isdigit(exp[i]))   // 피연산자라면...
		{   
			SetData(pnode, exp[i]-'0');   // 문자를 정수로 바꿔서 저장
		}
		else     // 연산자라면... 
		{   
			MakeRightSubTree(pnode, SPop(&amp;amp;stack));
			MakeLeftSubTree(pnode, SPop(&amp;amp;stack));
			SetData(pnode, exp[i]);
		}
		
		SPush(&amp;amp;stack, pnode);
	}
	return SPop(&amp;amp;stack);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&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;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;void ShowNodeData(int data)
{
	if(0&amp;lt;=data &amp;amp;&amp;amp; data &amp;lt;= 9)
		printf(&quot;%d &quot;, data); 
	else
		printf(&quot;%c &quot;, data);
}

void ShowPrefixTypeExp(BTreeNode * bit)  // 전위 표기법으로 수식 출력
{
	PreorderTraverse(bt, ShowNodeData);
}

void ShowInfixTypeExp(BTreeNode * bt)  // 중위 표기법으로 수식 출력
{
	InorderTraverse(bt, ShowNodeData);

}

void ShowPostfixTypeExp(BTreeNode * bt)  // 후위 표기법으로 수식 출력
{
	PostorderTraverse(bt, ShowNodeData);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.3. 수식 트리의 계산&lt;/h4&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;int EvaluateExpTree(BTreeNode * bt)
{
	int op1, op2;
	
	if(GetLeftSubTree(bt)==NULL &amp;amp;&amp;amp; GetRightSubTree(bt)==NULL) // 단말 노드라면(탈출 조건)
		return GetData(bt);
	
	op1 = EvaluateExpTree(GetLeftSubTree(bt));  // 왼쪽 서브트리 계산
	op2 = EvaluateExpTree(GetRightSubTree(bt)); // 오른쪽 서브트리 계산
	
	switch(GetData(bt)) // 연산자를 확인하여 연산을 진행
	{
	case '+':
	return op1+op2;
	case '-':
	return op1-op2;
	case '*':
	return op1*op2;
	case '/':
	return op1/op2;
	}
	
	return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 id=&quot;head52&quot; data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;윤성우의 열혈 자료구조 (윤성우 저, 2023.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/자료구조</category>
      <category>computer science</category>
      <category>오블완</category>
      <category>자료구조</category>
      <category>트리</category>
      <category>티스토리챌린지</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/52</guid>
      <comments>https://onyodev.tistory.com/52#entry52comment</comments>
      <pubDate>Sat, 23 Nov 2024 16:34:25 +0900</pubDate>
    </item>
    <item>
      <title>큐(queue)</title>
      <link>https://onyodev.tistory.com/51</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 윤성우 저 - &quot;윤성우의 열혈 자료구조&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;1. 큐의 이해와 ADT 정의&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선입선출의 자료구조 (FIFO: First In First Out)&lt;/li&gt;
&lt;li&gt;큐의 ADT 정의&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;void QueueInit(Queue * pq);
- 큐의 초기화를 진행한다
- 큐 생성 후 제일 먼저 호출되는 함수

int QIsEmpty(Queue * pq);
- 큐가 빈 경우 TRUE, 아닌 경우 FALSE

void Enqueue(Queue *pq, Data data);
- 큐에 데이터를 저장한다. 매개변수 data로 전달된 값을 저장

Data Dequeue(Queue *pq);
- 저장순서가 가장 앞선 데이터를 삭제
- 삭제된 데이터는 반환
- 본 함수의 호출을 위해서는 데이터가 존재

Data QPeek(Queue *pq)
- 저장순서가 가장 앞선 데이터를 반환하되 삭제하지 않음
- 본 함수의 호출을 위해서는 데이터가 존재

&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;2. 큐의 배열 기반 구현&lt;/h1&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.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;enqueue&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;304&quot; data-origin-height=&quot;302&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DixIr/btsKR438m1T/XXHp7p0RDebZBt6kYBmVdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DixIr/btsKR438m1T/XXHp7p0RDebZBt6kYBmVdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DixIr/btsKR438m1T/XXHp7p0RDebZBt6kYBmVdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDixIr%2FbtsKR438m1T%2FXXHp7p0RDebZBt6kYBmVdK%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;304&quot; height=&quot;302&quot; data-origin-width=&quot;304&quot; data-origin-height=&quot;302&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;dequeue&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;286&quot; data-origin-height=&quot;298&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sgCbo/btsKRo9Qhzq/TsUOFCKXkkfS8v7RuHcBnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sgCbo/btsKRo9Qhzq/TsUOFCKXkkfS8v7RuHcBnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sgCbo/btsKRo9Qhzq/TsUOFCKXkkfS8v7RuHcBnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsgCbo%2FbtsKRo9Qhzq%2FTsUOFCKXkkfS8v7RuHcBnK%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;286&quot; height=&quot;298&quot; data-origin-width=&quot;286&quot; data-origin-height=&quot;298&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. 원형 큐의 이해&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;R과 F를 회전시켜 큐를 구성하는 방식&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;231&quot; data-origin-height=&quot;245&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dC4Zzl/btsKQzxi0aZ/NCCnl0zCJSdQWMEA3597ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dC4Zzl/btsKQzxi0aZ/NCCnl0zCJSdQWMEA3597ck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dC4Zzl/btsKQzxi0aZ/NCCnl0zCJSdQWMEA3597ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdC4Zzl%2FbtsKQzxi0aZ%2FNCCnl0zCJSdQWMEA3597ck%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;231&quot; height=&quot;245&quot; data-origin-width=&quot;231&quot; data-origin-height=&quot;245&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원형 큐의 enqueue와 dequeue&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;708&quot; data-origin-height=&quot;266&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYc1dd/btsKRoaWeZx/xSPKB1mK6DRkKj0c5m6TdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYc1dd/btsKRoaWeZx/xSPKB1mK6DRkKj0c5m6TdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYc1dd/btsKRoaWeZx/xSPKB1mK6DRkKj0c5m6TdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYc1dd%2FbtsKRoaWeZx%2FxSPKB1mK6DRkKj0c5m6TdK%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;708&quot; height=&quot;266&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;266&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;683&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5HkX3/btsKSkZRXUG/dXksM9HXcPbEaZKslkZCEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5HkX3/btsKSkZRXUG/dXksM9HXcPbEaZKslkZCEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5HkX3/btsKSkZRXUG/dXksM9HXcPbEaZKslkZCEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5HkX3%2FbtsKSkZRXUG%2FdXksM9HXcPbEaZKslkZCEk%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;683&quot; height=&quot;263&quot; data-origin-width=&quot;683&quot; data-origin-height=&quot;263&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uQ7A2/btsKRaYlvWb/d2G6HaprTGMCkcmtbVjBBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uQ7A2/btsKRaYlvWb/d2G6HaprTGMCkcmtbVjBBK/img.png&quot; data-origin-width=&quot;237&quot; data-origin-height=&quot;226&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;51.79&quot; style=&quot;width: 51.1876%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uQ7A2/btsKRaYlvWb/d2G6HaprTGMCkcmtbVjBBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuQ7A2%2FbtsKRaYlvWb%2Fd2G6HaprTGMCkcmtbVjBBK%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;237&quot; height=&quot;226&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxc7uE/btsKSuOK4ug/gUD76mh2tQApM2MQUKUEd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxc7uE/btsKSuOK4ug/gUD76mh2tQApM2MQUKUEd1/img.png&quot; data-origin-width=&quot;205&quot; data-origin-height=&quot;210&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;48.21&quot; style=&quot;width: 47.6496%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxc7uE/btsKSuOK4ug/gUD76mh2tQApM2MQUKUEd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbxc7uE%2FbtsKSuOK4ug%2FgUD76mh2tQApM2MQUKUEd1%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;205&quot; height=&quot;210&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;F와 R의 위치로 가득 찬 경우와 빈 경우를 구분할 수 없음&lt;/li&gt;
&lt;li&gt;그래서 배열을 가득 채우지 않고 배열의 길이가 N인 경우 데이터가 N-1개가 채워졌을 때 가득 찬 것으로 가정함&lt;/li&gt;
&lt;li&gt;큐 구현 시의 연산
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;enqueue 연산 시, R이 가리키는 위치를 한 칸 이동시킨 다음에 R이 가리키는 위치에 데이터를 저장&lt;/li&gt;
&lt;li&gt;dequeue 연산 시, F가 가리키는 위치를 한 칸 이동시킨 다음, F가 가리키는 위치에 저장된 데이터를 반환 및 소멸&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;큐의 상태
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가득 찬 상태: R이 가리키는 위치의 앞을 F가 가리킨다.&lt;/li&gt;
&lt;li&gt;텅 빈 상태: F와 R이 동일한 위치를 가리킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3. 원형 큐의 구현&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;/ul&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#define QUE_LEN 100
typedef int Data;

typedef struct _cQueue
{
int front;
int rear;
Data queArr[QUE_LEN];
} CQueue;

typedef CQueue Queue;

void QueueInit(Queue * pq);
int QIsEmpty(Queue * pq);

void Enqueue(Queue * pq, Data data);
Data Dequeue(Queue * pq);
Data QPeek(Queue * pq);
&lt;/code&gt;&lt;/pre&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;/ul&gt;
&lt;pre class=&quot;xl&quot;&gt;&lt;code&gt;void QueueInit(Queue * pq)
{
	pq-&amp;gt;front = 0;
	pq-&amp;gt;rear = 0;
}

int QIsEmpty(Queue * pq);
{
	if(pq-&amp;gt;front == pq-&amp;gt;rear)
		return TRUE;
	else
		return FALSE;
}

int NextPosIdx(int pos)  // 큐의 다음 위치에 해당하는 인덱스 값 반환
{
	if(pos == QUE_LEN-1)  // 배열의 마지막 요소의 인덱스 값이라면
		return 0;
	else
		return pos+1;
}

void Enqueue(Queue * pq, Data data)
{
	if(NextPosIdx(pq-&amp;gt;rear) == pq-&amp;gt;front) // 큐가 꽉 차있다면
	{
		printf(&quot;Queue Memory Error!&quot;);
		exit(-1);
	}
	
	pq-&amp;gt;rear = NextPosIdx(pq-&amp;gt;rear); // rear을 한 칸 이동
	pq-&amp;gt;queArr[pq-&amp;gt;rear] = data;  // rear이 가리키는 곳에 데이터 저장
}

Data Dequeue(Queue * pq)
{
	if(QIsEmpty(pq))
	{
		printf(&quot;Queue Memory Error!&quot;);
		exit(-1);	
	}
	
	pq-&amp;gt;front = NextPosIdx(pq-&amp;gt;front);  // front를 한 칸 이동
	return pq-&amp;gt;queArr{pq-&amp;gt;front];  // front가 가리키는 데이터 반환
	
}

Data QPeek(Queue * pq)
{
	if(QIsEmpty(pq))
	{
		printf(&quot;Queue Memory Error!&quot;);
		exit(-1);		
	}
	
	return pq-&amp;gt;queArr[NextPosIdx(pq-&amp;gt;front)];
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 큐의 연결 리스트 기반 구현&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1. 연결 리스트 기반 큐의 헤더파일&lt;/h4&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;typedef int Data;

typedef struct _node
{
	Data data;
	struct _node * next;
} Node;

typedef struct _lQueue
{
	int front;
	int rear;
} LQueue;

typedef LQueue Queue;

void QueueInit(Queue * pq);
int QIsEmpty(Queue * pq);

void Enqueue(Queue * pq, Data data);
Data Dequeue(Queue * pq);
Data QPeek(Queue * pq);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2. 연결 리스트 기반 큐의 구현&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;624&quot; data-origin-height=&quot;141&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mDL6H/btsKSDETvKf/ONT4Jwdvi1ap1w0pPidhp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mDL6H/btsKSDETvKf/ONT4Jwdvi1ap1w0pPidhp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mDL6H/btsKSDETvKf/ONT4Jwdvi1ap1w0pPidhp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmDL6H%2FbtsKSDETvKf%2FONT4Jwdvi1ap1w0pPidhp1%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;624&quot; height=&quot;141&quot; data-origin-width=&quot;624&quot; data-origin-height=&quot;141&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;zephir&quot;&gt;&lt;code&gt;void QueueInit(Queue * pq)
{
	pq-&amp;gt;front = NULL;
	pq-&amp;gt;rear = NULL;
}

int QIsEmpty(Queue * pq)
{
	if(pq-&amp;gt;front == NULL)
		return TRUE;
	else
		return FALSE;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WEnKo/btsKRu9ZLlQ/nratTgrmfs6qgqn6t2Dgv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WEnKo/btsKRu9ZLlQ/nratTgrmfs6qgqn6t2Dgv0/img.png&quot; data-origin-width=&quot;331&quot; data-origin-height=&quot;175&quot; data-is-animation=&quot;false&quot; style=&quot;width: 38.4244%; margin-right: 10px;&quot; data-widthpercent=&quot;39.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WEnKo/btsKRu9ZLlQ/nratTgrmfs6qgqn6t2Dgv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWEnKo%2FbtsKRu9ZLlQ%2FnratTgrmfs6qgqn6t2Dgv0%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;331&quot; height=&quot;175&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uIJhh/btsKQP7Sxon/hXB31DOXq6q3PUx4GxYckk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uIJhh/btsKQP7Sxon/hXB31DOXq6q3PUx4GxYckk/img.png&quot; data-origin-width=&quot;234&quot; data-origin-height=&quot;141&quot; data-is-animation=&quot;false&quot; style=&quot;width: 33.7143%; margin-right: 10px;&quot; data-widthpercent=&quot;34.52&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uIJhh/btsKQP7Sxon/hXB31DOXq6q3PUx4GxYckk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuIJhh%2FbtsKQP7Sxon%2FhXB31DOXq6q3PUx4GxYckk%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;234&quot; height=&quot;141&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ecAFus/btsKR9K3UBQ/m6NmkFNQPHViA17HUNMKQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ecAFus/btsKR9K3UBQ/m6NmkFNQPHViA17HUNMKQ0/img.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;179&quot; data-is-animation=&quot;false&quot; style=&quot;width: 25.5357%;&quot; data-widthpercent=&quot;26.14&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ecAFus/btsKR9K3UBQ/m6NmkFNQPHViA17HUNMKQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FecAFus%2FbtsKR9K3UBQ%2Fm6NmkFNQPHViA17HUNMKQ0%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;225&quot; height=&quot;179&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;xl&quot;&gt;&lt;code&gt;void Enqueue(Queue * pq, Data data)
{
	Node * newNode = (Node*)malloc(sizeof(Node));
	newNode-&amp;gt;Next = NULL;
	newNode-&amp;gt;data = data;
	
	if(QIsEmpty(pq))  // 첫번째 노드의 추가라면
	{
		pq-&amp;gt;front = newNode;  // front가 새 노드를 가리키게 하고
		pq-&amp;gt;rear = newNode;   // rear도 새 노드를 가리키게 한다
	}
	else
	{
		pq-&amp;gt;rear-&amp;gt;next = newNode;  // 마지막 노드가 새 노드를 가리키게 하고
		pq-&amp;gt;rear = newNode;  // rear가 새 노드를 가리키게 한다.
	}
}
&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;847&quot; data-origin-height=&quot;169&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kDPwg/btsKSGnTuhM/yEotWI6M7nRl0pUwIk29Rk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kDPwg/btsKSGnTuhM/yEotWI6M7nRl0pUwIk29Rk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kDPwg/btsKSGnTuhM/yEotWI6M7nRl0pUwIk29Rk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkDPwg%2FbtsKSGnTuhM%2FyEotWI6M7nRl0pUwIk29Rk%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;847&quot; height=&quot;169&quot; data-origin-width=&quot;847&quot; data-origin-height=&quot;169&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;F가 다음 노드를 가리키게 한다.&lt;/li&gt;
&lt;li&gt;F가 이전에 가리키던 노드를 소멸시킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;Data Dequeue(Queue * pq)
{
	Node * delNode;
	Data retData;
	
	if(QIsEmpty(pq))
	{		
		printf(&quot;Queue Memory Error!&quot;);
		exit(-1);		
	}
	
	delNode = pq-&amp;gt;front;          // 삭제할 노드의 주소값 저장
	retData = delNode-&amp;gt;data;      // 삭제할 노드가 지닌 값 저장
	pq-&amp;gt;front = pq-&amp;gt;front-&amp;gt;next;  // 삭제할 노드의 다음 노드를 front가 가리킴
	
	free(delNode);
	return retData;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 덱(Deque)의 이해와 구현&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.1. 덱의 이해와 ADT 정의&lt;/h4&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;/li&gt;
&lt;li&gt;뒤로 넣기&lt;/li&gt;
&lt;li&gt;앞에서 빼기&lt;/li&gt;
&lt;li&gt;뒤에서 빼기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;덱 자료구조의 ADT&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;void DequeInit(Deque *pdeq);
- 덱의 초기화를 진행
- 덱 생성 후 제일 먼저 호출

int DQisEmpty(Deque *pdeq);
- 덱이 빈 경우 TRUE, 그렇지 않은 경우 FALSE 반환

void DQAddFirst(Deque *pdeq, Data data);
- 덱의 머리에 데이터를 저장, data로 전달된 값을 저장함

void DQAddLast(Deque *pdeq, Data data);
- 덱의 꼬리에 데이터를 저장, data로 전달된 값을 저장함

Data DQRemoveFirst(Deque *pdeq);
- 덱의 머리에 위치한 데이터를 반환 및 소멸

Data DQRemoveLast(Deque *pdeq);
- 덱의 꼬리에 위치한 데이터를 반환 및 소멸

Data DQGetFirst(Deque *pdeq);
- 덱의 머리에 위치한 데이터를 반환

Data DQGetLast(Deque *pdeq);
- 덱의 꼬리에 위치한 데이터를 반환

&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.2. 덱의 구현&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;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;191&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ILYDk/btsKSmwCkDG/7jLFAVseAfS92WFP6nkJM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ILYDk/btsKSmwCkDG/7jLFAVseAfS92WFP6nkJM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ILYDk/btsKSmwCkDG/7jLFAVseAfS92WFP6nkJM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FILYDk%2FbtsKSmwCkDG%2F7jLFAVseAfS92WFP6nkJM0%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;879&quot; height=&quot;191&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;191&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;xl&quot;&gt;&lt;code&gt;void DequeInit(Deque *pdeq)
{
	pdeq-&amp;gt;head = NULL;
	pdeq-&amp;gt;tail = NULL;
}

int DQisEmpty(Deque *pdeq)
{
	if(pdeq-&amp;gt;head == NULL)  // head가 NULL이면 빈 덱
		return TRUE;
	else
		return FALSE;
}

void DQAddFirst(Deque *pdeq, Data data)
{
	Node * newNode = (Node*)malloc(sizeof(Node));
	newNode-&amp;gt;data = data;
	
	newNode-&amp;gt;next = pdeq-&amp;gt;head;
	
	if(DQisEmpty(pdeq))
		pdeq-&amp;gt;tail = newNode;
	else
		pdeq-&amp;gt;head-&amp;gt;prev = newNode;
	
	newNode-&amp;gt;prev = NULL;
	pdeq-&amp;gt;head = newNode;
}

void DQAddLast(Deque *pdeq, Data data)
{
	Node * newNode = (Node*)malloc(sizeof(Node));
	newNode-&amp;gt;data = data;
	newNode-&amp;gt;prev = pdeq-&amp;gt;tail;
	
	if(DQisEmpty(pdeq))
		pdeq-&amp;gt;head = newNode;
	else
		pdeq-&amp;gt;tail-&amp;gt;next = newNode;
	
	newNode-&amp;gt;next = NULL;
	pdeq-&amp;gt;tail = newNode;
}

Data DQRemoveFirst(Deque *pdeq)
{
	Node * rnode = pdeq-&amp;gt;head;
	Data rdata;
	if(DQIsEmpty(pdeq)){....}
	rdata = pdeq-&amp;gt;head-&amp;gt;data;
	
	pdeq-&amp;gt;head = pdeq-&amp;gt;head-&amp;gt;next;
	free(rnode);
	
	if(pdeq-&amp;gt;head == NULL)
		pdeq-&amp;gt;tail = NULL;
	else
		pdeq-&amp;gt;head-&amp;gt;prev = NULL;
	
	return rdata;
}
- 덱의 머리에 위치한 데이터를 반환 및 소멸

Data DQRemoveLast(Deque *pdeq);
{
	Node * rnode = pdeq-&amp;gt;tail;
	Data rdata;
	if(DQIsEmpty(pdeq)){....}
	rdata = pdeq-&amp;gt;tail-&amp;gt;data;
	
	pdeq-&amp;gt;tail = pdeq-&amp;gt;tail-&amp;gt;prev;
	free(rnode);
	
	if(pdeq-&amp;gt;tail == NULL)
		pdeq-&amp;gt;head = NULL;
	else
		pdeq-&amp;gt;tail-&amp;gt;next = NULL;
	
	return rdata;
}

Data DQGetFirst(Deque *pdeq)
{
	if(DQIsEmpty(pdeq)){....}
	return pdeq-&amp;gt;head-&amp;gt;data;
}

Data DQGetLast(Deque *pdeq);
{
	if(DQIsEmpty(pdeq)){....}
	return pdeq-&amp;gt;tail-&amp;gt;data;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;head52&quot; data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;윤성우의 열혈 자료구조 (윤성우 저, 2023.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/자료구조</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/51</guid>
      <comments>https://onyodev.tistory.com/51#entry51comment</comments>
      <pubDate>Thu, 21 Nov 2024 19:01:34 +0900</pubDate>
    </item>
    <item>
      <title>스택(stack)</title>
      <link>https://onyodev.tistory.com/50</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 윤성우 저 - &quot;윤성우의 열혈 자료구조&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 스택의 이해와 ADT 정의&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;후입선출 방식의 자료구조 (LIFO: Last-In, First-Out)&lt;/li&gt;
&lt;li&gt;스택자료의 ADT&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732181723973&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void StackInit(Stack *pstack);
- 스택의 초기화를 진행
- 스택 생성 후 제일 먼저 호출되어야 하는 함수

int SIsEmpty(Stack *pstack);
- 스택이 빈 경우 TRUE, 아닌 경우 FALSE

void SPush(Stack *pstack, Data data);
- 스택에 데이터를 저장, 매개변수 data로 전달된 값을 저장

Data SPop(Stack *pstack);
- 마지막에 저장된 요소를 삭제
- 삭제된 데이터는 반환
- 본 함수의 호출을 위해서는 데이터가 존재해야 함

Data SPeek(Stack *pstack);
- 마지막에 저장한 요소를 반환하되 삭제하지 않음
- 본 함수의 호출을 위해서는 데이터가 존재해야 함&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;2. 스택의 배열 기반 구현&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. 구현의 논리와 헤더파일의 정의&lt;/h4&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;마지막에 저장된 데이터의 위치를 기억해야 함&lt;/li&gt;
&lt;li&gt;push: Top을 위로 한 칸 올리고, Top이 가리키는 위치에 데이터 저장&lt;/li&gt;
&lt;li&gt;pop: Top이 가리키는 데이터를 반환하고, Top을 아래로 한 칸 내림&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. 배열 기반 스택 구현&lt;/h4&gt;
&lt;pre id=&quot;code_1732181779652&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typedef struct _arrayStack
{
	Data StackArr[STACK_LEN];
	int topIndex;
} ArrayStack;

void StackInit(Stack *pstack)
{
	pstack-&amp;gt;topIndex = -1;  // -1: 빈 상태
}

int SIsEmpty(Stack *pstack)
{
	if(pstack-&amp;gt;topIndex == -1)
		return TRUE;
	else
		return FALSE;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-level=&quot;2&quot;&gt;Push와 Pop&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732181821779&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void SPush(Stack *pstack, Data data)
{
	pstack-&amp;gt;topIndex += 1;
	pstack-&amp;gt;stackArr[topIndex] = data;
}

Data SPop(Stack *pstack)
{
	int rIdx;
	
	if(SIsEmpty(pstack)){
		printf(&quot;Stack Memory Error!&quot;);
		exit(-1);
	}
	
	rIdx = pstack-&amp;gt;topIndex
	pstack-&amp;gt;topIndex -=1   // pop 연산으로 topIndex 값 하나 감소
	
	return pstack-&amp;gt;stackArr[rIdx];
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SPeek&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732181850698&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Data SPeek(Stack *pstack)
{
	if(SIsEmpty(pstack))
	{
		printf(&quot;Stack Memory Error!&quot;);
		exit(-1);
	}
	
	return pstack-&amp;gt;stackArr[pstack-&amp;gt;topIndex];
}&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;3. 스택의 연결 리스트 기반 구현&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1. 연결 리스트 기반 스택의 논리와 헤더파일 정의&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;ldquo;스택도 연결 리스트이다. 다만 저장된 순서의 역순으로 조회가 가능한 연결 리스트&amp;rdquo;&lt;/li&gt;
&lt;li&gt;연결리스트 기반 스택 ADT&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732182688440&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typedef int Data;

typedef struct _node
{
	Data data;
	struct _node *next
} Node;

typedef struct _listStack
{
	Node *head;
} ListStack;

typedef ListStack Stack;

void StackInit(Stack *pstack);
int SIsEmpty(Stack *pstack);

void SPush(Stack *pstack, Data data);
Data SPop(Stack *pstack);
Data SPeek(Stack *pstack);&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;3.2. 연결 리스트 기반 스택의 구현&lt;/h4&gt;
&lt;pre id=&quot;code_1732182705914&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void StackInit(Stack *pstack)
{
	pstack-&amp;gt;head = NULL;
}

int SIsEmpty(Stack *pstack)
{
	if(pstack-&amp;gt;head == NULL)
		return TRUE;
	else
		return FALSE;
}

void SPush(Stack *pstack, Data data)
{
	Node * newNode = (Node*)malloc(sizeof(Node));
	
	newNode-&amp;gt;data = data;
	newNode-&amp;gt;next = pstack-&amp;gt;head;
	
	pstack-&amp;gt;head = newNode;
}

Data SPop(Stack *pstack)
{
	Data rdata;
	Node *rnode;
	
	if(SIsEmpty(pstack)){
		printf(&quot;Stack Memory Error!&quot;);
		exit(-1);
	}
	
	rdata = pstack-&amp;gt;head-&amp;gt;data; // 삭제할 노드의 데이터를 임시로 저장
	rnode = pstack-&amp;gt;head;    // 삭제할 노드의 주소 값을 임시로 저장
	
	pstack-&amp;gt;head = pstack-&amp;gt;head-&amp;gt;next;  // 삭제할 노드의 다음 노드를 head가 가리킴
	free(rnode);  // 노드 삭제
	return rdata;
}

Data SPeek(Stack *pstack)
{
	if(SIsEmpty(pstack)){
		printf(&quot;Stack Memory Error!&quot;);
		exit(-1);
	}
	
	return pstack-&amp;gt;head-&amp;gt;data;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 계산기 프로그램 구현&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.1. 계산기 프로그램의 성격&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;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.2. 수식의 표기법: 중위(infix), 전위(prefix), 후위(postfix) 표기법&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;중위 표기법: 5 + 2 / 7&lt;/li&gt;
&lt;li&gt;전위 표기법: + 5 / 2 7&lt;/li&gt;
&lt;li&gt;후위 표기법: 5 2 7 / +&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.3. 과정 1: 중위 표기법 &amp;rarr; 후위 표기법 - 괄호 X&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;연산자를 만나면 무조건 쟁반으로&lt;br /&gt;&lt;br /&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;590&quot; data-origin-height=&quot;148&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCDdBf/btsKSvGUaQx/GM9NrRxZHK79KZ9aKrDnok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCDdBf/btsKSvGUaQx/GM9NrRxZHK79KZ9aKrDnok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCDdBf/btsKSvGUaQx/GM9NrRxZHK79KZ9aKrDnok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCDdBf%2FbtsKSvGUaQx%2FGM9NrRxZHK79KZ9aKrDnok%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;590&quot; height=&quot;148&quot; data-origin-width=&quot;590&quot; data-origin-height=&quot;148&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;588&quot; data-origin-height=&quot;146&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/skKEi/btsKRgKV4us/kla7dBNNpcJ38qrn5p4VCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/skKEi/btsKRgKV4us/kla7dBNNpcJ38qrn5p4VCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/skKEi/btsKRgKV4us/kla7dBNNpcJ38qrn5p4VCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FskKEi%2FbtsKRgKV4us%2Fkla7dBNNpcJ38qrn5p4VCK%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;588&quot; height=&quot;146&quot; data-origin-width=&quot;588&quot; data-origin-height=&quot;146&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;587&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vlwgx/btsKSCMKDvp/map1EPeZoWUFCLkNa33w51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vlwgx/btsKSCMKDvp/map1EPeZoWUFCLkNa33w51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vlwgx/btsKSCMKDvp/map1EPeZoWUFCLkNa33w51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVlwgx%2FbtsKSCMKDvp%2Fmap1EPeZoWUFCLkNa33w51%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;587&quot; height=&quot;150&quot; data-origin-width=&quot;587&quot; data-origin-height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;/figure&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;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;/li&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;/li&gt;
&lt;/ul&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;589&quot; data-origin-height=&quot;153&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lbZOX/btsKSFCImg7/z1pKRLSP7p1fYcD2esRPO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lbZOX/btsKSFCImg7/z1pKRLSP7p1fYcD2esRPO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lbZOX/btsKSFCImg7/z1pKRLSP7p1fYcD2esRPO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlbZOX%2FbtsKSFCImg7%2Fz1pKRLSP7p1fYcD2esRPO1%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;589&quot; height=&quot;153&quot; data-origin-width=&quot;589&quot; data-origin-height=&quot;153&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;589&quot; data-origin-height=&quot;151&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbEBtW/btsKRm5h35c/EaI8EkbrRPVs8N0i2OlcWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbEBtW/btsKRm5h35c/EaI8EkbrRPVs8N0i2OlcWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbEBtW/btsKRm5h35c/EaI8EkbrRPVs8N0i2OlcWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbEBtW%2FbtsKRm5h35c%2FEaI8EkbrRPVs8N0i2OlcWk%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;589&quot; height=&quot;151&quot; data-origin-width=&quot;589&quot; data-origin-height=&quot;151&quot;/&gt;&lt;/span&gt;&lt;/figure&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;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;li&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;/li&gt;
&lt;li&gt;마지막까지 쟁반에 남아있는 연산자들은 하나씩 꺼내서 옮김&lt;/li&gt;
&lt;/ul&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;4.4. 과정 1: 중위 표기법 &amp;rarr; 후위 표기법 - 괄호 존재&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;549&quot; data-origin-height=&quot;213&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mKru4/btsKSuuszl2/XL8pIPB22EjCkrgn9Rk2Pk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mKru4/btsKSuuszl2/XL8pIPB22EjCkrgn9Rk2Pk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mKru4/btsKSuuszl2/XL8pIPB22EjCkrgn9Rk2Pk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmKru4%2FbtsKSuuszl2%2FXL8pIPB22EjCkrgn9Rk2Pk%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;549&quot; height=&quot;213&quot; data-origin-width=&quot;549&quot; data-origin-height=&quot;213&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;550&quot; data-origin-height=&quot;209&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UUAS7/btsKQ8lQYYV/w0RewJuGhqc1wFc6KZCCq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UUAS7/btsKQ8lQYYV/w0RewJuGhqc1wFc6KZCCq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UUAS7/btsKQ8lQYYV/w0RewJuGhqc1wFc6KZCCq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUUAS7%2FbtsKQ8lQYYV%2Fw0RewJuGhqc1wFc6KZCCq0%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;550&quot; height=&quot;209&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;209&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;545&quot; data-origin-height=&quot;210&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nkopn/btsKQwHE48d/pXtbk0r0VqBkxAuyEf3T8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nkopn/btsKQwHE48d/pXtbk0r0VqBkxAuyEf3T8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nkopn/btsKQwHE48d/pXtbk0r0VqBkxAuyEf3T8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnkopn%2FbtsKQwHE48d%2FpXtbk0r0VqBkxAuyEf3T8K%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;545&quot; height=&quot;210&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;210&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;545&quot; data-origin-height=&quot;234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2fvMO/btsKQOgRqJU/gUD8iNt3Ao4pr2DfiU3cCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2fvMO/btsKQOgRqJU/gUD8iNt3Ao4pr2DfiU3cCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2fvMO/btsKQOgRqJU/gUD8iNt3Ao4pr2DfiU3cCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2fvMO%2FbtsKQOgRqJU%2FgUD8iNt3Ao4pr2DfiU3cCK%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;545&quot; height=&quot;234&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;234&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;( 연산자&lt;/b&gt;는 &lt;b&gt;)연산자&lt;/b&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;551&quot; data-origin-height=&quot;216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c650pu/btsKRTPgQsI/9WTRnq2dEjjWRbAHvIkU50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c650pu/btsKRTPgQsI/9WTRnq2dEjjWRbAHvIkU50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c650pu/btsKRTPgQsI/9WTRnq2dEjjWRbAHvIkU50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc650pu%2FbtsKRTPgQsI%2F9WTRnq2dEjjWRbAHvIkU50%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;551&quot; height=&quot;216&quot; data-origin-width=&quot;551&quot; data-origin-height=&quot;216&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;544&quot; data-origin-height=&quot;215&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HQnVr/btsKRbQonVP/ndGaVl5u74u0LKp7Sx7jqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HQnVr/btsKRbQonVP/ndGaVl5u74u0LKp7Sx7jqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HQnVr/btsKRbQonVP/ndGaVl5u74u0LKp7Sx7jqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHQnVr%2FbtsKRbQonVP%2FndGaVl5u74u0LKp7Sx7jqk%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;544&quot; height=&quot;215&quot; data-origin-width=&quot;544&quot; data-origin-height=&quot;215&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;h4 data-ke-size=&quot;size20&quot;&gt;4.5. 중위 표기법 &amp;rarr; 후위 표기법 구현&lt;/h4&gt;
&lt;pre id=&quot;code_1732182900154&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int GetOpPrec(char op)
{
	switch(op)
	{
	case '*';
	case '/';
		return 5;  // 가장 높은 연산의 우선순위
	case '+';
	case '-';
		return 3;  // 중간 우선순위
	case '(';
		return 1;  // 가장 낮은 연산의 우선순위
	}
	
	return -1;   // 등록되지 않은 연산자임을 알림!
}

int WhoPrecOp(char op1, char op2)
{
	int op1Prec = GetOpPrec(op1);
	int op2Prec = GetOpPrec(op2);
	
	if(op1Prec &amp;gt; op2Prec)   // op1의 우선순위가 높은 경우
		return 1;
	else if(op1Prec &amp;lt; op2Prec)  // op2의 우선순위가 높은 경우
		return -1;
	else
		return 0;  // op1와 op2의 우선순위가 같다면
}

void ConvToRPNExp(char exp[])  // 후위 표기법의 수식으로 전환
{
  Stack stack;
	int expLen = strlen(exp);
	char * convExp = (char*)malloc(expLen+1);  // 변환된 수식을 담을 공간 마련
	
	int i, idx=0;
	char tok, popOp;
	
	memset(convExp, 0, sizeof(char)*expLen+1);  // 할당된 배열을 0으로 초기화
	StackInit(&amp;amp;stack);
	
	for(i=0; i&amp;lt;expLen; i++) {
		tok = exp[i];
		if(isdigit(tok))  // tok에 저장된 문자가 숫자인지 확인
		{
			convExp[idx++] = tok;  // 숫자이면 배열 conExp에 그냥 저장
		}
		else  // 숫자가 아니라면(연산자라면)
		{
			switch(tok)
			{
			case '(':  // 여는 소괄호라면
				SPush(&amp;amp;stack, tok);  // 스택에 쌓는다
				break;
			case ')':  // 닫는 소괄호라면
				while(1)  // 반복해서,
				{
					popOp = SPop(&amp;amp;stack);  // 스택에서 연산자를 꺼내어.
					if(popOp == '(')  // 연산자 ( 을 만날 때까지 
						break;
					convExp[idx++] = popOp;  
				}
				break;
			case '+': case '-':
			case '*': case '/':
			// 스택에 연산자가 존재하면서 먼저 연산되어야 하는 연산자가 남아있을때 까지
				while(!SIsEmpty(&amp;amp;stack) &amp;amp;&amp;amp; WhoPrecOp(SPeek(&amp;amp;stack), tok) &amp;gt;= 0) 
					conExp[idx++] = SPop(&amp;amp;stack);
				SPush(&amp;amp;stack, tok);
				break;
			}
		}
	}
	while(!SIsEmpty(&amp;amp;stack))  // 스택에 남아 있는 모든 연산자를,
		convExp[idx++] = SPop(&amp;amp;stack);  // 배열 conExp로 이동한다.
	
	strcpy(exp, convExp);  // 변환된 수식을 exp에 복사하고,
	free(convExp);  // conExp는 소멸시킨다.
}&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;4.6. 후위 표기법 수식 계산&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;li&gt;계산결과는 다시 스택에 넣는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732182926150&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int EvalRPExp(char exp[])
{
	Stack stack;
	int expLen = strlen(exp);
	int i;
	char tok, op1, op2;
	
	StackInit(&amp;amp;stack);
	
	for(i=0; i&amp;lt;expLen; i++)  // 수식을 구성하는 문자 각각을 대상으로 반복
	{ 
		tok = exp[i];  // 한 문자씩 tok에 저장하고
		if(isdigit(tok))  // 문자 내용이 정수인지 확인
		{
			SPush(&amp;amp;stack, tok - '0');  // 정tnaus 숫자로 변환후 스택에 PUSH
		}
		else
		{
			op2 = SPop(&amp;amp;stack);  // 스택에서 두번째 연산자 꺼냄
			op1 = SPop(&amp;amp;stack);  // 스택에서 첫번째 연산자 꺼냄
			
			switch(tok)
			{
			case '+':
				SPush(&amp;amp;stack, op1+op2);
				break;
			case '-':
				SPush(&amp;amp;stack, op1-op2);
				break;
			case '*':
				SPush(&amp;amp;stack, op1*op2);
				break;
			case '/':
				SPush(&amp;amp;stack, op1/op2);
				break;
			}
		}
	}
	return SPop(&amp;amp;stack);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 id=&quot;head52&quot; data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;윤성우의 열혈 자료구조 (윤성우 저, 2023.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/자료구조</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/50</guid>
      <comments>https://onyodev.tistory.com/50#entry50comment</comments>
      <pubDate>Thu, 21 Nov 2024 18:56:03 +0900</pubDate>
    </item>
    <item>
      <title>관계 데이터 연산</title>
      <link>https://onyodev.tistory.com/49</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 김연희 저 - &quot;데이터베이스 개론 3판&quot;을 공부하고 정리하여 작성하였습니다.&lt;/blockquote&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 data-ke-size=&quot;size26&quot;&gt;1. 관계 데이터 연산의 개념&lt;/h2&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;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;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;/li&gt;
&lt;li&gt;&lt;b&gt;관계 해석&lt;/b&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;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 관계 대수&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. 관계 대수의 개념과 연산자&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;/li&gt;
&lt;li&gt;일반 집합 연산자&amp;nbsp;&amp;nbsp;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 136px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 36px;&quot;&gt;
&lt;td style=&quot;height: 36px; width: 13.285%;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;연산자&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 36px; width: 8.9372%;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;기호&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 36px; width: 10.9903%;&quot;&gt;표현&lt;/td&gt;
&lt;td style=&quot;height: 36px; width: 66.6667%;&quot;&gt;의미&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;height: 25px; width: 13.285%;&quot;&gt;교집합&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 8.9372%;&quot;&gt;&amp;cap;&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 10.9903%;&quot;&gt;R &amp;cap; S&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 66.6667%;&quot;&gt;릴레이션 R과 S의 교집합을 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;height: 25px; width: 13.285%;&quot;&gt;차집합&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 8.9372%;&quot;&gt;－&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 10.9903%;&quot;&gt;R - S&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 66.6667%;&quot;&gt;릴레이션 R과 S의 차집합을 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;height: 25px; width: 13.285%;&quot;&gt;카디션 &lt;br /&gt;프로젝트&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 8.9372%;&quot;&gt;&amp;times;&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 10.9903%;&quot;&gt;R x S&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 66.6667%;&quot;&gt;릴레이션 R의 각 튜플과 릴레이션 S의 각 튜플을 모두 연결하여 만든 새로운 튜플 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;height: 25px; width: 13.285%;&quot;&gt;합집합&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 8.9372%;&quot;&gt;&amp;cup;&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 10.9903%;&quot;&gt;R &amp;cup; S&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 66.6667%;&quot;&gt;릴레이션 R과 S의 합집합을 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;li&gt;순수 관계 연산자&amp;nbsp; &amp;nbsp;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.57488%;&quot;&gt;연산자&lt;/td&gt;
&lt;td style=&quot;width: 9.66183%;&quot;&gt;기호&lt;/td&gt;
&lt;td style=&quot;width: 25.2416%;&quot;&gt;표현&lt;/td&gt;
&lt;td style=&quot;width: 56.401%;&quot;&gt;의미&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.57488%;&quot;&gt;셀렉트&lt;/td&gt;
&lt;td style=&quot;width: 9.66183%;&quot;&gt;&amp;sigma;&lt;/td&gt;
&lt;td style=&quot;width: 25.2416%;&quot;&gt;$\sigma_{\text{조건}}$(R)&lt;/td&gt;
&lt;td style=&quot;width: 56.401%;&quot;&gt;릴레이션 R에서 조건을 만족하는 튜플들을 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.57488%;&quot;&gt;프로젝트&lt;/td&gt;
&lt;td style=&quot;width: 9.66183%;&quot;&gt;&amp;pi;&lt;/td&gt;
&lt;td style=&quot;width: 25.2416%;&quot;&gt;$\pi_{\text{속성리스트}}$(R)&lt;/td&gt;
&lt;td style=&quot;width: 56.401%;&quot;&gt;릴레이션 R에서 주어진 속성들의 값으로만 구성된 튜플들을 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.57488%;&quot;&gt;조인&lt;/td&gt;
&lt;td style=&quot;width: 9.66183%;&quot;&gt;$\Join$&lt;/td&gt;
&lt;td style=&quot;width: 25.2416%;&quot;&gt;R $\Join$ S&lt;/td&gt;
&lt;td style=&quot;width: 56.401%;&quot;&gt;공통 속성을 이용해 릴레이션 R과 S의 튜플들을 연결하여 만든 새로운 튜플들을 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.57488%;&quot;&gt;디비전&lt;/td&gt;
&lt;td style=&quot;width: 9.66183%;&quot;&gt;&amp;divide;&lt;/td&gt;
&lt;td style=&quot;width: 25.2416%;&quot;&gt;R &amp;divide; S&lt;/td&gt;
&lt;td style=&quot;width: 56.401%;&quot;&gt;릴레이션 S의 모든 튜플과 관련이 있는 릴레이션 R의 튜플들을 반환&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;2.2. 일반 집합 연산자&lt;/h4&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: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;일반 집합 연산자는 연산을 위해 피연산자 2개가 필요함&lt;/li&gt;
&lt;li&gt;2개의 릴레이션이 합병 가능해야 함.
&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개의 릴레이션에서 서로 대응되는 속성의 도메인이 같다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;합집합&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;릴레이션 R에 속하거나 릴레이션 S에 속하는 모든 튜플로 결과 릴레이션을 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;교집합&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;릴레이션 R과 릴레이션 S에 공통으로 속하는 튜플로 결과 릴레이션을 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;차집합&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;릴레이션 R에는 존재하지만 릴레이션 S에는 존재하지 않는 튜플들로 결과 릴레이션을 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;카디션 프로덕트&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;릴레이션 R에 속한 각 튜플과 릴레이션 S에 속한 튜플을 모두 연결하여 만들어진 새로운 튜플로 결과 릴레이션을 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3. 순수 관계 연산자&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;셀렉트&lt;/b&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;표기: $\sigma_{\text{조건식}}$&lt;b&gt;(릴레이션)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;데이터 언어 형식: &lt;b&gt;릴레이션 where 조건식&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;조건식은 비교 연산자를 이용해 구성하는데 이를 비교식 또는 프레디킷(predicate)라 함&lt;/li&gt;
&lt;li&gt;교환적 특징을 가짐&lt;/li&gt;
&lt;li&gt;$\sigma_{\text{조건식1}}(\sigma_{\text{조건식2}}(릴레이션)) = \sigma_{\text{조건식2}}(\sigma_{\text{조건식1}}(릴레이션)) = \sigma_{\text{조건식1&amp;and;조건식2}}(릴레이션)$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로젝트&lt;/b&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;b&gt;$\pi_{\text{속성리스트}}$(릴레이션)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;데이터 언어 형식: &lt;b&gt;릴레이션[속성리스트]&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;조인&lt;/b&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;b&gt;릴레이션1&lt;/b&gt; $\Join$ &lt;b&gt;릴레이션2&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;일반적으로 동등 조인의 표기로 사용되며 그 외의 조인은 조금씩 다르게 표기&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세타 조인(theta-join)&lt;/b&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;릴레이션1&lt;/b&gt; $\Join_{\text{A&amp;theta;B}}$ &lt;b&gt;릴레이션2&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&amp;theta;(theta)에는 비교연산자가 들어가는데 &lt;b&gt;&amp;theta; 연산자가 =인 조인이 동등 조인&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자연 조인(Natural-join)&lt;/b&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;릴레이션1&lt;/b&gt; $\Join_{\text{N}}$ &lt;b&gt;릴레이션2&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디비전&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;S의 모든 튜플과 관련 있는 릴레이션 R의 튜플로 결과 릴레이션을 구성&lt;/li&gt;
&lt;li&gt;릴레이션 R이 릴레이션 S의 모든 속성을 포함하고 있어야 연산이 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.4. 확장된 관계 대수 연산자&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;세미 조인($R \ltimes S$ )
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;릴레이션 S의 조인 속성으로만 구성한 릴레이션을 릴레이션 R에 자연 조인&lt;/li&gt;
&lt;li&gt;결과적으로 자연 조인 연산에 참여할 수 있는 튜플만 선택해 결과 릴레이션 구성&lt;/li&gt;
&lt;li&gt;세미 조인을 활용하면 검색에 불필요한 속성을 미리 제거하여 비용을 줄일 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;외부 조인($R \Join_{\text{outer}} S$ )
&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;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 관계 해석&lt;/h2&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;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;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스 개론 3판 (김연희 저, 2024.1)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/데이터베이스</category>
      <category>computer science</category>
      <category>관계대수</category>
      <category>관계연산자</category>
      <category>데이터베이스</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/49</guid>
      <comments>https://onyodev.tistory.com/49#entry49comment</comments>
      <pubDate>Thu, 21 Nov 2024 18:34:24 +0900</pubDate>
    </item>
    <item>
      <title>관계 데이터 모델</title>
      <link>https://onyodev.tistory.com/48</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 김연희 저 - &quot;데이터베이스 개론 3판&quot;을 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 관계 데이터 모델의 개념&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;관계 데이터 모델은 하나의 개체에 대한 데이터를 &lt;b&gt;릴레이션(relation)&lt;/b&gt; 하나에 담아 데이터베이스에 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1. 관계 데이터 모델의 기본 용어&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;속성&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;릴레이션의 열을 속성 또는 attribute라고 함.&lt;/li&gt;
&lt;li&gt;릴레이션이 파일 관리 시스템의 파일을 말한다면, 속성은 해당 파일의 &lt;b&gt;필드(field)&lt;/b&gt;에 대응&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;튜플&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;릴레이션의 행을 튜플(tuple)이라 부름&lt;/li&gt;
&lt;li&gt;튜플은 파일 관리 시스템 관점에서 해당 파일의 &lt;b&gt;레코드(record)&lt;/b&gt;에 대응함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;도메인&lt;/b&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;li&gt;그래서 속성이 가질 수 있는 모든 원자 값의 모임이라 정의함&lt;/li&gt;
&lt;li&gt;도메인의 모든 값을 일일이 나열해 정의하기 어려운 경우 &lt;b&gt;데이터 타입으로 정의&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;데이터 타입을 도메인, 변수를 속성이라 생각하면 이해가 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;널 값&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;릴레이션에 있는 특정 튜플 속성 값을 모르거나 적합한 값이 없는 경우를 널(Null) 값으로 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;차수&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;하나의 릴레이션에서 속성의 전체 개수를 차수(degree)라 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;카디널리티&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;하나의 릴레이션에서 튜플의 전체 개수를 카디널리티(cardinality)라 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2. 릴레이션과 데이터베이스의 구성&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;릴레이션 스키마&lt;/b&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;/ul&gt;
릴레이션이름(속성이름1, 속성이름2, &amp;hellip; 속성이름n)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;릴레이션 스키마는 릴레이션 내포(relation intension)라고 부름&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;릴레이션 인스턴스&lt;/b&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;li&gt;릴레이션 인스턴스를 보면 릴레이션 실제 내용을 파악할 수 있고 내부적으로 데이터베이스 관리 시스템이 데이터 조작어를 이용해 릴레이션 인스턴스를 조작함&lt;/li&gt;
&lt;li&gt;릴레이션 인스턴스는 간단히 릴레이션 혹은 릴레이션 외연(relation extension)이라 부름&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터베이스 스키마와 데이터베이스 인스턴스&lt;/b&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;li&gt;데이터베이스 인스턴스는 특정 시점에 데이터베이스에서 저장된 데이터 내용의 전체 집합을 의미함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3. 릴레이션의 특성&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&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;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.4. 키의 종류&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;슈퍼키&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;후보키&lt;/b&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;li&gt;슈퍼키 중에서 최소성을 만족하는 키가 후보키가 될 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기본키&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;여러 후보키 중 기본적으로 사용할 키를 반드시 선택해야 하는데 이것이 &lt;b&gt;기본키(primary key)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;기본키를 선택할 때 고려되는 기준
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;널 값을 가질 수 있는 속성이 포함된 후보키는 부적합 ex) 입력하지 않아도 되는 속성&lt;/li&gt;
&lt;li&gt;값이 자주 변경될 수 있는 속성이 포함된 후보키는 부적합 ex) 주소&lt;/li&gt;
&lt;li&gt;단순한 후보키를 기본키로 선택, 주로 정수나 단순 문자열을 선택한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;대체키&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;외래키&lt;/b&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;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 관계 데이터 모델의 제약&lt;/h2&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;무결성(integrity)&lt;/b&gt;: 데이터에 결함이 없는 상태, 즉 데이터가 정확하고 유효하게 유지된 상태&lt;/li&gt;
&lt;li&gt;무결성 제약조건의 주요 목적은 데이터베이스에 저장된 데이터의 무결성을 보장하고 데이터베이스의 상태를 일관되게 유지하는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. 개체 무결성 제약조건&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;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. 참조 무결성 제약조건&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;/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;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스 개론 3판 (김연희 저, 2024.1)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/데이터베이스</category>
      <category>computer  science</category>
      <category>관계데이터모델</category>
      <category>데이터베이스</category>
      <category>오블완</category>
      <category>키의종류</category>
      <category>티스토리챌린지</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/48</guid>
      <comments>https://onyodev.tistory.com/48#entry48comment</comments>
      <pubDate>Thu, 21 Nov 2024 18:23:08 +0900</pubDate>
    </item>
    <item>
      <title>연결 리스트(Linked List) 3</title>
      <link>https://onyodev.tistory.com/47</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 윤성우 저 - &quot;윤성우의 열혈 자료구조&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 원형 연결 리스트(Circular Linked List)&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1. 원형 연결 리스트의 이해&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;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;206&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOjsSN/btsKQ52vzQS/xzpc8YwZOqjyVcjkxZ5RJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOjsSN/btsKQ52vzQS/xzpc8YwZOqjyVcjkxZ5RJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOjsSN/btsKQ52vzQS/xzpc8YwZOqjyVcjkxZ5RJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOjsSN%2FbtsKQ52vzQS%2Fxzpc8YwZOqjyVcjkxZ5RJ0%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;479&quot; height=&quot;206&quot; data-origin-width=&quot;479&quot; data-origin-height=&quot;206&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로운 숫자 1을 머리에 추가하는 경우와 꼬리에 추가하는 경우는 각각 이렇다.&lt;/li&gt;
&lt;li&gt;서로 연결되어 있기 때문에 머리와 꼬리의 구분이 없다고도 한다.&lt;/li&gt;
&lt;li&gt;하지만 변수 head가 가리키는 노드가 다르다.&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;578&quot; data-origin-height=&quot;226&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KwGpV/btsKQuV2i0f/VAmCWwi5asknuDgOMbVaE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KwGpV/btsKQuV2i0f/VAmCWwi5asknuDgOMbVaE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KwGpV/btsKQuV2i0f/VAmCWwi5asknuDgOMbVaE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKwGpV%2FbtsKQuV2i0f%2FVAmCWwi5asknuDgOMbVaE1%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;578&quot; height=&quot;226&quot; data-origin-width=&quot;578&quot; data-origin-height=&quot;226&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;581&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDrcxD/btsKQHgp9ot/UkiZGoJY5fWz5bJmAPlr10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDrcxD/btsKQHgp9ot/UkiZGoJY5fWz5bJmAPlr10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDrcxD/btsKQHgp9ot/UkiZGoJY5fWz5bJmAPlr10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDrcxD%2FbtsKQHgp9ot%2FUkiZGoJY5fWz5bJmAPlr10%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;581&quot; height=&quot;222&quot; data-origin-width=&quot;581&quot; data-origin-height=&quot;222&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2. 변형된 연결 리스트&lt;/h4&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;꼬리를 가리키는 포인터 변수 &amp;rarr; tail&lt;/li&gt;
&lt;li&gt;머리를 가리키는 포인터 변수 &amp;rarr; tail&amp;rarr;next&lt;/li&gt;
&lt;/ul&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;615&quot; data-origin-height=&quot;240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bA7vT7/btsKRhuPb1l/mlfG5FiukDgAap24yIjyt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bA7vT7/btsKRhuPb1l/mlfG5FiukDgAap24yIjyt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bA7vT7/btsKRhuPb1l/mlfG5FiukDgAap24yIjyt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbA7vT7%2FbtsKRhuPb1l%2FmlfG5FiukDgAap24yIjyt0%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;615&quot; height=&quot;240&quot; data-origin-width=&quot;615&quot; data-origin-height=&quot;240&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3. 변형된 원형 연결 리스트의 헤더파일&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LNext 함수는 무한 반복 호출이 가능하며 리스트의 끝에 도달할 경우 첫번째 노드부터 다시 조회 가능&lt;/li&gt;
&lt;li&gt;그리고 삽입 함수를 두 가지로 나눔.&lt;/li&gt;
&lt;li&gt;원형 연결 리스트의 ADT&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732090982553&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typdef int Data;

typedef struct _node
{
	Data data;
	struct_node *next;
} Node;

typedef struct _CLL
{
	Node * tail;
	Node * cur;
	Node * before;
	int numOfData;
} CList;

typedef CList List;

void ListInit(List *plist);
void LInsert(List (*plist, Data data);  // 꼬리에 노드 추가
void LInsertFront(List *plist, Data data);  // 머리에 노드 추가

int LFirst(List *plist, Data * pdata);
int LNext(List *plist, Data * pdata);
Data LRemove(List *plist);
int LCount(List *plist);&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.4. 변형된 원형 연결 리스트의 구현&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리스트의 초기화와 노드 삽입
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;초기화&amp;nbsp;&lt;/li&gt;
&lt;li&gt;노드 삽입&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732091074158&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void ListInit(List *plist)
{
	plist-&amp;gt;tail = NULL;
	plist-&amp;gt;cur = NULL;
	plist-&amp;gt;before = NULL;
	plist-&amp;gt;numOfData = 0;
}&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;585&quot; data-origin-height=&quot;204&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FTpzW/btsKPFRtXRC/Z2SyaERsPww8z4Lc1ZK55k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FTpzW/btsKPFRtXRC/Z2SyaERsPww8z4Lc1ZK55k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FTpzW/btsKPFRtXRC/Z2SyaERsPww8z4Lc1ZK55k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFTpzW%2FbtsKPFRtXRC%2FZ2SyaERsPww8z4Lc1ZK55k%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;585&quot; height=&quot;204&quot; data-origin-width=&quot;585&quot; data-origin-height=&quot;204&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1732091261000&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void LInsert~(List *plist, Data data)
{
	Node * newNode = (Node*)malloc(sizeof(Node)); // 새 노드 생성 후 데이터 저장
	newNode-&amp;gt;data = data;
	
	if(plist-&amp;gt;tail == NULL) // 첫번째 노드 삽입
	{
		plist-&amp;gt;tail = newNode; // tail이 새 노드를 가리키게 함
		newNode-&amp;gt;next = newNode; // 새 노드 자신을 가리키게 함
	}
	else
	{
		// LInsert와 LInsertFront의 차이..
	}
	
	(plist-&amp;gt;numOfData)++;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;LInsertFront&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;263&quot; data-origin-height=&quot;168&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dozz3l/btsKO8zNrQe/iaHy2jCKtqsYL5XETfaxp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dozz3l/btsKO8zNrQe/iaHy2jCKtqsYL5XETfaxp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dozz3l/btsKO8zNrQe/iaHy2jCKtqsYL5XETfaxp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdozz3l%2FbtsKO8zNrQe%2FiaHy2jCKtqsYL5XETfaxp0%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;263&quot; height=&quot;168&quot; data-origin-width=&quot;263&quot; data-origin-height=&quot;168&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;363&quot; data-origin-height=&quot;169&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDYmr6/btsKQ8ZcCnY/rzGLsN51IKrjOfuvKk629K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDYmr6/btsKQ8ZcCnY/rzGLsN51IKrjOfuvKk629K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDYmr6/btsKQ8ZcCnY/rzGLsN51IKrjOfuvKk629K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDYmr6%2FbtsKQ8ZcCnY%2FrzGLsN51IKrjOfuvKk629K%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;363&quot; height=&quot;169&quot; data-origin-width=&quot;363&quot; data-origin-height=&quot;169&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1732091273660&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// else 이하 부분 코드

newNode-&amp;gt;next = plist-&amp;gt;tail-&amp;gt;next;  // 새 노드와 4가 저장된 노드 연결
plist-&amp;gt;tail-&amp;gt;next = newNode;  // 2가 저장된 노드와 새 노드 연결&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;LInsert&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;312&quot; data-origin-height=&quot;272&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ddxPYX/btsKQy5aAGa/ktccgArsaAAmXEsvFkpsM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ddxPYX/btsKQy5aAGa/ktccgArsaAAmXEsvFkpsM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ddxPYX/btsKQy5aAGa/ktccgArsaAAmXEsvFkpsM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FddxPYX%2FbtsKQy5aAGa%2FktccgArsaAAmXEsvFkpsM1%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;312&quot; height=&quot;272&quot; data-origin-width=&quot;312&quot; data-origin-height=&quot;272&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1732091282683&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// else 이하 부분 코드

newNode-&amp;gt;next = plist-&amp;gt;tail-&amp;gt;next;
plist-&amp;gt;tail-&amp;gt;next = newNode;
plist-&amp;gt;tail = newNode;  // LInsertFront 함수와의 유일한 차이점&lt;/code&gt;&lt;/pre&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;/ul&gt;
&lt;pre id=&quot;code_1732091347646&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typedef struct _CLL
{
	Node * tail;
	Node * cur;
	Node * before;
	int numOfData;
} CList;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;구조체의 멤버 cur과 before의 역할은 단순 연결 리스트와 동일&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;687&quot; data-origin-height=&quot;247&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0V0Gv/btsKRm3Zg5V/a8SczsHGlVoVHXDfvC1fA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0V0Gv/btsKRm3Zg5V/a8SczsHGlVoVHXDfvC1fA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0V0Gv/btsKRm3Zg5V/a8SczsHGlVoVHXDfvC1fA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0V0Gv%2FbtsKRm3Zg5V%2Fa8SczsHGlVoVHXDfvC1fA1%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;687&quot; height=&quot;247&quot; data-origin-width=&quot;687&quot; data-origin-height=&quot;247&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1732091384195&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int LFirst(List *plist, Data pdata)
{
	if(plist-&amp;gt;tail == NULL)   // 저장된 노드가 없다면
		return FALSE;
		
	plist-&amp;gt;before = plist-&amp;gt;tail;   // before가 꼬리를 가리켜야 함
	plist-&amp;gt;cur = plist-&amp;gt;tail-&amp;gt;next;  // cur이 머리를 가리키게 함
	
	*pdata = plist-&amp;gt;cur-&amp;gt;data;  // cur이 가리키는 노드의 데이터 반환
	return TRUE;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/B2Urk/btsKQHnbnZk/xp6GfIGGZgJnKiSrkgWK5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/B2Urk/btsKQHnbnZk/xp6GfIGGZgJnKiSrkgWK5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/B2Urk/btsKQHnbnZk/xp6GfIGGZgJnKiSrkgWK5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FB2Urk%2FbtsKQHnbnZk%2Fxp6GfIGGZgJnKiSrkgWK5K%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;692&quot; height=&quot;252&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1732091403042&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int LNext(List *plist, Data *pdata)
{
	if(plist-&amp;gt;tail == NULL)   // 저장된 노드가 없다면
		return FALSE;
		
	plist-&amp;gt;before = plist-&amp;gt;cur;   // before가 다음 노드를 가리키게 함
	plist-&amp;gt;cur = plist-&amp;gt;cur-&amp;gt;next;  // cur이 다음 노드를 가리키게 함
	
	*pdata = plist-&amp;gt;cur-&amp;gt;data;  // cur이 가리키는 노드 데이터 반환
	return TRUE;
}&lt;/code&gt;&lt;/pre&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: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;삭제는 대부분의 경우 상대적으로 복잡한 편&lt;/li&gt;
&lt;li&gt;삭제할 노드의 이전 노드가 삭제할 노드의 다음 노드를 가리키게 한다.&lt;/li&gt;
&lt;li&gt;포인터 변수 cur을 한칸뒤로 이동시킨다.&lt;/li&gt;
&lt;li&gt;삭제할 노드가 tail인 경우의 예외도 포함시켜 줌&lt;/li&gt;
&lt;/ul&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;678&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csxTLO/btsKQ6UDQRB/N7vjaDxlk7EEfpCaHnTgz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csxTLO/btsKQ6UDQRB/N7vjaDxlk7EEfpCaHnTgz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csxTLO/btsKQ6UDQRB/N7vjaDxlk7EEfpCaHnTgz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcsxTLO%2FbtsKQ6UDQRB%2FN7vjaDxlk7EEfpCaHnTgz0%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;678&quot; height=&quot;225&quot; data-origin-width=&quot;678&quot; data-origin-height=&quot;225&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;704&quot; data-origin-height=&quot;315&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvcF3A/btsKRf4Y99O/ko8s8xP4LPrzFd4fFK8zMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvcF3A/btsKRf4Y99O/ko8s8xP4LPrzFd4fFK8zMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvcF3A/btsKRf4Y99O/ko8s8xP4LPrzFd4fFK8zMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvcF3A%2FbtsKRf4Y99O%2Fko8s8xP4LPrzFd4fFK8zMK%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;704&quot; height=&quot;315&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;315&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1732091485741&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Data LRemove(List *plist)
{
	Node * rpos = plist-&amp;gt;cur;
	Data rdata = rpos-&amp;gt;data;
	
	if(rpos == plist-&amp;gt;tail)  // 삭제 대상을 tail이 가르키면
	{
		if(plist-&amp;gt;tail == plist-&amp;gt;tail-&amp;gt;next)
			plist-&amp;gt;tail = NULL;
		else
			plist-&amp;gt;tail = plist-&amp;gt;before;
	}
	
	plist-&amp;gt;before-&amp;gt;next = plist-&amp;gt;cur-&amp;gt;next;
	plist-&amp;gt;cur = plist-&amp;gt;before
	
	free(rpos);
	(plist-&amp;gt;numOfData)--;
	return rdata;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 양방향 연결 리스트&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. 양방향 연결 리스트의 이해&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;627&quot; data-origin-height=&quot;163&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ppRXo/btsKPdVxG0R/opX600XDh4I6w0lKC8PSO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ppRXo/btsKPdVxG0R/opX600XDh4I6w0lKC8PSO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ppRXo/btsKPdVxG0R/opX600XDh4I6w0lKC8PSO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FppRXo%2FbtsKPdVxG0R%2FopX600XDh4I6w0lKC8PSO1%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;627&quot; height=&quot;163&quot; data-origin-width=&quot;627&quot; data-origin-height=&quot;163&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1732091510820&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typedef struct _node
{
	Data data;
	struct _node * next;  // 오른쪽 노드를 가리키는 포인터 변수
	struct _node * prev;
} Node&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;814&quot; data-origin-height=&quot;182&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cj5kaW/btsKPdOMpVF/UTHSAZRFK1jTgEJgaGhKIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cj5kaW/btsKPdOMpVF/UTHSAZRFK1jTgEJgaGhKIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cj5kaW/btsKPdOMpVF/UTHSAZRFK1jTgEJgaGhKIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcj5kaW%2FbtsKPdOMpVF%2FUTHSAZRFK1jTgEJgaGhKIK%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;814&quot; height=&quot;182&quot; data-origin-width=&quot;814&quot; data-origin-height=&quot;182&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;668&quot; data-origin-height=&quot;210&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cshSbH/btsKQawDXMl/vJCC56LCKKf4mtkQVmtjV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cshSbH/btsKQawDXMl/vJCC56LCKKf4mtkQVmtjV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cshSbH/btsKQawDXMl/vJCC56LCKKf4mtkQVmtjV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcshSbH%2FbtsKQawDXMl%2FvJCC56LCKKf4mtkQVmtjV0%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;668&quot; height=&quot;210&quot; data-origin-width=&quot;668&quot; data-origin-height=&quot;210&quot;/&gt;&lt;/span&gt;&lt;/figure&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;h4 data-ke-size=&quot;size20&quot;&gt;2.2. 양방향 연결 리스트 헤더파일&lt;/h4&gt;
&lt;pre id=&quot;code_1732091544218&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typdef int Data;

typedef struct _node
{
	Data data;
	struct _node * next;
	struct _node * prev;
} Node;

typedef struct _DLinkedList
{
	Node * head;
	Node * cur;
	int numOfData;
} DBLinkedList;

typedef DBLinkedList List;

void ListInit(List *plist);
void LInsert(List (*plist, Data data);

int LFirst(List *plist, Data * pdata);
int LNext(List *plist, Data * pdata);
int LPrevios(List *plist, Data * pdata);  // LNext 함수의 반대 방향 노드 참조
int LCount(List *plist);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3. 양방향 연결 리스트의 구현&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;/ul&gt;
&lt;pre id=&quot;code_1732091567033&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void ListInit(List *plist)
{
	plist-&amp;gt;head = NULL;
	plist-&amp;gt;numOfData = 0;
}&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;701&quot; data-origin-height=&quot;365&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMrHg8/btsKQeFVaj0/qybIfNPVH7JKdAO2LvPxNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMrHg8/btsKQeFVaj0/qybIfNPVH7JKdAO2LvPxNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMrHg8/btsKQeFVaj0/qybIfNPVH7JKdAO2LvPxNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMrHg8%2FbtsKQeFVaj0%2FqybIfNPVH7JKdAO2LvPxNK%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;701&quot; height=&quot;365&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;365&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1732091606130&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void LInsert(List *plist, Data data) // 첫번째 노드 추가 과정
{
	Node * newNode = (Node*)malloc(sizeof(Node));
	newNode-&amp;gt;data = data;
	
	// 아래 문장에서 plist-&amp;gt;head는 NULL이다
	newNode-&amp;gt;next = plist-&amp;gt;head;  // 새 노드의 next를 NULL로 초기화
	newNode-&amp;gt;prev = NULL;         // 새 노드의 prev를 NULL로 초기화
	plist-&amp;gt;head = newNode;        // 포인터 변수 head가 새 노드 가리키게 함
	
	(plist-&amp;gt;numOfData)++; 
}

void LInsert(List *plist, Data data) // 두번째 이후 노드 추가 과정
{
	Node * newNode = (Node*)malloc(sizeof(Node));
	newNode-&amp;gt;data = data;
	
	newNode-&amp;gt;next = plist-&amp;gt;head;
	if(plist-&amp;gt;head != NULL)
		plist-&amp;gt;head-&amp;gt;prev = newNode;
		  
	newNode-&amp;gt;prev = NULL;         
	plist-&amp;gt;head = newNode;        
	
	(plist-&amp;gt;numOfData)++; 
}&lt;/code&gt;&lt;/pre&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: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;LFirst와 LNext는 단방향 연결 리스트와 차이가 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732091630918&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int LFirst(List *plist, Data *pdata)
{
	if(plist-&amp;gt;head  == NULL)
		return FALSE;
		
	plist-&amp;gt;cur = plist-&amp;gt;head  // cur이 첫번째 노드를 가리킴
	*pdata = plist-&amp;gt;cur-&amp;gt;data // cur이 가리키는 노드의 데이터 반환
	return TRUE;
}

int LNext(List *plist, Data *pdata)
{
	if(plist-&amp;gt;cur-&amp;gt;next == NULL)
		return FALSE;
		
	plist-&amp;gt;cur = plist-&amp;gt;cur-&amp;gt;next;  // cur을 오른쪽으로 이동
	*pdata = plist-&amp;gt;cur-&amp;gt;data  // cur이 가리키는 노드의 데이터 반환
	return TRUE;
}

int LPrevious(List *plist, Data *pdata)
{
	if(plist-&amp;gt;cur-&amp;gt;prev == NULL)
		return FALSE;
		
	plist-&amp;gt;cur = plist-&amp;gt;cur-&amp;gt;prev; // cur을 왼쪽으로 이동
	*pdata = plist-&amp;gt;cur-&amp;gt;data  // cur이 가리키는 노드의 데이터 반환
	return TRUE; 
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 id=&quot;head52&quot; data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;윤성우의 열혈 자료구조 (윤성우 저, 2023.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/자료구조</category>
      <category>computer science</category>
      <category>양방향 연결 리스트</category>
      <category>오블완</category>
      <category>자료구조</category>
      <category>티스토리챌린지</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/47</guid>
      <comments>https://onyodev.tistory.com/47#entry47comment</comments>
      <pubDate>Wed, 20 Nov 2024 17:34:37 +0900</pubDate>
    </item>
    <item>
      <title>연결 리스트(Linked List) 2</title>
      <link>https://onyodev.tistory.com/46</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 윤성우 저 - &quot;윤성우의 열혈 자료구조&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 연결 리스트의 개념적 이해&lt;/h2&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;1.1. 어떤 것을 연결하는 것인가&lt;/h4&gt;
&lt;pre id=&quot;code_1731901344312&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typedef struct _node
{
int data; // 데이터를 담을 공간
struct _node * next; // 연결의 도구!
} Node;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 구조체 멤버 &lt;b&gt;next&lt;/b&gt;는 Node형 구조체 변수의 주소값을 저장할 수 있는 포인터 변수&lt;/li&gt;
&lt;li&gt;구조체의 첫번째 멤버 data에 값을 저장할 수 있음을 근거로 함&lt;/li&gt;
&lt;li&gt;next는 구조체 변수와 구조체 변수를 연결할 목적으로 선언되었고 next를 통해 모든 Node형 구조체 변수는 다른 Node형 구조체 변수를 가리킬 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;435&quot; data-origin-height=&quot;226&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0uuc6/btsKMHgKXsP/ShZszjot9fmbCYbol098z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0uuc6/btsKMHgKXsP/ShZszjot9fmbCYbol098z1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0uuc6/btsKMHgKXsP/ShZszjot9fmbCYbol098z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0uuc6%2FbtsKMHgKXsP%2FShZszjot9fmbCYbol098z1%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;435&quot; height=&quot;226&quot; data-origin-width=&quot;435&quot; data-origin-height=&quot;226&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;111&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KoBDi/btsKLj2o1za/Jyc3Kn6npzLuS1OQKwe5L0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KoBDi/btsKLj2o1za/Jyc3Kn6npzLuS1OQKwe5L0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KoBDi/btsKLj2o1za/Jyc3Kn6npzLuS1OQKwe5L0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKoBDi%2FbtsKLj2o1za%2FJyc3Kn6npzLuS1OQKwe5L0%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;512&quot; height=&quot;111&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;111&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2. 연결 리스트에서의 데이터 삽입&lt;/h4&gt;
&lt;pre id=&quot;code_1731901429143&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int main(void)
{
	Node * head = NULL;  // 리스트의 머리를 가리키는 포인터 변수
	Node * tail = NULL;  // 리스트의 꼬리를 가리키는 포인터 변수
	Node * cur = NULL;   // 저장된 데이터의 조회에 사용되는 포인터 변수
	
	Node * newNode = NULL;
	int readData;

	while(1)
	{
		printf(&quot;자연수 입력: &quot;);
		scanf(&quot;%d&quot;, &amp;amp;readData);
		if(readData &amp;lt; 1)
			break;
		
		// 노드의 추가과정
		newNode = (Node*)malloc(sizeof(Node));   // 노드의 생성
		newNode-&amp;gt;data = readData;   // 노드에 데이터 저장
		newNode-&amp;gt;next = NULL;       // 노드의 next를 NULL로 초기화
		
		if(head == NULL)  // 첫번째 노드인 경우
			head = newNode; // 첫번째 노드를 head가 가리키게 함
		else    
			tail-&amp;gt;next = newNode;
		tail = newNode  // 노드의 끝을 tail이 가리키게 함
	
	}&lt;/code&gt;&lt;/pre&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;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;180&quot; data-origin-height=&quot;120&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brgXw3/btsKNcOazgw/LoDSHMRdGfQyC42guwFZf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brgXw3/btsKNcOazgw/LoDSHMRdGfQyC42guwFZf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brgXw3/btsKNcOazgw/LoDSHMRdGfQyC42guwFZf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrgXw3%2FbtsKNcOazgw%2FLoDSHMRdGfQyC42guwFZf1%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;180&quot; height=&quot;120&quot; data-origin-width=&quot;180&quot; data-origin-height=&quot;120&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt; &lt;span data-token-index=&quot;0&quot;&gt;두번째 노드 추가완료&lt;/span&gt; &lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;283&quot; data-origin-height=&quot;144&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b85Y1h/btsKNWD70QF/ygBCmllHLsULUY665YRSWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b85Y1h/btsKNWD70QF/ygBCmllHLsULUY665YRSWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b85Y1h/btsKNWD70QF/ygBCmllHLsULUY665YRSWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb85Y1h%2FbtsKNWD70QF%2FygBCmllHLsULUY665YRSWK%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;283&quot; height=&quot;144&quot; data-origin-width=&quot;283&quot; data-origin-height=&quot;144&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt; &lt;span data-token-index=&quot;0&quot;&gt;다수의 노드를 추가한 결과&lt;/span&gt; &lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;412&quot; data-origin-height=&quot;121&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/co0UOb/btsKL2lI7hA/Dhkana1TtS7NwkqC9cDkHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/co0UOb/btsKL2lI7hA/Dhkana1TtS7NwkqC9cDkHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/co0UOb/btsKL2lI7hA/Dhkana1TtS7NwkqC9cDkHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fco0UOb%2FbtsKL2lI7hA%2FDhkana1TtS7NwkqC9cDkHk%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;412&quot; height=&quot;121&quot; data-origin-width=&quot;412&quot; data-origin-height=&quot;121&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3. 연결 리스트에서의 데이터 조회&lt;/h4&gt;
&lt;pre id=&quot;code_1731901664797&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if(head == NULL)
{
	printf(&quot;저장된 자연수가 존재하지 않습니다. \n&quot;);
}
else
{
	cur = head;  // cur이 리스트의 첫번째 노드를 가리킨다
	printf(&quot;%d &quot;, cur-&amp;gt;data);  // 첫번째 데이터 출력
	
	while(cur-&amp;gt;next != NULL)  // 연결된 노드가 존재한다면
	{
		cur = cur-&amp;gt;next;  // cur이 다음 노드를 가리키게 한다.
		printf(&quot;%d &quot;, cur-&amp;gt;data); 
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wmTOK/btsKMMPY4Hs/gCF1oq3Nkk1XlZ1RtWuiRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wmTOK/btsKMMPY4Hs/gCF1oq3Nkk1XlZ1RtWuiRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wmTOK/btsKMMPY4Hs/gCF1oq3Nkk1XlZ1RtWuiRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwmTOK%2FbtsKMMPY4Hs%2FgCF1oq3Nkk1XlZ1RtWuiRK%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;495&quot; height=&quot;228&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;228&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.4. 연결 리스트에서의 데이터 삭제&lt;/h4&gt;
&lt;pre id=&quot;code_1731901727279&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if(head == NULL)
{
	return 0;  // 삭제할 노드가 존재하지 않음
}
else
{
	Node * delNode = head;  
	Node * delNextNode = head-&amp;gt;next;
	
	printf(&quot;%d을 삭제\n&quot;, head-&amp;gt;data);
	free(delNode);  // 첫번째 노드 삭제
	while(delNextNode != NULL)  // 두번째 노드 삭제
	{
		delNode = delNextNode;
		delNextNode = delNextNode-&amp;gt;next;
		printf(&quot;%d을 삭제\n&quot;, delNode-&amp;gt;data);
		free(delNode);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;delNextNode라는 포인터 변수를 둬 &amp;lsquo;삭제될 노드&amp;rsquo;를 가리키는 다음 노드 주소값을 저장하는 이유는 head가 가리키는 노드를 그냥 지우면 그 다음 노드 정보를 아는 노드가 없어져 갈 수가 없게 됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfopNk/btsKK96QP1K/7GU39Xw2LiBsbkeysq8iGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfopNk/btsKK96QP1K/7GU39Xw2LiBsbkeysq8iGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfopNk/btsKK96QP1K/7GU39Xw2LiBsbkeysq8iGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfopNk%2FbtsKK96QP1K%2F7GU39Xw2LiBsbkeysq8iGk%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;498&quot; height=&quot;224&quot; data-origin-width=&quot;498&quot; data-origin-height=&quot;224&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;h2 data-ke-size=&quot;size26&quot;&gt;2. 단순 연결 리스트의 ADT 구현&lt;/h2&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;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. 정렬 기능이 추가된 연결 리스트의 ADT 정의&lt;/h4&gt;
&lt;pre id=&quot;code_1731901785927&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void ListInit(List *plist);
- 초기화할 리스트의 주소 값을 인자로 전달
- 리스트 생성 후 제일 먼저 호출되어야 하는 함수

void LInsert(List *plist, LData data);
- 리스트에 데이터를 저장함. 매개변수 data에 전달된 값을 저장

int LFirst(List *plist, LData *pdata);
- 첫번째 데이터가 pdata가 가르키는 메모리에 저장된다
- 데이터의 참조를 위한 초기화가 진행된다.
- 참조 성공 시 TRUE, 실패 시 FALSE 반환
 
int LNext(List *plist, LData *pdata);
- 참조된 데이터의 다음 데이터가 pdata가 가리키는 메모리에 저장된다.
- 순차적인 참조를 위해서 반복 호출이 가능하다.
- 참조를 새로 시작하려면 먼저 LFirst 함수를 호출해야 함
- 참조 성공 시 TRUE, 실패 시 FALSE 반환

LData LRemove(List *plist, LData target);
- LFirst 또는 LNext 함수의 마지막 반환 데이터를 삭제
- 삭제된 데이터는 반환함
- 마지막 데이터를 삭제하므로 연이은 반복 호출을 허용하지 않음 

int LCount(List *plist);
- 리스트에 저장된 데이터 수를 반환

void SetSortRule(List *plist, int (*comp)(LData d1, LData d2));
- 리스트에 정렬의 기준이 되는 함수를 등록
- 반환형이 int이고 LData형 인자 두 개를 전달받는 함수의 주소값을 두번째 인자로 전달!&lt;/code&gt;&lt;/pre&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: circle;&quot; data-ke-list-type=&quot;circle&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;장점: 포인터 변수 tail이 불필요&lt;/li&gt;
&lt;li&gt;단점: 저장된 순서를 유지하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;li&gt;단점: 포인터 변수 tail이 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;리스트 자료구조는 저장된 순서를 유지하는 것이 그렇게 중요하지 않아 머리에 추가하는 방식도 좋음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;int (*comp)(LData d1, LData d2)&lt;/b&gt; 의 값은 다음과 같이 정의된 함수의 주소 값&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731901812913&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int WhoIsPrecede(LData d1, LData d2)
{
	if(d1 &amp;lt; d2)
		return 0; // d1이 정렬상 앞서면
	else
		return 1; // d2가 정렬상 앞서면
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. 더미 노드(Dummy Node) 기반의 단순 연결 리스트&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;499&quot; data-origin-height=&quot;61&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1XJRX/btsKM1TEuWU/QDP6RLv82IjTMuG1EiKx00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1XJRX/btsKM1TEuWU/QDP6RLv82IjTMuG1EiKx00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1XJRX/btsKM1TEuWU/QDP6RLv82IjTMuG1EiKx00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1XJRX%2FbtsKM1TEuWU%2FQDP6RLv82IjTMuG1EiKx00%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;499&quot; height=&quot;61&quot; data-origin-width=&quot;499&quot; data-origin-height=&quot;61&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;첫번째 노드는 포인터 변수 head가 가리킨다는 점에서 다른 노드들과 차이가 있음&lt;/li&gt;
&lt;li&gt;이로 인해 노드를 추가, 삭제, 조회하는 방법에 있어 첫번째 노드와 두번째 이후의 노드에 차이가 생김&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;86&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dkI2OI/btsKMJr8W0w/61wQkXJycw1Q30yzsehx11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dkI2OI/btsKMJr8W0w/61wQkXJycw1Q30yzsehx11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dkI2OI/btsKMJr8W0w/61wQkXJycw1Q30yzsehx11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdkI2OI%2FbtsKMJr8W0w%2F61wQkXJycw1Q30yzsehx11%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;595&quot; height=&quot;86&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;86&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;포인터 변수 tail이 사라졌고 리스트 맨 앞에 더미 노드를 넣음&lt;/li&gt;
&lt;li&gt;이렇게 되면 처음 추가되는 노드가 구조상 두번째노드가 되므로 추가, 삭제, 조회 시 일관된 형태로 구성할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3. 정렬 기능이 추가된 연결 리스트 구조체와 헤더파일 정의&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;/ul&gt;
&lt;pre id=&quot;code_1731901922185&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typedef struct _node  // typedef int LData
{
	int data;
	struct _node * next;
} Node;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;연결 리스트 구현이 필요한 다음 유형의 변수들은 구조체로 묶지 않고 main 함수의 지역변수로 선언하거나 전역변수로 선언함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731901947617&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Node *head;  // 연결 리스트의 머리를 가리키는 포인터 변수
Node *cur;   // 참조를 위한 포인터 변수&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-level=&quot;2&quot;&gt;그렇지만 배열을 하나만 사용할 건 아니지 않는가. 그렇기 때문에 프로그램을 구현할 때에는 typedef struct_node 안에 다 넣어서 선언해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731901976897&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#define TRUE 1
#define FALSE 0

typedef int LData;
typedef struct _node
{
	LData data;
	struct _node * next;
} Node;

typedef struct _linkedList
{
	Node *head;  // 더미 노드를 가리키는 멤버
	Node *cur;   // 참조 및 삭제를 가리키는 멤버
	Node *before;  // 삭제를 돕는 멤버
	int numOfData; // 저장된 데이터의 수를 기록하기 위한 멤버
	int (*comp)(LData d1, LData d2);  // 정렬의 기준을 등록하기 위한 멤버
} LinkedList;

typedef LinkedList List;

void ListInit(List * plist);
void LInsert(List * plist, LData data);
int LFirst(List * plist, LData * pdata);
int LNext(List * plist, LData * pdata);

LData LRemove(List * plist);
int LCount(List * plist);
void SetSortRule(List * plist, int (*comp)(LData d1, LData d2));&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.4. 더미 노드 기반의 단순 연결 리스트 구현 1: 리스트 초기화 및 노드 삽입&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;/ul&gt;
&lt;pre id=&quot;code_1731902010324&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void ListInit(List *plist)
{
	plist-&amp;gt;head = (Node*)malloc(sizeof(Node));
	plist-&amp;gt;head-&amp;gt;next = NULL;
	plist-&amp;gt;comp = NULL;
	plist-&amp;gt;numOfData = 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;228&quot; data-origin-height=&quot;103&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKHvmS/btsKNUTR8Xs/m80xJBiJ5d4XH0gPjtw2SK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKHvmS/btsKNUTR8Xs/m80xJBiJ5d4XH0gPjtw2SK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKHvmS/btsKNUTR8Xs/m80xJBiJ5d4XH0gPjtw2SK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKHvmS%2FbtsKNUTR8Xs%2Fm80xJBiJ5d4XH0gPjtw2SK%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;228&quot; height=&quot;103&quot; data-origin-width=&quot;228&quot; data-origin-height=&quot;103&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&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;/ul&gt;
&lt;pre id=&quot;code_1731902083102&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void LInsert(List *plist, LData data)
{
	if(plist-&amp;gt;comp == NULL) // 정렬기준이 마련되지 않았다면
		FInsert(plist, data); // 머리에 노드 추가
	else
		SInsert(plist, data); // 정렬기준에 근거하여 노드 추가
}

void FInsert(List *plis, LData data)
{
	Node * newNode = (Node*)malloc(sizeof(Node)); // 새노드 생성
	newNode-&amp;gt;data = data;    // 새 노드에 데이터 저장
	
	newNode-&amp;gt;next = plist-&amp;gt;head-&amp;gt;next; // 1. 새 노드가 다른 노드를 가리키게 함
	plist-&amp;gt;head-&amp;gt;next = newNode; // 2. 더미 노드가 새 노드를 가리키게 함
	
	(plist-&amp;gt;numOfData)++;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;403&quot; data-origin-height=&quot;161&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b875zj/btsKLr0otVX/KkSM7X1dFAa4JJq5KntQP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b875zj/btsKLr0otVX/KkSM7X1dFAa4JJq5KntQP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b875zj/btsKLr0otVX/KkSM7X1dFAa4JJq5KntQP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb875zj%2FbtsKLr0otVX%2FKkSM7X1dFAa4JJq5KntQP0%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;403&quot; height=&quot;161&quot; data-origin-width=&quot;403&quot; data-origin-height=&quot;161&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;518&quot; data-origin-height=&quot;161&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dczZGZ/btsKLfFUmYd/golz4eXWI5bJkDi9wSLl9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dczZGZ/btsKLfFUmYd/golz4eXWI5bJkDi9wSLl9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dczZGZ/btsKLfFUmYd/golz4eXWI5bJkDi9wSLl9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdczZGZ%2FbtsKLfFUmYd%2Fgolz4eXWI5bJkDi9wSLl9K%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;518&quot; height=&quot;161&quot; data-origin-width=&quot;518&quot; data-origin-height=&quot;161&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.5. 더미 노드 기반의 단순 연결 리스트 구현 2: 데이터 조회&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-level=&quot;2&quot;&gt;LFirst&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731902182409&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int LFirst(List *plist, LData *pdata)
{
	if(plist-&amp;gt;head-&amp;gt;next == NULL) // 더미 노드가 NULL을 가리키면
		return FALSE; // 반환할 데이터 없음
	
	plist-&amp;gt;before = plist-&amp;gt;head;  // before은 더미 노드를 가리키게 함
	plist-&amp;gt;cur = plist-&amp;gt;head-&amp;gt;next; // cur은 첫번째 노드를 가리키게 함
	
	*pdata = plist-&amp;gt;cur-&amp;gt;data; // 첫번째 노드의 데이터를 전달
	return TRUE; // 데이터 반환 성공	
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;610&quot; data-origin-height=&quot;158&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0oyoo/btsKLaEEvAI/OPcE8Zw9lyBfPo6PNGQXqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0oyoo/btsKLaEEvAI/OPcE8Zw9lyBfPo6PNGQXqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0oyoo/btsKLaEEvAI/OPcE8Zw9lyBfPo6PNGQXqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0oyoo%2FbtsKLaEEvAI%2FOPcE8Zw9lyBfPo6PNGQXqk%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;610&quot; height=&quot;158&quot; data-origin-width=&quot;610&quot; data-origin-height=&quot;158&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LNext&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731902199824&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int LNext(List *plist, LData *pdata)
{
	if(plist-&amp;gt;cur-&amp;gt;next == NULL)  // cur이 NULL을 가리킨다면,
		return FALSE;   // 반환할 데이터 없음
		
	plist-&amp;gt;before = plist-&amp;gt;cur;  // cur이 가리키던 것을 before가 가리킴
	plist-&amp;gt;cur = plist-&amp;gt;cur-&amp;gt;next;  // cur은 그 다음 노드를 가리킴
	
	*pdata = plist-&amp;gt;cur-&amp;gt;data;  // cur이 가리키는 노드의 데이터 전달
	return TRUE;  // 데이터 반환 성공
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzswzB/btsKL8sIu0z/BxQjGWTulJzNRH8VRwLNok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzswzB/btsKL8sIu0z/BxQjGWTulJzNRH8VRwLNok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzswzB/btsKL8sIu0z/BxQjGWTulJzNRH8VRwLNok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzswzB%2FbtsKL8sIu0z%2FBxQjGWTulJzNRH8VRwLNok%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;599&quot; height=&quot;254&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;254&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.6. 더미 노드 기반의 단순 연결 리스트 구현 3: 노드의 삭제&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;바로 이전에 호출된 LFirst 혹은 LNext 함수가 반환한 데이터를 삭제&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;615&quot; data-origin-height=&quot;227&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckme0w/btsKMESclf8/eBpZzopuxYV4ZplL81cey1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckme0w/btsKMESclf8/eBpZzopuxYV4ZplL81cey1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckme0w/btsKMESclf8/eBpZzopuxYV4ZplL81cey1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fckme0w%2FbtsKMESclf8%2FeBpZzopuxYV4ZplL81cey1%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;615&quot; height=&quot;227&quot; data-origin-width=&quot;615&quot; data-origin-height=&quot;227&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1731902286778&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;LData LRemove(List *plist)
{
	Node *rpos = plist-&amp;gt;cur;  // 소멸 대상의 주소 값을 rpos에 저장
	LData rdata = rpos-&amp;gt;data; // 소멸 대상의 데이터를 rdata에 저장
	
	plist-&amp;gt;before-&amp;gt;next = plist-&amp;gt;cur-&amp;gt;next; // 1. 소멸 대상을 리스트에서 제거
	plist-&amp;gt;cur = plist-&amp;gt;before;  // 2. cur이 가리키는 위치를 재조정
	
	free(rpos);  // 리스트에서 제거된 노드 소멸
	(plist-&amp;gt;numOfData)--;  // 저장된 데이터 수 하나 감소
	return rdata;  // 제거된 노드의 데이터 반환
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;176&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdo7JF/btsKMPzdOrD/jBa4QkqDKhyIV8jxRQCuTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdo7JF/btsKMPzdOrD/jBa4QkqDKhyIV8jxRQCuTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdo7JF/btsKMPzdOrD/jBa4QkqDKhyIV8jxRQCuTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcdo7JF%2FbtsKMPzdOrD%2FjBa4QkqDKhyIV8jxRQCuTk%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;601&quot; height=&quot;176&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;176&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;261&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3oMJu/btsKLpIhe50/TIWUbZGPeBhqxHIkOxU5B1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3oMJu/btsKLpIhe50/TIWUbZGPeBhqxHIkOxU5B1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3oMJu/btsKLpIhe50/TIWUbZGPeBhqxHIkOxU5B1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3oMJu%2FbtsKLpIhe50%2FTIWUbZGPeBhqxHIkOxU5B1%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;680&quot; height=&quot;261&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;261&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;504&quot; data-origin-height=&quot;186&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhrXwj/btsKMMvMGwL/7jq7xyhzrExuSTBcaUhSV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhrXwj/btsKMMvMGwL/7jq7xyhzrExuSTBcaUhSV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhrXwj/btsKMMvMGwL/7jq7xyhzrExuSTBcaUhSV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhrXwj%2FbtsKMMvMGwL%2F7jq7xyhzrExuSTBcaUhSV1%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;504&quot; height=&quot;186&quot; data-origin-width=&quot;504&quot; data-origin-height=&quot;186&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 연결 리스트의 정렬 삽입 구현&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1. 연결 리스트에서의 정렬기준 설정&lt;/h4&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;SetSortRule 함수&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;SetSortRule 함수를 통해서 전달된 함수정보를 저장하기 위한 LinkedList의 &lt;b&gt;멤버 comp&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;comp에 등록된 정렬기준을 근거로 데이터를 저장하는 &lt;b&gt;SInsert 함수&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&amp;rarr; &lt;b&gt;&amp;ldquo;SetSortRule 함수가 호출되면서 정령의 기준이 리스트의 멤버 comp에 등록되면, SInsert 함수 내에서는 comp에 등록된 정렬의 기준을 근거로 데이터를 정렬하여 저장&amp;rdquo;&lt;/b&gt;&lt;/li&gt;
&lt;li data-level=&quot;2&quot;&gt;코드&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731902368646&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void SetSortRule(List * plist, int (*comp)(LData d1, LData d2))
{
	plist-&amp;gt;comp = comp;
}

void SInsert(List * plist, LData data)
{
	Node * newNode = (Node*)malloc(sizeof(Node));   // 새 노드 생성
	Node * pred = plist-&amp;gt;head;  // pred는 더미 노드를 가리킴
	newNode-&amp;gt;data = data;  // 새 노드에 데이터 저장
	
	// 새 노드가 들어갈 위치를 찾기 위한 반복문!
	while(pred-&amp;gt;next != NULL &amp;amp;&amp;amp; plist-&amp;gt;comp(data, pred-&amp;gt;next-&amp;gt;data) != 0)
	{
		pred = pred-&amp;gt;next; // 다음 노드로 이동
	}
	
	newNode-&amp;gt;next = pred-&amp;gt;next;  // 새 노드의 오른쪽을 연결
	pred-&amp;gt;next = newNode;  // 새 노드의 왼쪽을 연결
	
	(plist-&amp;gt;numOfData)++;  // 저장된 데이터 수 하나 증가
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;125&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XjbXk/btsKMDFPqXD/OrN1wHoQW9jhCar5jgIY81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XjbXk/btsKMDFPqXD/OrN1wHoQW9jhCar5jgIY81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XjbXk/btsKMDFPqXD/OrN1wHoQW9jhCar5jgIY81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXjbXk%2FbtsKMDFPqXD%2FOrN1wHoQW9jhCar5jgIY81%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;508&quot; height=&quot;125&quot; data-origin-width=&quot;508&quot; data-origin-height=&quot;125&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;515&quot; data-origin-height=&quot;277&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ON92g/btsKMExVlz0/9FUOuOhaRhOaQ4QtSYpvmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ON92g/btsKMExVlz0/9FUOuOhaRhOaQ4QtSYpvmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ON92g/btsKMExVlz0/9FUOuOhaRhOaQ4QtSYpvmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FON92g%2FbtsKMExVlz0%2F9FUOuOhaRhOaQ4QtSYpvmk%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;515&quot; height=&quot;277&quot; data-origin-width=&quot;515&quot; data-origin-height=&quot;277&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;267&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Od0vW/btsKL62LupY/ZKtTwC4zig73mPbdtuvkVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Od0vW/btsKL62LupY/ZKtTwC4zig73mPbdtuvkVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Od0vW/btsKL62LupY/ZKtTwC4zig73mPbdtuvkVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOd0vW%2FbtsKL62LupY%2FZKtTwC4zig73mPbdtuvkVk%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;520&quot; height=&quot;267&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;267&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;694&quot; data-origin-height=&quot;279&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ncekq/btsKMaRGrwi/7EpYDfYfZC9Nz1ta8d9Ofk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ncekq/btsKMaRGrwi/7EpYDfYfZC9Nz1ta8d9Ofk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ncekq/btsKMaRGrwi/7EpYDfYfZC9Nz1ta8d9Ofk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fncekq%2FbtsKMaRGrwi%2F7EpYDfYfZC9Nz1ta8d9Ofk%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;694&quot; height=&quot;279&quot; data-origin-width=&quot;694&quot; data-origin-height=&quot;279&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.2. 정렬의 핵심 - while 반복문&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;반복 조건 1 : pred-&amp;gt;next != NULL
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pred가 리스트의 마지막 노드를 가리키는지 묻기 위한 연산&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;반복 조건 2: plist-&amp;gt;comp(data, pred-&amp;gt;next-&amp;gt;data) != 0
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새 데이터와 pred의 다음 노드에 저장된 데이터의 우선순위 비교를 위한 함수 호출&lt;/li&gt;
&lt;li&gt;comp가 0을 반환
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;첫 번째 인자인 data가 정렬 순서상 앞서서 head에 더 가까워야 하는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;comp가 1을 반환
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;두 번째 인자인 pred-&amp;gt;next-&amp;gt;data가 정렬 순서상 앞서서 head에 더 가까워야 하는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.3. 정렬의 기준을 설정하기 위한 함수의 정의&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;첫번째 인자의 정렬 우선순위가 높으면 0을, 그렇지 않으면 1을 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731902447635&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int WhoIsPrecede(int d1, int d2)
{
	if(d1 &amp;lt; d2)
		return 0; // d1이 정렬 순서상 앞선다.
	else
		return 1; // d2가 정렬 순서상 앞서거나 같다.
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 id=&quot;head52&quot; data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;윤성우의 열혈 자료구조 (윤성우 저, 2023.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/자료구조</category>
      <category>computer science</category>
      <category>연결리스트</category>
      <category>자료구조</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/46</guid>
      <comments>https://onyodev.tistory.com/46#entry46comment</comments>
      <pubDate>Mon, 18 Nov 2024 13:01:30 +0900</pubDate>
    </item>
    <item>
      <title>연결 리스트(Linked List) 1</title>
      <link>https://onyodev.tistory.com/45</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 윤성우 저 - &quot;윤성우의 열혈 자료구조&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 추상 자료형(Abstract Data Type)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;ldquo;구체적인 기능의 완성과정을 언급하지 않고, 순수하게 기능이 무엇인지를 나열한 것&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;ex) 지갑 Wallet 구조체가 있을 때&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;type Wallet = {
  coin100Num: number;
  bill5000Num: number;

  // 돈을 꺼내는 기능
  takeOutMoney: (value: number) =&amp;gt; { coin100: number; bill5000: number } | string;

  // 돈을 넣는 기능
  putMoney: (coin100: number, bill5000: number) =&amp;gt; void;
};
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;추상 자료형도 자료형이기에 &amp;lsquo;기능&amp;rsquo; 혹은 &amp;lsquo;연산&amp;rsquo;과 관련된 내용을 명시할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 배열을 이용한 리스트의 구현&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. 리스트의 이해&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;/li&gt;
&lt;li&gt;리스트 자료구조는 데이터를 나란히 저장하고 중복된 데이터의 저장을 막지 않음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;리스트 자료구조의 ADT &lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731900934369&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void ListInit(List *plist); 
- 초기화할 리스트의 주소 값을 인자로 전달 
- 리스트 생성 후 제일 먼저 호출되어야 하는 함수 

void LInsert(List *plist, LData data); 
- 리스트에 데이터를 저장함. 매개변수 data에 전달된 값을 저장 

int LFirst(List *plist, LData *pdata); 
- 첫번째 데이터가 pdata가 가르키는 메모리에 저장된다 
- 데이터의 참조를 위한 초기화가 진행된다. 
- 참조 성공 시 TRUE, 실패 시 FALSE 반환 

int LNext(List *plist, LData *pdata); 
- 참조된 데이터의 다음 데이터가 pdata가 가리키는 메모리에 저장된다. 
- 순차적인 참조를 위해서 반복 호출이 가능하다. 
- 참조를 새로 시작하려면 먼저 LFirst 함수를 호출해야 함 
- 참조 성공 시 TRUE, 실패 시 FALSE 반환 

LData LRemove(List *plist, LData target); 
- LFirst 또는 LNext 함수의 마지막 반환 데이터를 삭제 
- 삭제된 데이터는 반환함 
- 마지막 데이터를 삭제하므로 연이은 반복 호출을 허용하지 않음 

int LCount(List *plist); 
- 리스트에 저장된 데이터 수를 반환​&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. 리스트 구현 방법&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;헤더파일의 정의&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구조체 ArrayList는 데이터의 저장공간을 배열로 선언했고 저장된 데이터의 수를 기록하기 위한 멤버도 있음&lt;/li&gt;
&lt;li&gt;LFirst, LNext, LRmove 함수를 위한 멤버도 존재함.&lt;/li&gt;
&lt;li&gt;리스트에 다양한 종류의 데이터를 저장할 수 있도록 typedef 선언도 해줌
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;typedef ArrayList List;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;삽입과 조회&lt;/b&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;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;배열초기화 및 데이터 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731901044932&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void ListInit(List * plist); // 초기화
void LInsert(List * plist, LData data);  // 데이터 저장


void ListInit(List * plist)
{
	(plist -&amp;gt; numOfData) = 0; // 리스트에 저장된 데이터 수 = 0
	(plist -&amp;gt; curPosition) = -1; // 현재 아무 위치도 가리키지 않음
}

void LInsert(List * plist, LData data)
{
	if(plist -&amp;gt;numOfData &amp;gt;= LIST_LEN) // 더 이상 저장할 공간이 없다면
	{
		puts(&quot;저장이 불가능합니다.&quot;);
		return;
	}
	
	plist-&amp;gt;arr[plist-&amp;gt;numOfData] = data; // 데이터 저장
	(plist -&amp;gt; numOfData)++; // 저장된 데이터 수 증가
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&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;/ul&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731901135755&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int LFirst(List * plist, LData *pdata); // 첫번째 조회
int LNext(List * plist , LData *pdata); // 두번째 이후 조회

int LFirst(List * plist, LData *pdata)
{
	if(plist-&amp;gt;numOfData == 0) // 저장된 데이터가 하나도 없으면
		return FALSE;
		
	(plist-&amp;gt;curPosition) = 0; // 참조위치 초기화 (첫번째 위치를 의미)
	*pdata = plist-&amp;gt;arr[0]  // pdata가 가리키는 공간에 데이터 저장
}

int LNext(List * plist, LData *pdata)
{
	if(plist-&amp;gt;curPosition &amp;gt;= (plist-&amp;gt;numOfData)-1) // 더 이상 참조할 데이터가 없다면
		return FALSE;
	
	(plist-&amp;gt;curPosition)++;
	*pdata = plist-&amp;gt;arr[plist-&amp;gt;curPosition];
	return TRUE;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;삭제 + count&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LFirst 함수나 LNext 함수의 호출을 통해서 바로 직전에 참조가 이뤄진 데이터를 삭제하는 것&lt;/li&gt;
&lt;li&gt;LRemove 함수가 호출되면 리스트의 멤버 curPositrion을 확인해서 조회가 이뤄진 데이터의 위치를 확인한 후, 그 데이터를 삭제&lt;/li&gt;
&lt;li&gt;그리고 앞에서부터 데이터를 채우는 것이 원칙이기 때문에 중간 데이터가 삭제되면 뒤에 저장된 데이터들은 한칸씩 앞으로 이동시켜 그 빈 공간을 채워야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;xl&quot;&gt;&lt;code&gt;LData LRemove(List * plist); // 최근 조회가 이루어진 데이터를 삭제

LData LRemove(List *plist)
{
	int rpos = plist-&amp;gt;curPosition; // 삭제할 데이터의 인덱스 값 참조
	int num = plist-&amp;gt;numOfData;
	int i;
	LData rdata = plist-&amp;gt;arr[rpos]; // 삭제할 데이터를 임시로 저장
	
	// 삭제를 위한 데이터의 이동을 진행하는 반복문
	for(i=rpos; i&amp;lt;num; i++)
		plist-&amp;gt;arr[i] = plist-&amp;gt; arr[i+1];
	
	(plist-&amp;gt;numOfData)--;  // 데이터의 수 감소
	(plist-&amp;gt;curPosition)--;  // 참조위치를 하나 되돌린다. (데이터 하나가 없어져 다 앞으로 이동해서)
	 return rdata;  // 삭제된 데이터의 반환
}

// 리스트에 저장된 데이터 수 반환
int LCount(List * plist)
{
	return plist-&amp;gt;numOfData;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3. 리스트에 구조체 변수 저장&lt;/h4&gt;
&lt;pre class=&quot;xl&quot;&gt;&lt;code&gt;typedef struct _point
{
	int xpos;
	int ypos;
} Point;

// Point 변수의 xpos, ypos 값 설정
void SetPointPos(Point *ppos, int xpos, int ypos)
{
	ppos-&amp;gt;xpos = xpos;
	ppos-&amp;gt;ypos = ypos;
}

// Point 변수의 xpos, ypos 정보 출력
void ShowPointPos(Point *ppos)
{
	printf(&quot;[%d, %d] \\n&quot;, ppos-&amp;gt;xpos, ppos-&amp;gt;ypos);
}

// 두 Point 변수의 비교
int PointComp(Point *pos1, Point *pos2)
{
	if(pos1-&amp;gt;xpos == pos2-&amp;gt;xpos &amp;amp;&amp;amp; pos1-&amp;gt;ypos == pos2-&amp;gt;ypos)
		return 0;
	else if(pos1-&amp;gt;xpos == pos2-&amp;gt;xpos)
		return 1;
	else if(pos1-&amp;gt;ypos == pos2-&amp;gt;ypos)
		return 2;
	else
		return -1;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.4. 배열의 장점과 단점&lt;/h4&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;/li&gt;
&lt;li&gt;삭제의 과정에서 데이터의 이동(복사)가 매우 빈번하게 일어남&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;/ul&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 id=&quot;head52&quot; data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;윤성우의 열혈 자료구조 (윤성우 저, 2023.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/자료구조</category>
      <category>computer science</category>
      <category>배열</category>
      <category>연결리스트</category>
      <category>오블완</category>
      <category>자료구조</category>
      <category>티스토리챌린지</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/45</guid>
      <comments>https://onyodev.tistory.com/45#entry45comment</comments>
      <pubDate>Mon, 18 Nov 2024 12:40:18 +0900</pubDate>
    </item>
    <item>
      <title>데이터 모델링</title>
      <link>https://onyodev.tistory.com/44</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 김연희 저 - &quot;데이터베이스 개론 3판&quot;을 공부하고 정리하여 작성하였습니다.&lt;/blockquote&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 data-ke-size=&quot;size26&quot;&gt;1. 데이터 모델링과 데이터 모델의 개념&lt;/h2&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;추상화(abstraction)&lt;/b&gt;라 한다.&lt;/li&gt;
&lt;li&gt;추상화를 통해 데이터를 저장할 때 어떤 구조로 저장해야 할 지를 결정해야 함.&lt;/li&gt;
&lt;li&gt;이때 현실 세계의 코끼리에 대한 중요 데이터를 추출하여 개념 세계로 옮기는 작업을 &lt;b&gt;개념적 모델링(conceptual modeling)&lt;/b&gt;이라 함.&lt;/li&gt;
&lt;li&gt;그리고 개념 세계의 데이터를 데이터베이스에 저장할 구조를 결정하고 이 구조로 표현하는 작업을 &lt;b&gt;논리적 모델링(logical modeling)&lt;/b&gt;이라 함.&lt;/li&gt;
&lt;li&gt;이러한 모델링을 쉽게 할 수 있도록 &lt;b&gt;데이터 모델(data model)&lt;/b&gt;이 도와주게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1. 데이터 모델&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;개념적 데이터 모델&lt;/b&gt;과 &lt;b&gt;논리적 데이터 모델&lt;/b&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;은 개념적 구조를 논리적 데이터 모델링하여 데이터베이스의 논리적 구조로 표현하는 도구&lt;/li&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;li&gt;&lt;b&gt;논리적 데이터 모델이서 데이터 구조&lt;/b&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;에는 &lt;b&gt;구조적 측면의 제약 사항&lt;/b&gt;과 연산을 적용하는 경우 허용할 수 있는 &lt;b&gt;의미적 측면의 제약 사항&lt;/b&gt;이 있다.&lt;/li&gt;
&lt;li&gt;보통은 개념적 데이터 모델링과 논리적 데이터 모델링을 통틀어 데이터베이스 설계라 함.&lt;/li&gt;
&lt;li&gt;데이터 모델링 과정을 통해 논리적 구조가 결정되면, 실제로 저장되는 형태를 의미하는 물리적 구조로 변환하는 작업을 통해 현실 세계 데이터를 컴퓨터 세계 데이터로 저장&lt;/li&gt;
&lt;li&gt;개념적 데이터 모델 중 가장 많이 쓰이는 것이 &lt;b&gt;개체-관계 모델(E-R model)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;논리적 데이터 모델 중에서는 &lt;b&gt;관계 데이터 모델(relational data model)&lt;/b&gt;이 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 개체-관계 모델&lt;/h2&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;개체-관계 다이어그램(ERD: Entity-Relationship Diagram)&lt;/b&gt;라 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. 개체&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1770&quot; data-origin-height=&quot;1043&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjisEc/btsKLlyILZa/yTgkvjLV85qIO2qLCCuIgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjisEc/btsKLlyILZa/yTgkvjLV85qIO2qLCCuIgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjisEc/btsKLlyILZa/yTgkvjLV85qIO2qLCCuIgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjisEc%2FbtsKLlyILZa%2FyTgkvjLV85qIO2qLCCuIgk%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;632&quot; height=&quot;372&quot; data-origin-width=&quot;1770&quot; data-origin-height=&quot;1043&quot;/&gt;&lt;/span&gt;&lt;/figure&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;li&gt;개체는 다른 개체와 구별되는 이름을 갖고 있고 각 개체만의 고유한 특성이나 상태, 즉 속성을 갖고 있음&lt;/li&gt;
&lt;li&gt;개체를 고유한 이름과 속성들로 정의한 것을 개체 타입이라 함.&lt;/li&gt;
&lt;li&gt;개체를 구성하고 있는 속성이 실제 값을 가짐으로써 &lt;b&gt;실제화된 개체&lt;/b&gt;를 &lt;b&gt;개체 인스턴스&lt;/b&gt;라 함.&lt;/li&gt;
&lt;li&gt;특정 개체 타입에 대한 &lt;b&gt;개체 인스턴스들을 모아놓은 것&lt;/b&gt;을 &lt;b&gt;개체 집합&lt;/b&gt;이라 함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개체&lt;/b&gt;와 &lt;b&gt;속성&lt;/b&gt;은 파일 구조에서 &lt;b&gt;레코드&lt;/b&gt;와 &lt;b&gt;필드&lt;/b&gt; 용어에 대응함&lt;/li&gt;
&lt;li&gt;개체 타입은 레코드 타입에, 개체 인스턴스는 레코드 인스턴스에 대응됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. 속성&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;/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;1749&quot; data-origin-height=&quot;852&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSGY4l/btsKMKqEgMJ/O3tVHz2Vlhv14yCK9cHNJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSGY4l/btsKMKqEgMJ/O3tVHz2Vlhv14yCK9cHNJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSGY4l/btsKMKqEgMJ/O3tVHz2Vlhv14yCK9cHNJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSGY4l%2FbtsKMKqEgMJ%2FO3tVHz2Vlhv14yCK9cHNJ1%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;677&quot; height=&quot;330&quot; data-origin-width=&quot;1749&quot; data-origin-height=&quot;852&quot;/&gt;&lt;/span&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;단일 값 속성과 다중 값 속성
&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;li&gt;다중값 속성은 이중 타원으로 표현함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&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;단순 속성&lt;/b&gt;은 의미를 더 분해할 수 없는 속성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;복합 속성&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;li&gt;판매가격 = 가격 * 할인율, 나이 = 현재년도 - 출생년도&lt;/li&gt;
&lt;li&gt;E-R 다이어그램에서 점선 타원으로 표현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;널(NULL) 속성
&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;/li&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;/li&gt;
&lt;li&gt;모든 개체 인스턴스의 키 속성 값이 다르므로 개체 집합에 존재하는 각 개체 인스턴스들을 식별하는 데 사용&lt;/li&gt;
&lt;li&gt;키를 둘 이상의 속성들로 구분하기도 함.&lt;/li&gt;
&lt;li&gt;개체 타입을 정의할 때 중요한 제약조건은 키 속성의 값이 개체 인스턴스마다 달라서 이 값으로 개체 인스턴스를 구분할 수 있어야 함.&lt;/li&gt;
&lt;li&gt;키 속성은 &lt;b&gt;밑줄&lt;/b&gt;을 그어 표현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3. 관계&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;&amp;ldquo;&lt;b&gt;고객&lt;/b&gt;은 &lt;b&gt;책&lt;/b&gt;을 &lt;b&gt;구매&lt;/b&gt;한다.&amp;rdquo; &amp;rarr; &lt;b&gt;구매&lt;/b&gt;는 &lt;b&gt;고객&lt;/b&gt;과 &lt;b&gt;책&lt;/b&gt; 개체 사이의 관계가 될 수 있음&lt;/li&gt;
&lt;li&gt;관계를 통해서만 개체들 간의 연관성을 이용한 업무를 처리할 수 있음&lt;/li&gt;
&lt;li&gt;관계를 여러 개체 사이에서 정의되는 &lt;b&gt;관계 타입&lt;/b&gt;과 실제 속성 값으로 구성된 특정 개체 인스턴스들 간에 맺어진 실제 관계인 &lt;b&gt;관계 인스턴스&lt;/b&gt;로 구분하여 표현함.&lt;/li&gt;
&lt;li&gt;고객 개체와 책 개체 사이에 정의된 &lt;b&gt;구매&lt;/b&gt; 관계는 &lt;b&gt;관계 타입&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;이름 속성의 값이 &amp;ldquo;정소화&amp;rdquo;인 고객 개체 인스턴스와 제목 속성의 값이 &amp;ldquo;데이터베이스개론&amp;rdquo;인 책 개체 인스턴스 사이에 맺어진 실제 관계는 &lt;b&gt;관계 인스턴스&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;관계도 개체처럼 속성을 가질 수 있음&lt;/li&gt;
&lt;li&gt;관계는 E-R 다이어그램에서 &lt;b&gt;마름모&lt;/b&gt;로 표현됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;관계 유형&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;일대일(1:1) 관계
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개체 A의 각 개체 인스턴스와 개체 B의 개체 인스턴스 하나와 관계를 맺을 수 있고,개체 B의 각 개체 인스턴스와 개체 A의 개체 인스턴스 하나와 관계를 맺을 수 있는 경우&lt;/li&gt;
&lt;li&gt;남편 - 아내 혼인 관계&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;일대다(1:n) 관계
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개체 A의 각 개체 인스턴스는 개체 B의 개체 인스턴스 여러 개와 관계를 맺을 수 있지만,개체 B의 각 개체 인스턴스와 개체 A의 개체 인스턴스 하나와만 관계를 맺을 수 있는 경우&lt;/li&gt;
&lt;li&gt;부서 - 사원 소속 관계&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;다대다(n:m) 관계
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개체 A의 각 개체 인스턴스와 개체 B의 개체 인스턴스 여러 개와 관계를 맺을 수 있고,개체 B의 각 개체 인스턴스와 개체 A의 개체 인스턴스 여러개와 관계를 맺을 수 있는 경우&lt;/li&gt;
&lt;li&gt;고객 - 책 구매 관계&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;관계의 참여 특성&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개체 A와 B 사이의 관계에서 개체 A의 모든 개체 인스턴스가 관계에 반드시 참여해야 한다면 개체 A가 관계에 &lt;b&gt;&amp;lsquo;필수적 참여한다&amp;rsquo;&lt;/b&gt; 또는 &lt;b&gt;&amp;lsquo;전체 참여한다&amp;rsquo;&lt;/b&gt;라고 함.&lt;/li&gt;
&lt;li&gt;개체 A의 개체 인스턴스 중 일부만 관계에 참여하면 &lt;b&gt;&amp;lsquo;선택적 참여한다&amp;rsquo;&lt;/b&gt; 또는 &lt;b&gt;&amp;lsquo;부분참여 한다&amp;rsquo;&lt;/b&gt;라고 함.&lt;/li&gt;
&lt;li&gt;필수 참여관계는 &lt;b&gt;이중선&lt;/b&gt;으로 표현함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;관계의 종속성&lt;/b&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;개체 B가 독자적으로 존재할 수 없고 개체 A에 종속되면 개체 B가 개체 A에 종속된다고 함&lt;/li&gt;
&lt;li&gt;이러한 종속을 특별히 &lt;b&gt;존재 종속(existence dependence)&lt;/b&gt;라고 함.&lt;/li&gt;
&lt;li&gt;이 때 개체 B는 약한 개체라 하고 개체 A를 강한 개체라고 함.&lt;/li&gt;
&lt;li&gt;강한 개체와 약한 개체는 일반적으로 일대다의 관계이며, 약한 개체는 강한 개체와의 관계에 필수적으로 참여한다는 특징이 있음&lt;/li&gt;
&lt;li&gt;일반적으로 약한 개체는 강한 개체의 키를 포함하여 키를 구성함&lt;/li&gt;
&lt;/ul&gt;
ex) 직원 - 부양가족의 경우
&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;b&gt;부분키&lt;/b&gt;라 함.&lt;/li&gt;
&lt;li&gt;약한 개체는 이중 사각형으로 표현하고 약한 개체가 강한 개체와 맺는 관계는 이중 마름모로 표현함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.4. E-R 다이어그램&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;구성&lt;/b&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;li&gt;개체나 관계의 속성 표현: 타원&lt;/li&gt;
&lt;li&gt;각 요소를 연결: 연결선&lt;/li&gt;
&lt;li&gt;관계 유형: 레이블&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 논리적 데이터 모델&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1. 논리적 데이터모델의 개념과 특성&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;어떤 형태로 저장&lt;/b&gt;할 지에 대한 구조를 설계하는 데 이 구조를 &lt;b&gt;논리적 데이터 모델&lt;/b&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;&lt;/li&gt;
&lt;li&gt;일반적으로 많이 사용되는 논리적 데이터 모델은 &lt;b&gt;관계 데이터 모델&lt;/b&gt;로 2차원 테이블 형태&lt;/li&gt;
&lt;li&gt;이전에는 &lt;b&gt;데이터 모델&lt;/b&gt;과 &lt;b&gt;네트워크 데이터 모델&lt;/b&gt;이 많이 사용됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.2. 계층 데이터 모델&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;980&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zbvXM/btsKMhP2kPx/9fiVh1OmYW6rcM6CoJND41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zbvXM/btsKMhP2kPx/9fiVh1OmYW6rcM6CoJND41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zbvXM/btsKMhP2kPx/9fiVh1OmYW6rcM6CoJND41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzbvXM%2FbtsKMhP2kPx%2F9fiVh1OmYW6rcM6CoJND41%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;456&quot; height=&quot;296&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;980&quot;/&gt;&lt;/span&gt;&lt;/figure&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;li&gt;두 개체 사이에 관계를 하나만 정의할 수 있어 관계에 이름을 붙여 구분할 필요가 없음&lt;/li&gt;
&lt;li&gt;별도의 개체를 추가로 생성하여 다대다 관계를 표현&lt;/li&gt;
&lt;li&gt;트리 구조이기 때문에 루트 역할을 하는 개체가 존재하며 사이클이 없음&lt;/li&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;/li&gt;
&lt;li&gt;그리고 이 일대다 관계를 부모 자식 관계라 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점&lt;/b&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;그리고 데이터의 삽입&amp;bull;수정&amp;bull;삭제 등 연산이나 검색이 쉽지 않다는 단점&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.3. 네트워크 데이터 모델&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1039&quot; data-origin-height=&quot;504&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CavOn/btsKLZvlUsD/lnLxYfvT6HS4Z6y4PshrM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CavOn/btsKLZvlUsD/lnLxYfvT6HS4Z6y4PshrM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CavOn/btsKLZvlUsD/lnLxYfvT6HS4Z6y4PshrM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCavOn%2FbtsKLZvlUsD%2FlnLxYfvT6HS4Z6y4PshrM1%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;495&quot; height=&quot;240&quot; data-origin-width=&quot;1039&quot; data-origin-height=&quot;504&quot;/&gt;&lt;/span&gt;&lt;/figure&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;li&gt;두 개체 간의 관계를 여러 개 정의할 수 있어 관계에 이름으로 구분&lt;/li&gt;
&lt;li&gt;두 개체 사이의 일대다 관계들을 이용해 다대다 관계를 표현함&lt;/li&gt;
&lt;li&gt;일대다 관계의 개체를 각각 오너(owner)와 멤버(member)라 부르고 이들 사이의 관계를 &lt;b&gt;오너-멤버 관계&lt;/b&gt;라 함.&lt;/li&gt;
&lt;li&gt;계층 데이터 모델과 달리 멤버 개체도 오너 개체 여러 개와 관계를 맺을 수 있음&lt;/li&gt;
&lt;li&gt;같은 개체들 사이 관계를 2개 이상 표현할 수 있어 계층 데이터 모델보다 개념적 구조를 논리적 구조로 좀 더 자연스럽게 표현할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점&lt;/b&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;그리고 데이터의 삽입&amp;bull;수정&amp;bull;삭제 등 연산이나 검색이 더 어려워지는 단점&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: 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;h4 data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스 개론 3판 (김연희 저, 2024.1)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/데이터베이스</category>
      <category>computer science</category>
      <category>데이터베이스</category>
      <category>모델링</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/44</guid>
      <comments>https://onyodev.tistory.com/44#entry44comment</comments>
      <pubDate>Sun, 17 Nov 2024 09:46:27 +0900</pubDate>
    </item>
    <item>
      <title>데이터베이스 시스템</title>
      <link>https://onyodev.tistory.com/43</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 김연희 저 - &quot;데이터베이스 개론 3판&quot;을 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 데이터베이스 시스템의 정의&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1. 데이터베이스 시스템&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;전체 시스템&lt;/b&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;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2. 데이터베이스 시스템 구성&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;데이터베이스&lt;/b&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;&lt;/li&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;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 데이터베이스의 구조&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. 스키마(schema)&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;데이터 구조와 제약조건&lt;/b&gt;을 정의한 것을 말함&lt;/li&gt;
&lt;li&gt;그리고 정의된 스키마에 따라 데이터베이스에 실제로 저장된 값을 &lt;b&gt;인스턴스&lt;/b&gt;라 함&lt;/li&gt;
&lt;li&gt;스키마는 한번 정의되면 자주 변경되진 않지만, 인스턴스는 계속 변하는 특성을 지님&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. 3단계 데이터베이스 구조&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미국의 표준화 기관인 ANSI/SPARC에서 데이터베이스의 복잡한 내부 구조를 감추고 일반 사용자가 데이터베이스를 쉽게 이해하고 이용할 수 있도록 &lt;b&gt;3단계 데이터베이스 구조&lt;/b&gt;를 제안&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개별 사용자 관점에서 바라보는 외부 단계 &amp;rarr; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;집주인&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;조직 전체 관점에서 바라보는 개념 단계 &amp;rarr; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;관리인&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;물리적인 저장 장치의 관점에서 바라보는 내부 단계 &amp;rarr; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;건설 업체&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;외부 단계&lt;/b&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;li&gt;사용자마다 생각하는 데이터베이스 구조가 다른데 이처럼 외부 단계에서 사용자에게 필요한 데이터베이스를 정의한 것을 &lt;b&gt;외부 스키마(external schema)&lt;/b&gt;라 함.&lt;/li&gt;
&lt;li&gt;하나의 데이터베이스에는 외부 스키마가 여러 개 존재할 수 있고, 외부 스키마 하나를 사용 목적이 같은 사용자들이 공유할 수 있음&lt;/li&gt;
&lt;li&gt;외부 스키마는 전체 데이터베이스 중 사용자가 관심을 가지는 일부분으로 볼 수 있어 &lt;b&gt;서브 스키마(sub schema)&lt;/b&gt;라고도 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개념 단계&lt;/b&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;전체 데이터베이스의 논리적 구조를 정의&lt;/b&gt;하고 이를 &lt;b&gt;개념 스키마(conceptual schema)&lt;/b&gt;라 함&lt;/li&gt;
&lt;li&gt;개념 스키마는 모든 개별 사용자가 생각하는 데이터베이스의 모습을 하나로 합친 형태&lt;/li&gt;
&lt;li&gt;개념 스키마는 전체 데이터베이스에 저장되는 &lt;b&gt;데이터 유형, 데이터 간 관계 및 제약조건&lt;/b&gt;에 대한 정의 뿐만 아니라 &lt;b&gt;데이터 보안 정책, 접근 권한&lt;/b&gt;에 대한 정의도 포함됨.&lt;/li&gt;
&lt;li&gt;데이터를 물리적으로 저장하는 방법이나 데이터 저장 장치와는 독립적&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;내부 단계&lt;/b&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;내부 스키마(internal schema)&lt;/b&gt;라 함.&lt;/li&gt;
&lt;li&gt;데이터는 저장 장치에 파일 형태로 저장되는데 내부 스키마는 파일에 데이터를 저장하는 &lt;b&gt;레코드의 구조&lt;/b&gt;, 레코드를 구성하는 &lt;b&gt;필드 크기&lt;/b&gt;, 인덱스를 이용한 &lt;b&gt;레코드 접근 경로&lt;/b&gt; 등을 정의함.&lt;/li&gt;
&lt;li&gt;내부 스키마는 데이터베이스의 개념 스키마에 대한 물리적 저장 구조를 표현하므로 하나의 데이터베이스에 하나만 존재함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;ex) 쇼핑몰의 데이터베이스&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;872&quot; data-origin-height=&quot;748&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AfifC/btsKLv17GKC/bq9GsdkoGKJmCvzl6kK3U1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AfifC/btsKLv17GKC/bq9GsdkoGKJmCvzl6kK3U1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AfifC/btsKLv17GKC/bq9GsdkoGKJmCvzl6kK3U1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAfifC%2FbtsKLv17GKC%2Fbq9GsdkoGKJmCvzl6kK3U1%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;872&quot; height=&quot;748&quot; data-origin-width=&quot;872&quot; data-origin-height=&quot;748&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;외부 단계&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;개념 단계&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;내부 단계&lt;/b&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;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3. 데이터 독립성&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;스키마 사이의 대응 관계를 사상 또는 매핑(mapping)이라 함.&lt;/li&gt;
&lt;li&gt;외부 스키마와 개념 스키마는 외부/개념 사상에 의해 대응&lt;/li&gt;
&lt;li&gt;개념 스키마와 내부 스키마는 개념/내부 사상에 의해 대응&lt;/li&gt;
&lt;li&gt;데이터베이스 관리 시스템은 미리 정의된 외부/개념 사상과 개념/내부 사상 정보를 이용해 사용자가 원하는 데이터에 접근할 수 있음&lt;/li&gt;
&lt;li&gt;데이터베이스를 3단계 구조로 나누고, 단계별로 스키마를 유지하며 스키마 사이의 대응 관계를 정의하는 궁극적인 목적은 &lt;b&gt;데이터 독립성&lt;/b&gt;을 실현하기 위함.&lt;/li&gt;
&lt;li&gt;데이터 독립성은 하위 스키마를 변경하더라도 상위 스키마가 영향을 받지 않는 특성을 말함.&lt;/li&gt;
&lt;li&gt;3단계 데이터베이스 구조에는 논리적 데이터 독립성과 물리적 데이터 독립성이 존재&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;논리적 데이터 독립성&lt;/b&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;외부/개념 사상 정보(응용 인터페이스)&lt;/b&gt;만 잘 수정해주면 관련 없는 외부 스키마는 수정할 필요가 없음&lt;/li&gt;
&lt;li&gt;개념 스키마에 새로운 내용이 추가되거나 기존 내용이 삭제되는 경우에도 외부 스키마는 영향을 받지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;물리적 데이터 독립성&lt;/b&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;개념/내부 사상 정보(저장 인터페이스)&lt;/b&gt;만 잘 수정하면 데이터베이스의 논리적 구조는 영향이 없음&lt;/li&gt;
&lt;li&gt;내부 스키마에 새로운 인덱스가 추가되거나 기존 인덱스가 삭제되는 경우에도 개념 스키마는 영향을 받지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.4. 데이터 사전&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;데이터 사전&lt;/b&gt; 또는 &lt;b&gt;시스템 카탈로그&lt;/b&gt;라고 함.&lt;/li&gt;
&lt;li&gt;데이터베이스 내 데이터를 정확하고 효율적으로 사용하기 위한 스키마, 사상 정보, 다양한 제약조건 등이 저장됨&lt;/li&gt;
&lt;li&gt;이것도 데이터베이스 일종이기 때문에 &lt;b&gt;시스템 데이터베이스&lt;/b&gt;라고도 함.&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;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 데이터베이스 사용자&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1. 데이터베이스 관리자&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스 시스템을 운영 &amp;bull; 관리하며 조직 내 사용자를 위해 데이터베이스를 설계 및 구축&lt;/li&gt;
&lt;li&gt;데이터베이스 운영 &amp;bull; 관리를 책임지므로 컴퓨터 시스템이나 데이터베이스와 관련한 지식과 경험이 필요&lt;/li&gt;
&lt;li&gt;주요 업무
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&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;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;li&gt;레코드들 간의 저장 순서와 레코드에 빠르게 접근하기 위해 인덱스를 만들 기준 필드 등도 결정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;li&gt;데이터베이스를 이 규칙에 따라 제어하여 데이터의 정확성과 유효성 유지&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;li&gt;허가된 사용자에게 적절한 권한 부여&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;li&gt;시스템 전체 성능 향상 및 시스템 장비 교체 시 데이터베이스 재구성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.2. 최종사용자&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;/li&gt;
&lt;li&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;/li&gt;
&lt;li&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;메뉴나 GUI 형태의 응용 프로그램을 통해 데이터베이스를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.3. 응용 프로그래머&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C 언어, Java와 같은 프로그래밍 언어로 응용 프로그램을 작성할 때 데이터베이스에 접근하는 데이터 조작어를 삽입하는 사용자&lt;/li&gt;
&lt;li&gt;데이터 정의어를 삽입하기도 하지만 주로 데이터 조작어를 사용&lt;/li&gt;
&lt;li&gt;최종 사용자는 응용 프로그래머가 작성한 응용 프로그램을 이용해 데이터베이스에 접근할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 데이터 언어&lt;/h2&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;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;li&gt;데이터 제어어&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.1. 데이터 정의어(DDL)&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;/li&gt;
&lt;li&gt;데이터 정의어로 정의된 스키마는 데이터 사전에 저장되고 수정 및 삭제 시에도 데이터 사전에 반영&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.2. 데이터 조작어(DML)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자가 데이터의 삽입&amp;bull;삭제&amp;bull;수정&amp;bull;검색 등의 처리를 데이터베이스 관리 시스템에 요구하기 위해 사용함&lt;/li&gt;
&lt;li&gt;사용자가 실제 데이터 값을 활용하기 위해 사용하는 언어&lt;/li&gt;
&lt;li&gt;설명 방식에 따라 &lt;b&gt;절차적 데이터 조작어&lt;/b&gt;와 &lt;b&gt;비절차적 데이터 조작어&lt;/b&gt;로 나뉨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;절차적 데이터 조작어&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비절차적 데이터 조작어&lt;/b&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;b&gt;선언적 언어&lt;/b&gt;라고 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.3. 데이터 제어어&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;무결성(integrity)&lt;/b&gt;: 데이터베이스에 정확하고 유효한 데이터만 유지한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보안(security):&lt;/b&gt; 허가받지 않는 사용자가 데이터에 접근하는 것을 차단하거나, 허가된 사용자가 접근 권한이 있는 데이터에만 접근할 수 있게 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;회복(recovery)&lt;/b&gt;: 장애가 발생해도 데이터의 일관성을 유지한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동시성(concurrency)&lt;/b&gt;: 여러 사용자가 같은 데이터에 동시에 접근하여 처리할 수 있게 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 데이터베이스 관리 시스템의 구성&lt;/h2&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;질의 처리기&lt;/b&gt;와 &lt;b&gt;저장 데이터 관리자&lt;/b&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;792&quot; data-origin-height=&quot;658&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p9okN/btsKMLpm5hy/V2sfMYiNLnliGUc3y6zl6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p9okN/btsKMLpm5hy/V2sfMYiNLnliGUc3y6zl6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p9okN/btsKMLpm5hy/V2sfMYiNLnliGUc3y6zl6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp9okN%2FbtsKMLpm5hy%2FV2sfMYiNLnliGUc3y6zl6K%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;792&quot; height=&quot;658&quot; data-origin-width=&quot;792&quot; data-origin-height=&quot;658&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.1. 질의 처리기&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;DDL 컴파일러&lt;/b&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;li&gt;데이터 정의어로 작성된 기존 스키마의 삭제 &lt;b&gt;&amp;bull;&lt;/b&gt; 수정 요청도 처리하고 변경된 내용을 데이터 사전에 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DML 프리 컴파일러&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;응용 프로그램에 삽입된 데이터 조작어를 추출하여 DML 컴파일러에 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DML 컴파일러&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 조작어로 작성된 데이터의 처리(삽입&amp;bull;삭제&amp;bull;수정&amp;bull;검색) 요구를 분석하여 런타임 데이터베이스 처리기가 이해할 수 있도록 해석&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;런타임 데이터베이스 처리기&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;저장 데이터 관리자를 통해 데이터베이스에 접근하여, DML 컴파일러로부터 전달받은 데이터 처리 요구를 데이터베이스에서 실제로 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트랜잭션 관리자&lt;/b&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;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.2. 저장 데이터 관리자&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;/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;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스 개론 3판 (김연희 저, 2024.1)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/데이터베이스</category>
      <category>computer science</category>
      <category>데이터 언어</category>
      <category>데이터베이스</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/43</guid>
      <comments>https://onyodev.tistory.com/43#entry43comment</comments>
      <pubDate>Sat, 16 Nov 2024 13:35:25 +0900</pubDate>
    </item>
    <item>
      <title>재귀(Recursion)</title>
      <link>https://onyodev.tistory.com/42</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 윤성우 저 - &quot;윤성우의 열혈 자료구조&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 함수의 재귀적 호출의 이해&lt;/h2&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;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 재귀의 활용&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;피보나치 수열&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$$ fib(n) = \begin{cases} 0, &amp;amp; \text{if } n = 1 \\ 1, &amp;amp; \text{if } n = 2 \\ fib(n-1) + fib(n-2), &amp;amp; \text{otherwise } \end{cases} $$&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;fib(n) 실행 시, fib(n-1)가 다시 호출되고 이후, fib(n-2)가 실행됨&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;function fibonacci(n) {
  if (n == 1){ 
  	return 0;
   } else if (n == 2) {
   	return 1;
   }
  	return fibonacci(n - 1) + fibonacci(n - 2);
}

console.log(fibonacci(10));  // 결과: 55&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;1055&quot; data-origin-height=&quot;643&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bL57vI/btsKJ2LtuB9/R29MY8zncG0Hi3XcLvYyu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bL57vI/btsKJ2LtuB9/R29MY8zncG0Hi3XcLvYyu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bL57vI/btsKJ2LtuB9/R29MY8zncG0Hi3XcLvYyu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbL57vI%2FbtsKJ2LtuB9%2FR29MY8zncG0Hi3XcLvYyu1%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;655&quot; height=&quot;399&quot; data-origin-width=&quot;1055&quot; data-origin-height=&quot;643&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 하노이 타워&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기둥이 3개가 있고 맨 왼쪽 기둥에 있는 원반을 맨 오른쪽으로 그대로 옮기는 게임&lt;/li&gt;
&lt;li&gt;큰 원반이 작은 원반 위에 있으면 안됨&lt;/li&gt;
&lt;li&gt;원반의 개수가 n으로 무한히 커져도 변하지 않는 과정이 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;작은 원반 n-1개를 기둥 A에서 B로 이동&lt;/li&gt;
&lt;li&gt;큰 원반 1개를 A에서 C로 이동&lt;/li&gt;
&lt;li&gt;작은 원반 n-1개를 B에서 C로 이동&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;rarr; from에 꽃혀있는 num개의 원반을 by를 거쳐 to로 이동&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 탈출 조건: 이동해야 할 원반의 개수가 1개인 경우&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;function hanoi(n, start, end, aux) {
  if (n === 1) {
    // 원반이 하나일 경우 직접 목표 지점으로 이동
    console.log(`Move disk 1 from ${start} to ${end}`);
    return;
  }

  // n-1개의 원반을 보조 기둥으로 이동
  hanoi(n - 1, start, aux, end);

  // 가장 큰 원반을 목표 기둥으로 이동
  console.log(`Move disk ${n} from ${start} to ${end}`);

  // n-1개의 원반을 목표 기둥으로 이동
  hanoi(n - 1, aux, end, start);
}

// 예시: 원반 3개를 A에서 C로 이동
hanoi(3, 'A', 'C', 'B');

&lt;/code&gt;&lt;/pre&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;/ul&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;Move disk 1 from A to C
Move disk 2 from A to B
Move disk 1 from C to B
Move disk 3 from A to C
Move disk 1 from B to A
Move disk 2 from B to C
Move disk 1 from A to C
&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;h4 id=&quot;head52&quot; data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;윤성우의 열혈 자료구조 (윤성우 저, 2023.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/자료구조</category>
      <category>computer science</category>
      <category>오블완</category>
      <category>자료구조</category>
      <category>재귀</category>
      <category>티스토리챌린지</category>
      <category>피보나치</category>
      <category>하노이탑</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/42</guid>
      <comments>https://onyodev.tistory.com/42#entry42comment</comments>
      <pubDate>Thu, 14 Nov 2024 16:49:18 +0900</pubDate>
    </item>
    <item>
      <title>자료구조와 알고리즘의 이해</title>
      <link>https://onyodev.tistory.com/41</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 윤성우 저 - &quot;윤성우의 열혈 자료구조&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 자료구조에 대한 기본적인 이해&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자료구조: &lt;b&gt;&amp;ldquo;데이터를 표현하고 저장하는 방법&amp;rdquo;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;알고리즘: &lt;b&gt;&amp;ldquo;자료구조를 대상으로 하는 문제의 해결 방법&amp;rdquo;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;자료구조의 분류&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;745&quot; data-origin-height=&quot;356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XaYJp/btsKJ2dBXqJ/3VAussjkTTEJcmv8EmLJ4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XaYJp/btsKJ2dBXqJ/3VAussjkTTEJcmv8EmLJ4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XaYJp/btsKJ2dBXqJ/3VAussjkTTEJcmv8EmLJ4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXaYJp%2FbtsKJ2dBXqJ%2F3VAussjkTTEJcmv8EmLJ4K%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;745&quot; height=&quot;356&quot; data-origin-width=&quot;745&quot; data-origin-height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 알고리즘의 성능분석 방법&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. 시간복잡도와 공간 복잡도&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;시간 복잡도(time complexity)&lt;/b&gt; : 속도에 해당하는 알고리즘 수행시간 분석결과&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공간 복잡도(space complexity)&lt;/b&gt; : 메모리 사용량에 대한 분석결과&lt;/li&gt;
&lt;li&gt;일반적으로 알고리즘을 평가할 땐 시간 복잡도에 초점을 맞춤&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. 순차 탐색 알고리즘과 시간 복잡도 분석&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n개의 원소를 갖고 있는 배열 내에서 타겟 값을 찾는 경우&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최선의 경우: 바로 찾을 경우 1&lt;/li&gt;
&lt;li&gt;최악의 경우: 모든 원소를 다 탐색해야 할 경우 n&lt;/li&gt;
&lt;li&gt;알고리즘의 평가는 &lt;b&gt;&amp;ldquo;최악의 경우&amp;rdquo;&lt;/b&gt;를 주로 염두하여 평가함&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3. 이진 탐색(Binary Search) 알고리즘의 소개&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;이진 탐색 알고리즘 과정&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1731569381622&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const array = [1,2,3,7,9,12,21,23,27]
// 3이 어디있는지를 찾는 과정

// 1. 배열의 시작 인덱스와 끝을 지정함
const [start, end] = [0, 8]

// 4. start &amp;lt;= end 일 때까지 1~3을 반복하고 arr[middle] == 3이면 종료
while(start &amp;lt;= end){
    // 2. 해당 값을 합하여 그 결과를 2로 나눔
    let middle = Math.floor((start + end) / 2) // 4

    // 3. 얻은 결과 4를 인덱스로 하여 arr[4]에 저장된 값이 3인지 확인
    if (arr[middle] &amp;gt; 3) {
        end = middle - 1 // 3
    } else if(arr[middle] &amp;lt; 3) {
        start = middle + 1
    } else if(arr[middle] == 3) {
        console.log(middle)
        break
    }
}&lt;/code&gt;&lt;/pre&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;이진 탐색 알고리즘 시간 복잡도(최악) : $T(n) = log_2n$&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.4. 대표적인 빅-오(Big-O)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빅-오(Big-O): 시간복잡도 함수 T(n)에서 가장 영향력이 큰 부분만을 표시하는 기법&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;color: #333333; text-align: start; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-style=&quot;style3&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: ;&quot;&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;(크기순)&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: ;&quot;&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;O(1)&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;&lt;b&gt;상수형 빅-오&lt;/b&gt;, 데이터 수와 상관없이 연산횟수가 고정인 유형의 알고리즘&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: ;&quot;&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;O($logn$)&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;&lt;b&gt;로그형 빅-오&lt;/b&gt;, 데이터 수 증가율에 비해 연산횟수 증가율이 훨씬 낮은 알고리즘&lt;br /&gt;가장 바람직한 유형&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: ;&quot;&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;O($n$)&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;&lt;b&gt;선형 빅-오,&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;데이터 수와 연산횟수가 비례함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: ;&quot;&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;O($nlogn$)&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;&lt;b&gt;선형로그형 빅-오&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: ;&quot;&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;O($n^2$)&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;데이터의 제곱에 해당하는 연산횟수, 주로 중첩 반복문&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: ;&quot;&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;O($n^3$)&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;데이터의 세제곱에 해당하는 연산횟수, 삼중 중첩 반복문&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: ;&quot;&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;O($2^n$)&lt;/td&gt;
&lt;td style=&quot;width: ;height: ;&quot;&gt;&lt;b&gt;지수형 빅-오&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;head52&quot; data-level=&quot;2&quot; data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;윤성우의 열혈 자료구조 (윤성우 저, 2023.10)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>[컴퓨터 과학자 스터디]/자료구조</category>
      <category>computer science</category>
      <category>알고리즘</category>
      <category>이진탐색</category>
      <category>자료구조</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/41</guid>
      <comments>https://onyodev.tistory.com/41#entry41comment</comments>
      <pubDate>Thu, 14 Nov 2024 16:35:05 +0900</pubDate>
    </item>
    <item>
      <title>데이터베이스 관리 시스템</title>
      <link>https://onyodev.tistory.com/40</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 김연희 저 - &quot;데이터베이스 개론 3판&quot;을 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 데이터베이스 관리 시스템의 등장 배경&lt;/h2&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&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;/li&gt;
&lt;li&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;li&gt;파일의 구조를 변경하면 응용 프로그램도 함께 변경되어야 함. &lt;b&gt;(데이터 종속성)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;bull;수정&amp;bull;실행 권한 부여를 파일 단위로 일일이 부여하는 것이 어려움&lt;/li&gt;
&lt;li&gt;파일에 문제가 발생한 경우 데이터를 일관된 상태로 유지하기 어려움&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;bull;삽입&amp;bull;삭제 등의 기본 데이터 관리 기능을 포함해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 데이터베이스 관리 시스템의 정의&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. 데이터베이스 관리 시스템의 주요 기능&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&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;/ul&gt;
&lt;/li&gt;
&lt;li&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;b&gt;삽입&amp;bull;수정&amp;bull;삭제&amp;bull;검색&lt;/b&gt;하는 연산을 효율적으로 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;bull;수정&amp;bull;삭제 후에도 내용이 일관되면서 무결성을 유지하고 장애가 발생해도 회복&lt;/li&gt;
&lt;li&gt;권한이 있는 사용자에게만 데이터 접근을 허용하여 보안 유지&lt;/li&gt;
&lt;li&gt;여러 사용자가 데이터베이스에 동시에 접근하여 데이터를 처리할 수 있도록 제어&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 데이터베이스 관리 시스템의 장&amp;bull;단점&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1. 데이터베이스 관리 시스템의 장점&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;데이터 중복 통제&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 독립성 확보&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 동시 공유&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 보안 향상&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 무결성 유지&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;표준화&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장애 발생 시 회복&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;응용 프로그램 개발 비용 감소&lt;/b&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;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.2. 데이터베이스 관리 시스템의 단점&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;비용이 많이 듦&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;백업과 회복 방법이 복잡함&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;중앙 집중 관리로 인한 취약점이 존재&lt;/b&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;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 데이터베이스 관리 시스템의 발전 과정&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.1. 1세대 데이터베이스 관리 시스템: 네트워크&amp;bull;계층 DBMS&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1960~1970년대에 사용된 네트워크 DBMS와 계층 DBMS가 1세대에 속함&lt;/li&gt;
&lt;li&gt;네트워크 DBMS
&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;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ex) IDS(Integrated Data Store)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;계층 DBMS
&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;네트워크 DBMS보다 단순한 구조지만 구조 변경이 어렵단 단점&lt;/li&gt;
&lt;/ul&gt;
&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ex) IMS(Information Management System)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.2. 2세대 데이터베이스 관리 시스템: 관계 DBMS&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1980년대 초반부터 계속 사용해온 관계DBMS가 2세대에 속함&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;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ex) Oracle, MS SQL 서버, MySQL, 인포믹스, 마리아DB, Access 등&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.3. 3세대 데이터베이스 관리 시스템: 객체지향&amp;bull;객체관계 DBMS&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1980년대 후반에 등장한 객체지향 DBMS는 객체지향 프로그래밍에서 도입한 객체 개념을 이용해 데이터베이스를 구성하는 객체지향 데이터 모델을 사용&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;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;ex) O2, ONTOS, GemStone 등&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1990년대 후반에 등장한 객체관계 DBMS는 관계 데이터 모델에 객체지향 개념을 도입한 객체관계 데이터 모델을 사용&lt;/li&gt;
&lt;li&gt;객체지향 DBMS와 관계 DBMS의 개념을 통합한 개념&lt;/li&gt;
&lt;li&gt;기존 관계 DBMS로 분류된 제품들이 객체지향 기능을 지원하면서 객체관계 DBMS로 분류되는데 &lt;b&gt;오라클&lt;/b&gt;이 대표적&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.4. 4세대 이후 데이터베이스 관리 시스템: NoSQL&amp;bull;NewSQL DBMS&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;NoSQL DBMS는 안정성과 일관성 유지와 같은 복잡한 기능을 포기하고 데이터 구조를 미리 정하지 않음&lt;/li&gt;
&lt;li&gt;확장성이 뛰어나 여러 대의 서버 컴퓨터에 데이터를 분산하여 저장하고 처리하는 환경에 사용&lt;/li&gt;
&lt;li&gt;SNS를 제공하는 회사들이 NoSQL의 필요성을 강조하면서 주목받게 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ex) MongoDB, HBase, Cassandra, Redis, Neo4j, OrientDB 등&lt;/b&gt;&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;그렇다고 관계 DBMS를 온전히 대체하진 않는다.&lt;/li&gt;
&lt;li&gt;NewSQL DBMS는 안정성과 일관성을 유지하면서 SQL을 이용해 복잡하고 다양한 데이터를 처리할 수 있음&lt;/li&gt;
&lt;li&gt;관계 DMBS의 장점과 NoSQL의 확장성과 유연성 모두 지원하며 정형 및 비정형 데이터를 안정적으로 빠르게 처리할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ex) 구글 스패너, VoltDB, NuoDB 등&lt;/b&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;자료&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스 개론 3판 (김연희 저, 2024.1)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/데이터베이스</category>
      <category>computer science</category>
      <category>데이터베이스</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/40</guid>
      <comments>https://onyodev.tistory.com/40#entry40comment</comments>
      <pubDate>Thu, 14 Nov 2024 16:27:45 +0900</pubDate>
    </item>
    <item>
      <title>데이터베이스 기본 개론</title>
      <link>https://onyodev.tistory.com/39</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 김연희 저 - &quot;데이터베이스 개론 3판&quot;을 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;1. 데이터베이스의 필요성&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터(data): 현실 세계에서 단순히 관찰하거나 측정하여 수집한 사실이나 값&lt;/li&gt;
&lt;li&gt;정보(information): 데이터를 의사결정에 유용하게 활용할 수 있도록 처리하여 체계적으로 조직한 결과물&lt;/li&gt;
&lt;li&gt;데이터에서 정보를 추출하는 과정 또는 방법을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;정보 처리&lt;/b&gt;라 함.&lt;/li&gt;
&lt;li&gt;즉, 데이터를 상황에 맞게 분석하거나 해석하여 데이터 간 의미 관계를 파악하는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;1.1. 정보 시스템과 데이터베이스&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정보시스템(information system): 조직 운영에 필요한 데이터를 수집하여 유용한 정보를 만들어 주는 수단&lt;/li&gt;
&lt;li&gt;정보 시스템은 사용 목적에 따라 부르는 명칭이 다름&lt;/li&gt;
&lt;li&gt;&lt;b&gt;경영 정보 시스템(Management Information System):&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;기업의 경영 관리에 필요한 의사 결정용 정보 시스템&lt;/li&gt;
&lt;li&gt;&lt;b&gt;의사 결정 지원 시스템(Decision Support System):&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;복합적이고 광범위한 의사 결정을 위해 사용되는 정보 시스템&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;2. 데이터베이스의 정의와 특징&lt;/h2&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;2.1. 데이터베이스의 정의&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반적으로 특정 조직의 여러 사용자가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;공유&lt;/b&gt;하여 사용할 수 있도록&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;통합&lt;/b&gt;해서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;저장&lt;/b&gt;한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;운영&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;데이터의 집합이라 정의함.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;데이터베이스는 공유 데이터&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터베이스는 통합 데이터&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;데이터베이스는 저장 데이터&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터베이스는 운영 데이터&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;2.2. 데이터베이스의 특징&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&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;li&gt;&lt;b&gt;동시 공유&lt;/b&gt;: 여러 사용자가 동시에 이용할 수 있는 동시 공유의 특징을 제공해야 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;참조:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;저장된 주소나 위치가 아닌 데이터의 내용, 즉 값으로 참조할 수 있어야 함&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;3. 데이터 과학 시대의 데이터&lt;/h2&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;3.1. 형태에 따른 데이터 분류&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;정형 데이터&lt;/b&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;/ul&gt;
&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ex) 엑셀 스프레드 시트, 관계 데이터베이스의 테이블&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;반정형 데이터&lt;/b&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;데이터 내용에 대한 구조를 파악하는 파싱(parsing)이 필요하고 보통 파일 형태로 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;ex) HTML, XML, jSON 문서나 웹 로그, 센서 데이터 등&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비정형 데이터&lt;/b&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;/ul&gt;
&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;ex) 소셜 데이터의 텍스트, 영상, 이미지, 음성 , 워드 등&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;XML 데이터베이스와 멀티미디어 데이터베이스&lt;/b&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot; data-text-less=&quot;닫기&quot; data-text-more=&quot;더보기&quot; data-ke-type=&quot;moreLess&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;XML 데이터베이스
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;웹에서 시스템 간 데이터 교환을 위해 작성된 XML 문서를 효율적으로 저장하고 검색할 수 있도록 개발&lt;/li&gt;
&lt;li&gt;기존 데이터베이스에 XML 문서를 하나의 단위로 저장하는 방법과 XML 전용 데이터베이스를 따로 구성하는 방법으로 나뉨&lt;/li&gt;
&lt;li&gt;후자의 경우 데이터처리를 위해 XQuery를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;3.2. 특성에 따른 분류&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;범주형 데이터&lt;/b&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;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;/li&gt;
&lt;li&gt;&lt;b&gt;수치형 데이터&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&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;/li&gt;
&lt;li&gt;연속형 데이터: 연속적으로 이어지는 값을 가진 데이터&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스 개론 3판 (김연희 저, 2024.1)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/데이터베이스</category>
      <category>computer science</category>
      <category>데이터베이스</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/39</guid>
      <comments>https://onyodev.tistory.com/39#entry39comment</comments>
      <pubDate>Thu, 14 Nov 2024 16:24:30 +0900</pubDate>
    </item>
    <item>
      <title>보안</title>
      <link>https://onyodev.tistory.com/36</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 고재성, 이상훈 저 - &quot;IT 엔지니어를 위한 네트워크 입문&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 보안의 개념과 정의&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.1. 정보보안의 정의&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;ldquo;다양한 위협으로부터 보안을 보호하는 것&amp;rdquo;&lt;/li&gt;
&lt;li&gt;3대 보안 정의
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;기밀성(Confidentiality): 인가되지 않은 사용자가 정보를 보지 못하게 하는 모든 작업&lt;/li&gt;
&lt;li&gt;무결성(Integrity): 정확하고 완전한 정보 유지에 필요한 모든 작업
&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;대표적인 기술은 MD5, SHA와 같은 해시 함수를 이용해 변경 여부를 파악&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;가용성(Availabilty): 정보가 필요할 때 접근을 허락하는 일련의 작업&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이 3대 요소 외에 추가로 진정성, 책임성, 부인 방지, 신뢰성 유지를 정보보안 활동 중 하나로 정의하기도 함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.2. 네트워크의 정보 보안&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;네트워크 보안 1차 목표: 시스템을 공격해 유출하거나 시스템이 역할을 못하게 하는 행위를 네트워크에서 적절히 막는 것&lt;/li&gt;
&lt;li&gt;네트워크 보안 2차 목표: 정보가 네트워크를 통해 복제, 이동되어 유출되는 것을 막는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.3. 네트워크 보안의 주요 개념&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;468&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YvyzJ/btsKEQkaK9i/Fm7UEdIqozkw98kbbABwc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YvyzJ/btsKEQkaK9i/Fm7UEdIqozkw98kbbABwc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YvyzJ/btsKEQkaK9i/Fm7UEdIqozkw98kbbABwc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYvyzJ%2FbtsKEQkaK9i%2FFm7UEdIqozkw98kbbABwc0%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;612&quot; height=&quot;326&quot; data-origin-width=&quot;879&quot; data-origin-height=&quot;468&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;트러스트 네트워크,&lt;/b&gt; 신뢰할 수 없는 외부 네트워크를 &lt;b&gt;언트러스트 네트워크&lt;/b&gt;로 구분&lt;/li&gt;
&lt;li&gt;그리고 우리가 운영하는 내부 네트워크이지만 신뢰할 수 없는 외부 사용자에게 개방해야 하는 서비스 네트워크를 DMZ 네트워크라 부름
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;일반적으로 인터넷에 공개되는 서비스가 이 네트워크에 배치됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;네트워크 보안 분야는 트래픽의 방향과 용도에 따라 두 가지로 나뉨
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;인터넷 시큐어 게이트웨이(Internet Secure Gateway)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트러스트(또는 DMZ) 네트워크에서 언트러스트 네트워크로의 통신을 통제&lt;/li&gt;
&lt;li&gt;SWG, 웹 필터, 애플리케이션 컨트롤, 샌드박스와 같은 다양한 서비스나 네트워크 장비가 포함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 센터 시큐어 게이트웨이(Data Cneter Secure Gateway)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언트러스트 네트워크에서 트러스트(또는 DMZ)로의 통신을 통제&lt;/li&gt;
&lt;li&gt;IPS, DCSG, WAF, Anti-DDoS 등의 장비가 사용됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3.1. 네트워크 보안 정책 수립에 따른 분류&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&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;일반적으로 IP와 통신 정보에 대해 명확히 아는 경우에 사용&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;블랙리스트
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;공격이라고 명확히 판단되거나 문제가 있던 IP 리스트나 패킷 리스트를 기반으로 DB를 만들어 해당 정보로 방어하는 형태&lt;/li&gt;
&lt;li&gt;각종 패턴으로 공격을 방어하는 네트워크 장비(IPS, 안티바이러스, WAF)들은 일반적으로 이 기법을 제공&lt;/li&gt;
&lt;li&gt;인터넷 어디선가 공격을 당할 때 분석해 공격기법을 판단해 탐지하도록 DB를 만드는데 이를 공격 패턴(signature)라 함&lt;/li&gt;
&lt;/ol&gt;
&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;최근 보안 위협이 증가하면서 화이트리스트 기반 정책이 많아짐&lt;/li&gt;
&lt;li&gt;이를 위해선 통신 정보를 상세히 알고 세부적인 통제가 필요함&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3.2. 정탐, 오탐, 미탐(탐지 에러 타입)&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 58.9532%; height: 54px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.1702%; height: 20px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 20.6589%; height: 20px;&quot;&gt;공격 상황&lt;/td&gt;
&lt;td style=&quot;width: 18.6499%; height: 20px;&quot;&gt;정상 상황&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 15.1702%; height: 17px;&quot;&gt;공격 인지 &lt;br /&gt;(공격 알람)&lt;/td&gt;
&lt;td style=&quot;width: 20.6589%; height: 17px;&quot;&gt;True Positive &lt;br /&gt;(정상 탐지)&lt;/td&gt;
&lt;td style=&quot;width: 18.6499%; height: 17px;&quot;&gt;False Positive&lt;br /&gt;(오 탐지)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 15.1702%; height: 17px;&quot;&gt;정상 인지&lt;br /&gt;(공격 알람 x)&lt;/td&gt;
&lt;td style=&quot;width: 20.6589%; height: 17px;&quot;&gt;False Negative &lt;br /&gt;(미 탐지)&lt;/td&gt;
&lt;td style=&quot;width: 18.6499%; height: 17px;&quot;&gt;True Negative &lt;br /&gt;(정상 탐지)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;True Positve, True Negative의 경우 정상적인 동작이므로 &lt;b&gt;정탐&lt;/b&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;이라 부름, 이 경우 공격 패턴 업데이트가 되지 않거나 과도한 예외 처리가 된 경우 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.4. 네트워크 정보 보안의 발전 추세와 고려사항&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;li&gt;보안 영역 내부는 해킹 기술의 발전에 대응하여 발전하는 경우&lt;/li&gt;
&lt;li&gt;최근 빅데이터와 머신 러닝 발전으로 빅데이터와 머신러닝 기법을 보안에 적용해 빠르게 대응하는 시스템과 서비스를 개발하는 추세&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 보안 솔루션의 종류&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1148&quot; data-origin-height=&quot;293&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cid0Ci/btsKDFKPLOx/HyX46pT6OrvVX54JtOFnm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cid0Ci/btsKDFKPLOx/HyX46pT6OrvVX54JtOFnm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cid0Ci/btsKDFKPLOx/HyX46pT6OrvVX54JtOFnm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcid0Ci%2FbtsKDFKPLOx%2FHyX46pT6OrvVX54JtOFnm0%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;774&quot; height=&quot;198&quot; data-origin-width=&quot;1148&quot; data-origin-height=&quot;293&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 센터에서 보안 장비를 디자인할 때 DDoS - 방화벽 - IPS - WAF 형태와 같이 여러 단계로 공격을 막도록 인라인 상에 장비를 배치&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1. DDoS 방어 장비&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;759&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OsWHk/btsKElZaBks/Hsiv8fcfYdj5luPauuP2mk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OsWHk/btsKElZaBks/Hsiv8fcfYdj5luPauuP2mk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OsWHk/btsKElZaBks/Hsiv8fcfYdj5luPauuP2mk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOsWHk%2FbtsKElZaBks%2FHsiv8fcfYdj5luPauuP2mk%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;694&quot; height=&quot;612&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;759&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DoS (Denial of Service) 공격은 다양한 방법으로 공격 목표에 서비스 부하를 가해 정상적인 서비스를 방해하는 기법&lt;/li&gt;
&lt;li&gt;DoS 공격은 적이 공격 출발지에서 공격하는 것이 일반적이었고 비교적 탐지가 쉽고 짧은 시간 안에 탐지만 하면 IP 주소 기반으로 방허가 가능&lt;/li&gt;
&lt;li&gt;이런 탐지를 회피하고 더 짧은 시간에 공격 성과를 내기 위해 다수의 봇을 이용해 분산 공격을 수행하는 DDoS 공격기법이 등장&lt;/li&gt;
&lt;li&gt;DDoS 장비는 데이터 센터 네트워크 내부와 외부의 경계에서 공격을 방어하는 데 이것은 볼류메트릭 공격을 우선 막기 위함&lt;/li&gt;
&lt;li&gt;볼류메트릭 공격(Volumetric Attack): 회선 사용량이나 그 이상의 트래픽을 과도하게 발생시켜 회선 사용을 방해하는 공격&lt;/li&gt;
&lt;li&gt;회선을 공급해주는 ISP나 네트워크 ISP와 연결되는 데이터 센터 네트워크의 가장 바깥쪽에 위치시켜 이 공격을 완화해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2. 방화벽&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;4계층에서 동작하는 패킷 필터링 장비이며 3,4 계층 정보를 기반으로 정책을 세울 수 있음&lt;/li&gt;
&lt;li&gt;그리고 해당 정책과 매치되는 패킷이 방화벽을 통과하면 그 패킷을 허용/거부할 수 있음&lt;/li&gt;
&lt;li&gt;일반적으로 DDoS 방어 장비 바로 뒤에 놓는 네트워크 보안 장비&lt;/li&gt;
&lt;li&gt;3,4계층에서 동작하여 다른 장비에 비해 비교적 간단히 동작하고 성능도 우수&lt;/li&gt;
&lt;li&gt;최근 고성능 방화벽은 ASIC이나 FPGA와 같은 전용 칩을 이용해 가속하므로 대용량을 요구하는 데이터 센터에서도 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.3. IDS, IPS&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IDS(침입 탐지 시스템)과 IPS(침입 방지 시스템)는 방화벽에서 방어할 수 없는 다양한 애플리케이션 공격을 방어하는 장비&lt;/li&gt;
&lt;li&gt;최근에는 애플리케이션 공격을 방어하는 장비를 IPS로 통칭함&lt;/li&gt;
&lt;li&gt;사전에 공격 데이터베이스(Signiture)를 제조사나 위협 인텔리전스 서비스 업체로부터 받음&lt;/li&gt;
&lt;li&gt;이후 IDS와 IPS 장비에 인입된 패킷이 보유한 공격 데이터베이스에 해당하는 공격일 때, 차단하거나 모니터링 후 관리자에게 알림을 보내 공격 시도를 알림&lt;/li&gt;
&lt;li&gt;기존에는 블랙리스트 기반 방어만 제공했지만 프로파일링 기반 방어 기법이 IPS 장비에 적용되어 애플리케이션을 골라 방어할 수 있는 애플리케이션 컨트롤 기능이 추가되어 화이트리스트 방어 기법도 적용됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.4. WAF(Web Application Firewall)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;웹 서버를 보호하는 전용 보안 장비로 HTTP, HTTPS처럼 웹 서버에서 동작하는 웹 프로토콜의 공격을 방어함&lt;/li&gt;
&lt;li&gt;IDS/IPS 장비보다 범용성이 떨어지지만 웹 프로토콜에 대해선 더 세밀히 방어할 수 있음&lt;/li&gt;
&lt;li&gt;WAF는 다음과 같이 다양한 형태의 장비나 소프트웨어로 제공됨
&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;li&gt;ADC 플러그인&lt;/li&gt;
&lt;li&gt;프록시 장비 플러그인&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;WAF는 IPS 회피공격을 방어할 수 있음
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;IPS는 데이터를 조합하지 않고 처리하지만 WAF는 프락시 서버와 같이 패킷을 데이터 형태로 조합해 처리할 수 있음&lt;/li&gt;
&lt;li&gt;그래서 회피 공격을 쉽게 만들기 어렵고 데이터의 일부를 수정, 추가하는 기능을 수행&lt;/li&gt;
&lt;li&gt;공격 트래픽을 방어만 하지 않고 공격자에게 통보하거나 민감한 데이터가 유출될 때 그 정보만 제거해 보내줄 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.5. 샌드박스&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;샌드박스 등장 배경&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;보안 장비의 발전으로 해커들의 공격 방식이 악성 코드를 관리자 PC에 우회적으로 심고 이 악성 코드를 이용해 관리자 PC를 컨트롤하는 방식으로 변함&lt;/li&gt;
&lt;li&gt;악성 코드가 든 이메일을 관리자에게 보내거나 관리자가 악성 코드를 내려받도록 유도하는 방법을 사용&lt;/li&gt;
&lt;li&gt;이후 이 PC들을 외부에서 컨트롤하도록 C&amp;amp;C(Command &amp;amp; Control) 서버를 만들고 감염 PC들을 이 C&amp;amp;C 서버로 연결하도록 조작&lt;/li&gt;
&lt;li&gt;이런 공격들이 발전해 현재 APT(Advanced Persistent Threat: 지속 공격)와 ATA(Advanced Target Attack: 지능형 표적 공격)가 되었음&lt;/li&gt;
&lt;li&gt;APT와 ATA 공격을 막기 위해 IPS 장비와 C&amp;amp;C 서버와의 통신을 탐지할 수 있는 다양한 형태의 Anti-APT 솔루션들이 개발됨&lt;/li&gt;
&lt;li&gt;샌드박스는 APT의 공격을 방어하는 대표적인 장비로 악성 코드를 샌드박스 시스템 안에서 직접 실행&lt;/li&gt;
&lt;li&gt;가상 운영체제 안에서 각종 파일을 직접 실행시키고 그 행동을 모니터링해 그 파일의 악성 코드 여부를 판별함&lt;/li&gt;
&lt;/ul&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;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;li&gt;기존 보안시스템이 탐지하지 못하도록 암호화, 난독화시켜 오랫동안 여러 단계에 거쳐 공격&lt;/li&gt;
&lt;li&gt;파일을 직접 실행한 후 파일의 행동을 모니터링하면 이런 악성 코드를 감싼 많은 트릭을 제거하거나 탐지할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.6. NAC(Network Access Control)&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;내부 PC 관리나 보안 패치로 대응하더라도 외부 PC가 내부망에 접속해 보안사고를 일으키거나 악성 코드를 전파하는 문제점들이 많아 등장함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.7. IP 제어&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IP 제어 솔루션은 NAC와 비슷하지만 국내에서 많이 사용하며 NAC와 다른 목적으로 개발&lt;/li&gt;
&lt;li&gt;보안사고 추적이 쉽도록 고정 IP 사용 권고 지침이 금융권에 내려오면서 IP를 할당하고 추적하는 솔루션이 필요해짐&lt;/li&gt;
&lt;li&gt;할당된 IP를 관리하고 나아가 정확히 의도된 IP 할당이 아니면 정상적으로 네트워크를 사용하지 못하게 하는 기능이 필요하여 개발됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.8. 접근 통제&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;에이전트 기반, 에이전트리스, 구현 방법에 따라 다양하게 분류되지만 대부분 배스천 호스트(Bastion Host) 기반으로 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;배스천 호스트&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;/li&gt;
&lt;li&gt;서버 호스트의 방화벽에 배스천 호스트에서 출발한 통신만 허용&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;h3 data-ke-size=&quot;size23&quot;&gt;2.9. VPN&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자 기반의 VPN 서비스를 제공해 주는 장비를 말함.&lt;/li&gt;
&lt;li&gt;기존에는 별도의 VPN 서비스를 제공하는 하드웨어가 있었지만 현재는 방화벽이나 라우터 장비에 VPN 기능이 포함&lt;/li&gt;
&lt;li&gt;가장 많이 사용하는 VPN
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IPSEC: 주로 네트워크 연결용으로 사용&lt;/li&gt;
&lt;li&gt;SSL: 사용자가 내부 네트워크에 연결할 때 주로 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 방화벽&lt;/h2&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;일반적으로 방화벽은 네트워크 3,4 계층에서 동작하며 세션을 인지하는 상태 기반 엔진(Stateful Packet Inspection)으로 동작함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.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;이런 초기 방화벽을 스테이트리스(Stateless) 또는 패킷 필터(Packet Filter) 방화벽이라고 함&lt;/li&gt;
&lt;li&gt;패킷이 장비에 인입되면 해당 패킷이 방화벽에 설정된 정책에 일치되는 것이 있는지 확인&lt;/li&gt;
&lt;li&gt;이때 참고하는 조건을 5-튜플이라 하고 패킷의 3,4계층 헤더 중 5가지 주요 필드를 뜻함
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Source IP&lt;/li&gt;
&lt;li&gt;Destination IP&lt;/li&gt;
&lt;li&gt;Protocol No&lt;/li&gt;
&lt;li&gt;Source Port&lt;/li&gt;
&lt;li&gt;Destination Port&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이와 같은 패킷 필터링 방화벽은 지정된 구간에서 간단하게 실행할 때는 큰 문제가 없음&lt;/li&gt;
&lt;li&gt;하지만 인터넷 통신과 같이 불특정 다수 기반 정책을 정의할 때 룰셋이 복잡해지고 보안이 약화됨&lt;/li&gt;
&lt;li&gt;5-튜플 외의 3,4계층 헤더를 변조해 공격하면 방어가 불가능&lt;/li&gt;
&lt;li&gt;하지만 패킷 필터링 동작이 간단하여 네트워크 장비에 활용되거나 현재도 특수한 기능에 사용&lt;/li&gt;
&lt;li&gt;지정된 IP를 방어하는데 부하가 적어 블랙리스트 처리르 위해 방화벽 내부 패킷 필터링 엔진과 SPI 엔진을 함께 동작시키기도 함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2. 현대적 방화벽의 등장(SPI 엔진)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 우리가 방화벽이라 하는 모든 장비는 세션 기반으로 동작하는 상태 기반(SPI) 엔진을 탑재함&lt;/li&gt;
&lt;li&gt;패킷 필터 엔진은 가볍고 빠르지만 통신의 양방향성을 인지하지 못함&lt;/li&gt;
&lt;li&gt;내부 사용자가 외부의 특정 웹페이지에 접속할 때 3 웨이 핸드셰이크를 거친 후 HTTP 요청과 응답 과정을 거침&lt;/li&gt;
&lt;li&gt;패킷 필터 방화벽에서 이런 트래픽을 처리하기 위해 정책을 선언하려면 외부로 나가는 목적지에 대해서 모든 패킷을 허용해야 함&lt;/li&gt;
&lt;li&gt;이 경우 내부 &amp;rarr; 외부는 가능하지만 외부 &amp;rarr; 내부에 대한 정책이 없어 통신이 되지 않음&lt;/li&gt;
&lt;li&gt;외부 &amp;rarr; 내부 응답 설정 시 정책을 설정해야 한다면 출발지는 모든 IP여야 하고 목적지 서비스 포트도 랜덤 포트를 지정하므로 역시 모든 포트가 돼야 함&lt;/li&gt;
&lt;li&gt;이런 정책은 보안에 너무 취약하기 때문에 패킷 상태를 인지해 패킷의 인과 관계를 파악할 수 있는 상태 기반 SPI 엔진이 등장&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;SPI 엔진&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;/li&gt;
&lt;li&gt;내부 &amp;rarr; 외부 인터넷으로 통신을 시도해 받은 응답과 외부에서 내부로 직접 들어오려는 패킷을 구분할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.3. 방화벽 동작 방식&lt;/h3&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;방화벽 제조사 별로 방화벽 동작이 다양하므로 제조사가 제공하는 Packet Processing Flow 문서를 참조하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&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;장비에 패킷이 들어오면 우선 세션 테이블 확인&lt;/li&gt;
&lt;li&gt;조건에 맞는 세션 정보가 세션 테이블에 있을 때, 포워딩 테이블 확인(라우팅, ARP 포함)&lt;/li&gt;
&lt;li&gt;조건에 맞는 세션 정보가 세션 테이블에 없을 때, 방화벽 정책 확인&lt;/li&gt;
&lt;li&gt;방화벽 정책은 전체를 확인하여 없을 때 암시적 거부(Implicit Denial) 규칙을 참고해 거부&lt;/li&gt;
&lt;li&gt;허용 규칙이 있으면 내용을 세션 테이블에 적는다&lt;/li&gt;
&lt;li&gt;포워딩 테이블을 확인(라우팅, ARP 포함)&lt;/li&gt;
&lt;li&gt;조건에 맞는 정보가 포워딩 테이블에 있을 때, 적절한 인터페이스로 패킷을 포워딩&lt;/li&gt;
&lt;li&gt;조건에 맞는 정보가 포워딩 테이블에 없을 때, 패킷 폐기&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;SPI 엔진을 가진 방화벽은 세션 인지 기능이 있어 OSI 3,4 계층의 세부적인 필드도 함께 확인&lt;/li&gt;
&lt;li&gt;TCP 컨트롤 플래그에 따라 동작 방식이 변하거나 시퀀스와 ACK 번호가 갑자기 변경되는 걸 인지해 세션 탈취 공격을 일부 방어할 수 있음 &lt;b&gt;(TCP Anti-Replay)&lt;/b&gt;&lt;/li&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;3.4. ALG&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;FTP의 경우, 세션 방화벽 등장 이전에 개발되어 세션 장비를 고려하지 못해 방화벽이 있는 경우 정산적인 통신을 못함&lt;/li&gt;
&lt;li&gt;FTP는 컨트롤 프로토콜과 데이터 프로토콜이 분리되어 동작하고 반대로 세션을 맺음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;FTP 동작에서의 문제&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FTP 액티브 모드에서는 초기 접속 방향과 반대로 데이터 프로토콜이 동작해 방화벽이 정상적으로 통과할 수 없음&lt;/li&gt;
&lt;li&gt;FTP 통신 방식을 패시브 모드로 변경하면 패시브 모드 자체를 제공하지 못하는 컴포넌트도 있고 이미 개발된 애플리케이션 변경이 불가능한 경우도 있음&lt;/li&gt;
&lt;li&gt;그래서 ALG 기능을 통해 방화벽에서 FTP 액티브 모드를 통과시키기 위해 애플리케이션 프로토콜을 확인하고 필요에 따라 세션을 인지해 포트를 자동으로 열어줌&lt;/li&gt;
&lt;li&gt;ALG 기능은 PAT(Port Address Translation) 기능이 동작하는 방화벽에서 PAT를 정상적으로 통과하지 못하는 프로토콜들을 자동으로 인지해 애플리케이션 정보를 변경해 주거나 세션 테이블을 만들어주는 작업을 수행함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;FTP 프로토콜이 방화벽을 지나갈 때 방화벽 동작 순서&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;FTP ALG 기능은 초기 FTP 요청 커맨드를 모니터링&lt;/li&gt;
&lt;li&gt;서버 쪽에서 사용할 데이터 세션에서 사용할 포트를 클라이언트로 알려줄 때, 이 정보를 확인하고 적절한 세션 정보를 만듦. 서버의 출발지 IP와 포트는 TCP 20번으로, 클라이언트의 IP와 서버에서 알려준 포트를 도착지로 하는 세션을 만들어 세션 테이블에 올림&lt;/li&gt;
&lt;li&gt;서버에서 클라이언트로 데이터 세션을 열 때, 세션 테이블에 이미 정보가 들어 있어 정책을 확인하지 않고 패킷을 포워딩&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.6. 방화벽의 한계&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;방화벽이 대중화되자 공격 목표가 시스템이나 계정 탈취에서 서비스 중단 쪽으로 바뀌고 DDoS 공격이 새로운 트렌드가 됨&lt;/li&gt;
&lt;li&gt;방화벽을 우회하는 공격이 개발되고 특히 대규모 웜 공격으로 인터넷 서비스가 마비되면서 방화벽의 한계가 옴&lt;/li&gt;
&lt;li&gt;SPI 엔진 기반 방화벽은 OSI 3,4 계층에서만 동작하여 애플리케이션 영역을 검사하지 못함&lt;/li&gt;
&lt;li&gt;근본적으로 바이러스나 백도어, 인터넷 웜을 방어할 수 없고 취약점을 악용한 공격도 방어할 수 없음&lt;/li&gt;
&lt;li&gt;이런 웜 공격을 막기 위해 IPS가 등장함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;현대 방화벽 NGFW, UTM&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;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;li&gt;APT 공격에 대응하는 샌드박스 기능에 연계되어 제공되기도 함&lt;/li&gt;
&lt;li&gt;NGFW(Next Generation FireWall), UTM(Unified Threat Management)은 방화벽을 애플리케이션 영역까지 확장한 보안 장비&lt;/li&gt;
&lt;li&gt;NGFW는 보안 장비 기능들이 논리적으로 통합되어 있고 UTM은 물리적인 엔진을 통합해 함께 동작하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;NFV(Network Function Virtualization)&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;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;x86 기반의 하드웨어에 가상화 서버 형태로 라우터, 방화벽, L4 스위치와 같은 장비를 탑재&lt;/li&gt;
&lt;li&gt;성능에 한계가 있지만 서비스 체이닝 기술을 이용해 새로운 서비스를 쉽게 추가, 삭제 ,적용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. IPS, IDS&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IPS/IDS는 OSI 3~7 계층까지 검사하고 방화벽은 OSI 3,4 계층 영역만 검사함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.1. IPS, IDS의 정의&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1152&quot; data-origin-height=&quot;327&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/og1Z1/btsKFiHkm2h/2RJ68sZqHPId4MgcEoFtjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/og1Z1/btsKFiHkm2h/2RJ68sZqHPId4MgcEoFtjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/og1Z1/btsKFiHkm2h/2RJ68sZqHPId4MgcEoFtjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fog1Z1%2FbtsKFiHkm2h%2F2RJ68sZqHPId4MgcEoFtjk%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;772&quot; height=&quot;219&quot; data-origin-width=&quot;1152&quot; data-origin-height=&quot;327&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IDS(Intrusion Detection System): 공격자가 시스템을 해킹할 때 탐지를 목적으로 개발된 시스템&lt;/li&gt;
&lt;li&gt;IPS(Intrusion Prevention System): 공격이 발견되면 직접 차단하는 능력을 갖춘 장비, 트래픽이 지나가는 인라인 상에 장비를 배치&lt;/li&gt;
&lt;li&gt;적극적으로 통신에 개입해 유해 트래픽을 차단, 방어하는 것 외 회피 공격을 차단하기 위한 세션 이해 가능 여부, 능동적 방어를 위한 어노말리(Anomaly) 등 다양한 기능으로 구분&lt;/li&gt;
&lt;li&gt;IPS는 &lt;b&gt;호스트 기반 IPS&lt;/b&gt;와 &lt;b&gt;네트워크 기반 IPS&lt;/b&gt;로 구분됨&lt;/li&gt;
&lt;li&gt;일반적인 IPS는 네트워크 기반 NIPS이고 클라우드 내부에서도 네트워크 기반 NIPS로 바뀌는 추세&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.2. IPS, IDS 동작 방식&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;4.2.1. 패턴 매칭 방식&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시그니처(signature) 방식, 데이터베이스 방식 방어라고도 함&lt;/li&gt;
&lt;li&gt;기존 공격이나 취약점을 통해 공격 방식에 대한 데이터베이스를 습득하고 그 최신 내용을 유지하다가 공격을 파악하는 기술&lt;/li&gt;
&lt;li&gt;패턴 기반 방어가 IPS의 상당 부분을 차지하므로 IPS는 많은 공격 데이터베이스를 보유해야 하고 최신 공격 방식을 반영하는 것이 중요&lt;/li&gt;
&lt;li&gt;IPS는 갖고 있는 공격 패턴 데이터를 활용해 특별한 문자열을 모니터링하다가 자신이 보유한 데이터베이스에 매칭되는 패킷이 들어오면 방어&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.2.2. 어노말리 공격 방어&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;블랙리스트 기반 패턴 매칭 기반 방어의 한계 때문에 IPS에서도 화이트리스트 기반의 방어기법이 개발됨&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;프로파일 어노말리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;평소 관리자가 정해놓은 기준이나 IPS 장비가 모니터링해 정해진 기준과 다른 행위가 일어나면 공격으로 판단&lt;/li&gt;
&lt;li&gt;이 기능은 동적 프로파일 기능이 강화되면서 향후 DDoS 방어 장비로 진화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로토콜 어노말리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;좀비 PC의 공격에 대한 탐지와 방어를 위해 사용&lt;/li&gt;
&lt;li&gt;실제 해당 서비스 포트에서 동작 프로토콜이 아닌 다른 프로토콜을 사용하는 경우 이것을 파악해 적절히 제어하는 기법&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.3. IPS, IDS의 한계와 극복(NGIPS)&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;IPS의 한계&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IPS는 네트워크 상에 빠른 속도로 애플리케이션 레벨까지 확인하기 위해 플로(flow) 엔진을 사용&lt;/li&gt;
&lt;li&gt;이 엔진은 흘러가는 상황을 모니터링해 공격을 탐지하므로 IPS 장비를 비교적 쉽게 우회함&lt;/li&gt;
&lt;li&gt;IPS는 &lt;b&gt;오탐이 많이 발생&lt;/b&gt;하여 초기 설치 환경에 맞는 튜닝작업을 오래 해줘야 하고 별도의 인력이 장비 모니터링과 환경에 맞는 최적화 작업을 지속해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;NGIPS 출시&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IPS의 기능을 향상시켜 문제를 해결한 NGIPS(Next Generation IPS)가 출시됨&lt;/li&gt;
&lt;li&gt;애플리케이션을 인지하거나 다양한 시스템과 연동&lt;/li&gt;
&lt;li&gt;APT 공격을 방어하기 위한 일부 기능이 탑재되거나 다양한 외부 시스템과 연동&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;IPS가 공격 데이터베이스를 얻는 방법&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;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;li&gt;공격에 대한 방어가 없고 해커는 공격 대상으로 생각하여 공격&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. DDoS 방어 장비&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;759&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mCqcQ/btsKCMRqEJZ/JMIg0ZG6Joo8h1tJ3fLL61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mCqcQ/btsKCMRqEJZ/JMIg0ZG6Joo8h1tJ3fLL61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mCqcQ/btsKCMRqEJZ/JMIg0ZG6Joo8h1tJ3fLL61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmCqcQ%2FbtsKCMRqEJZ%2FJMIg0ZG6Joo8h1tJ3fLL61%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;539&quot; height=&quot;475&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;759&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.1. DDoS 방어 장비의 정의&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;초기에는 네트워크 장비의 취약점을 공격했지만 현재는 다양한 DDoS 공격 형태가 등장&lt;/li&gt;
&lt;li&gt;DDoS 방어 장비는 볼류메트릭 공격을 방어하기 위해 트래픽 프로파일링 기법을 주로 사용하고 다양한 공격 정보를 수집한 데이터베이스를 활용하기도 함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.2. DDoS 방어 장비 동작 방식&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DDoS 방어 서비스로는 클라우드 서비스, 회선 사업자의 방어 서비스, DDoS 방어 장비를 사내에 설치하는 방법이 있음&lt;/li&gt;
&lt;li&gt;그 외 회선 사업자와 DDoS 방어 장비를 이원화해 협조하는 서비스도 등장&lt;/li&gt;
&lt;li&gt;DDoS는 대규모 공격이기 때문에 탐지 장비와 방어 장비를 구분하는 경우가 많았음&lt;/li&gt;
&lt;li&gt;DDoS 공격을 탐지해 공격을 수행하는 IP 리스트를 넘겨주면 방어 장비나 ISP 내부에서 이 IP를 버리는 것이 가장 일반적인 DDoS 방어 기법&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;DDoS 판별 방식&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&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;/li&gt;
&lt;li&gt;습득한 데이터와 일치하지 않는 과도한 트래픽이 인입되면 알려주고 차단&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;보안 데이터베이스 기반 방어
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IP 평판 데이터베이스를 공유해 DDoS 공격으로 사용된 IP 기반으로 방어 여부 결정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.3. DDoS 공격 타입&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.60467%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 30.2325%;&quot;&gt;&lt;span style=&quot;color: #ffffff; text-align: start;&quot;&gt; 볼류메트릭 공격&amp;nbsp; &lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 31.0465%;&quot;&gt;프로토콜 공격&lt;/td&gt;
&lt;td style=&quot;width: 30.1163%;&quot;&gt;&amp;nbsp;애플리케이션 공격&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.60467%;&quot;&gt;정의&lt;/td&gt;
&lt;td style=&quot;width: 30.2325%;&quot;&gt;대용량의 트래픽을 사용해 공격 대상의 대역폭을 포화시키는 공격 &lt;br /&gt;&lt;br /&gt;간단한 증폭기술을 사용해 생성하기 쉬움&lt;/td&gt;
&lt;td style=&quot;width: 31.0465%;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;3,4 계층 프로토콜 스택의 취약점을 악용해 대상을 액세스할 수 있게 만드는 공격&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 30.1163%;&quot;&gt;&lt;span&gt;7계층 프로토콜 스택의 약점을 악용하는 공격&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;가장 정교한 공격 및 식별, 완화에 가장 까다로운 공격&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.60467%;&quot;&gt;동작 &lt;br /&gt;방식&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 30.2325%;&quot;&gt;&lt;span&gt;공격에 의해 생성된 트래픽 양은 최종 자원에 대한 액세스를 완전히 차단할 수 있음&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;쓸모없는 패킷이 회선을 모두 차지해 정상적인 서비스 트래픽이 통과할 수 없음&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 31.0465%;&quot;&gt;&lt;span&gt;공격 대상이나 중간 위험 리소스의 처리 용량을 모두 사용해 서비스 중단을 유발&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;일반적인 네트워크 장비나 네트워크 보안 장비를 대상으로 공격&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;br /&gt;공격 대상 장비의 CPU, 메모리 자원을 고갈시킴&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 30.1163%;&quot;&gt;&lt;span&gt;대상과의 연결을 설정한 후 프로세스와 트랜잭션을 독점해 서버 자원을 소모시킴&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;애플리케이션 프로토콜 자체의 취약점이나 플랫폼의 취약점을 악용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 8.60467%;&quot;&gt;사례&lt;/td&gt;
&lt;td style=&quot;width: 30.2325%;&quot;&gt;NTP 증폭, DNS 증폭, UDP 플러드, TCP 플러드&lt;/td&gt;
&lt;td style=&quot;width: 31.0465%;&quot;&gt;Syn 플러드, Ping of Death&lt;/td&gt;
&lt;td style=&quot;width: 30.1163%;&quot;&gt;HTTP 플러드, DNS 서비스 공격, Slowloris 등&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;h3 data-ke-size=&quot;size23&quot;&gt;5.4. 볼류메트릭 공격&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;회선 공급을 해주는 ISP 내부나 사용자 네트워크 최상단에 위치시켜 공격을 완화해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ ISP: Internet Service Provider&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;미리 악성 코드에 감염되어 해커가 컨트롤하는 좀비 PC가 많아야 함&lt;/li&gt;
&lt;li&gt;최근에는 대부분 좀비 PC가 적거나 더 강한 DDoS 공격을 위한 &lt;b&gt;증폭 공격&lt;/b&gt;이 증가함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;증폭 공격&lt;/b&gt;: 공격자가 상대적으로 적은 대역폭으로 중간 리플랙터에 패킷을 보내면 이 트래픽이 증폭되어 피해자 네트워크에 수십~수백 배의 공격 트래픽이 발생하는 공격법&lt;/li&gt;
&lt;li&gt;혼자서는 대부분 방어가 불가능하여 ISP를 통한 방어나 Cloud DDoS 솔루션을 통해 서비스 네트워크로 트래픽이 도달하지 못하도록 조치해야 함&lt;/li&gt;
&lt;li&gt;클라우드 기반 서비스는 DDoS, WAF와 같은 방어 장비가 필요하지 않은 장점이 있음&lt;/li&gt;
&lt;li&gt;실제 서비스 앞에 미리 클라이언트 요청을 받아 처리한 후 문제가 없는 요청만 서버 쪽으로 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. VPN&lt;/h2&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;&lt;b&gt;전용 회선과 VPN&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터넷 망이 아닌 전용 회선으로 직접 연결할 때도 VPN을 추가 구성하는 경우가 있음&lt;/li&gt;
&lt;li&gt;전용 회선은 종단 간 직접 연결하지만 데이터가 그대로 흐르므로 암호화가 되지 않음&lt;/li&gt;
&lt;li&gt;보안을 위해서 전용 회선에 VPN을 추가하여 데이터를 암호화함&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가입자 입장의 VPN 기술은 인터넷 공용 망을 사용하므로 안전한 통신을 위한 암호화와 인증 같은 보안 강화 기술을 적용해야 함&lt;/li&gt;
&lt;li&gt;과거에는 PPTP, L2TP, GRE와 같이 암호화를 지원하지 않거나 매우 간단한 암호화만 지원했는데 최근에는 IPSEC의 보안 기술이 추가적으로 함께 사용됨&lt;/li&gt;
&lt;li&gt;본사-지사 같은 네트워크 대 네트워크 연결에는 IPSEC VPN이 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 경우, VPN이 연결되는 본사와 지사에 모두 IPSEC VPN 지원 네트워크 장비가 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;개인 사용자가 접속하는 경우 SSLVPN이 사용됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 경우, PC나 모바일 단말과 같은 원격지는 별도의 네트워크 장비가 필요하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.1. VPN 동작 방식&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;일반적으로 VPN이라 부르는 프로토콜은 터널링에 보안을 위한 다양한 기술이 포함됨.&lt;/li&gt;
&lt;li&gt;패킷 암호화, 인증, 무결성 체크 등의 보안 기능을 이용해 패킷이 노출돼도 감청할 수 없도록 보호&lt;/li&gt;
&lt;li&gt;현재 IPSEC과 SSL이 가장 많이 사용됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;VPN 지원 형태&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Host to Host 통신 보호
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;두 호스트 간에 직접 VPN 터널을 연동하는 기법, 잘 안 쓰임&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Network to Network 통신 보호
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;본사-지사 같은 특정 네트워크를 가진 두 종단을 연결, IPSEC 프로토콜 스택이 가장 많이 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Host가 Network로 접근할 때 보호
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모바일 사용자가 일반 인터넷망을 통해 사내망으로 연결하는 경우, IPSEC과 SSL 프로토콜이 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&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;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;li&gt;피해자가 패킷과 데이터를 처리하는 방법과 보안 장비의 다른 부분을 집중 공격하며 IPS가 메인 타깃&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IT 엔지니어를 위한 네트워크 입문 (고재성, 이상훈 저, 2020.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/네트워크</category>
      <category>computer science</category>
      <category>DDOS</category>
      <category>IPS</category>
      <category>네트워크</category>
      <category>방화벽</category>
      <category>보안</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/36</guid>
      <comments>https://onyodev.tistory.com/36#entry36comment</comments>
      <pubDate>Mon, 11 Nov 2024 14:01:36 +0900</pubDate>
    </item>
    <item>
      <title>웹캐싱 기법</title>
      <link>https://onyodev.tistory.com/35</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 반효경 저 - &quot;운영체제와 정보기술의 원리&quot;를 공부하고 정리하여 작성하였습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 웹캐싱&lt;/h2&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;90년대 중반부터는 웹의 보편화와 CDN의 활성화로 원격지의 객체를 캐싱하는 기법의 중요성도 높아짐&lt;/li&gt;
&lt;li&gt;&lt;b&gt;웹캐싱&lt;/b&gt;이란 웹 사용자에 의해 빈번히 요청되는 데이터를 사용자와 지리적으로 가까운 웹캐시 서버에 보관해 빠른 서비스를 가능하게 하는 기법&lt;/li&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;가 사용되는데 그룹에 속한 웹서버의 객체들을 캐싱하여 서버의 부하를 직접적으로 줄이고 웹 사용자의 지연시간을 줄이는 역할을 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1. 캐시 교체 알고리즘&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;버퍼캐싱과 페이징 등 전통적인 캐싱시스템에서 LRU 알고리즘 등으로 폭넓게 연구됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2. 일관성 유지 기법&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;/li&gt;
&lt;li&gt;하지만 웹캐시에서는 전통적 컴퓨터 시스템과 달리 일관성 유지 여부가 큰 문제는 아니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 웹캐싱의 교체 알고리즘&lt;/h2&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;2.1. 교체 알고리즘의 성능 척도&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전통적 캐싱 환경에서의 캐시 교체 알고리즘의 목표는 캐시적중률(Hit Rate)를 높이는 것이면 충분했음.&lt;/li&gt;
&lt;li&gt;캐시적중률: 사용자의 총 요청 중 캐시에서 적중되어 서비스된 요청의 비율&lt;/li&gt;
&lt;li&gt;요즘에는 객체의 크기와 인출비용이 다 다르기 때문에 참조 가능성과 이질성을 함께 고려하여 객체들의 가치를 평가해야 함.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;캐시적중률 = $\sum h_i / \sum r_i$&lt;/li&gt;
&lt;li&gt;바이트적중률 = $\sum (s_i \cdot h_i) / \sum (s_i \cdot r_i)$&lt;/li&gt;
&lt;li&gt;지연감소율 = $\sum (d_i \cdot h_i) / \sum (d_i \cdot r_i)$&lt;/li&gt;
&lt;li&gt;비용절감률 = $\sum (s_i \cdot h_i) / \sum (s_i \cdot r_i)$
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;$h_i$ : 객체 i의 캐시 적중 횟수&lt;/li&gt;
&lt;li&gt;$r_i$ : 객체 i의 총 참조 횟수&lt;/li&gt;
&lt;li&gt;$s_i$ : 객체 i의 크기&lt;/li&gt;
&lt;li&gt;$d_i$ : 객체 i의 근원지 서버로부터 인출 지연시간&lt;/li&gt;
&lt;li&gt;$c_i$ : 객체 i의 인출비용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. 참조 가능성의 예측&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;일반적으로 LRU, LFU 등의 과거 참조 기록에 의한 방법을 사용한다.&lt;/li&gt;
&lt;li&gt;LFU는 최근 참조된 객체에 대한 평가가 어렵고 LRU는 많이 참조된 객체에 대한 평가가 어렵다는 문제점이 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;LRU-K&lt;/b&gt;는 최근 K번째 참조된 시각에 의거해 가치를 평가하는 방법이 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;LRFU(Least Recently Frequently Used)&lt;/b&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;&lt;span style=&quot;color: #ee2323;&quot;&gt;시간지역성 관점&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;시간지역성의 관점에서 대부분 객체의 직전 참조 시각을 활용하고 LNC-R 알고리즘만 과거 K번째 참조 시각을 이용함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;참조인기도 관점&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;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;시간지역성 &amp;amp; 참조인기도 관점&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;LRV 알고리즘과 MIX 알고리즘은 직전 참조 시각과 객체 참조 횟수를 동시에 고려해 예측&lt;/li&gt;
&lt;li&gt;최근은 시간지역성에 기반한 GD-SIZE 알고리즘에 참조 인기도를 결합시키는 방법을 연구&lt;/li&gt;
&lt;li&gt;LUV 알고리즘은 버퍼캐싱에서 연구된 LRFU 알고리즘을 웹캐시 특성에 맞게 일반화했고 과거 모든 참조 기록을 이용&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3. 객체의 이질성에 대한 고려&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;실제로는 비용절감률을 높이는게 주류&lt;/b&gt;&lt;/li&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;/li&gt;
&lt;li&gt;LNC-R, SW-LFU, SLRU, LRV, LUV 등이 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;두번째 부류는 GD-SIZE 계열의 알고리즘
&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;노화 메커니즘&lt;/b&gt;과 객체의 인출 비용에 관계없이 모든 객체들에 대해 동일한 값을 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.4. 알고리즘의 시간 복잡도&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시간복잡도 측면에서 현실성이 없다면 쓰일 수 없다. 프락시캐시의 경우 수십만~수백만 객체가 존재하기 때문에 O(N) 이상을 사용해선 안됨.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보통은 O(logN)을 넘지 않는 것이 바람직함.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;새롭게 참조된 객체의 가치에 맞는 위치를 찾아주기 위해서 &lt;b&gt;대부분의 알고리즘들은 힙(heap) 자료구조를 활용하여 O(logN)의 시간복잡도에 각종 캐시 연산을 구현함&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;시간에 따라 객체의 가치가 변하는 경우, 힙을 이용한 구현이 불가능하여 O(N)의 시간복잡도를 필요하게 됨&lt;/li&gt;
&lt;li&gt;이러한 알고리즘은 &lt;b&gt;근사적인 구현 방법을 사용해 시간 복잡도를 낮춘다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 웹캐시의 일관성 유지 기법&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반적인 웹캐싱 시스템에서는 적응적 TTL 기법을 사용하여 약한 일관성 유지 기법을 사용&lt;/li&gt;
&lt;li&gt;약한 일관성 유지 기법이란 변경되었을 가능성이 높은 경우에만 확인하는 기법을 말함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;강한 일관성 유지 기법&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Polling-every-time: 캐시 내에 이미 존재하는 객체에 대한 요청이 있을 때마다 근원지 서버에 객체의 변경 여부를 확인하는 방법&lt;/li&gt;
&lt;li&gt;invalidation: 근원지 서버가 자신의 객체를 캐싱하고 있는 모든 프락시서버를 기록해두었다가 해당 개체가 변경된 경우 해당 프락시서버들에 변경사실을 알려주는 방법&lt;/li&gt;
&lt;li&gt;이 둘은 사용자에게 변경되기 이전의 정보를 제공할 가능성이 없는 기법&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;약한 일관성 유지 기법&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;adaptive TTL: 캐시 내에 이미 존재하는 객체에 대한 요청이 있을 때, 해당 객체에 대한 최종 변경 시각과 최종 확인 시각을 고려해 변경되었을 가능성이 높다고 판단되는 경우에만 근원지 서버에 변경 여부를 확인하는 방법. 변경가능성은 LMF에 의해 판단하며 LMF가 임계값 이상인 경우에만 근원지 서버에 변경 여부를 확인&lt;/li&gt;
&lt;li&gt;LMF = (현재 시각 - 최종확인 시각)/ (최종확인 시각 - 최종변경 시각)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 웹캐시의 공유 및 협력 기법&lt;/h2&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;웹캐시 간의 공유는 **인터넷 캐시 프로토콜(ICP)**에 의해 이루어짐&lt;/li&gt;
&lt;li&gt;ICP는 동료 프락시캐시들 사이에서 웹 객체의 검색 및 전송을 지원하는 프로토콜&lt;/li&gt;
&lt;li&gt;프락시서버에서 사용자가 요구한 웹 객체를 갖고 있지 않은 경우, 모든 주변 프락시에게 ICP 질의를 멀티캐스트하고 이후 답신을 받아 사용자에게 전달&lt;/li&gt;
&lt;li&gt;웹캐시들 간의 공유를 위한 또 다른 시도로는 캐시 배열 간 경로지정 프로토콜 CARP가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;CARP(Cache Array Routing Protocol)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공유 웹캐시들에 동일한 웹 객체들이 중복 저장되는 것을 막기 위해 URL 공간을 분할해, 각각의 캐시는 자신들에게 배정되는 객체들만을 캐싱하게 됨&lt;/li&gt;
&lt;li&gt;디렉토리 기반 프로토콜에서는 공유 웹캐시에 저장된 객체들의 위치 정보를 디렉토리에 유지함으로써 ICP 프로토콜의 멀티캐스트 부담을 없애고자 함&lt;/li&gt;
&lt;li&gt;하지만 디렉토리 유지 및 관리에 부담이 생겨 디렉토리 서버 부하를 줄이기 위해 여러 개의 디렉토리 서버를 두기도 함&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 웹캐시의 사전인출 기법&lt;/h2&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;li&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;/li&gt;
&lt;li&gt;대화식 사전인출 기법
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML 문서에 대한 요청을 했을 때 웹캐시는 캐싱하고 있던 HTML 문서를 미리 파싱&lt;/li&gt;
&lt;li&gt;그 문서에 포함되거나 연결된 웹 객체를 미리 받아와서 사용자의 후속 요청에 곧바로 전달하는 기법&lt;/li&gt;
&lt;/ul&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;은 캐싱된 객체의 &lt;b&gt;유효성을 미리 확인&lt;/b&gt;해두었다가 사용자가 해당 객체의 &lt;b&gt;요청 시&lt;/b&gt; 웹서버에 변경 여부를 확인하지 않고 &lt;b&gt;곧바로 보내주는 방법&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 동적 웹 객체의 캐싱 기법&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ASP, CGI 등 동적 웹 콘텐츠를 처리하는 부분이 전체 웹서비스 지연시간 중 상당 부분을 차지하고 웹 서버의 과부하를 일으킴&lt;/li&gt;
&lt;li&gt;요청받은 내용에 대해 프로그램을 실행한 후 그 결과물을 보내주어야 하기 때문에 데이터 관리가 더 어려움&lt;/li&gt;
&lt;li&gt;현재까지의 동적 웹콘텐츠 캐싱은 주로 웹서버 내부에서 빠른 처리를 위해 웹서버 전위에 설치하는 역방향 프록시캐시 또는 웹서버 가속기 중 일부에서 활용 중&lt;/li&gt;
&lt;li&gt;HTML 등의 규약에 동적 웹콘텐츠 중 캐싱 가능한 곳을 부분적으로 표시하는 태그 등을 활용하여 향후에는 일반적인 웹캐시에서도 이와 같은 기법이 활용&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;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;운영체제와 정보기술의 원리 (반효경 저, 2020.5)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/운영체제</category>
      <category>computer science</category>
      <category>운영체제</category>
      <category>웹캐시</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/35</guid>
      <comments>https://onyodev.tistory.com/35#entry35comment</comments>
      <pubDate>Mon, 11 Nov 2024 11:47:46 +0900</pubDate>
    </item>
    <item>
      <title>디스크 관리</title>
      <link>https://onyodev.tistory.com/34</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;이 글은 반효경 저 - &quot;운영체제와 정보기술의 원리&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&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 data-ke-size=&quot;size26&quot;&gt;1. 디스크의 구조&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;605&quot; data-origin-height=&quot;488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yvlTu/btsKD2d9cbU/12Eit97Lxbihtx1OsmGuA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yvlTu/btsKD2d9cbU/12Eit97Lxbihtx1OsmGuA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yvlTu/btsKD2d9cbU/12Eit97Lxbihtx1OsmGuA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyvlTu%2FbtsKD2d9cbU%2F12Eit97Lxbihtx1OsmGuA1%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;454&quot; height=&quot;366&quot; data-origin-width=&quot;605&quot; data-origin-height=&quot;488&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디스크는 컴퓨터 시스템의 대표적인 비휘발성 2차 저장장치이다.&lt;/li&gt;
&lt;li&gt;디스크는 논리블록이라 부르는 일정한 크기의 저장공간들로 이루어진 1차원 배열로 취급함&lt;/li&gt;
&lt;li&gt;디스크가 저장 시에나 디스크 외부로 입출력이 일어날 때에도 논리블록 단위로 발생함.&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;섹터(sector)&lt;/b&gt;: 각 논리블록이 저장되는 디스크 내 물리적 위치, 논리블록 하나와 1대1 매핑&lt;/li&gt;
&lt;li&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;각각의 원판은 트랙(track)으로 구성되고 각 트랙은 섹터로 나뉘며 섹터에 최소한의 단위 정보가 저장됨.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실린더(cylinder)&lt;/b&gt;: 여러 개의 원판에서 상대적 위치가 동일한 트랙들의 집합&lt;/li&gt;
&lt;li&gt;디스크에 데이터를 읽고 쓰기 위해서 암(arm)이 해당 섹터가 위치한 실린더로 이동 후 원판이 회전하여 디스크 헤드가 저장된 섹터 위치에 도달해야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 디스크 스케줄링&lt;/h2&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;탐색시간&lt;/b&gt;: 디스크 헤드를 해당 실린더 위치로 이동시키는 데 걸리는 시간 (r방향 이동)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;회전지연시간&lt;/b&gt;: 디스크가 회전해서 읽고 쓰려는 섹터가 헤드 위치에 도달하기까지의 시간 (&amp;omega; 방향 이동)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;전송시간&lt;/b&gt;: 해당 섹터가 헤드 위치에 도달한 후 데이터를 실제로 섹터에 읽고 쓰는 데 소요되는 시간&lt;/li&gt;
&lt;li&gt;디스크 입출력 효율을 높이기 위해선 접근시간을 최소화해야 하는데 이때 &lt;b&gt;탐색시간&lt;/b&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;h4 data-ke-size=&quot;size20&quot;&gt;2.1. FCFS(First Come First Served) 스케줄링&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;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. SSTF(Shortest Seek Time First) 스케줄링&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;기아 현상&lt;/b&gt;을 발생시킬 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3. SCAN 알고리즘&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;/li&gt;
&lt;li&gt;엘리베이터 스케줄링 알고리즘이라고도 부름.&lt;/li&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;2.4. C-SCAN 알고리즘&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SCAN처럼 헤드가 한쪽 끝에서 다른 쪽 끝으로 이동하며 가는 길목에 있는 모든 요청을 처리함&lt;/li&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;2.5. LOOK과 C-LOOK 알고리즘&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LOOK 알고리즘은 SCAN과 달리 그 방향에 더 이상 대기 중인 요청이 없으면 즉시 이동방향을 반대로 바꾸는 스케줄링 방식&lt;/li&gt;
&lt;li&gt;C-LOOK 알고리즘은 전방에 요청이 없을 때 방향을 바꾸는 측면에서 LOOK과 유사하며, 한쪽 방향으로 이동할 때에만 요청을 처리한다는 점에서 C-SCAN과 유사함&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 다중 디스크 환경에서의 스케줄링&lt;/h2&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;li&gt;그리고 일부 디스크에 오류가 발생해도 지속적인 서비스가 가능하고 정보의 유실을 방지할 수 있음&lt;/li&gt;
&lt;li&gt;다중 디스크 환경에서는 어느 디스크에서 요청을 처리할지 결정하는 스케줄링 문제가 발생&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;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 디스크의 저전력 관리&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.1. 비활성화 기법&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디스크의 상태는 전력 소모를 기준으로 4가지로 나눌 수 있음
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;활동(active): 현재 헤드가 데이터를 읽거나 쓰고 있는 상태&lt;/li&gt;
&lt;li&gt;공회전(idle): 디스크는 회전 중이지만 데이터를 읽거나 쓰진 않은 상태&lt;/li&gt;
&lt;li&gt;준비(standby): 디스크는 회전하지 않지만 인터페이스가 활성화된 상태&lt;/li&gt;
&lt;li&gt;휴면(sleep): 디스크가 회전하지 않고 인터페이스도 비활성화된 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;비활성화 상태에서 디스크를 읽는 작업이 활성 상태일 때보다 전력이 많이 소모됨&lt;/li&gt;
&lt;li&gt;후속 요청까지의 시간 간격이 일정 시간 이상일 경우에만 디스크의 회전을 정지시키는 것이 전력 소모를 절감하는 데 효과적&lt;/li&gt;
&lt;li&gt;이는 장치를 비활성화할 시점을 결정하기 위해 미래의 요청 시점을 맞추는 것이 중요함&lt;/li&gt;
&lt;li&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;li&gt;확률기반 기법: 디바이스의 상태변경 시간 간격을 구하기 위해 확률분포를 통해 요청을 모델링하고 마르코프 체인 등과 같은 통계적 모델을 이용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.2. 회전속도 조절 기법&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;/li&gt;
&lt;li&gt;최근에는 워크로드의 특성을 활용해 회전속도를 조절하려는 시도락 이루어짐&lt;/li&gt;
&lt;li&gt;멀티미디어 환경에서는 시간에 따른 순차적 데이터 접근이 이루어져 주기성과 규칙성을 활용해 참조에 대한 예측이 가능함.&lt;/li&gt;
&lt;li&gt;전력 소모를 최소화하기 위해 실시간 응용프로그램 재생률(bit rate)과 버퍼 크기에 따라 디스크의 회전속도를 조절해서 전력 소모를 최소화하는 기법도 제안됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.3. 디스크의 데이터 배치 기법&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;디스크 내에 데이터 복제본을 많이 만들어 헤드 위치에서 가까운 복제본에 접근하게 하여 응답시간과 전력 절감을 얻는 FS2 파일 시스템이 제안됨&lt;/li&gt;
&lt;li&gt;복제본이 있는 경우, 쓰기 연산에서 일관성 문제가 발생할 수 있으나 FS2에서는 헤드의 위치에서 가까운 복제본에 데이터를 쓰면 나머니는 주소 테이블에 무효화 연산을 수행해 쓰기연산의 효율성도 높임&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.4. 버퍼캐싱 및 사전인출 기법&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;/li&gt;
&lt;li&gt;이 둘을 통합하여 디스크가 저전력 모드일때는 입출력 처리를 최대한 지연시키고 정상 전력 모드로 돌아오면 사전인출을 공격적으로 시행&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.5. 쓰기전략을 통한 저전력 디스크 기법&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;/li&gt;
&lt;li&gt;활성 상태일 때는 쓰는 방식으로 전력 소모를 줄이는 방&lt;/li&gt;
&lt;/ul&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;&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;운영체제와 정보기술의 원리&lt;/span&gt; (&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;반효경&lt;span&gt; &lt;/span&gt;&lt;/span&gt;저, 2020.5)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/운영체제</category>
      <category>computer science</category>
      <category>디스크</category>
      <category>디스크스케줄링</category>
      <category>운영체제</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/34</guid>
      <comments>https://onyodev.tistory.com/34#entry34comment</comments>
      <pubDate>Mon, 11 Nov 2024 11:43:49 +0900</pubDate>
    </item>
    <item>
      <title>가상 메모리</title>
      <link>https://onyodev.tistory.com/33</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;이 글은 반효경 저 - &quot;운영체제와 정보기술의 원리&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;운영체제는 프로그램 실행 시 CPU에서 즉시 필요한 부분만 메모리에 로드하고, 나머지는 디스크의 스왑 영역에 저장하여 메모리 사용을 최적화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;프로그램 입장에선 물리적 메모리 크기에 대한 제약을 생각할 필요가 없고 자기 자신만이 메모리를 사용하는 것처럼 프로그램하는 것을 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;이렇게 되면 프로그램은 0번지부터 시작하는 자기 자신만의 메모리 주소공간을 가정할 수 있는데 이를 가상메모리라 부른다.&lt;/b&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 요구 페이징&lt;/h2&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;요구 페이징은 특정 페이지에 대해 CPU의 요청이 들어온 후 해당 페이지를 메모리에 적재&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;699&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WO7wK/btsKz1f8pxj/BVFhRH6kYKQhzZFuXJ9ycK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WO7wK/btsKz1f8pxj/BVFhRH6kYKQhzZFuXJ9ycK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WO7wK/btsKz1f8pxj/BVFhRH6kYKQhzZFuXJ9ycK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWO7wK%2FbtsKz1f8pxj%2FBVFhRH6kYKQhzZFuXJ9ycK%2Fimg.jpg&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;573&quot; height=&quot;556&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;699&quot;/&gt;&lt;/span&gt;&lt;/figure&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;li&gt;이 비트는 특정 페이지가 참조되어 메모리에 적재된 경우 무효값에서 유효값으로 바뀜&lt;/li&gt;
&lt;li&gt;그리고 디스크의 스왑영역으로 쫓겨날 때에는 다시 무효값으로 바뀜&lt;/li&gt;
&lt;li&gt;CPU가 참조하려는 페이지가 현재 메모리에 올라와 있지 않아 유효-무효 비트가 무효로 세팅된 경우를 &lt;b&gt;페이지 부재(page fault)&lt;/b&gt;가 일어났다고 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1. 요구 페이징의 페이지 부재 처리&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1389&quot; data-origin-height=&quot;642&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/756AF/btsKBm4ut1h/hE6BkE0OIRd5NNkWeWfxmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/756AF/btsKBm4ut1h/hE6BkE0OIRd5NNkWeWfxmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/756AF/btsKBm4ut1h/hE6BkE0OIRd5NNkWeWfxmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F756AF%2FbtsKBm4ut1h%2FhE6BkE0OIRd5NNkWeWfxmk%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;1389&quot; height=&quot;642&quot; data-origin-width=&quot;1389&quot; data-origin-height=&quot;642&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU가 무효 페이지에 접근하면 주소 변환을 담당하는 MMU가 페이지 부재 트랩을 발생&lt;/li&gt;
&lt;li&gt;이후 CPU 제어권이 커널모드로 전환되고 페이지 부재 처리루틴이 호출됨
&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;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;비어 있는 프레임이 없다면 기존 메모리에 올라와 있는 페이지 중 하나를 디스크로 쫓아냄 (스왑 아웃)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;디스크로부터 메모리에 적재하기까지 시간이 오래 걸리므로 &lt;b&gt;페이지 부재를 발생시킨 프로세스는 CPU를 빼앗기고 봉쇄 상태가 됨&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;현재까지 수행되던 CPU 레지스터 상태 및 프로그램 카운터값을 프로세스 제어블록에 저장함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;디스크 입출력이 완료되어 인터럽트가 발생하면 페이지 테이블에서 해당 페이지의 유효-무효 비트를 유효로 설정하고 봉쇄되었던 프로세스를 준비 큐로 이동시킴&lt;/li&gt;
&lt;li&gt;이 프로세스가 다시 CPU를 할당받으면 프로세스 제어블록에 저장했던 값을 복원시켜 이전 명령부터 실행을 재개&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2. 요구 페이징의 성능&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;페이지 부재의 발생 빈도&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;유효 접근시간 = (1-P) x 메모리 접근시간&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;P x (페이지 부재 발생 처리 오버헤드 + 메모리에 빈 프레임 없는 경우 스왑 아웃 오버헤드 + 요청된 페이지의 스왑 인 오버헤드 + 프로세스의 재시작 오버헤드)&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;P = 페이지 부재 발생 비율 (0 &amp;le; P &amp;le; 1)&lt;/li&gt;
&lt;li&gt;페이지 부재가 없는 경우 메모리에만 접근하면 되고 페이지 부재가 발생하면 이와 같은 과정을 모두 거치게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 페이지 교체&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;888&quot; data-origin-height=&quot;714&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dilfuf/btsKBa4dORf/yGdeLQDI13aLpumNigCLi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dilfuf/btsKBa4dORf/yGdeLQDI13aLpumNigCLi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dilfuf/btsKBa4dORf/yGdeLQDI13aLpumNigCLi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdilfuf%2FbtsKBa4dORf%2FyGdeLQDI13aLpumNigCLi0%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;688&quot; height=&quot;553&quot; data-origin-width=&quot;888&quot; data-origin-height=&quot;714&quot;/&gt;&lt;/span&gt;&lt;/figure&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;li&gt;이경우 메모리에 올라와 있는 페이지 중 하나를 디스크로 쫓아내야 함&lt;/li&gt;
&lt;li&gt;이 과정을 &lt;b&gt;페이지 교체&lt;/b&gt;라고 하는데 어떻게 쫓아낼지를 결정하는 알고리즘을 &lt;b&gt;교체 알고리즘&lt;/b&gt;이라 한다.&lt;/li&gt;
&lt;li&gt;페이지 교체 알고리즘의 성능은 페이지 참조열에 대해 페이지 부재율을 계산함으로써 평가됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. 최적 페이지 교체&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;실제 알고리즘 성능에 대한 상한선&lt;/b&gt;을 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. 선입선출 알고리즘&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;/li&gt;
&lt;li&gt;페이지 프레임을 늘렸음에도 오히려 페이지 부재가 늘어나는 상황을 &lt;b&gt;FIFO의 이상 현상&lt;/b&gt;이라 부름&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3. LRU(Least Recently Used) 알고리즘&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;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.4. LFU(Least Frequently Used) 알고리즘&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;/li&gt;
&lt;li&gt;페이지 참조 횟수를 계산하는 방식에 따라 나뉠 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Incache-LFU&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Perfect-LFU&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;LFU 알고리즘은 LRU 알고리즘보다 오랜 시간 동안의 참조 기록을 반영할 수 있음&lt;/li&gt;
&lt;li&gt;LFU는 시간에 따른 페이지 참조의 변화를 반영하지 못하고 LRU보다 구현이 복잡하단 단점이 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.5. 클럭 알고리즘&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1007&quot; data-origin-height=&quot;487&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dKTKvm/btsKBoHZOpM/9uAvayEn9OYwZKhIeBsnd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dKTKvm/btsKBoHZOpM/9uAvayEn9OYwZKhIeBsnd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dKTKvm/btsKBoHZOpM/9uAvayEn9OYwZKhIeBsnd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdKTKvm%2FbtsKBoHZOpM%2F9uAvayEn9OYwZKhIeBsnd1%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;744&quot; height=&quot;360&quot; data-origin-width=&quot;1007&quot; data-origin-height=&quot;487&quot;/&gt;&lt;/span&gt;&lt;/figure&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;LRU를 근사시킨 알고리즘으로 NUR(Not Used Recently) 또는 NRU라 불림&lt;/li&gt;
&lt;li&gt;클럭 알고리즘은 오랫동안 참조되지 않은 페이지 중 하나를 교체함&lt;/li&gt;
&lt;li&gt;하드웨어 지원으로 훨씬 빠르고 효율적이며 대부분의 시스템에서 사용함&lt;/li&gt;
&lt;li&gt;교체할 페이지를 선정하기 위해 페이지 프레임들의 참조비트를 순차적으로 조사&lt;/li&gt;
&lt;li&gt;참조 비트는 각 프레임마다 하나씩 존재하며 그 프레임 내의 페이지가 존재하여 참조될 때 하드웨어에 의해 1로 자동 세팅&lt;/li&gt;
&lt;li&gt;참조비트가 1인 페이지가 없는 경우 0으로 바꾼 후 지나가고 0인 페이지는 교체함&lt;/li&gt;
&lt;li&gt;모든 페이지 프레임을 다 조사한 후 첫번째 페이지 프레임부터 조사 작업을 반복함&lt;/li&gt;
&lt;li&gt;참조비트는 그 페이지가 참조되면 다시 1로 세팅되기 때문에 &lt;b&gt;한 바퀴동안 쓰이지 않으면 교체됨&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;페이지가 한 번의 순환 동안 메모리에 유지되어 재사용 기회를 얻기 때문에 &lt;b&gt;2차 기회 알고리즘&lt;/b&gt;으로도 알려져 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 페이지 프레임의 할당&lt;/h2&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&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;li&gt;&lt;b&gt;우선순위 할당 방식&lt;/b&gt;: 프로세스의 우선순위에 따라 페이지 프레임을 다르게 할당&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;CPU에서 명령을 실행할 때는 일반적으로 여러 페이지를 동시에 참조&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;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 전역교체와 지역교체&lt;/h2&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;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;li&gt;교체 알고리즘에 근거해 할당되는 메모리 양을 가변적으로 함.&lt;/li&gt;
&lt;li&gt;LRU,LFU, 클럭 등 알고리즘을 물리적 메모리 내 전체 페이지 프레임을 대상으로 하는 경우 적용됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;li&gt;LRU, LFU 등의 알고리즘을 프로세스 별로 독자 운영할 경우 적용됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 스레싱(thrashing)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;418&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dDtPhZ/btsKz4RtEfJ/ohhqu4I4WCHxohVqyKKICk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dDtPhZ/btsKz4RtEfJ/ohhqu4I4WCHxohVqyKKICk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dDtPhZ/btsKz4RtEfJ/ohhqu4I4WCHxohVqyKKICk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdDtPhZ%2FbtsKz4RtEfJ%2Fohhqu4I4WCHxohVqyKKICk%2Fimg.jpg&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;487&quot; height=&quot;297&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;418&quot;/&gt;&lt;/span&gt;&lt;/figure&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;이 경우 페이지 부재율이 크게 상승해 CPU 이용률이 급격히 떨어짐&lt;/li&gt;
&lt;li&gt;이와 같은 현상을 스레싱이라 함.&lt;/li&gt;
&lt;li&gt;스레싱 발생 시나리오 (악순환)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;운영체제는 CPU 이용률이 낮은 경우를 메모리에 올라가 있는 프로세스 수가 적어서라고 판단함.&lt;/li&gt;
&lt;li&gt;준비 큐에 있는 프로세스를 계속 메모리에 올리려 함.&lt;/li&gt;
&lt;li&gt;그런데 CPU 이용률이 낮다는 것은 준비 큐가 비는 경우가 생긴다는 의미&lt;/li&gt;
&lt;li&gt;메모리에 올라와 있는 프로세스 수가 너무 적어 이들 프로세스가 모두 I/O 작업을 하면서 준비 큐가 비는 경우가 생겼다는 뜻&lt;/li&gt;
&lt;li&gt;CPU 이용률이 낮으면 운영체제는 메모리에 올라가는 프로세스 수를 늘려버림&lt;/li&gt;
&lt;li&gt;그러면 각 프로세스에 할당되는 메모리 공간이 지나치게 적어짐&lt;/li&gt;
&lt;li&gt;각 프로세스는 페이지 부재를 또 발생시킴&amp;hellip;&lt;/li&gt;
&lt;li&gt;이후 정해진 프로세스 수를 다 채우면 서로의 페이지를 교체하며 스왑 인-아웃을 지속적으로 발생시켜 오버헤드가 늘어남&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이런 스레싱을 방지하기 위한 워킹셋 알고리즘과 페이지 부재 빈도 알고리즘이 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ MPD(Multi-Programming Degree, 다중프로그래밍의 정도): 메모리에 동시에 올라가 있는 프로세스의 수&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.1. 워킹셋 알고리즘&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;지역성 집합&lt;/b&gt;이라 함.&lt;/li&gt;
&lt;li&gt;이러한 지역성 집합이 메모리에 동시에 올라갈 수 있도록 보장하는 메모리 알고리즘을 말함.&lt;/li&gt;
&lt;li&gt;프로세스의 워킹셋을 구성하는 페이지들이 한꺼번에 메모리에 올라갔을 때에 유효하고 그렇지 않은 경우 할당된 페이지 프레임들을 모두 반납시키고 주소 공간 전체를 디스크로 스왑아웃시킴&lt;/li&gt;
&lt;li&gt;한꺼번에 메모리에 올라갈 페이지들의 집합을 결정하기 위해 &lt;b&gt;워킹셋 윈도우(&amp;Delta;)&lt;/b&gt;를 사용함&lt;/li&gt;
&lt;li&gt;윈도우의 크기가 &amp;Delta;인 경우, 워킹셋 알고리즘은 시각 t1에서의 워킹셋 WS(t1)을 시간 간격 [t1-&amp;Delta;,t1]사이에서 참조된 서로 다른 페이지들의 집합으로 정의&lt;/li&gt;
&lt;li&gt;해당 시간 범위 내에 페이지들은 메모리에 유지하고 그렇지 않은 페이지들은 쫓아냄&lt;/li&gt;
&lt;li&gt;즉, 페이지가 참조된 시점부터 &amp;Delta;시간 동안은 메모리에 유지하고 그 시점이 지나면 메모리에서 지움&lt;/li&gt;
&lt;li&gt;워킹셋 알고리즘은 메모리에 올라와 있는 프로세스들의 워킹셋 크기의 합 &amp;gt; 프레임의 수 인 경우 일부 프로세스를 스왑 아웃 시켜 남은 프로세스의 워킹셋이 모두 메모리에 올라가도록 함&lt;/li&gt;
&lt;li&gt;반면 모두 할당한 후에도 프레임이 남을 경우, 스왑 아웃당했던 프로세스를 다시 메모리에 올려 워킹셋을 할당하여 MPD를 증가시킴&lt;/li&gt;
&lt;li&gt;&amp;Delta; 가 너무 작으면, 지역성 집합을 수용하지 못할 수 있음&lt;/li&gt;
&lt;li&gt;&amp;Delta; 가 너무 크면, MPD가 너무 감소해 CPU 이용률이 떨어짐&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.2. 페이지 부재 빈도 (Page Fault Frequency: PFF) 알고리즘&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;390&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/U4U7C/btsKAACpM2F/JzzS9RAXSA91R5ZL4iYHIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/U4U7C/btsKAACpM2F/JzzS9RAXSA91R5ZL4iYHIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/U4U7C/btsKAACpM2F/JzzS9RAXSA91R5ZL4iYHIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FU4U7C%2FbtsKAACpM2F%2FJzzS9RAXSA91R5ZL4iYHIk%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;556&quot; height=&quot;257&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;390&quot;/&gt;&lt;/span&gt;&lt;/figure&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;li&gt;추가할 빈 프레임이 없는 경우 일부 프로세스를 스왑 아웃시켜 확보함.&lt;/li&gt;
&lt;li&gt;하한값 이하로 떨어질 경우 여유있다 생각하여 프레임을 감소시킴&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;/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;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;운영체제와 정보기술의 원리&lt;/span&gt; (&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;반효경&lt;span&gt; &lt;/span&gt;&lt;/span&gt;저, 2020.5)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/운영체제</category>
      <category>computer science</category>
      <category>가상메모리</category>
      <category>스레싱</category>
      <category>운영체제</category>
      <category>페이지교체</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/33</guid>
      <comments>https://onyodev.tistory.com/33#entry33comment</comments>
      <pubDate>Thu, 7 Nov 2024 21:55:06 +0900</pubDate>
    </item>
    <item>
      <title>로드 밸런서</title>
      <link>https://onyodev.tistory.com/32</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 고재성, 이상훈 저 - &quot;IT 엔지니어를 위한 네트워크 입문&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&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 data-ke-size=&quot;size26&quot;&gt;1. 부하 분산&lt;/h2&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;li&gt;로드 밸런서에는 서비스를 위한 가상 IP(VIP)를 하나 제공하고 사용자는 동일한 가상 IP를 통해 각 서버로 접근&lt;/li&gt;
&lt;li&gt;이 외에도 로드 밸런서는 각 서버의 상태를 체크해 서비스가 가능한 서버로만 사용자 요청 분산&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;FWLB(FireWall Load Balancing)&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;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;li&gt;이러한 문제를 해결하고 동시에 이중화된 방화벽을 모두 사용하기 위해 사용됨.&lt;/li&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;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;FWLB를 사용하더라도 방화벽에 장애가 발생하는 경우를 대비하여 방화벽에서 설정이 필요함&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 부하 분산 방법&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가상 IP(Virtual IP): 서비스를 위해 사용되는 IP주소이므로 서비스 IP 주소라고도 함&lt;/li&gt;
&lt;li&gt;리얼 IP(Real IP): 각 서버의 실제 IP 주소&lt;/li&gt;
&lt;li&gt;로드 밸런서에 의해 가상 IP에 실제 서버들이 바인딩됨.&lt;/li&gt;
&lt;li&gt;로드밸런서에서는 부하 분산을 위한 그룹을 설정할 때 IP 주소(3계층)뿐만 아니라 서비스 포트(4계층)까지 지정해 만듦&lt;/li&gt;
&lt;li&gt;그리고 VIP 설정된 서비스 포트와 실제 서버 서비스 포트를 다르게 설정할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 헬스 체크&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1. 헬스 체크 방식&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;ICMP
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;단순히 서버가 살아 있는지 여부만 체크하는 방법으로 잘 사용하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TCP 서버 포트
&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;등록된 서비스 포트로 SYN &amp;rarr; SYN,ACK &amp;rarr; ACK로 응답, FIN을 보내 헬스체크 종료&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TCP 서비스 포트: Half Open
&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;SYN &amp;rarr; SYN, ACK &amp;rarr; RST로 마무리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;HTTP 상태 코드
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;서비스 포트까지는 TCP로 정상적으로 열리지만 웹 서비스에 대한 응답이 정상적이지 않은 경우 사용&lt;/li&gt;
&lt;li&gt;3방향 핸드셰이크를 거치고나서 HTTP를 요청해 정상상태 코드(200 OK)를 응답하는 지 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;li&gt;비정상적인 응답이라도 응답 내용에 확인하려는 문자열이 포함된 경우, 정상으로 판단&lt;/li&gt;
&lt;li&gt;그래서 정상 코드 값도 확인하거나 특정 문자열을 지정해서 확인해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3방향 vs 4방향 연결 종료(Close)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;4방향 핸드셰이크로 연결을 종료했지만 경우에 따라 3방향 핸드셰이크로 연결을 종료하기도 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.2. 헬스 체크 주기와 타이머&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1163&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bs1WTC/btsKAr6kDQ2/NVYKphPidX10hFGcoMokZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bs1WTC/btsKAr6kDQ2/NVYKphPidX10hFGcoMokZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bs1WTC/btsKAr6kDQ2/NVYKphPidX10hFGcoMokZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbs1WTC%2FbtsKAr6kDQ2%2FNVYKphPidX10hFGcoMokZK%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;1163&quot; height=&quot;375&quot; data-origin-width=&quot;1163&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;주기(interval)&lt;/b&gt;: 로드 밸런서에서 서버로 헬스 체크 패킷을 보내는 주기&lt;/li&gt;
&lt;li&gt;&lt;b&gt;응답 시간:&lt;/b&gt; 로드 밸런서에서 서버로 헬스 체크 패킷을 보내고 응답 시간을 기다리는 시간&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시도 횟수(Retries)&lt;/b&gt;: 로드 밸런서에서 헬스 체크 실패 시 최대 시도 횟수&lt;/li&gt;
&lt;li&gt;&lt;b&gt;타임아웃(Timeout)&lt;/b&gt;: 로드 밸런서에서 헬스 체크 실패 시 최대 대기 시간&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서비스 다운 시의 주기(Dead Interval)&lt;/b&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;/li&gt;
&lt;/ul&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;주기 &amp;gt; 응답시간&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 부하 분산 알고리즘&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.7443%;&quot;&gt;&lt;b&gt; 부하분산 알고리즘&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 78.1394%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.7443%;&quot;&gt;라운드 로빈&lt;/td&gt;
&lt;td style=&quot;width: 78.1394%;&quot;&gt;현재 구성된 장비에서 부하를 순차적으로 분산함.&lt;br /&gt;총 누적 세션 수는 동일하지만 활성화된 세션 수는 달라질 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.7443%;&quot;&gt;최소 접속 방식&lt;/td&gt;
&lt;td style=&quot;width: 78.1394%;&quot;&gt;현재 구성된 장비 중 가장 활성화된 세션 수가 적은 장비로 부하를 분산함.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.7443%;&quot;&gt;가중치 기반 라운드 로빈&lt;/td&gt;
&lt;td style=&quot;width: 78.1394%;&quot;&gt;라운드 로빈 방식과 동일하지만 각 장비에 가중치를 두어 가중치가 높은 장비에 부하를 더 많이 분산함.&lt;br /&gt;처리 용량이 다른 서버에 부하를 분산하기 위한 분산 알고리즘&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.7443%;&quot;&gt;가중치 기반 최소 접속 방식&lt;/td&gt;
&lt;td style=&quot;width: 78.1394%;&quot;&gt;최소 접속 방식과 동일하지만 각 장비에 가중치를 부여해 가중치가 높은 장비에 부하를 더 많이 분산함.&lt;br /&gt;처리 용량이 다른 서버에 부하를 분산하기 위한 분산 알고리즘&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.7443%;&quot;&gt;해시&lt;/td&gt;
&lt;td style=&quot;width: 78.1394%;&quot;&gt;해시 알고리즘을 이용한 부하 분산&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.1. 라운드 로빈&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;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.2. 최소 접속 방식&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;/li&gt;
&lt;li&gt;각 장비에 연결된 현재 세션 수를 파악하여 가장 적에 연결된 장비로 서비스 요청을 보냄&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.3. 해시&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;/li&gt;
&lt;li&gt;알고리즘에는 주로 출발지 IP주소, 목적지 IP주소, 출발지 서비스 포트, 목적지 서비스 포트를 사용&lt;/li&gt;
&lt;li&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;li&gt;세션을 유지해야 하는 서비스에 적합한 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;해시와 최소 접속 방식의 장점을 결한한 분산 방법도 있음&lt;/li&gt;
&lt;li&gt;라운드 로빈이나 최소 접속 방식을 사용하면서 **스티커(sticker)**를 주어 한 번 접속한 커넥션을 유지하는 방법&lt;/li&gt;
&lt;li&gt;처음 들어온 서비스 요청을 세션 테이블에 두고 같은 요청이 들어오면 같은 장비로 분산해 세션을 유지해 주는 기법&lt;/li&gt;
&lt;li&gt;그럼에도 세션 테이블은 타임아웃이 있어 타임아웃 이후에는 해당 기법이 유효하지 않을 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 로드 밸런서 구성 방식&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로드 밸런서의 구성 위치에 따라 2가지로 나뉨&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;1828&quot; data-origin-height=&quot;822&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x0qa4/btsKAvucuoS/0FPZdJZm4fYVBm4TqPwaiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x0qa4/btsKAvucuoS/0FPZdJZm4fYVBm4TqPwaiK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x0qa4/btsKAvucuoS/0FPZdJZm4fYVBm4TqPwaiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx0qa4%2FbtsKAvucuoS%2F0FPZdJZm4fYVBm4TqPwaiK%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;1828&quot; height=&quot;822&quot; data-origin-width=&quot;1828&quot; data-origin-height=&quot;822&quot;/&gt;&lt;/span&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;원암(One-Arm) 구성
&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;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;인라인(Inline) 구성
&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;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.1. 원암 구성&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;/li&gt;
&lt;li&gt;불필요한 트래픽이 로드 밸런서를 경유하지 않아 로드 밸런서 부하를 줄일 수 있음&lt;/li&gt;
&lt;li&gt;스위치 - 로드 밸런서 간의 대역폭을 최소화할 수 있고 대역폭이 부족한 경우 해당 구간만 증설하면 되기 때문에 확장에 유리함.&lt;/li&gt;
&lt;li&gt;로드 밸런서의 부하 감소 뿐만 아니라 장애 영향도를 줄이기 위해 사용&lt;/li&gt;
&lt;li&gt;부하 분산을 이용
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;부하 분산에 사용되는 서비스 IP 정보를 로드 밸런서가 갖고 있어 서버로 유입되는 트래픽은 먼저 로드 밸런서를 거침&lt;/li&gt;
&lt;li&gt;로드 밸런서에서는 각 실제 서버로 트래픽을 분산하고 서버의 응답 트래픽은 다시 로드 밸런서를 거쳐 사용자에게 응답&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;서버의 응답 트래픽이 로드 밸런서를 다시 거치려면 서비스 IP에 대해 실제 서버로 Destination NAT와 로드 밸런서가 가진 Source NAT도 함께 이루어짐&lt;/li&gt;
&lt;li&gt;Source NAT를 하지 않는 경우, DSR(Direct Server Return)을 사용함&lt;/li&gt;
&lt;/ul&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;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;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.2. 인라인 구성&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;/li&gt;
&lt;li&gt;4계층 이상의 데이터를 처리하는 로드 밸런서는 용량이 L3 장비보다 적으며 처리 용량이 커지면 가격이 널뛰기 때문에 로드 밸런서 부하에 따른 성능을 고려해야 함&lt;/li&gt;
&lt;/ul&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;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;로드 밸런서와 연결된 스위치 상에서 VRF와 같은 가상화를통해 논리적으로 분리한 경우 나타남&lt;/li&gt;
&lt;li&gt;이런 경우는 물리적 구성이 아닌 논리적 구성도로 이해하여 인라인 구성이 됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 로드 밸런서 동작 모드&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6.1. 트랜스패런트 모드&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜스패런트(transparent: 투명) 구성은 로드 밸런서가 OSI 2계층 스위치처럼 동작하는 구성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;로드 밸런서에서 서비스하기 위해 사용하는 VIP 주소와 실제 서버가 동일한 네트워크를 사용하는 구성&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;기존에 사용하던 네트워크 대역을 그대로 사용하여 네트워크 재설계가 필요 없음&lt;/li&gt;
&lt;li&gt;기존 망의 트래픽 흐름에 미치는 영향 없이 로드 밸런서를 쉽게 구성할 수 있음&lt;/li&gt;
&lt;li&gt;트랜스패런트 구성에서는 트래픽이 로드 밸런서를 지나가도
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;부하 분산 서비스를 받는 트래픽인 경우만 4계층 이상의 기능을 수행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;받지 않는 경우 기존 L2 스위치와 동일한 스위칭 기능 수행, 그래서 L2 구조라 부르기도 함&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;원암 구성과 인라인 구성 모두 사용할 수 있는 동작 모드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;요청&lt;/b&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;1628&quot; data-origin-height=&quot;464&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcGDZ6/btsKA9qkKSq/5BfmsAkh7ABH2oMjXeRUrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcGDZ6/btsKA9qkKSq/5BfmsAkh7ABH2oMjXeRUrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcGDZ6/btsKA9qkKSq/5BfmsAkh7ABH2oMjXeRUrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcGDZ6%2FbtsKA9qkKSq%2F5BfmsAkh7ABH2oMjXeRUrK%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;776&quot; height=&quot;221&quot; data-origin-width=&quot;1628&quot; data-origin-height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;로드 밸런서로 들어온 패킷은 목적지 ip 주소를 vip에 바인딩되어 있는 실제 ip주소로 변경
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;목적지 IP 주소 10.10 &amp;rarr; 10.11, 목적지 MAC 주소 B &amp;rarr; C&lt;/li&gt;
&lt;li&gt;로드 밸런서와 목적지 서버가 동일한 네트워크 대역이므로 L3 장비를 지날때처럼 출발지 MAC 주소가 변경되진 않음&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;서비스 요청 패킷의 목적지 정보가 변경되면 실제 서버로 패킷이 전달됨.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;로드 밸런서에서 서비스를 위한 VIP 주소가 실제 서버의 IP 주소로 변경해 전송하므로 목적지 NAT가 되었다고 함&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;응답&lt;/b&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;1678&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NBfWf/btsKACmipFp/7yChEDluMGKsrk4P9TRL30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NBfWf/btsKACmipFp/7yChEDluMGKsrk4P9TRL30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NBfWf/btsKACmipFp/7yChEDluMGKsrk4P9TRL30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNBfWf%2FbtsKACmipFp%2F7yChEDluMGKsrk4P9TRL30%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;667&quot; height=&quot;149&quot; data-origin-width=&quot;1678&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&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;로드 밸런서를 지나면서 요청할 때와 반대로 출발지의 IP 주소가 실제 서버 IP에서 VIP로 변경됨&lt;/li&gt;
&lt;li&gt;하지만 이미 게이트웨이의 MAC 주소를 갖고 있어 목적지 MAC 주소는 변경되지 않음&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;하지만 동일 네트워크에서 서비스를 호출할 때는 서비스 응답이 로드 밸런서를 거치지 않을 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6.2. 라우티드 모드&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;/li&gt;
&lt;li&gt;인라인 구성과 원암 구성에서 모두 가능함.&lt;/li&gt;
&lt;li&gt;보안 강화 목적으로 서버쪽 네트워크를 사설로 구성하여 서버에 직접 접속하는 것을 막기 위한 용도로 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;요청&lt;/b&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GNyqW/btsKADMjoUj/uWkQAoOvFc4Y37mnFhpRW0/img.png&quot; data-image-src=&quot;https://blog.kakaocdn.net/dn/GNyqW/btsKADMjoUj/uWkQAoOvFc4Y37mnFhpRW0/img.png&quot; data-origin-width=&quot;1666&quot; data-origin-height=&quot;441&quot; /&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;사용자는 서비스 IP인 VIP 주소 10.10으로 서비스를 요청&lt;/li&gt;
&lt;li&gt;로드 밸런서로 들어온 패킷은 목적지 IP 주소를 VIP에 바인딩된 실제 서버 IP 주소인 20.11로 변경함
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;라우팅을 수행하면서 로드 밸런서를 통과하므로 일반 라우팅과 동일하게 출발지 MAC 주소: A &amp;rarr; D,목적지 MAC 주소: B &amp;rarr; C&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;목적지 IP와 출발지/목적지 MAC이 변경된 패킷은 라우팅 테이블을 확인해 실제 서버로 전송
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;로드 밸런서는 서비스를 위한 VIP 주소에서 실제 서버의 IP 주소로 변경해 전송하므로 목적지 NAT가 되었다고 함&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;응답&lt;/b&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;1641&quot; data-origin-height=&quot;454&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cowLHR/btsKAhbCQt7/OHeeochkZESpp75qDpw3k1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cowLHR/btsKAhbCQt7/OHeeochkZESpp75qDpw3k1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cowLHR/btsKAhbCQt7/OHeeochkZESpp75qDpw3k1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcowLHR%2FbtsKAhbCQt7%2FOHeeochkZESpp75qDpw3k1%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;766&quot; height=&quot;212&quot; data-origin-width=&quot;1641&quot; data-origin-height=&quot;454&quot;/&gt;&lt;/span&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;목적지 IP가 외부 네트워크이므로 목적지 MAC은 외부로 나가는 관문인 로드 밸런서의 MAC 주소가 됨&lt;/li&gt;
&lt;li&gt;로드 밸런서로 들어온 패킷은 출발지 IP 주소를 실제 서버의 IP인 20.11에서 사용자가 서비스를 위해 요청했던 VIP인 10.10으로 변환&lt;/li&gt;
&lt;li&gt;요청 트래픽과 마찬가지로 출발지와 목적지의 MAC 주소를 변경한 후 사용자에게 응답 패킷을 전송&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6.3. DSR 모드&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;/li&gt;
&lt;li&gt;로드 밸런서를 경유하지 않으므로 원암 구성에서만 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실제 서버의 네트워크를 로드 밸런서가 가지는 지 여부&lt;/b&gt;에 따라 L2 DSR과 L3 DSR으로 구분됨&lt;/li&gt;
&lt;li&gt;로드 밸런서 전체 트래픽이 감소해 로드 밸런서 부하가 감소함.&lt;/li&gt;
&lt;li&gt;반면, DSR 모드의 서비스 응답이 로드 밸런서를 경유하지 않으므로 문제 발생시, 확인이 어려움&lt;/li&gt;
&lt;li&gt;L2 DSR과 L3 DSR의 경우는 로드 밸런서 설정 외에 서버에서도 추가 설정 필요&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트래픽 흐름&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;사용자는 서비스 IP인 VIP로 서비스를 요청&lt;/li&gt;
&lt;li&gt;로드 밸런서로 들어온 서비스 요청 패킷은 서버에서 로드밸런서를 거치지 않고 응답하기 때문에 로드 밸런서를 통한 Source NAT를 수행할 수 없음&lt;/li&gt;
&lt;li&gt;사용자 입장에서는 실제 서버 IP로 응답을 받게 되고 요청했던 주소 IP와 다르기 때문에 비정상적인 응답으로 간주&lt;/li&gt;
&lt;li&gt;그래서 서비스 요청 시 목적지 IP는 VIP 그대로 유지하고, MAC 주소만 실제 서버 MAC 주소로 변경&lt;/li&gt;
&lt;li&gt;서버에서 수신할 때, 목적지 IP 주소가 서버 주소와 맞지 않으면 폐기되므로 루프백 인터페이스를 생성해 VIP 주소를 할당&lt;/li&gt;
&lt;li&gt;루프백에 설정된 IP 주소도 수신할 수 있도록 설정함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 로드 밸런서 유의 사항&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;7.1. 원암 구성의 동일 네트워크 사용 시&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자가 서비스 IP로 요청하면 로드 밸런서에서는 실제 서버의 IP 주소로 Destination NAT한 후 서버로 전달&lt;/li&gt;
&lt;li&gt;서버는 다시 사용자에게 응답할 때 게이트웨이 장비인 L3 스위치를 통해 응답하는데 이때 원암 구성에서는 사용자에게 바로 응답&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용자 입장에선 10.10로 요청했는데 10.11에서 응답이 와버린 상황&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;해결방법&lt;/b&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;Source NAT를 사용&lt;/li&gt;
&lt;li&gt;DSR 모드&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;7.2. 동일 네트워크 내에서 서비스 IP 호출&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;동일 네트워크 내인 경우 로드 밸런서를 거치지 않고 바로 응답&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;요청한 입장에선 요청한 IP 주소가 아닌 다른 IP 주소에서 응답이 오게 됨&lt;/li&gt;
&lt;li&gt;이 경우, 서비스 요청이 로드 밸런서를 거칠 때 출발지 IP 주소를 로드 밸런서의 IP로 변경하는 Source NAT를 사용&lt;/li&gt;
&lt;li&gt;DSR 모드를 사용해 실제 서버에서 로드 밸런서를 거치지 않고 직접 응답&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IT 엔지니어를 위한 네트워크 입문 (고재성, 이상훈 저, 2020.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/네트워크</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/32</guid>
      <comments>https://onyodev.tistory.com/32#entry32comment</comments>
      <pubDate>Thu, 7 Nov 2024 16:35:03 +0900</pubDate>
    </item>
    <item>
      <title>메모리 관리</title>
      <link>https://onyodev.tistory.com/31</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;이 글은 반효경 저 - &quot;운영체제와 정보기술의 원리&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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 data-ke-size=&quot;size26&quot;&gt;1. 주소 바인딩&lt;/h2&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;b&gt;가상 주소&lt;/b&gt;라고 부름&lt;/li&gt;
&lt;li&gt;CPU는 프로세스마다 독립적으로 갖는 논리적 주소에 근거해 명령을 실행&lt;/li&gt;
&lt;li&gt;논리적 주소는 각 프로세스마다 독립적으로 할당되며 0번지부터 시작&lt;/li&gt;
&lt;li&gt;물리적 주소: 물리적 메모리에 실제로 올라가는 위치&lt;/li&gt;
&lt;li&gt;물리적 메모리의 낮은 주소 영역에는 운영체제가 올라가고 높은 주소 영역에는 사용자 프로세스들이 올라감&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주소 바인딩(address binding)&lt;/b&gt;: 프로세스의 논리적 주소를 물리적 주소로 연결시켜주는 작업&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1. 주소 바인딩 방식&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;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;컴파일 타임 바인딩(compile time binding)&lt;/b&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;li&gt;프로그램이 올라가 있는 물리적 메모리 주소를 변경하기 위해선 컴파일을 다시 해야 함&lt;/li&gt;
&lt;li&gt;현대 시분할 방식에선 잘 사용하지 않는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;로드 타임 바인딩(load time binding)&lt;/b&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;로더(loader)의 책임 하에 물리적 메모리 주소가 부여됨&lt;/li&gt;
&lt;li&gt;프로그램이 종료될 때까지 물리적 메모리 상의 위치가 고정됨&lt;/li&gt;
&lt;li&gt;컴파일러가 재배치 가능 코드를 생성한 경우에 가능한 주소 바인딩 방식&lt;/li&gt;
&lt;li&gt;로더(loader): 사용자 프로그램을 메모리에 적재시키는 프로그램&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실행시간 바인딩(execution time binding)&lt;/b&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;CPU가 주소를 참조할 때마다 해당 데이터가 물리적 메모리의 위치를 주소 매핑 테이블을 이용해 바인딩을 점검해야 함&lt;/li&gt;
&lt;li&gt;기준 레지스터와 한계 레지스터를 포함한 MMU(Memory Management Unit)라는 하드웨어적 지원이 있어야 가능한 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2. MMU 기법&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1614&quot; data-origin-height=&quot;1052&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BMQJ0/btsKslkEYyu/vaSY9DF6iykm6tzmOmCsTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BMQJ0/btsKslkEYyu/vaSY9DF6iykm6tzmOmCsTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BMQJ0/btsKslkEYyu/vaSY9DF6iykm6tzmOmCsTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBMQJ0%2FbtsKslkEYyu%2FvaSY9DF6iykm6tzmOmCsTK%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;573&quot; height=&quot;373&quot; data-origin-width=&quot;1614&quot; data-origin-height=&quot;1052&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU가 특정 프로세스의 &lt;b&gt;논리적 주소&lt;/b&gt;를 참조하려 할 때 그 주소값에 기준 레지스터 값을 더해 &lt;b&gt;물리적 주소값&lt;/b&gt;을 얻어냄&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; &amp;nbsp; ※ MMU 기법에서 사용자 프로그램이나 CPU는 &lt;b&gt;논리적 주소만 다룸&lt;/b&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;MMU 기법은 문맥교환으로 CPU에서 수행 중인 프로세스가 바뀔 때마다 재배치 레지스터의 값을 그 프로세스에 해당하는 값으로 재설정해줌&lt;/li&gt;
&lt;li&gt;여러 프로세스가 동시에 올라가 있는 경우, 다른 프로그램의 영역을 침범할 수 있어 메모리 보안에 문제가 발생&lt;/li&gt;
&lt;li&gt;이를 방지하기 위해 운영체제는 &lt;b&gt;한계 레지스터(limit register)&lt;/b&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;1055&quot; data-origin-height=&quot;523&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tRXAx/btsKruQACDC/kK8Kc4sNsuamq7Ouyg3iBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tRXAx/btsKruQACDC/kK8Kc4sNsuamq7Ouyg3iBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tRXAx/btsKruQACDC/kK8Kc4sNsuamq7Ouyg3iBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtRXAx%2FbtsKruQACDC%2FkK8Kc4sNsuamq7Ouyg3iBK%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;1055&quot; height=&quot;523&quot; data-origin-width=&quot;1055&quot; data-origin-height=&quot;523&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 메모리 관련 용어&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. 동적로딩&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;/li&gt;
&lt;li&gt;프로세스 내의 실행이 필요한 부분이 실제로 불릴 때마다 메모리를 적재하는 것을 말함&lt;/li&gt;
&lt;li&gt;실제 프로그램 코드 중 상당은 &lt;b&gt;오류 처리루틴&lt;/b&gt;과 같이 특수한 경우에 가끔 사용되는 &lt;b&gt;방어용 코드&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;그래서 프로세스 주소 공간 전체를 물리적 메모리를 올리는 경우 메모리 낭비가 심해짐&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. 동적연결&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;연결(linking)&lt;/b&gt;: 소스 코드를 컴파일하여 생성된 &lt;b&gt;목적 파일과 라이브러리 파일들을 묶어 하나의 실행 파일을 생성하는 과정&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;동적연결은 목적 파일과 라이브러리 파일 사이의 &lt;b&gt;연결을 프로그램의 실행 시점까지 지연시키는 기법&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;정적연결에서는 코드와 라이브러리 코드가 모두 합쳐져서 실행파일이 생성&lt;/li&gt;
&lt;li&gt;따라서 실행파일 크기가 크고 동일한 라이브러리를 각 프로세스별로 메모리에 적재하게 되어 메모리 낭비가 심함&lt;/li&gt;
&lt;li&gt;동적연결은 라이브러리가 실행 시점에 연결되고 실행파일의 라이브러리 호출 부분에 해당 라이브러리를 찾기 위한 스텁(stub) 코드를 둔다.&lt;/li&gt;
&lt;li&gt;스텁을 통해 해당 라이브러리가 메모리에 존재하는 경우 참조하고,그렇지 않은 경우 디스크에서 동적 라이브러리 파일을 찾아 적재한 후 수행&lt;/li&gt;
&lt;li&gt;동적연결에서는 다수의 프로그램이 &lt;b&gt;공통으로 사용하는 라이브러리를 한 번만 적재&lt;/b&gt;하여 메모리 사용의 효율을 높일 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3. 중첩&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;/li&gt;
&lt;li&gt;중첩은 운영체제 지원 없이 프로그래머가 직접 구현했고 이런 이유로 &lt;b&gt;수작업 중첩&lt;/b&gt;이라고도 부름&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.4. 스와핑&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1637&quot; data-origin-height=&quot;932&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAUKGI/btsKrOHGDh2/SERKXtV8P7Ei50nVa6ckKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAUKGI/btsKrOHGDh2/SERKXtV8P7Ei50nVa6ckKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAUKGI/btsKrOHGDh2/SERKXtV8P7Ei50nVa6ckKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAUKGI%2FbtsKrOHGDh2%2FSERKXtV8P7Ei50nVa6ckKK%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;627&quot; height=&quot;357&quot; data-origin-width=&quot;1637&quot; data-origin-height=&quot;932&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;스왑 영역(swap area)&lt;/b&gt;: 혹은 백킹스토어(backing store), 디스크 내의 파일 시스템과는 별도로 존재하는 일정 영역&lt;/li&gt;
&lt;li&gt;파일 시스템과는 다르게 스왑 영역은 프로세스가 수행 중인 동안에만 디스크에 일시적으로 저장하는 공간&lt;/li&gt;
&lt;li&gt;스왑 영역은 다수의 사용자 프로세스를 담아야 하기에 충분히 커야하고 접근 속도도 보장되어야 함&lt;/li&gt;
&lt;li&gt;스와핑은 특정한 이유로 수행 중인 프로세스의 주소 공간을 일시적으로 메모리에서 디스크로 내려놓는 것을 말함.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;스왑 인(swap in): 디스크 &amp;rarr; 메모리&lt;/li&gt;
&lt;li&gt;스왑 아웃(swap out): 메모리 &amp;rarr; 디스크&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;스와핑의 역할은 메모리에 올라간 프로세스 수를 조절하는 것&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;li&gt;디스크 내의 스왑영역에서 프로세스 주소 공간이 순차적으로 저장됨&lt;/li&gt;
&lt;li&gt;스와핑 소요 시간은 데이터를 읽고 쓰는 전송 시간이 대부분을 차지함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 물리적 메모리 할당 방식&lt;/h2&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;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;/li&gt;
&lt;li&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;/li&gt;
&lt;li&gt;프로세스를 메모리에 올리는 방식에 따라 연속할당 방식과 불연속할당 방식으로 나뉨&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1. 연속할당 방식&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;/li&gt;
&lt;li&gt;분할을 관리하는 방식에 따라 가변분할과 고정분할로 나뉨&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;고정분할(fixed partition allocation)&lt;/b&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;li&gt;&lt;b&gt;외부조각(external fragmentation)&lt;/b&gt;: 프로그램의 크기보다 분할의 크기가 작아 비어있는데도 적재하지 못해 발생하는 메모리 공간&lt;/li&gt;
&lt;li&gt;&lt;b&gt;내부조각(internal fragmentation)&lt;/b&gt;: 프로그램의 크기가 분할의 크기보다 작아 적재하고 남는 메모리 공간&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가변분할(variable partition allocation)&lt;/b&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;li&gt;메모리에 존재하는 프로그램이 종료될 경우 중간에 빈 공간이 발생하며 이 공간이 새로 시작하는 프로그램보다 작은 경우 외부조각이 발생할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동적 메모리 할당 문제(dynamic storage-allocation problem)&lt;/b&gt;: 주소의 공간 크기가 n인 프로세스의 경우 메모리에 올릴 때 어떤 위치에 올릴 지에 대한 문제&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컴팩션(compaction)&lt;/b&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;li&gt;가급적 적은 수의 메모리 이동으로 효율적인 컴팩션을 수행해야 함&lt;/li&gt;
&lt;li&gt;이는 프로세스 주소가 동적으로 바뀔 수 있는 실행시간 바인딩 방식에서만 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.2. 동적 메모리 할당 문제&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;최초적합(first-fit)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;크기가 n 이상인 가용 공간 중 가장 먼저 찾아지는 곳에 할당하는 방법&lt;/li&gt;
&lt;li&gt;시간적인 면에서 효율적&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최적적합(best-fit)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;크기가 n 이상인 가장 작은 가용 공간을 찾아 할당하는 방법&lt;/li&gt;
&lt;li&gt;크기순으로 정렬되어 있지 않은 경우 모든 공간을 탐색해야 하므로 시간적 오버헤드 발생&lt;/li&gt;
&lt;li&gt;공간적인 면에서 효율적&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최악적합(worst-fit)&lt;/b&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;li&gt;더 큰 프로그램을 담을 수 있는 가용 공간을 소모하는 것이 문제&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.3. 불연속할당 방식&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;페이징(paging) 기법:&lt;/b&gt; 각 프로세스의 주소 공간을 동일한 크기의 페이지로 잘라서 메모리에 페이지 단위로 적재시키는 방법&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세그먼테이션(segmentation) 기법&lt;/b&gt;: 프로그램의 주소 공간을 코드, 데이터, 스택 등 의미 있는 단위인 세그먼트로 나누어 적재하는 기법&lt;/li&gt;
&lt;li&gt;&lt;b&gt;페이지드 세그먼테이션(paged segmentation) 기법&lt;/b&gt;: 세그먼트 하나를 다수의 페이지로 구성하는 기법&lt;/li&gt;
&lt;/ul&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 data-ke-size=&quot;size26&quot;&gt;4. 페이징 기법&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1087&quot; data-origin-height=&quot;1151&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c7hOZB/btsKr8sungD/7BkBy5Kgan1Nk02BUlRYek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c7hOZB/btsKr8sungD/7BkBy5Kgan1Nk02BUlRYek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c7hOZB/btsKr8sungD/7BkBy5Kgan1Nk02BUlRYek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc7hOZB%2FbtsKr8sungD%2F7BkBy5Kgan1Nk02BUlRYek%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;685&quot; height=&quot;725&quot; data-origin-width=&quot;1087&quot; data-origin-height=&quot;1151&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.1. 특징&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;/li&gt;
&lt;li&gt;페이징 기법에서는 물리적 메모리를 페이지와 동일한 크기의 프레임으로 미리 나눔&lt;/li&gt;
&lt;li&gt;메모리에 올리는 단위 = 페이지 단위&lt;/li&gt;
&lt;li&gt;메모리를 같은 크기로 미리 분할했더라도 빈 프레임이 있으면 어떤 위치든 사용될 수 있음&lt;/li&gt;
&lt;li&gt;그렇기 때문에 동적 메모리 할당 문제가 발생하지 않는 장점이 있음&lt;/li&gt;
&lt;li&gt;페이징 기법은 하나의 프로세스라 해도 페이지 단위로 물리적 메모리에 올라가는 위치가 상이함&lt;/li&gt;
&lt;li&gt;그래서 논리적 주소 &amp;rarr; 물리적 주소 변환 작업이 페이지 단위로 이루어져 주소 변환이 복잡함&lt;/li&gt;
&lt;li&gt;모든 프로세스가 각각의 주소 변환을 위한 &lt;b&gt;페이지 테이블&lt;/b&gt;을 갖고 있고 이는 프로세스가 가질 수 있는 페이지 개수만큼 주소 변환 엔트리를 갖고 있음&lt;/li&gt;
&lt;li&gt;프로그램 크기가 항상 페이지 크기의 배수가 되지는 않기 때문에 제일 마지막에 위치한 페이지는 내부조각이 발생할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.2. 주소 변환 기법&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1099&quot; data-origin-height=&quot;613&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9kOfq/btsKrdVKsh2/h000g51hKXVmci9SqS4MNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9kOfq/btsKrdVKsh2/h000g51hKXVmci9SqS4MNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9kOfq/btsKrdVKsh2/h000g51hKXVmci9SqS4MNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9kOfq%2FbtsKrdVKsh2%2Fh000g51hKXVmci9SqS4MNk%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;1099&quot; height=&quot;613&quot; data-origin-width=&quot;1099&quot; data-origin-height=&quot;613&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU가 사용하는 논리적 주소를 &lt;b&gt;페이지 번호(p)&lt;/b&gt;와 &lt;b&gt;페이지 오프셋(d)&lt;/b&gt;으로 나누어 주소 변환에 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;페이지 번호&lt;/b&gt;는 페이지 테이블 접근 시 &lt;b&gt;인덱스(index)&lt;/b&gt;로 활용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인덱스의 항목(entry)&lt;/b&gt;은 그 페이지의 물리적 메모리상의 기준 주소, 즉 시작 위치가 저장됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;페이지 오프셋&lt;/b&gt;은 하나의 페이지 내에서의 변위(displacement)를 알려줌&lt;/li&gt;
&lt;li&gt;따라서 기준 주소값에 변위를 더하여 논리적 주소에 대응되는 물리적 주소를 구함&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.3. 페이지 테이블 구현&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;CPU에서 실행 중인 프로세스의 페이지 테이블에 접근하기 위해 &lt;b&gt;페이지 테이블 기준 레지스터&lt;/b&gt;와 &lt;b&gt;페이지 테이블 길이 레지스터&lt;/b&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;: 페이지 테이블의 크기 보관&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.3.1. TLB(Translation Look-aside Buffer)&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;/li&gt;
&lt;li&gt;TLB로 사용되는 하드웨어는 가격이 비싸 빈번히 참조되는 페이지에 대한 주소 변환 정보만 담음&lt;/li&gt;
&lt;li&gt;요청된 페이지 번호가 TLB에 존재하면 곧바로 프레임 번호를 얻고, 그렇지 않은 경우 페이지 테이블로 가서 프레임 번호를 얻음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 문맥 교환 시 TLB의 이전 프로세스의 주소 변환 정보는 모두 지워짐&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;주소 저장 정보 비교 (페이지 테이블 vs TLB)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;페이지 테이블&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;TLB&lt;/b&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;/li&gt;
&lt;li&gt;오버헤드를 줄이기 위해 병렬탐색이 가능한 연관 레지스터를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;p data-ke-size=&quot;size16&quot;&gt;연관 레지스터 사용 시 &lt;b&gt;평균 메모리 접근 시간(Effective Access Time:EAT)&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리 접근 시간 = 1&lt;/li&gt;
&lt;li&gt;&amp;epsilon;: 연관 레지스터 접근 시간&lt;/li&gt;
&lt;li&gt;&amp;alpha;: 요청 페이지에 대한 정보가 연관 레지스터에 존재할 확률&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;$$ EAT = (1+\varepsilon)\alpha + (2+\varepsilon)(1-\alpha) = 2 + \varepsilon - \alpha $$&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.4. 계층적 페이징&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;2단계 페이징 기법&lt;/b&gt; 사용&lt;/li&gt;
&lt;li&gt;2단계 페이징 기법에서는 &lt;b&gt;외부 페이지 테이블&lt;/b&gt;과 &lt;b&gt;내부 페이지 테이블&lt;/b&gt;을 사용&lt;/li&gt;
&lt;li&gt;사용되지 않는 주소 공간에 대해서 외부 페이지 테이블의 항목을 NULL로 설정하고 여기에 대응하는 내부 페이지 테이블을 생성하지 않으면서 메모리를 절약&lt;/li&gt;
&lt;li&gt;2단계 페이징 기법을 사용하면 페이지 테이블 생성에 쓰이는 메모리를 절약&lt;/li&gt;
&lt;li&gt;하지만 주소 변환을 위해 접근해야 하는 페이지 테이블 수가 증가하여 시간적 손해가 생김&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.4.1. 2단계 페이징의 주소 변환&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스의 논리적 주소를 두 종류의 페이지 번호(P1,P2)와 페이지 오프셋(d)로 구분
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;P1: 외부 페이지 테이블 인덱스&lt;/li&gt;
&lt;li&gt;P2: 내부 페이지 테이블 인덱스&lt;/li&gt;
&lt;li&gt;논리적 주소를 &amp;lt;P1, P2, d&amp;gt;로 표시&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;외부 페이지 테이블로부터 P1만큼 떨어진 위치에서 내부 페이지 테이블의 주소를 얻음&lt;/li&gt;
&lt;li&gt;내부 페이지 테이블로부터 P2만큼 떨어진 위치에서 요청된 페이지가 존재하는 프레임 위치를 얻음&lt;/li&gt;
&lt;li&gt;해당 프레임으로부터 d만큼 떨어진 곳에서 원하는 정보에 접근&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;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;페이지 번호와 페이지 오프셋을 위한 비트 할당&lt;/span&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;32비트 주소 체계 시스템&lt;/li&gt;
&lt;li&gt;페이지 하나의 크기가 4KB&lt;/li&gt;
&lt;li&gt;페이지 테이블 항목 크기 4Byte&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2071&quot; data-origin-height=&quot;816&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xKEY4/btsKsgcTEWW/TuPLKE0b61ZFel2YiCdnKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xKEY4/btsKsgcTEWW/TuPLKE0b61ZFel2YiCdnKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xKEY4/btsKsgcTEWW/TuPLKE0b61ZFel2YiCdnKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxKEY4%2FbtsKsgcTEWW%2FTuPLKE0b61ZFel2YiCdnKk%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;2071&quot; height=&quot;816&quot; data-origin-width=&quot;2071&quot; data-origin-height=&quot;816&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&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;그래서 3단계,4단계에 이르는 다단계 페이지 테이블이 필요&lt;/li&gt;
&lt;li&gt;다단계 페이지 테이블을 사용하면 메모리 공간 소모를 줄일 수 있지만 메모리 접근 횟수가 늘어남&lt;/li&gt;
&lt;li&gt;TLB를 사용하면 다단계 페이징의 공간적 이득과 메모리 접근시간도 많이 늘어나지 않아 시간 효율성도 얻을 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ex) 연관 레지스터 사용 시 평균적인 메모리 접근시간 계산&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다단계 페이징: P = 4&lt;/li&gt;
&lt;li&gt;메모리 접근시간: M = 100ns&lt;/li&gt;
&lt;li&gt;TLB 접근시간: T = 20ns&lt;/li&gt;
&lt;li&gt;주소변환정보가 TLB에 존재할 확률: &amp;alpha; = 98%&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;$$ EAT = \alpha \times (M+T) + (1-\alpha) \times [(P+1)\times M + T]\\&lt;br /&gt;= 0.98 \times 120 + 0.02 \times 520 = 128(ns) $$&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.5. 역페이지 테이블&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;페이지 프레임 당 페이지 테이블에 하나의 항목을 두는 방식&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;즉, 물리적 주소에 대해 페이지 테이블을 만들고 시스템 전체에 페이지 테이블을 하나만 두는 방법&lt;/li&gt;
&lt;li&gt;페이지 테이블의 각 항목은 프로세스 번호(pid)와 프로세스 내 논리적 페이지 번호(p)를 담고 있음&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;h4 data-ke-size=&quot;size20&quot;&gt;4.6. 공유 페이지&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;공유 코드(shared code)&lt;/b&gt;: 메모리 공간의 효율적인 사용을 위해 여러 프로세스에 의해 &lt;b&gt;공통으로 사용될 수 있도록 작성된 코드&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;재진입 가능 코드 혹은 순수 코드라 부리며 읽기전용의 특성을 가짐&lt;/li&gt;
&lt;li&gt;공유 페이지는 공유 코드를 담고 있는 페이지를 말함.&lt;/li&gt;
&lt;li&gt;공유 페이지는 여러 프로세스를 물리적 메모리 하나에 적재하여 메모리를 효율적으로 사용하게 함&lt;/li&gt;
&lt;li&gt;공유 코드는 모든 프로세스의 논리적 주소 공간에서 동일한 위치에 존재해야 하는 제약점이 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사유 페이지&lt;/b&gt;: 프로세스들이 공유하지 않고 프로세스별로 독자적으로 사용하는 페이지(위치 무방)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.7. 메모리 보호&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;보호 비트(protection bit)&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;유효-무효 비트(valid-invalid bit)&lt;/b&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;b&gt;유효(valid)&lt;/b&gt;: 해당 메모리 프레임에 그 페이지가 존재함, 접근이 허용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;무효(invalid)&lt;/b&gt;: 프로세스가 그 주소를 쓰지 않거나 페이지가 물리적 메모리에 없고 백킹스토어에 존재하여 접근 권한이 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 세그먼테이션&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스의 주소 공간을 의미 단위인 세그먼트(segment)로 나누어 물리적 메모리에 올리는 기법&lt;/li&gt;
&lt;li&gt;하나의 프로세스를 구성하는 주소 공간은 일반적으로 코드(code), 데이터(data), 스택(stack) 등의 의미 있는 단위로 구분됨&lt;/li&gt;
&lt;li&gt;세그먼트는 주소 공간을 기능 단위 또는 의미 단위로 나눈 것을 뜻하고 그래서 크기가 제각각임&lt;/li&gt;
&lt;li&gt;프로세스의 주소 공간이 나누어져 각각 메모리에 적재되는 특징이 있음&lt;/li&gt;
&lt;li&gt;크기가 균일하지 않은 세그먼트들은 메모리에 적재하는 부가적인 관리 오버헤드가 발생&lt;/li&gt;
&lt;li&gt;크기가 제각각이어서 물리적 메모리 관리에서 외부조각이 발생&lt;/li&gt;
&lt;li&gt;그리고 어느 가용 공간에 할당할 것인지에 대한 문제가 발생함
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;최초적합(first fit)&lt;/b&gt;: 해당 세그먼트 크기보다 크거나 같은 첫번째 가용공간에 할당&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최적적합(best fit)&lt;/b&gt;: 세그먼트의 크기보다 크거나 같은 공간 중 가장 작은 공간에 할당&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.1. 세그먼테이션 기법에서의 주소 변환&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;677&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oZyU3/btsKr6az0wv/nrNtYeHHfRjxeWpn7otuck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oZyU3/btsKr6az0wv/nrNtYeHHfRjxeWpn7otuck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oZyU3/btsKr6az0wv/nrNtYeHHfRjxeWpn7otuck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoZyU3%2FbtsKr6az0wv%2FnrNtYeHHfRjxeWpn7otuck%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;1226&quot; height=&quot;677&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;677&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;논리적 주소가 &amp;lt;세그먼트 번호, 오프셋&amp;gt;으로 나뉘어 사용&lt;/li&gt;
&lt;li&gt;세그먼트 테이블을 사용하여 관리하고 기준점(base)와 한계(limit) 항목을 가짐
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;기준점(base)&lt;/b&gt;: 물리적 메모리에서 그 세그먼트의 시작 위치&lt;/li&gt;
&lt;li&gt;&lt;b&gt;한계(limit)&lt;/b&gt;: 그 세그먼트의 길이&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;세그먼트 길이가 균일하지 않기 때문에 세그먼트 길이 정보를 담고 있어야 함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세그먼트 테이블 기준 레지스터&lt;/b&gt;와 &lt;b&gt;세그먼트 테이블 길이 레지스터&lt;/b&gt;를 사용함.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;세그먼트 테이블 기준 레지스터(Segment-Table Base Register: STBR)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 CPU에서 실행 중인 프로세스의 세그먼트 테이블이 메모리의 어느 위치에 있는지 시작 주소를 담고 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;세그먼트 테이블 길이 레지스터(Segment-Table Length Register: STLR)
&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;확인 사항&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;요청된 세그먼트 번호가 STLR에 저장된 값보다 작은가?&lt;/li&gt;
&lt;li&gt;논리적 주소의 오프셋 값이 그 세그먼트의 길이보다 작은 값인가?&lt;/li&gt;
&lt;/ol&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;는 각 세그먼트의 주소 변환 정보가 유효한지, 즉 해당 세그먼트가 현재 물리적 메모리에 적재되어 있는지를 나타냄&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.2. 공유 세그먼트&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;/li&gt;
&lt;li&gt;공유하려는 코드와 사유 데이터 영역이 동일 페이지에 존재하는 경우가 발생하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 페이지드 세그먼테이션&lt;/h2&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;li&gt;세그먼트를 반드시 동일한 크기 페이지들의 집합으로 구성하고 페이지 단위로 물리적 메모리에 적재함&lt;/li&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;6.1. 페이지드 세그먼테이션 주소 변환&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;/li&gt;
&lt;li&gt;논리적 주소는 &amp;lt;&lt;b&gt;세그먼트 번호&lt;/b&gt;, &lt;b&gt;오프셋&lt;/b&gt;&amp;gt;으로 구성됨&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;논리적 주소의 상위 비트인 &lt;b&gt;세그먼트 번호&lt;/b&gt;를 통해 세그먼트 테이블의 해당 항목에 접근&lt;/li&gt;
&lt;li&gt;세그먼트 항목에는 &lt;b&gt;세그먼트 길이&lt;/b&gt;와 &lt;b&gt;세그먼트 테이블 시작 주소&lt;/b&gt;가 들어 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세그먼트 길이값&lt;/b&gt;과 논리적 주소 중 하위비트인 &lt;b&gt;오프셋&lt;/b&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;을 다시 상위/하위 비트로 나눔
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&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;/li&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;/ol&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;운영체제와 정보기술의 원리&lt;/span&gt; (&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;반효경&lt;span&gt; &lt;/span&gt;&lt;/span&gt;저, 2020.5)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/운영체제</category>
      <category>computer science</category>
      <category>메모리</category>
      <category>세그먼테이션</category>
      <category>운영체제</category>
      <category>페이징</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/31</guid>
      <comments>https://onyodev.tistory.com/31#entry31comment</comments>
      <pubDate>Fri, 1 Nov 2024 11:23:13 +0900</pubDate>
    </item>
    <item>
      <title>DNS</title>
      <link>https://onyodev.tistory.com/30</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 고재성, 이상훈 저 - &quot;IT 엔지니어를 위한 네트워크 입문&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. DNS 소개&lt;/h2&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;네트워크 설정에 입력한 DNS로 해당 도메인에 대한 IP 주소 질의를 보냄&lt;/li&gt;
&lt;li&gt;DNS 서버는 결괏값으로 요청한 도메인의 서비스 IP주소를 알려줌&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. DNS 구조와 명명 규칙&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;도메인은 역트리 구조로 &lt;b&gt;최상위 루트, Top-Level 도메인, Second-Level 도메인, Third-Level 도메인&lt;/b&gt;과 같이 하위 레벨로 원하는 주소를 단계적으로 찾음&lt;/li&gt;
&lt;li&gt;도메인 계층은 최대 128계층까지 구성할 수 있고 계층별 길이는 최대 63바이트이다.&lt;/li&gt;
&lt;li&gt;&amp;ldquo;.&amp;rdquo;를 포함한 전체 도메인 네임의 길이는 최대 255바이트&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. 루트 도메인&lt;/h4&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;DNS 서버는 사용자가 쿼리한 도메인에 대한 값을 직접 갖고 있거나 캐시에 저장된 정보를 이용해 응답&lt;/li&gt;
&lt;li&gt;만약 DNS 서버에 해당 도메인 정보가 없으면 루트 도메인을 관리하는 루트 DNS에 쿼리하게 됨&lt;/li&gt;
&lt;li&gt;전 세계에 13개가 있고 DNS 서버를 설치하면 루트 DNS의 IP 주소를 기록한 힌트 파일이 있음&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. Top-Level 도메인&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IANA(Internet Assinged Numbers Authority)에서 구분한 6가지 유형으로 구분&lt;br /&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Generic(gTLD)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;일반적인 최상위 도메인이며 세 글자 이상으로 구성 &lt;br /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;gTLD&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;com&lt;/td&gt;
&lt;td&gt;일반 기업체&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;edu&lt;/td&gt;
&lt;td&gt;4년제 이상 교육기관&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gov&lt;/td&gt;
&lt;td&gt;미국 연방정부기관&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;int&lt;/td&gt;
&lt;td&gt;국제기구, 기관&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mil&lt;/td&gt;
&lt;td&gt;미국 연방군사기관&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;net&lt;/td&gt;
&lt;td&gt;네트워크 관련 기관&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;org&lt;/td&gt;
&lt;td&gt;비영리기관&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;country-code(ccTLD)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;국가 최상위 도메인, 두 글자의 국가 코드 사용, ex) kr(대한민국)&lt;/li&gt;
&lt;li&gt;ccTLD를 사용한 경우 Second Level TLD 에선 gTLD처럼 사이트 용도에 따른 코드 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;sponsored(sTLD)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;특정 목적을 위한 스폰서를 두고 있는 최상위 도메인, ex) &amp;lsquo;.aero&amp;rsquo;, &amp;lsquo;.asia&amp;rsquo;, &amp;lsquo;.edu&amp;rsquo;,&amp;rsquo;.museum&amp;rsquo; 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;infrastructure
&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;lsquo;.arpa&amp;rsquo;: 인터넷 안정성을 유지하기 위해 새로운 모든 인프라 하위 도메인이 배치될 도메인 공간 역할&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;generic-restricted(grTLD)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;특정 기준을 충족하는 사람이나 단체가 사용할 수 있는 최상위 도메인 ex) &amp;lsquo;.biz&amp;rsquo;, &amp;lsquo;.name&amp;rsquo;, &amp;lsquo;.pro&amp;rsquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;test(tTLD)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;IDN(Internationalized Domain Names) 개발 프로세스에서 테스트 목적으로 사용하는 최상위 도메인 ex) &amp;lsquo;.test&amp;rsquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. DNS 동작 방식&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;도메인을 IP 주소로 변환하려면 DNS 서버에 도메인 쿼리하는 과정을 거쳐야 함&lt;/li&gt;
&lt;li&gt;DNS 서버 없이도 로컬에 도메인과 IP 주소를 직접 설정해 사용할 수도 있음&lt;/li&gt;
&lt;li&gt;hosts 파일에 도메인과 IP 주소를 설정해두면 해당 도메인 리스트는 항상 DNS 캐시에 저장됨&lt;/li&gt;
&lt;li&gt;※ hosts 파일: 로컬에서 도메인과 IP 주소를 관리하는 파일&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1. 클라이언트 관점의 DNS 질의 과정&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;324&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JoUMR/btsKnnbWc3U/StcrDGz6lLlbDB2a1NApFk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JoUMR/btsKnnbWc3U/StcrDGz6lLlbDB2a1NApFk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JoUMR/btsKnnbWc3U/StcrDGz6lLlbDB2a1NApFk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJoUMR%2FbtsKnnbWc3U%2FStcrDGz6lLlbDB2a1NApFk%2Fimg.jpg&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;509&quot; height=&quot;275&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;324&quot;/&gt;&lt;/span&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;도메인을 쿼리하면 DNS 서버에 쿼리를 하기 전 로컬에 있는 DNS 캐시 정보를 먼저 확인
&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;DNS 캐시 정보에는 기존 DNS 조회를 통해 확인한 DNS 캐시와 함께 hosts 파일에 저장되어 있는 정적 DNS 캐시가 함께 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;DNS 캐시 정보에 필요한 도메인 정보가 없으면 DNS 서버로 쿼리를 수행&lt;/li&gt;
&lt;li&gt;DNS 서버로부터 응답을 받으면 그 결과를 캐시에 먼저 저장&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;Windows 에서 DNS 캐시를 확인하려면 ipconfig /displaydns 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.2. DNS 시스템 관점에서의 결과값 응답 과정&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DNS는 워낙 방대하기 때문에 분산된 데이터베이스로 서로 도와주도록 설계&lt;/li&gt;
&lt;li&gt;자신이 가진 도메인 정보가 아니면 다른 DNS에 질의해 결과를 받을 수 있음&lt;/li&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVlap4/btsKn5BAQTg/GKLWbIETSoJGbRVZRKLZ7k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVlap4/btsKn5BAQTg/GKLWbIETSoJGbRVZRKLZ7k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVlap4/btsKn5BAQTg/GKLWbIETSoJGbRVZRKLZ7k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVlap4%2FbtsKn5BAQTg%2FGKLWbIETSoJGbRVZRKLZ7k%2Fimg.jpg&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;600&quot; height=&quot;286&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;286&quot;/&gt;&lt;/span&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;사용자 호스트는 &amp;lsquo;&lt;a href=&quot;http://zigispce.net&quot;&gt;zigispce.net&lt;/a&gt;&amp;rsquo;이라는 도메인 주소의 IP 주소가 로컬 캐시에 저장되어 있는지 확인&lt;/li&gt;
&lt;li&gt;&amp;lsquo;&lt;a href=&quot;http://zigispce.net&quot;&gt;zigispce.net&lt;/a&gt;&amp;rsquo;이 로컬 캐시에 저장되어 있이 않으면 사용자 호스트에 설정된 DNS에 &amp;lsquo;&lt;a href=&quot;http://zigispce.net&quot;&gt;zigispce.net&lt;/a&gt;&amp;rsquo;에 대해 쿼리&lt;/li&gt;
&lt;li&gt;DNS 서버는 &amp;lsquo;&lt;a href=&quot;http://zigispce.net&quot;&gt;zigispce.net&lt;/a&gt;&amp;rsquo;이 로컬 캐시와 자체에 설정되어 있는지 직접 확인하고 없으면 해당 도메인을 찾기 위해 루트 NS에 .net에 대한 TLD 정보를 가진 도메인 주소에 쿼리&lt;/li&gt;
&lt;li&gt;루트 DNS는 &amp;lsquo;&lt;a href=&quot;http://zigispce.net&quot;&gt;zigispce.net&lt;/a&gt;&amp;rsquo;의 TLDdls &amp;lsquo;.net&amp;rsquo;을 관리하는 TLD 네임 서버 정보를 DNS 서버에 응답&lt;/li&gt;
&lt;li&gt;DNS는 TLD 네임 서버에 &amp;lsquo;&lt;a href=&quot;http://zigispce.net&quot;&gt;zigispce.net&lt;/a&gt;&amp;rsquo;에 대한 정보를 다시 쿼리함&lt;/li&gt;
&lt;li&gt;TLD 네임 서버는 &amp;lsquo;&lt;a href=&quot;http://zigispce.net&quot;&gt;zigispce.net&lt;/a&gt;&amp;rsquo;에 대한 정보를 가진 zigi 네임 서버에 대한 정보를 DNS 서버로 응답&lt;/li&gt;
&lt;li&gt;DNS는 zigi 네임 서버에 &amp;lsquo;&lt;a href=&quot;http://zigispce.net&quot;&gt;zigispce.net&lt;/a&gt;&amp;rsquo;에 대한 정보를 쿼리&lt;/li&gt;
&lt;li&gt;zigi 네임 서버는 &amp;lsquo;&lt;a href=&quot;http://zigispce.net&quot;&gt;zigispce.net&lt;/a&gt;&amp;rsquo;에 대한 정보를 DNS 응답함.&lt;/li&gt;
&lt;li&gt;DNS는 &amp;lsquo;&lt;a href=&quot;http://zigispce.net&quot;&gt;zigispce.net&lt;/a&gt;&amp;rsquo;에 대한 정보를 로컬 캐시에 저장하고 사용자 호스트에 &amp;lsquo;&lt;a href=&quot;http://zigispce.net&quot;&gt;zigispce.net&lt;/a&gt;&amp;rsquo;에 대한 정보를 응답&lt;/li&gt;
&lt;li&gt;사용자 호스트는 DNS로부터 받은 &amp;lsquo;&lt;a href=&quot;http://zigispce.net&quot;&gt;zigispce.net&lt;/a&gt;&amp;rsquo;에 대한 IP 정보를 이용해 사이트에 접속&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 마스터와 슬레이브&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;195&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/91PrP/btsKltkhmRj/RfkZrkeNB2LYe6y4wHpDEK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/91PrP/btsKltkhmRj/RfkZrkeNB2LYe6y4wHpDEK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/91PrP/btsKltkhmRj/RfkZrkeNB2LYe6y4wHpDEK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F91PrP%2FbtsKltkhmRj%2FRfkZrkeNB2LYe6y4wHpDEK%2Fimg.jpg&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;600&quot; height=&quot;195&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;195&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;마스터와 슬레이브는 도메인에 대한 존(zone) 파일을 직접 관리하는지 여부로 구분&lt;/li&gt;
&lt;li&gt;마스터 서버는 존 파일을 직접 생성해 도메인 관련 정보를 관리&lt;/li&gt;
&lt;li&gt;슬레이브 서버는 마스터에서 만들어진 존 파일을 복제&lt;/li&gt;
&lt;li&gt;이 과정을 &lt;b&gt;영역 전송(Zone Transfer)&lt;/b&gt; 과정이라 함&lt;/li&gt;
&lt;li&gt;도메인 영역 전송을 위해 슬레이브 서버를 만들 때 도메인을 복제해올 마스터 서버 정보를 입력해야 함&lt;/li&gt;
&lt;li&gt;마스터 서버는 자신이 가진 도메인 정보를 받을 슬레이브 서버를 지정해 제한할 수 있음&lt;/li&gt;
&lt;li&gt;마스터-슬레이브는 이중화에서 일반적으로 사용하는 &lt;b&gt;액티브-스탠바이&lt;/b&gt;나 &lt;b&gt;액티브-액티브&lt;/b&gt; 형태로 구성하지 않음&lt;/li&gt;
&lt;li&gt;DNS 서버는 마스터 서버에 문제가 생기면 슬레이브 서버도 도메인에 대한 질의를 응답할 수 없음&lt;/li&gt;
&lt;li&gt;따라서 만료 시간 안에 마스터 서버를 복구하거나 슬레이브 서버를 마스터 서버로 전환해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마스터와 슬레이브는 도메인 별로 설정 가능하지만&lt;br /&gt;마스터 서버는 모든 도메인에 대해 마스터로 설정하고 &lt;br /&gt;슬레이브 서버는 모두 슬레이브로 설정하는 것이 바람직함&lt;/p&gt;
&lt;/blockquote&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;p style=&quot;color: #333333; text-align: start;&quot; 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;&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;/div&gt;
&lt;/div&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.5. DNS 주요 레코드&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;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 197px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;span style=&quot;color: #ffffff; text-align: start;&quot;&gt; 레코드 &lt;span style=&quot;text-align: start;&quot;&gt;종류&amp;nbsp;&lt;/span&gt; &lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;내용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;A(IPv4)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;도메인 주소를 IP 주소로(IPv4)로 매핑 (일대일, 다대일)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;AAAA(IPv6)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;도메인 주소를 IP 주소로(IPv6)로 매핑&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;CNAME(Canonical Name)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;도메인 주소에 대한 별칭&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;SOA(Start Of Authority)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;본 영역 데이터에 대한 권한&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;NS(Name Server)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;본 영역에 대한 네임 서버&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;MX(Mail eXchange)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;도메인에 대한 메일 서버 정보&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;PTR(Pointer)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;IP 주소를 도메인에 매핑(역방향)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;TXT(TeXT)&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;도메인에 대한 일반 텍스트&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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.6. DNS에서 알아두면 좋은 내용&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;도메인 위임&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;245&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dDh9h0/btsKlFrcQ5W/0kKgQsYvGZEPsukeNEWQNk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dDh9h0/btsKlFrcQ5W/0kKgQsYvGZEPsukeNEWQNk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dDh9h0/btsKlFrcQ5W/0kKgQsYvGZEPsukeNEWQNk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdDh9h0%2FbtsKlFrcQ5W%2F0kKgQsYvGZEPsukeNEWQNk%2Fimg.jpg&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;600&quot; height=&quot;245&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;245&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;br /&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;li&gt;CDN을 이용하거나 GSLB를 사용하는 것이 대표적인 경우&lt;/li&gt;
&lt;li&gt;도메인은 특정 계층의 레코드를 위임하면 해당 레코드의 하위 계층은 함께 위임처리됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TTL
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;DNS에 질의해 응답받은 결괏값을 캐시에서 유지하는 시간&lt;/li&gt;
&lt;li&gt;로컬 캐시에 저장된 도메인 정보를 TTL 값에 따라 그 시간만 로컬 캐시에 저장&lt;/li&gt;
&lt;li&gt;기본 TTL 값: 3,600(윈도), 10,800(리눅스)&lt;/li&gt;
&lt;/ol&gt;
&lt;b&gt;기타 도메인 관련 시간&lt;/b&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;refresh(새로 고침 간격)&lt;/b&gt;: 보조 네임 서버에서 Zone Transfer를 통해 정보를 주기적으로 받아오는 주기&lt;/li&gt;
&lt;li&gt;&lt;b&gt;retry(다시 시도 간격)&lt;/b&gt;: 보조 네임 서버가 주 네임 서버로 접근이 불가할 때 재시도하는 주기&lt;/li&gt;
&lt;li&gt;&lt;b&gt;expire(다음 날짜 이후 만료)&lt;/b&gt;: 보조 네임 서버가 주 네임 서버로부터 도메인 정보를 받아오지 못할 때 유지되는 시간&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&amp;nbsp;&lt;/li&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;/li&gt;
&lt;li&gt;정상적으로 발송하는 대량 이메일이 RBL 이력으로 간주되어 차단되는 것을 예방&lt;/li&gt;
&lt;li&gt;반대로 불법적인 스펨메일 사이트는 실시간 블랙리스트 정보로 관리해 메일 발송 제한&lt;/li&gt;
&lt;li&gt;KISA RBL 사이트에 화이트 도메인으로 등록해야 하며 SPF 레코드가 설정되어야 함.&lt;/li&gt;
&lt;li&gt;SPF 레코드를 작성하려면 TXT 레코드를 사용함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;li&gt;DNS에서는 해당 한글을 &amp;ldquo;퓨니 코드&amp;rdquo;로 변경하고 이것으로 DNS에 도메인을 생성해야 함&lt;/li&gt;
&lt;/ul&gt;
※ &lt;b&gt;퓨니코드&lt;/b&gt;: 애플리케이션 국제화 도메인 네임 기반 하에서 다국어 도메인이 아스키로 변환된 구문&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;2.7. 호스트 파일 설정&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;도메인과 IP 주소를 매핑해놓은 hosts 파일을 이용해 도메인-IP 주소 쿼리를 사용할 수 있음&lt;/li&gt;
&lt;li&gt;DNS 기능 이전부터 사용한 방식이며 테스트 목적 등으로 특정 도메인에 대해 설정한 값으로 접속할 때 사용할 수 있음&lt;/li&gt;
&lt;li&gt;hosts 파일 설정 도메인 정보가 DNS에 의한 질의보다 우선순위가 높음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DNS 의 시작&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DNS가 없던 ARPANET 시절에서는 ARPANET에 있는 컴퓨터의 IP 주소와 호스트를 매핑한 hosts.txt를 사용&lt;/li&gt;
&lt;li&gt;시간이 지나고 인터넷이 커지면서 텍스트 파일로는 한계가 왔고 이를 해결하기 위해 1983년 11월 RFC 882와 883을 통해 DNS 스펙이 발표됨&lt;/li&gt;
&lt;li&gt;이듬해인 1984년 그 스펙을 기준으로 앞에서 소개한 BIND가 만들어짐&lt;/li&gt;
&lt;li&gt;이후 스펙이 지속적으로 추가되면서 현재의 모습을 갖춤&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IT 엔지니어를 위한 네트워크 입문 (고재성, 이상훈 저, 2020.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/네트워크</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/30</guid>
      <comments>https://onyodev.tistory.com/30#entry30comment</comments>
      <pubDate>Mon, 28 Oct 2024 22:55:22 +0900</pubDate>
    </item>
    <item>
      <title>통신을 도와주는 네트워크 주요 기술</title>
      <link>https://onyodev.tistory.com/29</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 고재성, 이상훈 저 - &quot;IT 엔지니어를 위한 네트워크 입문&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. NAT/PAT&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 네트워크 주소에 다른 하나의 네트워크 주소로 변환하는 1:1 변환이 기본&lt;/li&gt;
&lt;li&gt;IP 주소가 고갈되는 문제를 해결하기 위해 여러 개의 IP를 하나의 IP로 변환하기도 함&lt;/li&gt;
&lt;li&gt;공식 용어는 &lt;b&gt;NAPT(Network Port Address Translation)&lt;/b&gt; ,실무에서는 PAT라는 용어로 많이 사용&lt;/li&gt;
&lt;li&gt;가장 많이 사용되는 NAT는 사설 IP주소에서 공인 IP 주소로 전환하는 경우이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;NAT는 IP 주소를 다른 IP 주소로 변환해 라우팅을 원활히 해주는 기술&amp;rdquo;&lt;br /&gt;- 인터넷 표준 문서 -&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1. NAT/PAT의 용도와 필요성&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;IPv4 주소 고갈 문제의 솔루션으로 사용&lt;/li&gt;
&lt;li&gt;보안을 강화하는 데 사용
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;외부와 통신할 때 내부 IP를 다른 IP로 변환해 외부에 사내 IP주소 체계를 숨길 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;IP 주소 체계가 같은 같은 두 개의 네트워크 간 통신을 가능하게 함
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;사용하는 사설 IP 대역이 같은 회사끼리의 통신을 위해 출발지와 도착지를 한꺼번에 변환하는 더블 NAT를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;불필요한 설정 변경을 줄일 수 있음
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;보통은 통신사업자나 IDC 쪽에서 IP를 할당받아 사용&lt;/li&gt;
&lt;li&gt;NAT/PAT를 사용할 경우 공인 IP 주소 변경 시 네트워크 장비의 설정만 변경하고 PC 설정 변경은 최소화 할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2. NAT 동작 방식&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cZlJh9/btsKmnQ9Pf5/0f5i5fn52M4laj5x9catFK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cZlJh9/btsKmnQ9Pf5/0f5i5fn52M4laj5x9catFK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cZlJh9/btsKmnQ9Pf5/0f5i5fn52M4laj5x9catFK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcZlJh9%2FbtsKmnQ9Pf5%2F0f5i5fn52M4laj5x9catFK%2Fimg.jpg&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;465&quot; height=&quot;332&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;428&quot;/&gt;&lt;/span&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;사용자는 웹 서버에 접근하기 위해 출발지 IP: 10.10.10.10, 목적지: 20.20.20.20, 서비스 포트: 80&lt;/li&gt;
&lt;li&gt;NAT 장비에서 사용자가 보낸 패킷을 수신한 후 NAT 정책에 따라 공인 IP 11.11.11.11로 주소 변경 후 NAT 테이블에 저장&lt;/li&gt;
&lt;li&gt;NAT 장비에서 출발지를 11.11.11.11로 변경해 웹 서버로 전송&lt;/li&gt;
&lt;li&gt;패킷을 수신한 웹 서버에서 사용자에게 응답을 보냄 (출발지 IP: 20.20.20.20, 목적지: 11.11.11.11)&lt;/li&gt;
&lt;li&gt;응답 패킷을 수신한 NAT는 원래 패킷을 발생시킨 출발지 IP 주소가 10.10.10.10임을 확인&lt;/li&gt;
&lt;li&gt;원래 패킷 출발지 IP(10.10.10.10)로 변경해 사용자에게 전송되면 최종 수신&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3. PAT 동작 방식&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PAT는 NAT 테이블에 출발지 IP 주소와 출발지 서비스 포트가 모두 변경되고 NAT 테이블에 기록됨&lt;/li&gt;
&lt;li&gt;하나의 IP만으로 다양한 포트 번호를 사용해 사용자를 구분할 수 있음&lt;/li&gt;
&lt;li&gt;서비스 포트의 개수가 제한되어 재사용이 됨&lt;/li&gt;
&lt;li&gt;동시 사용자가 많은 경우 정상 동작하지 않을 수 있고 공인 IP 주소를 하나가 아닌 풀(Pool)로 구성&lt;/li&gt;
&lt;li&gt;다수의 IP가 있는 출발지에서 목적지로 갈 때 NAT 테이블이 생성되고 응답에 대해 NAT 테이블을 참조할 수 있음&lt;/li&gt;
&lt;li&gt;하지만 PAT IP가 목적지인 경우 해당 IP가 어느 IP에 바인딩되는지 확인할 수 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.4. SNAT와 DNAT&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 IP 주소를 변환하는지에 따라 두 가지로 구분함
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SNAT(Source NAT): 출발지 주소를 변경하는 NAT&lt;/li&gt;
&lt;li&gt;DNAT(Destination NAT): 도착지 주소를 변경하는 NAT&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;트래픽이 출발하는 시작 지점을 기준으로 구분함.&lt;/li&gt;
&lt;li&gt;NAT 장비를 처음 통과할 때 NAT 테이블을 사용해 기록됨&lt;/li&gt;
&lt;li&gt;이후 응답 패킷이 NAT 장비에 들어오면 별도의 설정 없이 반대로 패킷을 변환하는 &lt;b&gt;역 NAT&lt;/b&gt;가 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;SNAT
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;사설 &amp;rarr; 공인으로 통신할 때 많이 사용&lt;/li&gt;
&lt;li&gt;보안상 SNAT를 사용할 때 사용&lt;/li&gt;
&lt;li&gt;로드 밸런서의 구성에 따라 SNAT를 사용
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;같은 대역일 때 로드밸런서를 거치지 않고 응답하는 경우가 있어 SNAT를 통해 로드 밸런서를 거치게 함&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;DNAT
&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;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.5. 동적 NAT와 정적 NAT&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;272&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brMCL8/btsKmIAM3Y8/a01XZmaT2KivOiIMRMTyd0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brMCL8/btsKmIAM3Y8/a01XZmaT2KivOiIMRMTyd0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brMCL8/btsKmIAM3Y8/a01XZmaT2KivOiIMRMTyd0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrMCL8%2FbtsKmIAM3Y8%2Fa01XZmaT2KivOiIMRMTyd0%2Fimg.jpg&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;600&quot; height=&quot;272&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;272&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적 NAT
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;출발지와 목적지 IP를 미리 매핑해 고정해놓은 NAT&lt;/li&gt;
&lt;li&gt;1:1 NAT라 부르기도 하며 방향성 없이 서비스 흐름을 고려할 필요가 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;동적 NAT
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;출발지나 목적지가 사전에 정해지지 않고 NAT를 수행할 때 IP를 동적으로 변경하는 것&lt;/li&gt;
&lt;li&gt;출발지와 목적지가 다수의 IP 풀이나 레인지(Range)로 설정&lt;/li&gt;
&lt;li&gt;NAT가 필요할 때 어떻게 매핑할 것인지 판단해 NAT를 수행하는 시점에 NAT 테이블을 만들어 관리&lt;/li&gt;
&lt;li&gt;NAT 테이블은 일정 시간 통신이 없는 경우 다시 사라지므로 서비스 흐름을 고려해 적용해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;정적 NAT 설정&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지정한 방향으로만 1:1 NAT가 적용되는 장비도 있음&lt;/li&gt;
&lt;li&gt;이런 장비에서는 방향성을 고려해 두 개의 NAT를 각각 설정해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. GSLB&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;315&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cloX3C/btsKmJsWakE/QGHNsY0DbMUyJJpaQ6vzAK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cloX3C/btsKmJsWakE/QGHNsY0DbMUyJJpaQ6vzAK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cloX3C/btsKmJsWakE/QGHNsY0DbMUyJJpaQ6vzAK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcloX3C%2FbtsKmJsWakE%2FQGHNsY0DbMUyJJpaQ6vzAK%2Fimg.jpg&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;514&quot; height=&quot;270&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;315&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DNS에서 동일한 레코드 이름으로 서로 다른 IP 주소를 동시에 설정할 수 있음&lt;/li&gt;
&lt;li&gt;이렇게 설정하면 도메인 질의에 따라 응답받는 IP 주소를 나누어 로드밸런싱할 수 있음&lt;/li&gt;
&lt;li&gt;하지만 DNS 로드밸런싱만으로는 정상적인 서비스를 할 수 없음&lt;/li&gt;
&lt;li&gt;DNS는 설정된 서비스 상태의 정상 여부를 확인하지 않고 질의에 무조건 응답함.&lt;/li&gt;
&lt;li&gt;특정 서비스에 문제가 있을 때는 DNS 서버가 인지하지 못하여 비정상 상태의 서비스 IP 주소를 응답해버리는 문제가 발생&lt;/li&gt;
&lt;li&gt;GSLB(Global Server/Service Load Balancing)는 DNS의 이런 문제를 해결해 도메인을 이용한 로드밸런싱 구현을 도와줌&lt;/li&gt;
&lt;li&gt;GSLB는 DNS와 동일하게 도메인 질의에 응답해주는 역할과 동시에 밸런서처럼 등록된 도메인에 연결된 서비스의 헬스 체크를 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. GSLB 동작 방식&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PbNRQ/btsKnlLXjJF/2HzQUWlA8zoomOwAKvdhFk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PbNRQ/btsKnlLXjJF/2HzQUWlA8zoomOwAKvdhFk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PbNRQ/btsKnlLXjJF/2HzQUWlA8zoomOwAKvdhFk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPbNRQ%2FbtsKnlLXjJF%2F2HzQUWlA8zoomOwAKvdhFk%2Fimg.jpg&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;513&quot; height=&quot;342&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&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;사용자가 &lt;a href=&quot;http://web.zigispace.net&quot;&gt;web.zigispace.net&lt;/a&gt;에 접속하기 위해 DNS에 질의&lt;/li&gt;
&lt;li&gt;LDNS는 &lt;a href=&quot;http://web.zigispace.net&quot;&gt;web.zigispace.net&lt;/a&gt;을 관리하는 NS 서버를 찾기 위해 root부터 순차 질의&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://web.zigispace.net&quot;&gt;zigispace.net&lt;/a&gt;을 관리하는 NS 서버로 &lt;a href=&quot;http://web.zigispace.net&quot;&gt;web.zigispace.net&lt;/a&gt;에 대해 질의&lt;/li&gt;
&lt;li&gt;DNS 서버는 GSLB로 &lt;a href=&quot;http://web.zigispace.net&quot;&gt;web.zigispace.net&lt;/a&gt;에 대해 위임했으므로 GSLB 서버가 NS 서버라고 LDNS에 응답&lt;/li&gt;
&lt;li&gt;LDNS는 다시 GSLB로 &lt;a href=&quot;http://web.zigispace.net&quot;&gt;web.zigispace.net&lt;/a&gt;에 대해 질의&lt;/li&gt;
&lt;li&gt;GSLB는 &lt;a href=&quot;http://web.zigispace.net&quot;&gt;web.zigispace.net&lt;/a&gt;에 대한 IP 주소값 중 현재 설정된 분산 방식에 따라 서울 혹은 부산 데이터 센터의 IP 주소값을 DNS에 응답&lt;/li&gt;
&lt;li&gt;GSLB에서 결괏값을 응답받은 LDNS는 사용자에게 &lt;a href=&quot;http://web.zigispace.net&quot;&gt;web.zigispace.net&lt;/a&gt;가 1.1.1.1로 서비스한다고 최종 응답&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;DNS와 거의 동일하게 동작하지만 서비스 IP 정보에 대한 헬스체크와 다양한 분산 방법을 사용하는 차이가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. GSLB 구성 방식&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;도메인 자체를 GSLB로 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 도메인에 속하는 모든 레코드 설정을 GSLB 장비에서 관리&lt;/li&gt;
&lt;li&gt;도메인에 대한 네임 서버를 GSLB로 지정하고 GSLB에서 도메인에 대한 모든 레코드를 등록해 처리하는 방식&lt;/li&gt;
&lt;li&gt;이 경우 모든 레코드에 대한 질의가 GSLB를 통해 이루어져 GSLB에 부담을 줌&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;도메인 내의 특정 레코드만 GSLB를 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DNS에서 도메인 설정 시 GSLB를 사용하려는 레코드에 대해서만 GSLB로 처리하도록 설정&lt;/li&gt;
&lt;li&gt;도메인 내의 특정 레코드에 대해서만 GSLB로 처리를 이관하는 방식을 사용&lt;/li&gt;
&lt;li&gt;처리를 이관하는 방식
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;별칭(Alias) 사용(CNAME 사용)&lt;/b&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;외부 CDN을 사용하거나 회사 내부에 GSLB를 사용해야 할 도메인이 많은 경우 한꺼번에 관리하기 위해 사용&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;343&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dKtAcq/btsKmlMT9BL/Irj8AUR6u9KSqFHABtTw6K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dKtAcq/btsKmlMT9BL/Irj8AUR6u9KSqFHABtTw6K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dKtAcq/btsKmlMT9BL/Irj8AUR6u9KSqFHABtTw6K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdKtAcq%2FbtsKmlMT9BL%2FIrj8AUR6u9KSqFHABtTw6K%2Fimg.jpg&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;599&quot; height=&quot;343&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;343&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;br /&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;사용자가 &lt;a href=&quot;http://web.zigispace.net/&quot;&gt;web.zigispace.net&lt;/a&gt;을 LDNS(1.1.1.1)로 질의&lt;/li&gt;
&lt;li&gt;LDNS는 &lt;a href=&quot;http://web.zigispace.net/&quot;&gt;web.zigispace.net&lt;/a&gt;을 관리하는 NS 서버를 찾기 위해 root부터 순차적으로 질의&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://web.zigispace.net/&quot;&gt;zigispace.net&lt;/a&gt;을 관리하는 DNS(2.2.2.2)에 &lt;a href=&quot;http://web.zigispace.net/&quot;&gt;web.zigispace.net&lt;/a&gt;의 주소 질의&lt;/li&gt;
&lt;li&gt;DNS 서버는 LDNS에게 별칭으로 &lt;a href=&quot;http://web.zigispace.net/&quot;&gt;web.zigispace.net&lt;/a&gt;은 &lt;a href=&quot;http://web.zigispace.net/&quot;&gt;web.zigispace.gslb.net&lt;/a&gt;이 관리하고 있다는 응답 수신&lt;/li&gt;
&lt;li&gt;다시 LDNS(1.1.1.1)는 gslb.net을 관리하는 NS 서버를 root부터 순차 질의&lt;/li&gt;
&lt;li&gt;LDNS(1.1.1.1)는 &lt;a href=&quot;http://web.zigispace.net/&quot;&gt;zigispace.gslb.net&lt;/a&gt;을 관리하는 NS 서버인 GSLB(3.3.3.3)에 web&lt;a href=&quot;http://web.zigispace.net/&quot;&gt;.zigispace.gslb.net&lt;/a&gt;에 대해 질의&lt;/li&gt;
&lt;li&gt;GSLB(3.3.3.3)는 LDNS(1.1.1.1)에 &lt;a href=&quot;http://web.zigispace.net/&quot;&gt;web.zigispace.gslb.net&lt;/a&gt;의 IP(10.10.10.10)를 응답&lt;/li&gt;
&lt;li&gt;LDNS(1.1.1.1)는 해당 결괏값(10.10.10.10)을 사용자에게 최종 응답&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;위임(Delegation) 사용(NS 사용)&lt;/b&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;/ul&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;345&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bs7lhD/btsKlsMoE4c/ZvZJkTpoLgMi2cB0QG7AMk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bs7lhD/btsKlsMoE4c/ZvZJkTpoLgMi2cB0QG7AMk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bs7lhD/btsKlsMoE4c/ZvZJkTpoLgMi2cB0QG7AMk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbs7lhD%2FbtsKlsMoE4c%2FZvZJkTpoLgMi2cB0QG7AMk%2Fimg.jpg&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;520&quot; height=&quot;299&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;345&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;br /&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;사용자가 &lt;a href=&quot;http://web.zigispace.net/&quot;&gt;web.zigispace.net&lt;/a&gt;을 LDNS(1.1.1.1)로 질의&lt;/li&gt;
&lt;li&gt;LDNS는 &lt;a href=&quot;http://web.zigispace.net/&quot;&gt;web.zigispace.net&lt;/a&gt;을 관리하는 NS 서버를 찾기 위해 root부터 순차적으로 질의&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://web.zigispace.net/&quot;&gt;zigispace.net&lt;/a&gt;을 관리하는 DNS(2.2.2.2)에 &lt;a href=&quot;http://web.zigispace.net/&quot;&gt;web.zigispace.net&lt;/a&gt;의 주소 질의&lt;/li&gt;
&lt;li&gt;DNS(2.2.2.2)는 GSLB(3.3.3.3)가 &lt;a href=&quot;http://web.zigispace.net/&quot;&gt;web.zigispace.net&lt;/a&gt;을 관리한다고 응답&lt;/li&gt;
&lt;li&gt;다시 LDNS(1.1.1.1)는 web.zigispace.net을 관리하는 NS 서버인 GSLB(3.3.3.3)에게 web.zigispace.net을 질의&lt;/li&gt;
&lt;li&gt;GSLB(3.3.3.3)는 LDNS(1.1.1.1)에 web.zigispace.net의 IP를 응답&lt;/li&gt;
&lt;li&gt;LDNS(1.1.1.1)는 해당 결괏값을 사용자에게 최종 응답&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;결론&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;별칭을 이용해 GSLB를 사용하는 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CDN처럼 GSLB를 운영해주는 외부 사업자가 있는 경우&lt;/li&gt;
&lt;li&gt;GSLB를 사용해야 하는 도메인이 많거나 별도의 GSLB를 운영해야 하는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;위임해서 GSLB를 사용하는 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DNS와 같은 도메인으로 GSLB를 운영하면서 계층적으로 GSLB를 이용한 FQDN을 관리할 때 사용&lt;/li&gt;
&lt;li&gt;FQDN(Full Qualified Domain Name): 인터넷에서 특정 컴퓨터, 장치 또는 자원을 고유하게 식별할 수 있는 완전한 도메인 이름&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3. GSLB 분산 방식&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GSLB 분산의 목적
&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;li&gt;지역적으로 가까운 서비스에 접속해 더 빠른 서비스 제공이 가능하도록 분산&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;GSLB의 헬스 체크 모니터링 요소
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;서비스 응답 시간/지연 (RTT/Latency)&lt;/li&gt;
&lt;li&gt;IP에 대한 지리 정보&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;해당 정보들을 활용해 서비스를 분산 처리함.&lt;/li&gt;
&lt;li&gt;사용자가 바라보는 Local DNS와 GSLB 간 값이므로 국가 설정을 잘 해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. DHCP&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DHCP(Dynamic Host Configuration Protocol): IP를 동적으로 할당하는 데 사용하는 프로토콜&lt;/li&gt;
&lt;li&gt;DHCP를 사용하면 사용자가 직접 입력해야 하는 IP 주소, 서브넷 마스크, 게이트웨이, DNS 정보를 자동으로 할당받아 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1. DHCP 프로토콜&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BOOTP(Bootstrap Protocol)라는 프로토콜을 기반으로 하며 호환도 됨&lt;/li&gt;
&lt;li&gt;BOOTP와 유사하게 동작하지만 몇 가지 기능이 추가된 확장 프로토콜&lt;/li&gt;
&lt;li&gt;DHCP는 서버와 클라이언트로 동작
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트 서비스 포트: 68(bootpc)&lt;/li&gt;
&lt;li&gt;서버 서비스 포트: 67(bootps)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.2. DHCP 동작 방식&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;402&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5tHFC/btsKl6hSF7G/IEQkGMsGbPwiApdddswqek/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5tHFC/btsKl6hSF7G/IEQkGMsGbPwiApdddswqek/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5tHFC/btsKl6hSF7G/IEQkGMsGbPwiApdddswqek/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5tHFC%2FbtsKl6hSF7G%2FIEQkGMsGbPwiApdddswqek%2Fimg.jpg&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;507&quot; height=&quot;340&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;402&quot;/&gt;&lt;/span&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;DHCP Discover
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DHCP 클라이언트는 DHCP 서버를 찾기 위해 DHCP Discover 메시지를 브로드캐스트로 전송&lt;/li&gt;
&lt;li&gt;출발지는 Zero IP 주소(0.0.0.0) , 목적지는 브로드캐스트 주소(255.255.255.255)&lt;/li&gt;
&lt;li&gt;IP 할당 중이기 때문에 UDP를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;DHCP Offer
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수신한 DHCP 서버는 클라이언트에 할당할 &lt;b&gt;IP 주소, 서브넷, 게이트웨이, DNS 정보, Lease Time 등의 정보&lt;/b&gt;를 포함한 DHCP 메시지를 클라이언트로 전송&lt;/li&gt;
&lt;li&gt;특정 클라이언트의 MAC주소와 IP 주소를 사전에 정의하면 설정된 대로 할당 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;DHCP Request
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DHCP 서버로부터 제안 받은 IP 주소와 DHCP 서버 정보를 포함한 DHCP 요청 메시지를 브로드캐스트로 전송&lt;/li&gt;
&lt;li&gt;DHCP 서버 여러 대가 동작하는 환경을 위해 브로드캐스트로 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;DHCP Ack
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DHCP 클라이언트로부터 IP 주소를 사용하겠다는 요청을 받으면 DHCP 서버에
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 IP를&lt;/li&gt;
&lt;li&gt;어떤 클라이언트가&lt;/li&gt;
&lt;li&gt;언제부터 사용하기 시작했는지&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;정보를 기록하고 DHCP Request 메시지를 정상적으로 수신했다는 응답 전송&lt;/li&gt;
&lt;li&gt;이것도 브로드캐스트로 해당 네트워크 내에 전체 전송&lt;/li&gt;
&lt;/ul&gt;
&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;DHCP를 통해 IP를 할당 받을 때는 IP 임대 시간이 있음&lt;/li&gt;
&lt;li&gt;만약 임대 시간이 다한 경우, 갱신 과정을 거쳐 IP 주소가 IP 풀에 다시 반환하지 않고 계속 사용함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;b&gt;DHCP 갱신 절차&lt;br /&gt;&lt;/b&gt;&lt;/b&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;251&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpk3WE/btsKlr08GAc/2WufUsD9sRNnPvkg6nYFP1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpk3WE/btsKlr08GAc/2WufUsD9sRNnPvkg6nYFP1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpk3WE/btsKlr08GAc/2WufUsD9sRNnPvkg6nYFP1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbpk3WE%2FbtsKlr08GAc%2F2WufUsD9sRNnPvkg6nYFP1%2Fimg.jpg&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;600&quot; height=&quot;251&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;251&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IP를 할당한 후 임대 시간의 50%가 지나면 갱신 과정을 수행&lt;/li&gt;
&lt;li&gt;DHCP Request와 DHCP ACK를 주고 받으면서 갱신 과정을 진행&lt;/li&gt;
&lt;li&gt;갱신 시에는 유니캐스트로 진행&lt;/li&gt;
&lt;li&gt;만약 갱신이 실패하면 남은 시간의 50%가 지난 시점에서 다시 갱신을 시도함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DHCP 메시지 타입과 항목&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;4가지 타입의 DHCP 메시지 외 더 다양한 메시지들이 존재함&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 81.1736%; height: 307px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 31.2958%; height: 20px;&quot;&gt;메시지 타입&lt;/td&gt;
&lt;td style=&quot;width: 68.7042%; height: 20px;&quot;&gt;내용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 31.2958%; height: 17px;&quot;&gt;DHCP Discover&lt;/td&gt;
&lt;td style=&quot;width: 68.7042%; height: 17px;&quot;&gt;클라이언트가 사용한 DHCP 서버를 찾는 메시지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 31.2958%; height: 17px;&quot;&gt;&lt;span style=&quot;background-color: #efefef; color: #333333; text-align: start;&quot;&gt;DHCP Offer&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.7042%; height: 17px;&quot;&gt;DHCP 서버가 IP 설정값에 대해 클라이언트에게 제안하는 메시지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 31.2958%; height: 17px;&quot;&gt;&lt;span style=&quot;background-color: #efefef; color: #333333; text-align: start;&quot;&gt;DHCP Request&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.7042%; height: 17px;&quot;&gt;DHCP 서버에서 제안받은 설정값을 요청하는 메시지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 31.2958%; height: 17px;&quot;&gt;&lt;span style=&quot;background-color: #efefef; color: #333333; text-align: start;&quot;&gt;DHCP Decline&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.7042%; height: 17px;&quot;&gt;현재 IP가 사용 중임을 클라이언트가 서버에 알려주는 메시지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 31.2958%; height: 17px;&quot;&gt;&lt;span style=&quot;background-color: #efefef; color: #333333; text-align: start;&quot;&gt;DHCP Ack&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.7042%; height: 17px;&quot;&gt;DHCP 서버가 클라이언트에 받은 요청을 수락하는 메시지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 31.2958%; height: 17px;&quot;&gt;&lt;span style=&quot;background-color: #efefef; color: #333333; text-align: start;&quot;&gt;DHCP Nak&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.7042%; height: 17px;&quot;&gt;DHCP 서버가 클라이언트에 받은 요청을 수락하지 않는다는 메시지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 31.2958%; height: 17px;&quot;&gt;&lt;span style=&quot;background-color: #efefef; color: #333333; text-align: start;&quot;&gt;DHCP Release&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.7042%; height: 17px;&quot;&gt;클라이언트가 현재 IP를 반납할 때 사용하는 메시지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 31.2958%; height: 17px;&quot;&gt;&lt;span style=&quot;background-color: #efefef; color: #333333; text-align: start;&quot;&gt;DHCP Inform&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 68.7042%; height: 17px;&quot;&gt;클라이언트가 서버에 IP 설정값을 요청하는 메시지&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ DHCP Starvation 공격 : &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;IP 풀에서 관리하는 모든 IP 주소를 소진시켜 IP를 할당받을 수 없도록 하는 공격 방식&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.3. DHCP 서버 구성&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DHCP 서버는 윈도 서버의 DHCP 서비스나 리눅스의 DHCP 데몬을 이용해 구성할 수 있음&lt;/li&gt;
&lt;li&gt;DHCP 서버 설정값
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;IP 주소풀(IP 범위)&lt;/li&gt;
&lt;li&gt;예외 IP 주소 풀(예외 IP 범위)&lt;/li&gt;
&lt;li&gt;임대 시간&lt;/li&gt;
&lt;li&gt;서브넷 마스크&lt;/li&gt;
&lt;li&gt;게이트웨이&lt;/li&gt;
&lt;li&gt;DNS&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.4. DHCP 릴레이&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;340&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c20bdU/btsKmT3scee/2kIvyRLYDjMV4V0KEZqR0k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c20bdU/btsKmT3scee/2kIvyRLYDjMV4V0KEZqR0k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c20bdU/btsKmT3scee/2kIvyRLYDjMV4V0KEZqR0k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc20bdU%2FbtsKmT3scee%2F2kIvyRLYDjMV4V0KEZqR0k%2Fimg.jpg&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;499&quot; height=&quot;283&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;340&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DHCP 서버에서 IP 주소를 할당받기 위해 모두 브로드캐스트를 사용함&lt;/li&gt;
&lt;li&gt;동일 네트워크에서만 전송되므로 각 네트워크마다 DHCP 서버가 있어야 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DHCP 릴레이 에이전트 기능&lt;/b&gt;을 사용하면 DHCP 서버 한 대로 여러 네트워크 대역에서 IP 풀을 관리할 수 있음&lt;/li&gt;
&lt;li&gt;DHCP 패킷을 중간에서 중계하는 역할을 수행함&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfoYbe/btsKl11VCxU/462kcq4gULSdS3kkzmkskk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfoYbe/btsKl11VCxU/462kcq4gULSdS3kkzmkskk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfoYbe/btsKl11VCxU/462kcq4gULSdS3kkzmkskk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfoYbe%2FbtsKl11VCxU%2F462kcq4gULSdS3kkzmkskk%2Fimg.jpg&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;524&quot; height=&quot;408&quot; data-origin-width=&quot;599&quot; data-origin-height=&quot;466&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&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;b&gt;DHCP Discover(클라이언트 &amp;rarr; 릴레이 에이전트)&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;DHCP 클라이언트는 DHCP 서버를 찾기 위해 &lt;b&gt;브로드캐스트&lt;/b&gt;로 패킷을 전송&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DHCP&lt;/b&gt;&amp;nbsp;&lt;b&gt;Discover(릴레이 에이전트 &amp;rarr;&lt;/b&gt;&amp;nbsp;&lt;b&gt;DHCP&lt;/b&gt;&amp;nbsp;&lt;b&gt;서버)&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;출발지와 목적지를 릴레이 에이전트 IP 주소와 DHCP 서버 IP 주소로 재작성&lt;/li&gt;
&lt;li&gt;이때는 주소가 DHCP 서버가 되었기 때문에 &lt;b&gt;유니캐스트&lt;/b&gt;로 보냄&lt;/li&gt;
&lt;li&gt;출발지 주소 &amp;ne; 릴레이 에이전트 IP 주소&lt;/li&gt;
&lt;li&gt;&lt;b&gt;출발지 주소&lt;/b&gt;: DHCP 서버로 가기 위한 방향의 인터페이스 IP 주소&lt;/li&gt;
&lt;li&gt;&lt;b&gt;릴레이 에이전트 IP 주소&lt;/b&gt;: DHCP 클라이언트가 속한 내부 인터페이스 IP 주소&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DHCP&lt;/b&gt;&amp;nbsp;&lt;b&gt;Offer(DHCP&lt;/b&gt;&amp;nbsp;&lt;b&gt;서버 &amp;rarr; 릴레이 에이전트)&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Discover를 수신한 DHCP 서버는 클라이언트에 할당할 주소와 서브넷, 게이트웨이,DNS 정보, 임대 시간(Lease Time) 등의 정보를 포함한 DHCP 메시지를 DHCP 릴레이 에이전트로 다시 전송&lt;/li&gt;
&lt;li&gt;DHCP Server Identifier는 DHCP 서버 자신이 됨&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DHCP&lt;/b&gt;&amp;nbsp;&lt;b&gt;Offer(릴레이 에이전트 &amp;rarr; 클라이언트)&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;DHCP Offer 메시지를 DHCP 클라이언트에 브로드캐스트로 다시 전송&lt;/li&gt;
&lt;li&gt;DHCP Server Identifier는 실제 DHCP 서버의 IP 주소 &amp;rarr; 릴레이 에이전트의 외부 인터페이스 IP 주소로 변경되어 전송&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DHCP&lt;/b&gt;&amp;nbsp;&lt;b&gt;Request(클라이언트 &amp;rarr; 릴레이 에이전트)&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;DHCP 서버로부터 제안받은 IP 주소와 DHCP 서버 정보를 포함한 DHCP 요청 메시지를 브로드캐스트로 전송&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DHCP&lt;/b&gt;&amp;nbsp;&lt;b&gt;Request(릴레이 에이전트 &amp;rarr;&lt;/b&gt;&amp;nbsp;&lt;b&gt;DHCP&lt;/b&gt;&amp;nbsp;&lt;b&gt;서버)&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;DHCP 클라이언트에서 보낸 DHCP 요청 메시지를 유니캐스트로 다시 변환해 DHCP 서버로 전달&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DHCP&lt;/b&gt;&amp;nbsp;&lt;b&gt;ACK(DHCP&lt;/b&gt;&amp;nbsp;&lt;b&gt;서버 &amp;rarr; 릴레이 에이전트)&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;해당 IP를 어떤 클라이언트가 언제부터 사용하기 시작했는지 정보를 기록&lt;/li&gt;
&lt;li&gt;DHCP Request 메시지를 정상적으로 수신했다는 응답을 전송&lt;/li&gt;
&lt;li&gt;마찬가지로 유니캐스트 형태로 전송&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DHCP&lt;/b&gt;&amp;nbsp;&lt;b&gt;ACK(릴레이 에이전트 &amp;rarr; 클라이언트)&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;DHCP 서버에서 받은 Ack 메시지를 클라이언트에 브로드캐스트로 다시 전달합니다.&lt;/li&gt;
&lt;/ol&gt;
&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;IT 엔지니어를 위한 네트워크 입문 (고재성, 이상훈 저, 2020.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/네트워크</category>
      <category>computer science</category>
      <category>dhcp</category>
      <category>NAT</category>
      <category>네트워크</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/29</guid>
      <comments>https://onyodev.tistory.com/29#entry29comment</comments>
      <pubDate>Mon, 28 Oct 2024 22:41:59 +0900</pubDate>
    </item>
    <item>
      <title>CPU 스케줄링</title>
      <link>https://onyodev.tistory.com/28</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;이 글은 반효경 저 - &quot;운영체제와 정보기술의 원리&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&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 data-ke-size=&quot;size26&quot;&gt;1. 프로그램 실행 기계어와 수행 과정&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1. 기계어 명령의 종류&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;CPU 내에서 실행
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Add 명령: CPU 내의 레지스터에 있는 두 값을 더해 레지스터에 저장하는 명령&lt;/li&gt;
&lt;li&gt;수행 속도가 매우 빠름&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;메모리 접근
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Load 명령: 메모리에 있는 데이터를 CPU로 읽어드리는 명령&lt;/li&gt;
&lt;li&gt;Store 명령: CPU에서 계산된 결괏값을 메모리에 저장하는 명령&lt;/li&gt;
&lt;li&gt;CPU 내의 명령보다는 느리지만 비교적 짧은 시간에 수행할 수 있는 명령&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;li&gt;디스크에서 파일 데이터를 읽어오거나 컴퓨터에서 처리된 결과를 디스크에 파일 형태로 저장하는 경우&lt;/li&gt;
&lt;li&gt;다른 명령에 비해 오랜 시간이 소요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;CPU나 메모리 접근에 필요한 명령은 &lt;b&gt;일반 명령&lt;/b&gt;에 해당함&lt;br /&gt;컴퓨터 시스템 내에서 모든 입출력 명령은 &lt;b&gt;특권 명령&lt;/b&gt;으로 규정됨&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2. 프로그램 수행 과정&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자 프로그램이 수행되는 과정은 CPU 작업과 I/O 작업의 반복으로 구성&lt;/li&gt;
&lt;li&gt;프로그램 수행 단계
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;CPU 버스트&lt;/b&gt;: 사용자 프로그램이 CPU를 직접 가지고 빠른 명령을 수행하는 단계&lt;/li&gt;
&lt;li&gt;&lt;b&gt;I/O 버스트&lt;/b&gt;: I/O 요청이 발생해 커널에 의해 입출력 작업을 진행하는 단계&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;프로세스 비중에 따른 분류
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;I/O 바운드 프로세스&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;I/O 요청이 빈번해 CPU 버스트가 짧게 나타나는 프로세스&lt;/li&gt;
&lt;li&gt;주로 사용자로부터 인터랙션을 계속 받으며 수행시키는 대화형 프로그램에 사용&lt;/li&gt;
&lt;li&gt;짧은 CPU 버스트를 많이 가지고 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CPU 바운드 프로세스&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;I/O 요청이 많지 않아 CPU 버스트가 길게 나타나는 프로세스&lt;/li&gt;
&lt;li&gt;CPU 작업에 소모하는 계산 위주의 프로그램에 사용&lt;/li&gt;
&lt;li&gt;소수의 긴 CPU 버스트를 가지고 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프로세스들의 CPU 버스트 분석 결과&lt;br /&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1176&quot; data-origin-height=&quot;960&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyS8Gm/btsKkmL9wFg/plGyRcGTWp1km5UBn5ZO11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyS8Gm/btsKkmL9wFg/plGyRcGTWp1km5UBn5ZO11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyS8Gm/btsKkmL9wFg/plGyRcGTWp1km5UBn5ZO11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyS8Gm%2FbtsKkmL9wFg%2FplGyRcGTWp1km5UBn5ZO11%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;383&quot; height=&quot;313&quot; data-origin-width=&quot;1176&quot; data-origin-height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;br /&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;대부분 짧은 CPU 버스트를 가지고 극히 일부분만 긴 CPU 버스트를 가짐&lt;/li&gt;
&lt;li&gt;CPU를 짧게 사용하고 &lt;b&gt;I/O 작업을 수행하는 프로세스가 많음&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;이런 프로세스는 CPU의 빠른 서비스를 필요로 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;즉, CPU 스케줄링 시 CPU 버스트가 짧은 프로세스에게 우선적으로 CPU를 사용할 수 있는 스케줄링이 필요&lt;/li&gt;
&lt;li&gt;&lt;b&gt;I/O 바운드 프로세스의 우선순위를 높이는 것&lt;/b&gt;이 좋음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. CPU 스케줄러&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;준비 상태에 있는 프로세스들 중 어떠한 프로세스에게 CPU를 할당할지 결정하는 운영체제 코드&lt;/li&gt;
&lt;li&gt;타이머 인터럽트 발생 시 호출되고 준비 큐에서 CPU를 기다리는 프로세스 중 하나를 선택해 CPU를 할당&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CPU 스케줄링이 필요한 상황&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;실행 상태에 있던 프로세스가 I/O 요청 등에 의해 봉쇄 상태로 바뀌는 경우 &lt;b&gt;(비선점형)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;실행 상태에 있던 프로세스가 타이머 인터럽트 발생에 의해 준비 상태로 바뀌는 경우 &lt;b&gt;(선점형)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;I/O 요청으로 봉쇄 상태에 있던 프로세스의 I/O 작업이 완료되어 인터럽트가 발생하여 이 프로세스의 상태가 준비 상태로 바뀌는 경우 &lt;b&gt;(선점형)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;CPU에서 실행 상태에 있는 프로세스가 종료되는 경우 &lt;b&gt;(비선점형)&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CPU 스케줄링 방식&lt;/b&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;: CPU가 획득한 프로세스가 스스로 CPU를 반납하기 전까지 CPU를 뺏기지 않는 방식&lt;/li&gt;
&lt;li&gt;&lt;b&gt;선점형 방식&lt;/b&gt;: 프로세스를 강제로 빼앗을 수 있는 스케줄링 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 디스패처&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선택된 프로세스가 CPU를 할당받고 작업을 수행할 수 있도록 환경설정을 하는 운영체제의 코드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디스패처를 통한 컨텍스트 스위칭&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;현재 수행 중이던 프로세스의 문맥을 그 프로세스의 PCB에 저장&lt;/li&gt;
&lt;li&gt;새롭게 선택된 프로세스의 문맥을 PCB로부터 복원 후 그 프로세스에게 넘기는 과정을 수행&lt;/li&gt;
&lt;li&gt;컨텍스트 스위칭 이후 시스템의 상태를 사용자모드로 전환&lt;/li&gt;
&lt;li&gt;사용자 프로그램은 복원된 문맥 중 프로그램 카운터로부터 현재 수행할 주소를 찾을 수 있음&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디스패치 지연시간(Dispatch Latency)&lt;/b&gt;: 하나의 프로세스를 정지시키고 다른 프로세스에게 CPU를 전달하기까지의 시간, 대부분 문맥교환 오버헤드에 해당&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 스케줄링의 성능 평가&lt;/h2&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: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;CPU 이용률&lt;/b&gt;: 전체 시간 중에서 CPU가 일을 한 시간의 비율&lt;/li&gt;
&lt;li&gt;&lt;b&gt;처리량&lt;/b&gt;: 주어진 시간 동안 준비 큐에서 기다리고 있는 프로세스 중 끝마친 프로세스 개수 &lt;br /&gt;(= &lt;b&gt;CPU 버스트를 완료한 프로세스의 개수&lt;/b&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;사용자 관점 지표
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;소요시간&lt;/b&gt;: (&lt;b&gt;CPU 버스트가 끝난 시점 - CPU를 요청한 시점&lt;/b&gt;)의 시간 &lt;br /&gt;( = &lt;b&gt;준비 큐 대기 시간 + CPU를 사용한 시간&lt;/b&gt;)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;대기시간&lt;/b&gt;: CPU 버스트 기간 중 프로세스가 준비 큐에서 CPU를 얻기 위해 기다린 시간의 합&lt;/li&gt;
&lt;li&gt;&lt;b&gt;응답시간&lt;/b&gt;: &lt;b&gt;프로세스가 준비 큐에 들어온 후&lt;/b&gt; 첫번째 CPU를 획득하기까지의 기다린 시간&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 여기서 기준은 프로그램 종료와는 관계가 없음.&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 스케줄링 알고리즘&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.1. 선입선출 스케줄링&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;준비 큐에 도착한 시간 순서대로 CPU를 할당하는 방식&lt;/li&gt;
&lt;li&gt;프로세스가 자발적으로 CPU를 반납할 때까지 빼앗지 않음&lt;/li&gt;
&lt;li&gt;CPU 버스트가 긴 프로세스가 먼저 도착할 경우 평균 대기시간이 길어짐 &lt;b&gt;(콘보이 현상)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.2. 최단작업 우선 스케줄링(SJF)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU 버스트가 가장 짧은 프로세스에게 제일 먼저 CPU를 할당하는 방식&lt;/li&gt;
&lt;li&gt;평균 대기시간을 가장 짧게 하는 최적 알고리즘&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비선점형 방식&lt;/b&gt;과 &lt;b&gt;선점형 방식&lt;/b&gt;으로 나뉠 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;선점형의 경우&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;실행 중인 P의 남은 CPU 버스트 시간 &amp;gt; 나중에 도착한 P의 CPU 버스트 시간&lt;/b&gt; 이면 CPU를 빼앗김&lt;/li&gt;
&lt;li&gt;이러한 SJF 선점형 구현 방식을 SRTF(Shortest Remaining Time First)라 함.&lt;/li&gt;
&lt;li&gt;준비큐 도착시간이 불규칙할 경우, 평균 대기시간을 최소화할 수 있는 알고리즘이 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비선점형의 경우&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;CPU를 점유하고 있는 프로세스가 CPU 버스트를 모두 수행할 때까지 기다려줌.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기아 현상(starvation)&lt;/b&gt;: &lt;b&gt;CPU 버스트가 긴 프로세스&lt;/b&gt;는 준비 큐에서 &lt;b&gt;무한정 기다리는 문제&lt;/b&gt;가 발생함&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.3. 우선순위 스케줄링&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;준비 큐에서 기다리는 프로세스들 중 우선순위가 가장 높은 프로세스에게 제일 먼저 CPU를 할당&lt;/li&gt;
&lt;li&gt;우선순위 값을 통해 결정하며 우선순위 값이 작을수록 우선순위가 높음&lt;/li&gt;
&lt;li&gt;우선순위 스케줄링도 &lt;b&gt;선점형 방식&lt;/b&gt;과 &lt;b&gt;비선점형 방식&lt;/b&gt;으로 각각 구현할 수 있음&lt;/li&gt;
&lt;li&gt;우선순위가 낮은 프로세스는 기아 현상을 겪을 수 있음&lt;/li&gt;
&lt;li&gt;이를 해결하기 위해 기다리는 시간이 길어지면 우선순위를 높이는 &lt;b&gt;노화(aging) 기법&lt;/b&gt;을 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.4. 라운드 로빈 스케줄링&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 프로세스가 CPU를 연속적으로 사용할 수 있는 시간이 특정 시간으로 제한하는 방식&lt;/li&gt;
&lt;li&gt;한 번에 연속적으로 사용할 수 있는 최대 시간을 &lt;b&gt;할당시간&lt;/b&gt;이라 하고 일반적으로 수십 밀리초 정도로 설정.&lt;/li&gt;
&lt;li&gt;여러 종류의 이질적인 프로세스가 같이 실행되는 환경에서 효과적&lt;/li&gt;
&lt;li&gt;타이머 인터럽트를 사용하여 CPU를 회수함.&lt;/li&gt;
&lt;li&gt;가장 공정한 스케줄링 방식이라 할 수 있고 대기시간도 CPU 버스트 시간에 비례해 증가함&lt;/li&gt;
&lt;li&gt;할당시간을 너무 짧게 설정할 경우 문맥교환의 오버헤드가 증가해 시스템 성능이 저하됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.5. 멀티레벨 큐&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;/li&gt;
&lt;li&gt;프로세스의 성격에 맞는 스케줄링을 적용하기 위해 준비 큐를 별도로 둠&lt;/li&gt;
&lt;li&gt;대화형 작업을 담는 전위 큐(foreground queue)와 계산 위주의 작업을 담는 후위 큐(background queue)로 분할하여 운영
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;전위 큐 &amp;rarr; 응답시간을 짧게 하기 위해 &lt;b&gt;라운드 로빈 스케줄링&lt;/b&gt; 활용&lt;/li&gt;
&lt;li&gt;후위 큐 &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&amp;rarr;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;응답시간이 큰 의미가 없기 때문에&lt;b&gt; FCFS 스케줄링 기법&lt;/b&gt;을 사용하여 문법교환 오버헤드를 줄임&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;어느 큐에 먼저 CPU를 할당할 것인지에 대한 스케줄링이 필요함
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&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;/li&gt;
&lt;li&gt;전위 큐에 우선순위를 높게 잡고 후위 큐를 낮게 잡음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;li&gt;큐에 CPU 시간을 적절한 비율로 할당&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.6. 멀티레벨 피드백 큐&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;/li&gt;
&lt;li&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;li&gt;프로세스를 승격/강등시키는 기준&lt;/li&gt;
&lt;li&gt;프로세스가 도착했을 때 들어갈 큐를 결정하는 기준 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ex) 예시&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;758&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kRATQ/btsKk5wtaMj/s6MQ5HFyp3KQ1Buj8C0DDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kRATQ/btsKk5wtaMj/s6MQ5HFyp3KQ1Buj8C0DDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kRATQ/btsKk5wtaMj/s6MQ5HFyp3KQ1Buj8C0DDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkRATQ%2FbtsKk5wtaMj%2Fs6MQ5HFyp3KQ1Buj8C0DDK%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;425&quot; height=&quot;289&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;758&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상위에 있는 큐일수록 우선순위가 높음&amp;nbsp;&lt;/li&gt;
&lt;li&gt;CPU 사용시간이 짧은 대화형 프로세스들은 우선순위가 가장 높은 큐에서 서비스를 받고 완료&lt;/li&gt;
&lt;li&gt;CPU 버스트 시간이 긴 프로세스는 할당시간이 10인 하위 큐로 내려가서 대기&lt;/li&gt;
&lt;li&gt;그래도 다 안되면 계산 작업으로 간주되어 최하위 큐로 이동하고 FCFS 스케줄링을 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.7. 다중처리기 스케줄링&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU가 여러 개인 시스템을 다중처리기 시스템이라 부름&lt;/li&gt;
&lt;li&gt;CPU가 여러 개인 경우, 프로세스를 준비 큐에 한 줄로 세워서 각 CPU가 알아서 다음 프로세스를 꺼내도록 할 수 있음&lt;/li&gt;
&lt;li&gt;특정 CPU에서만 수행되야 하는 프로세스도 있기 때문에 이 경우, 각 CPU 별로 줄 세우기를 할 수 있음&lt;/li&gt;
&lt;li&gt;일부 CPU에 작업이 편중되는 현상을 막기 위해 부하균형 메커니즘이 필요함.&lt;/li&gt;
&lt;li&gt;대칭형 다중처리: 각 CPU가 알아서 스케줄링을 결정하는 방식&lt;/li&gt;
&lt;li&gt;비대칭형 다중처리: 하나의 CPU가 다른 모든 CPU의 스케줄링 및 데이터 접근을 책임지는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.8. 실시간 스케줄링&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;데드라인이 얼마 남지 않은 요청을 먼저 처리하는 EDF(Earlist Deadline First) 스케줄링을 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 스케줄링 알고리즘의 평가&lt;/h2&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: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;큐잉모델&lt;/b&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;확률분포를 통해 프로세스들의 도착률과 CPU의 처리율을 입력값으로 삼음&lt;/li&gt;
&lt;li&gt;복잡한 수학적 계산을 통해 CPU 처리량, 프로세스 평균 대기시간 등을 계산&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시뮬레이션&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가상으로 CPU 스케줄링 프로그램을 작성한 후 프로그램 CPU 요청을 입력하여 결과를 보는 방식&lt;/li&gt;
&lt;li&gt;입력값은 실제 CPU 요청 내역(트레이스, trace)을 추출해 쓰거나 가상으로 생성할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구현 및 실측&lt;/b&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;운영체제 커널의 소스 코드 중 CPU 스케줄링을 수행하는 코드를 수정하여 커널을 컴파일 한 후 시스템 설치 과정을 수행함&lt;/li&gt;
&lt;li&gt;이후 동일한 프로그램을 원래 커널과 CPU 스케줄러를 수정한 커널에서 수행하고 실행시간을 측정하여 알고리즘 성능을 평가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;운영체제와 정보기술의 원리&lt;/span&gt; (&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;반효경&lt;span&gt; &lt;/span&gt;&lt;/span&gt;저, 2020.5)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/운영체제</category>
      <category>computer science</category>
      <category>CPU스케줄링</category>
      <category>운영체제</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/28</guid>
      <comments>https://onyodev.tistory.com/28#entry28comment</comments>
      <pubDate>Sun, 27 Oct 2024 22:03:35 +0900</pubDate>
    </item>
    <item>
      <title>로드 밸런서/방화벽: 4계층 장비(세션 장비)</title>
      <link>https://onyodev.tistory.com/27</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 고재성, 이상훈 저 - &quot;IT 엔지니어를 위한 네트워크 입문&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;0. 4계층 장비의 등장&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기존 네트워크 장비는 2계층이나 3계층에서 동작하는 장비를 지칭&lt;/li&gt;
&lt;li&gt;IP 부족으로 NAT 기술이 등장하고 보안용 방화벽, 프록시와 같은 장비들이 등장하여 4계층에서도 네트워크 장비가 많아짐&lt;/li&gt;
&lt;li&gt;4계층 장비는 통신의 방향성이나 순서와 같은 통신 전반의 관리가 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 4계층 장비의 특징&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TCP와 같은 4계층 헤더에 있는 정보를 이해하고 동작함&lt;/li&gt;
&lt;li&gt;4계층 이상의 장비는 세션 테이블과 세션 정보를 이해하는 것이 중요&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;세션 테이블&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;Symmetric(대칭) 경로 요구&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Inbound와 Outbound 경로가 일치해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;정보 변경(로드 밸런서)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IP 주소가 변경되며 확장된 L7 로드밸런서(ADC)는 애플리케이션 프로토콜 정보도 변경됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 로드 밸런서&lt;/h2&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;IP 주소나 4계층 정보, 애플리케이션 정보를 확인 및 수정하는 기능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스케일 아웃&lt;/b&gt;: 작은 장비 여러 대를 묶어 사용하는 방식이 가격을 낮출 수 있고 로드 밸런서가 이에 해당&lt;/li&gt;
&lt;li&gt;서비스에 사용되는 대표 IP 주소를 서비스 IP 주소로 가짐&lt;/li&gt;
&lt;li&gt;그리고 그 밑에 시스템이 늘어나면 로드 밸런서가 실제 IP로 변경해 요청을 보냄&lt;/li&gt;
&lt;li&gt;&lt;b&gt;L4 로드 밸런싱&lt;/b&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;b&gt;TCP, UDP 정보(특히 포트 넘버)를 기반&lt;/b&gt;으로 로드 밸런싱 수행&lt;/li&gt;
&lt;li&gt;4계층 정보로만 분산처리 하는 경우를 말함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;L7 로드 밸런싱&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;HTTP, SMTP, FTP와 같은 애플리케이션 프로토콜 정보를 기반&lt;/b&gt;으로 로드 밸런싱 수행&lt;/li&gt;
&lt;li&gt;HTTP 헤더 정보나 URI와 같은 정보를 기반으로 프로토콜을 이해한 후 부하를 분산&lt;/li&gt;
&lt;li&gt;일반적으로&lt;b&gt; ADC(Application Delivery Controller)&lt;/b&gt; 장비라 부르고 프록시 역할을 수행&lt;/li&gt;
&lt;li&gt;스퀴드(Squid)나 Nginx에서 수행하는 리버스 프록시와 유사한 기능을 지님&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;데이터 센터에서는 L4, L7 모두 지원하고 클라우드에서는 L4와 L7을 지원하는 컴포넌트를 계층별로 구분&lt;br /&gt;ex) AWS NLB - L4, ALB - L7&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. L4 스위치&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;4계층에서 동작하면서 로드 밸런서 기능이 있는 스위치&lt;/li&gt;
&lt;li&gt;외형은 스위치처럼 여러개의 포트를 지님&lt;/li&gt;
&lt;li&gt;스위치형 로드 밸런서가 가장 대중적이며 서버형, 스프트웨어형도 존재&lt;/li&gt;
&lt;li&gt;부하 분산, 성능 최적화, 리다이렉션 기능 제공&lt;/li&gt;
&lt;li&gt;L4 스위치가 동작하기 위해선 &lt;b&gt;가상 서버, 가상 IP, 리얼 서버, 리얼 IP&lt;/b&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;가상 IP: 사용자가 접근해야 하는 서비스 IP 주소&lt;/li&gt;
&lt;li&gt;리얼 서버: 실제 서비스를 수행하는 서버&lt;/li&gt;
&lt;li&gt;리얼 IP: 실제 서버의 IP&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;사용자는 L4 스위치의 가상 IP를 목적지로 서비스를 요청&lt;/li&gt;
&lt;li&gt;L4 스위치가 목적지로 설정된 가상 IP를 리얼 IP로 다시 변경해서 보내줌&lt;/li&gt;
&lt;li&gt;이 과정에서 부하를 어떤 방식으로 분산할지 결정할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. ADC&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;다양한 부하 분산, 정보 수정, 정보 필터링&lt;/b&gt;이 가능&lt;/li&gt;
&lt;li&gt;ADC는 이런 상세한 동작을 프록시로 동작&lt;/li&gt;
&lt;li&gt;대부분의 ADC는 L4 스위치의 기능을 포함함.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;4계층에서 애플리케이션 계층까지의 로드 밸런싱&lt;/b&gt; 기능 제공&lt;/li&gt;
&lt;li&gt;페일오버(Failover, 장애극복), 리다이렉션(Redirection) 기능도 함께 수행&lt;/li&gt;
&lt;li&gt;애플리케이션 프로토콜을 이해하고 최적화하는 기능 수행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;캐싱, 압축, 콘텐츠 변환 및 재작성, 인코딩 변환&lt;/b&gt; 등이 가능&lt;/li&gt;
&lt;li&gt;애플리케이션 프로토콜 최적화 기능&lt;/li&gt;
&lt;li&gt;플러그인 형태로 보안 강화 제공해 WAF(Web Application Firewall) 기능이나 HTML, XML 검증 및 변환 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3. L4 스위치 vs ADC&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;L4 스위치&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;TCP 계층에서의 최적화와 보안 기능도 제공함&lt;/li&gt;
&lt;li&gt;TCP 레벨의 간단한 DoS 공격을 방어하거나 서버 부하를 줄이기 위한 TCP 세션 재사용 기능 제공&lt;br /&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;129&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Zy44T/btsKinCidFk/f4EYox6aRYwImk7nrdtWL0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Zy44T/btsKinCidFk/f4EYox6aRYwImk7nrdtWL0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Zy44T/btsKinCidFk/f4EYox6aRYwImk7nrdtWL0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZy44T%2FbtsKinCidFk%2Ff4EYox6aRYwImk7nrdtWL0%2Fimg.jpg&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;600&quot; height=&quot;129&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;129&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ADC&lt;/b&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;ADC에서 콘텐츠 압축 기능을 수행하여 웹 서버의 부하를 줄여줌&lt;/li&gt;
&lt;li&gt;하드웨어 가속이나 소프트웨어 최적화를 통해 부하가 걸리는 작업을 최적화&lt;/li&gt;
&lt;li&gt;ADC에서는 SSL의 엔드 포인트로 동작해 클라이언트 - ADC 구간을 SSL로 처리해주고 ADC-웹 서버 사이를 일반 HTTP를 이용해 통신&lt;/li&gt;
&lt;li&gt;웹 서버 여러 대의 SSL 통신을 하나의 ADC에서 수용하기 위해 전용 SSL 가속 카드를 내장&lt;br /&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;96&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/muItI/btsKh77tl4N/AkMQi1R7tEeUNcG3kjMSxk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/muItI/btsKh77tl4N/AkMQi1R7tEeUNcG3kjMSxk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/muItI/btsKh77tl4N/AkMQi1R7tEeUNcG3kjMSxk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmuItI%2FbtsKh77tl4N%2FAkMQi1R7tEeUNcG3kjMSxk%2Fimg.jpg&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;600&quot; height=&quot;96&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;96&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&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;2.4. 시스템 확장 방법: 스케일 업과 스케일 아웃&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;301&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p9Zk3/btsKhONORhr/SKU6BvjZ7zmJyuX0d5ZH7K/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p9Zk3/btsKhONORhr/SKU6BvjZ7zmJyuX0d5ZH7K/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p9Zk3/btsKhONORhr/SKU6BvjZ7zmJyuX0d5ZH7K/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp9Zk3%2FbtsKhONORhr%2FSKU6BvjZ7zmJyuX0d5ZH7K%2Fimg.jpg&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;433&quot; height=&quot;301&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;301&quot;/&gt;&lt;/span&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;시스템 확장 방법
&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;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;기존 시스템에 CPU, 메모리, 디스크와 같은 내부 컴포넌트 용량을 키우거나 더 큰 용량의 시스템을 구매해 서비스를 옮기는 방법&lt;/li&gt;
&lt;li&gt;스케일 업은 확장을 미리 고려해 시스템을 구축하면 초기 비용이 커지는 문제가 있음&lt;/li&gt;
&lt;li&gt;반대로 서비스에 맞춰서 시스템을 구매하면 확장이 필요할 때 새롭게 시스템을 구매하면서 낭비되는 문제가 있음&lt;/li&gt;
&lt;li&gt;그리고 필요한 용량을 늘리면 비용이 기하급수적으로 증가하는 문제가 있음&lt;/li&gt;
&lt;li&gt;ex) 2GB CPU: 5만원, 4GB CPU: 20만원(!)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스케일 아웃&lt;/b&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;/li&gt;
&lt;/ul&gt;
&lt;/li&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;스케일 다운&lt;/b&gt;: 기존의 시스템보다 작은 용량의 시스템으로 서비스를 옮기는 방법&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스케일 인&lt;/b&gt;: 여러 개의 서비스를 합쳐 하나의 시스템으로 운영하는 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 방화벽&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;237&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjGcww/btsKgrNnJvW/gvNu3hK0f6fC9wKFV3nQNK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjGcww/btsKgrNnJvW/gvNu3hK0f6fC9wKFV3nQNK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjGcww/btsKgrNnJvW/gvNu3hK0f6fC9wKFV3nQNK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcjGcww%2FbtsKgrNnJvW%2FgvNu3hK0f6fC9wKFV3nQNK%2Fimg.jpg&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;501&quot; height=&quot;237&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;237&quot;/&gt;&lt;/span&gt;&lt;/figure&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;일반적으로 네트워크 3,4계층에서 동작하고 세션 인지, 관리하는 SPI 엔진을 기반으로 동작하는 장비를 일컬음&lt;/li&gt;
&lt;li&gt;방화벽은 NAT(Network Address Translation) 동작 방식과 유사하게 세션 정보를 장비 내부에 저장
&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;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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;세션 테이블을 이용해 패킷의 인과 관계를 파악할 수 있어 정책을 간단히 유지할 수 있음&lt;/li&gt;
&lt;li&gt;인터넷 방화벽의 경우 기본정책은 외부로 나가는 모든 패킷을 허용하고 내부로 들어오는 모든 패킷을 차단함&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 4계층 장비를 통과할 때의 유의점(세션 관리)&lt;/h2&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;li&gt;보안을 강화하기 위해 패킷을 포워드(forward)하거나 드롭(drop)할 수 있음&lt;/li&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;4.1. 세션 테이블 유지, 세션 정보 동기화&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;/li&gt;
&lt;li&gt;메모리 사용률을 유지하고 악의적인 공격에 대비하기 위해서 타임아웃값을 줄이기도 함.&lt;/li&gt;
&lt;li&gt;세션 테이블에 세션이 없는 상황에서 애플리케이션이 통신을 시도하려 하면&lt;br /&gt;&amp;rarr; 비정상 통신으로 판단해 패킷을 차단해버리기 때문에 세션 타임아웃값을 잘 조절해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;265&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sdCqt/btsKh1lXaRX/3XdE4OIQGQGfwNk2iKjW9k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sdCqt/btsKh1lXaRX/3XdE4OIQGQGfwNk2iKjW9k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sdCqt/btsKh1lXaRX/3XdE4OIQGQGfwNk2iKjW9k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsdCqt%2FbtsKh1lXaRX%2F3XdE4OIQGQGfwNk2iKjW9k%2Fimg.jpg&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;555&quot; height=&quot;245&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;265&quot;/&gt;&lt;/span&gt;&lt;/figure&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;3방향 핸드셰이크를 통해 정상적으로 세션 설정&lt;/li&gt;
&lt;li&gt;(2), (3) 세션 테이블을 참조해 방화벽에서 패킷 통과&lt;/li&gt;
&lt;li&gt;일정 시간 동안 통신 없음&lt;/li&gt;
&lt;li&gt;(4) 세션 타임으로 세션 테이블 만료&lt;/li&gt;
&lt;li&gt;세션 만료 후 애플리케이션 통신 시작&lt;/li&gt;
&lt;li&gt;(5) 세션이 만료되어 방화벽에서 패킷 드롭&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;이런 문제를 해결하기 위한 세션 장비와 애플리케이션에서 각각 적용할 수 있는 설정이 존재&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.1.1. 세션 장비 운영자 입장&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;세션 만료 시간 증가&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;이 경우, &lt;b&gt;애플리케이션의 세션 유지 시간 &amp;lt; 방화벽 세션 유지 시간&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;대부분의 세션 장비는 포트 번호나 IP 주소마다 별도의 세션 만료 시간을 정할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;세션 시간은 유지, 중간 패킷을 수용할 수 있도록 방화벽 설정
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;방화벽 옵션을 조정해 세션 테이블에 정보가 없는 ACK 패킷이 와도 세션을 새로 만들어 통과시키는 옵션을 사용&lt;/li&gt;
&lt;li&gt;전체적인 보안에 좋지 않기 때문에 비추&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;세션 장비에서 세션 타임아웃 시 양 단말에 세션 종료 통보
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;양 종단 장비의 세션 정보 &amp;ne; 세션 장비의 세션 정보&lt;/b&gt;일 때 발생하는 문제를 해결하기 위한 기능&lt;/li&gt;
&lt;li&gt;세션 타임 아웃 시 세션 정보를 삭제하지 않고 세션 정보 만료를 통보&lt;/li&gt;
&lt;li&gt;TCP의 RST 플래그를 1로 세팅해 양 종단 장비에 전송&lt;/li&gt;
&lt;li&gt;양 종단 장비에서 세션이 비정상 종료 된걸 판단하고 해당 세션을 끊음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동작 과정&lt;/b&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;/li&gt;
&lt;li&gt;(1) 세션 타임아웃값이 넘어 세션 만료&lt;/li&gt;
&lt;li&gt;(2) 방화벽에서 양 종단 장비에 RST 패킷 전송
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;A 장비에는 출발지 B, 도착지 A인 RST 패킷 전송&lt;/li&gt;
&lt;li&gt;B 장비에는 출발지 A, 도착지 B인 RST 패킷 전송&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;(3) RST 패킷을 받은 양 종단 장비는 해당 프로세스 종료&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.1.2. 개발자 입장&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&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;b&gt;더미 패킷(Dummy Packet)&lt;/b&gt;을 보냄&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.2. 비대칭 경로 문제&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;568&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6OCAk/btsKhwNu0af/Lvb6pOKkPqid2md1jkHkLK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6OCAk/btsKhwNu0af/Lvb6pOKkPqid2md1jkHkLK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6OCAk/btsKhwNu0af/Lvb6pOKkPqid2md1jkHkLK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6OCAk%2FbtsKhwNu0af%2FLvb6pOKkPqid2md1jkHkLK%2Fimg.jpg&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;310&quot; height=&quot;293&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;568&quot;/&gt;&lt;/span&gt;&lt;/figure&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;이 때 패킷을 지나가는 경로가 2개 이상이므로 인바운드 패킷과 아웃바운드 패킷의 경로가 같을 수 있음&lt;/li&gt;
&lt;li&gt;이 때 통과하는 장비가 &lt;b&gt;인바운드 패킷 = 아웃바운드 패킷&lt;/b&gt;인 경우 대칭 경로, 아닌 경우 비대칭 경로이다.&lt;/li&gt;
&lt;li&gt;세션 장비는 세션 테이블을 만들어 관리해야 하므로 패킷이 들어오고 나갈 때 동일한 장비를 통과해야 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비대칭 경로를 방화벽에서 처리하는 방법&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;세션 테이블 동기화&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;세션 동기화 시간 &amp;gt; 패킷 응답&lt;/b&gt;인 경우 정상 동작하지 않을 수 있음&lt;/li&gt;
&lt;li&gt;이 기능은 응답시간이 비교적 긴 인터넷 게이트웨이 방화벽에 사용&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세션 장비에서 다양한 방법으로 보정&amp;nbsp;&lt;br /&gt;&lt;/b&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JW8Vn/btsKgCgUv8T/p71RITycCmWjicPpj92rcK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JW8Vn/btsKgCgUv8T/p71RITycCmWjicPpj92rcK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JW8Vn/btsKgCgUv8T/p71RITycCmWjicPpj92rcK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJW8Vn%2FbtsKgCgUv8T%2Fp71RITycCmWjicPpj92rcK%2Fimg.jpg&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;410&quot; height=&quot;534&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/li&gt;
&lt;li&gt;강제로 다른 방화벽으로 패킷을 보내기 위해 방화벽 간 통신용 링크가 필요&lt;/li&gt;
&lt;li&gt;MAC 주소를 변경하는 &lt;b&gt;MAC 리라이팅(Rewriting)&lt;/b&gt;이나 기존 패킷에 MAC 주소를 한 번 더인캡슐레이션하는 &lt;b&gt;터널링(Tunneling) 기법&lt;/b&gt;으로 경로를 보정&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.3. 하나의 통신에서 두 개 이상의 세션이 사용될 때의 고려사항&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특별한 목적으로 2개 이상의 세션을 만드는 경우가 있음&lt;/li&gt;
&lt;li&gt;세션 장비도 세션 2개가 하나의 통신을 사용한다는 것을 알게 해야 함&lt;/li&gt;
&lt;li&gt;프로토콜은 &lt;b&gt;데이터 프로토콜&lt;/b&gt;과 &lt;b&gt;컨트롤 프로토콜&lt;/b&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;/li&gt;
&lt;li&gt;현대에는 하나의 프로토콜에서 헤더나 메시지로만 구분해서 해결하지만 일부는 두 개의 프로토콜을 분리해서 사용하기도 함 &lt;b&gt;ex) FTP&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4.3.1. FTP의 구동 방식&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;377&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PikXp/btsKitvF9MP/4LzDb2JlDSHtMsf8gNMdW1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PikXp/btsKitvF9MP/4LzDb2JlDSHtMsf8gNMdW1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PikXp/btsKitvF9MP/4LzDb2JlDSHtMsf8gNMdW1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPikXp%2FbtsKitvF9MP%2F4LzDb2JlDSHtMsf8gNMdW1%2Fimg.jpg&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;600&quot; height=&quot;377&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;377&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본적인 구동 방식은 Active 모드이고 &lt;b&gt;컨트롤 프로토콜과 데이터 프로토콜이 반대 방향으로 동작&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Active 모드
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;컨트롤 프로토콜: 명령어 전달, &lt;b&gt;클라이언트 &amp;rarr; 서버&lt;/b&gt;로 통신 시작&lt;/li&gt;
&lt;li&gt;데이터 프로토콜: 데이터 전달 , &lt;b&gt;서버 &amp;rarr; 클라이언트&lt;/b&gt;로 데이터 푸시&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HqYZW/btsKgPmMkNE/12YSM3GkJUSMK1XjWXvlRk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HqYZW/btsKgPmMkNE/12YSM3GkJUSMK1XjWXvlRk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HqYZW/btsKgPmMkNE/12YSM3GkJUSMK1XjWXvlRk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHqYZW%2FbtsKgPmMkNE%2F12YSM3GkJUSMK1XjWXvlRk%2Fimg.jpg&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;489&quot; height=&quot;375&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;460&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;br /&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;클라이언트가 FTP 서버에 접속, 클라이언트는 1023번 이상의 TCP 포트를 사용, 서버는 21번 포트 사용&lt;/li&gt;
&lt;li&gt;① 클라이언트가 서버에 데이터를 1025번 포트를 사용해 수신하겠다고 알림&lt;/li&gt;
&lt;li&gt;②서버는 클라이언트에게 1025번 포트를 사용해 송신하겠다고 응답&lt;/li&gt;
&lt;li&gt;③서버에서 데이터를 보냄, 클라이언트에서 응답하고 데이터 수신&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;NAT 환경인 경우, FTP가 동작하는 프로토콜을 모두 이해할 수 있는 별도의 기능을 동작시키는 &lt;b&gt;ALG(Application Layer Gateway)&lt;/b&gt;를 실행함&lt;/li&gt;
&lt;li&gt;ALG가 동작하면 반대 방향으로 시작하는 데이터 세션을 인지해 방화벽과 NAT 모두 동작시킴&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Passive 모드
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;Active 모드를 보완한 모드&lt;/li&gt;
&lt;li&gt;컨트롤 프로토콜, 데이터 프로토콜 모두 &lt;b&gt;클라이언트 &amp;rarr; 서버&lt;/b&gt;로 데이터를 요청해 동작&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvBC59/btsKf6vW1RQ/KKh09rrJ6ekJk0RjUuFZs1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvBC59/btsKf6vW1RQ/KKh09rrJ6ekJk0RjUuFZs1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvBC59/btsKf6vW1RQ/KKh09rrJ6ekJk0RjUuFZs1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvBC59%2FbtsKf6vW1RQ%2FKKh09rrJ6ekJk0RjUuFZs1%2Fimg.jpg&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;531&quot; height=&quot;423&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;478&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;br /&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;클라이언트가 서버에 접속. 클라언트는 1023번 이상의 TCP 포트를 사용, 서버는 TCP 21번 포트를 사용&lt;/li&gt;
&lt;li&gt;① 클라이언트가 Passive 모드를 사용하겠다고 알림&lt;/li&gt;
&lt;li&gt;② 서버는 클라이언트에 데이터 수신에 사용할 포트를 알림. 2024번 포트를 사용해 수신하겠다고 응답&lt;/li&gt;
&lt;li&gt;③ 클라이언트에서 서버에 데이터를 요청. ② 과정에서 서버에서 알려준 2024번 포트에 요청.&lt;/li&gt;
&lt;li&gt;데이터 전송&lt;/li&gt;
&lt;/ol&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;서버 쪽에 방화벽이 있는 경우, 데이터 다운로드를 위한 추가 포트를 FTP 서버에서 열어야 함&lt;/li&gt;
&lt;/ul&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;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IT 엔지니어를 위한 네트워크 입문 (고재성, 이상훈 저, 2020.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/네트워크</category>
      <category>computer science</category>
      <category>네트워크</category>
      <category>로드밸런서</category>
      <category>방화벽</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/27</guid>
      <comments>https://onyodev.tistory.com/27#entry27comment</comments>
      <pubDate>Thu, 24 Oct 2024 12:02:53 +0900</pubDate>
    </item>
    <item>
      <title>라우터/L3 스위치: 3계층 장비</title>
      <link>https://onyodev.tistory.com/26</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글은 고재성, 이상훈 저 - &quot;IT 엔지니어를 위한 네트워크 입문&quot;를 공부하고 정리하여 작성하였습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 라우터의 동작 방식과 역할&lt;/h2&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;패킷이 라우터로 들어오면 도착지 IP 주소와 라우팅 테이블을 비교해 최선의 경로로 패킷 전달&lt;/li&gt;
&lt;li&gt;패킷 포워딩 과정에서 기존 2계층 헤더 정보를 제거한 후 새로운 2계층 헤더를 제작&lt;/li&gt;
&lt;li&gt;이 동작 방식을 &lt;b&gt;경로 지정&lt;/b&gt;, &lt;b&gt;브로드캐스트 컨트롤&lt;/b&gt;, &lt;b&gt;프로토콜 변환&lt;/b&gt;이라 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1. 경로 지정&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;경로 정보를 모아 라우팅 테이블을 만들고 패킷의 도착지 IP주소를 확인해 경로를 지정하여 패킷을 포워딩함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;경로 정보를 얻는 역할&lt;/b&gt;과 &lt;b&gt;경로 정보를 확인하고 패킷을 포워딩하는 역할&lt;/b&gt;을 수행&lt;/li&gt;
&lt;li&gt;경로 정보를 얻는 방법
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;IP 주소를 입력하면서 얻는 방법&lt;/li&gt;
&lt;li&gt;관리자가 직접 입력하는 방법&lt;/li&gt;
&lt;li&gt;라우터끼리 서로 경로 정보를 자동으로 교환하는 방법 등&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2. 브로트캐스트 컨트롤&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;/li&gt;
&lt;li&gt;이 기능을 &lt;b&gt;&amp;ldquo;브로드캐스트 컨트롤/멀티캐스트 컨트롤&amp;rdquo;&lt;/b&gt;이라 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3. 프로토콜 변환&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;패킷이 들어오면 2계층까지의 헤더 정보를 벗겨내고 3계층 주소를 확인&lt;/li&gt;
&lt;li&gt;3계층 주소를 확인한 후 2계층 헤더 정보를 새로 만들어 외부로 내보냄&lt;/li&gt;
&lt;li&gt;저속 전용회선
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WAN 구간: PPP 프로토콜 사용&lt;/li&gt;
&lt;li&gt;LAN 구간: 이더넷 프로토콜 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 경로 지정 - 라우팅/스위칭&lt;/h2&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;/li&gt;
&lt;li&gt;정리된 경로 정보를 기반으로 패킷을 포워딩하는 역할&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;라우터는 서브넷 단위로 라우팅 정보를 습득하고 라우팅 정보를 최적화하기 위해 &lt;b&gt;서머리(summary) 작업&lt;/b&gt;을 통해 여러 개의 서브넷 정보를 뭉쳐 전달&lt;/li&gt;
&lt;li&gt;목적지 주소와 라우팅 테이블 정보가 정확히 일치하지 않더라도 목적지에 가장 근접한 정보를 찾아 패킷을 포워딩해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. 라우팅 동작과 라우팅 테이블&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;라우팅 동작&lt;/b&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;홉-바이-홉(Hop-by-Hop) 라우팅&lt;/b&gt;이라 부르고 인접한 라우터를 &lt;b&gt;넥스트 홉(Next Hop)&lt;/b&gt;이라 부름&lt;/li&gt;
&lt;li&gt;라우터는 패킷이 목적지로 가는 전체 경로를 파악하지 않고 최적의 넥스트 홉을 선택해 보내줌&lt;/li&gt;
&lt;li&gt;&lt;b&gt;넥스트 홉을 지정하는 방법&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;다음 라우터의 IP를 지정하는 방법&lt;/li&gt;
&lt;li&gt;라우터의 나가는 인터페이스를 지정하는 방법&lt;/li&gt;
&lt;li&gt;라우터의 나가는 인터페이스와 다음 라우터의 IP를 동시에 지정하는 방법&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;일반적으로는 라우터의 인터페이스 IP 주소를 지정하는 방법을 사용&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;상대방의 넥스트 홉 MAC 주소 정보를 알 때만 라우터의 나가는 인터페이스를 지정하는 방법을 쓸 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WAN구간의 PPP나 HLDC와 같은 프로토콜에서 MAC주소를 알 필요가 없는 경우&lt;/li&gt;
&lt;li&gt;상대방 라우터에서 프록시 ARP가 동작해 상대방 MAC 주소를 아는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;라우팅 테이블&lt;/b&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;li&gt;라우팅 테이블을 만들 때는 목적지 정보만 수집하고 목적지 주소를 확인해 패킷을 포워딩&lt;/li&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;/li&gt;
&lt;li&gt;넥스트 홉 IP 주소, 나가는 인터페이스 (선택 가능)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;소스 라우팅(Source Routing)&lt;/b&gt; 혹은 &lt;b&gt;폴리시 라우팅(Policy Routing)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;라우터에서 패킷의 출발지 주소를 활용한 PBR(Policy-Based Routing) 기능을 사용하기도 함&lt;/li&gt;
&lt;li&gt;이때는 라우팅 정책과 관련된 별도의 설정이 필요&lt;/li&gt;
&lt;li&gt;관리가 어렵고 문제 발생 시 해결이 어려워 특별한 목적에서만 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소스 라우팅과 PBR, 정책 라우팅&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PBR은 출발지 IP뿐만 아니라 도착지IP, 포트 번호와 같은 다양한 조건을 합쳐 사용할 수 있음&lt;/li&gt;
&lt;li&gt;PBR은 출발지 주소를 이용해 경로를 지정한다는 이유로 소스 라우팅이라 부르기도 하는데&lt;/li&gt;
&lt;li&gt;소스 라우팅의 원래 의미는 출발지에서 경로를 지정하는 것으로 의미가 약간 다름&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;루프가 없는 3계층: TTL (Time To Live)&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;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IP 헤더에는 TTL이라는 필드가 존재하여 살아 있는 시간이 제한됨&lt;/li&gt;
&lt;li&gt;TTL 값의 단위는 홉 단위이며 하나의 홉을 지날 때마다 1씩 줄어듦&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. 라우팅(라우터가 경로 정보를 얻는 방법)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;크게 3가지로 구분함
&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;/li&gt;
&lt;li&gt;다이나믹 라우팅&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;다이렉트 커넥티드&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용된 IP 주소와 서브넷 마스크로 속한 네트워크 주소 정보를 알 수 있음&lt;/li&gt;
&lt;li&gt;이 정보로 해당 네트워크에 대한 라우팅 테이블을 자동으로 만듦&lt;/li&gt;
&lt;li&gt;이 경로 정보를 &lt;b&gt;다이렉트 커넥티드&lt;/b&gt;라 함.&lt;/li&gt;
&lt;li&gt;다이렉트 커넥티드로 생성된 경로 정보는 강제로 지울 수 없고 해당 네트워크 설정을 지우거나 네트워크 인터페이스가 비활성화되야 자동으로 사라짐&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;b&gt;스태틱 라우팅&lt;br /&gt;&lt;/b&gt;&lt;/b&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20241023_143337359.jpg&quot; data-origin-width=&quot;5214&quot; data-origin-height=&quot;3320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bYkDXx/btsKgKLVDc5/HHaU8Rk0ZekuPhsnJKsRN1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bYkDXx/btsKgKLVDc5/HHaU8Rk0ZekuPhsnJKsRN1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bYkDXx/btsKgKLVDc5/HHaU8Rk0ZekuPhsnJKsRN1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbYkDXx%2FbtsKgKLVDc5%2FHHaU8Rk0ZekuPhsnJKsRN1%2Fimg.jpg&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;418&quot; height=&quot;266&quot; data-filename=&quot;KakaoTalk_20241023_143337359.jpg&quot; data-origin-width=&quot;5214&quot; data-origin-height=&quot;3320&quot;/&gt;&lt;/span&gt;&lt;/figure&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;li&gt;다이렉트 커넥티드처럼 연결된 인터페이스 정보가 삭제되거나 비활성화되면 라우팅 정보가 자동 삭제됨.&lt;/li&gt;
&lt;li&gt;논리 인터페이스는 물리 인터페이스가 비활성화되더라도 남아 있는 경우도 있어 라우팅 테이블에서 사라지지 않음&lt;/li&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;/li&gt;
&lt;li&gt;그래서 라우터 사이의 회선이나 장애가 발생할 경우 대처가 어려운 문제가 있음&lt;/li&gt;
&lt;li&gt;그리고 관리해야 할 네트워크 수가 많아지고 복잡해지면 관리자가 직접 관리하기 어려움&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;b&gt;다이나믹 라우팅&lt;br /&gt;&lt;/b&gt;&lt;/b&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;KakaoTalk_20241023_143337359_02qq.jpg&quot; data-origin-width=&quot;4850&quot; data-origin-height=&quot;3416&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVS3ls/btsKhb3iMy9/hYMisBwWJxUJc71rG64Kt1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVS3ls/btsKhb3iMy9/hYMisBwWJxUJc71rG64Kt1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVS3ls/btsKhb3iMy9/hYMisBwWJxUJc71rG64Kt1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVS3ls%2FbtsKhb3iMy9%2FhYMisBwWJxUJc71rG64Kt1%2Fimg.jpg&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;396&quot; height=&quot;279&quot; data-filename=&quot;KakaoTalk_20241023_143337359_02qq.jpg&quot; data-origin-width=&quot;4850&quot; data-origin-height=&quot;3416&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/li&gt;
&lt;li&gt;다이나믹 라우팅에서는 자신이 광고할 네트워크를 선언해야 함&lt;/li&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;이라 함&lt;/li&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;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3. 스위칭(라우터가 경로를 지정하는 방법)&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;스위칭&lt;/b&gt;: 패킷이 들어와 라우팅 테이블을 참조하여 최적의 경로를 찾아 포워딩하는 작업을 일컬음&lt;/li&gt;
&lt;li&gt;패킷의 목적지가 일치하지 않은 경우도 발생하는데 이땐 &lt;b&gt;Longest Prefix Match 기법&lt;/b&gt;을 이용해 가진 경로 중 가장 가까운 경로를 선택함.&lt;/li&gt;
&lt;li&gt;사실 이 작업은 부정확한 정보 중 가장 비슷한 정보를 찾는 작업이라서 많은 부하가 걸리는 작업&lt;/li&gt;
&lt;li&gt;그래서 한 번 스위칭을 수행한 정보를 캐시에 저장하고 뒤의 작업을 수행할 때 우선적으로 캐시 정보를 먼저 확인&lt;/li&gt;
&lt;li&gt;캐시 기술의 경우 &lt;b&gt;출발지 IP, 목적지 IP, 포트 번호 정보, 넥스트 홉 L2 정보&lt;/b&gt;까지 포함해 저장하는 경우도 있음&lt;/li&gt;
&lt;li&gt;레디스(Redis)와 같은 메모리 캐시를 이용해 데이터베이스 부하를 줄이는 기법과 유사&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Longest Prefix Match&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;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자신이 갖고 있는 라우팅 테이블에서 가장 좋은 항목을 찾는 알고리즘&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Maximum Prefix Length Match&lt;/b&gt;라고도 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;LPM(Longest Prefix Match Table)&lt;/b&gt;: 라우터나 스위치에서 관리할 수 있는 라우팅 테이블&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.4. 라우팅, 스위칭 우선순위&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;828&quot; data-origin-height=&quot;504&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UOTif/btsKhfYGZCz/RktBVI1qwUinXltoyxS1oK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UOTif/btsKhfYGZCz/RktBVI1qwUinXltoyxS1oK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UOTif/btsKhfYGZCz/RktBVI1qwUinXltoyxS1oK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUOTif%2FbtsKhfYGZCz%2FRktBVI1qwUinXltoyxS1oK%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;688&quot; height=&quot;419&quot; data-origin-width=&quot;828&quot; data-origin-height=&quot;504&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;경로 정보를 받은 방법&lt;/b&gt;과 &lt;b&gt;거리&lt;/b&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;/li&gt;
&lt;li&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;/li&gt;
&lt;li&gt;경로를 전달받은 네트워크(다이나믹 라우팅)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;가중치 순서는 &lt;b&gt;1 &amp;gt; 2 &amp;gt; 3&lt;/b&gt; 으로 기본적인 우선순위는 정해져 있지만 필요에 따라 관리자가 우선순위를 조정할 수 있음&lt;/li&gt;
&lt;li&gt;이런 우선순위를 &lt;b&gt;AD(Administrative Distance: 관리 거리)&lt;/b&gt;라 부르며 라우터 생산업체에 따라 조금씩 다름&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;[AD 값 표]&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 41.7442%; height: 255px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 14.1243%; height: 20px;&quot;&gt;우선순위&lt;/td&gt;
&lt;td style=&quot;width: 38.9709%; height: 20px;&quot;&gt;기본 디스턴스&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.1243%; height: 17px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 38.9709%; height: 17px;&quot;&gt;Connected Interface&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.1243%; height: 17px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 38.9709%; height: 17px;&quot;&gt;Static Route&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.1243%; height: 17px;&quot;&gt;20&lt;/td&gt;
&lt;td style=&quot;width: 38.9709%; height: 17px;&quot;&gt;External BGP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.1243%; height: 17px;&quot;&gt;110&lt;/td&gt;
&lt;td style=&quot;width: 38.9709%; height: 17px;&quot;&gt;OSPF&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.1243%; height: 17px;&quot;&gt;115&lt;/td&gt;
&lt;td style=&quot;width: 38.9709%; height: 17px;&quot;&gt;IS-IS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.1243%; height: 17px;&quot;&gt;120&lt;/td&gt;
&lt;td style=&quot;width: 38.9709%; height: 17px;&quot;&gt;RIP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.1243%; height: 17px;&quot;&gt;200&lt;/td&gt;
&lt;td style=&quot;width: 38.9709%; height: 17px;&quot;&gt;Internal BGP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 14.1243%; height: 10px;&quot;&gt;255&lt;/td&gt;
&lt;td style=&quot;width: 38.9709%; height: 10px;&quot;&gt;Unknown&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;코스트 값도 동일한 경우 ECMP(Equal-Cost Multi-Path) 기능으로 동일한 코스트 값을 가진 경로 값 정보를 활용해 트래픽을 분산함&lt;/li&gt;
&lt;li&gt;코스트 값은 일종의 거리를 나타내는 값이며 라우팅 프로토콜마다 기준이 다름
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RIP: 홉 수, OSPF: 대역폭, EIGRP: 다양한 값들의 연산&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;패킷을 스위칭할 때는 Longest Prefix Match 기법으로 우선순위를 정함.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;라우팅 우선순위&lt;/b&gt;
&lt;table style=&quot;height: 214px;&quot; width=&quot;497&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style13&quot;&gt;
&lt;thead&gt;
&lt;tr style=&quot;height: 27px;&quot;&gt;
&lt;th style=&quot;height: 27px; width: 91px;&quot;&gt;&amp;nbsp;&lt;/th&gt;
&lt;th style=&quot;height: 27px; width: 206px;&quot;&gt;&amp;nbsp;&lt;/th&gt;
&lt;th style=&quot;height: 27px; width: 192px;&quot;&gt;&amp;nbsp;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 91px;&quot;&gt;우선순위&lt;/td&gt;
&lt;td style=&quot;width: 206px;&quot;&gt;구분&lt;/td&gt;
&lt;td style=&quot;width: 192px;&quot;&gt;적용 방법&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;height: 25px; width: 91px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 206px;&quot;&gt;롱기스트 매치&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 192px;&quot;&gt;스위칭&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;height: 25px; width: 91px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 206px;&quot;&gt;AD(관리 거리)&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 192px;&quot;&gt;라우팅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;height: 25px; width: 91px;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 206px;&quot;&gt;코스트&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 192px;&quot;&gt;라우팅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;height: 25px; width: 91px;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 206px;&quot;&gt;부하 분산(ECMP)&lt;/td&gt;
&lt;td style=&quot;height: 25px; width: 192px;&quot;&gt;라우팅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 라우팅 설정 방법&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1. 다이렉트 커넥티드&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;라우팅 테이블을 확인해 목적지가 다이렉트 커넥티드라면 라우터는 L2 통신으로 목적지에 도달&lt;/li&gt;
&lt;li&gt;외부 네트워크로 통신하려면 스태틱 라우팅이나 다이나믹 라우팅에서 얻은 원격지 네트워크에 대한 라우팅 정보도 있어야 함&lt;/li&gt;
&lt;li&gt;IP주소를 잘못 설정하거나 서브넷 마스크를 정상 범위보다 작게 설정할 경우 다이렉트 커넥티드 라우팅 정보가 잘못 입력되게 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.2. 스태틱 라우팅&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;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style9&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;라우팅 설정 문법&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;background-color: #e6f5ff; color: #333333; text-align: center;&quot;&gt;ip route NETWORK NETMAST NEXTHOP&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;[네트워크 장비: 시스코]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot; colspan=&quot;2&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;ex)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;ip route 20.20.20.0 255.255.255.0 1.1.1.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span style=&quot;background-color: #e6f5ff; color: #333333; text-align: start;&quot;&gt;route add -net NETWORK/ Prefix gw NEXTHOP&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;[서버 운영 체제: 리눅스]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&amp;ldquo;목적지(네트워크/호스트 - 서브넷/서브넷 마스크)로 가려면 패킷을 넥스트 홉으로 보내야 한다.&amp;rdquo;&lt;/b&gt; 라는 의미&lt;/li&gt;
&lt;li&gt;네트워크 규모가 매우 커지거나 인터넷 연결을 할 때에는 라우팅 처리에 어려움이 있음&lt;/li&gt;
&lt;li&gt;많은 라우팅 정보를 처리하기 위해서는 대용량의 인터넷 라우팅 전용 라우터가 필요함&lt;/li&gt;
&lt;li&gt;인터넷 라우팅 전용 라우터는 인터넷 사업자가 운영하기 때문에 우리가 이용하는데 문제가 없던 것&lt;/li&gt;
&lt;li&gt;인터넷 경로 정보를 받아 처리할 만큼 규모가 크지 않은 경우, 스태틱 라우팅을 확장한 &lt;b&gt;디폴트 라우팅&lt;/b&gt;을 사용함&lt;/li&gt;
&lt;li&gt;디폴트 라우팅은 스태틱 라우팅의 IP주소와 서브넷 마스크를 모두 0으로 만든 방법&lt;/li&gt;
&lt;li&gt;서브넷 마스크를 이용해 네트워크를 뽑는 2진수 and 연산을 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서브넷 마스크 1은 체크, 0은 체크하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 디폴트 게이트웨이: 라우팅 능력이 없는 장비에서 사용함&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.3. 다이나믹 라우팅&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IT 환경을 구축할 때에는 SPoF를 없애기 위해 두 개 이상의 경로를 유지함&lt;/li&gt;
&lt;li&gt;스태틱 라우팅 만으로는 대체 경로를 구성하긴 힘듦&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1293&quot; data-origin-height=&quot;370&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqIuyp/btsKhb3kNsL/qo2U5HKN1GQXdpi5kbpVsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqIuyp/btsKhb3kNsL/qo2U5HKN1GQXdpi5kbpVsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqIuyp/btsKhb3kNsL/qo2U5HKN1GQXdpi5kbpVsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqIuyp%2FbtsKhb3kNsL%2Fqo2U5HKN1GQXdpi5kbpVsk%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;1293&quot; height=&quot;370&quot; data-origin-width=&quot;1293&quot; data-origin-height=&quot;370&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;역할에 따른 분류&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터넷에는 AS(Autonomous System)라는 자율 시스템이 존재&lt;/li&gt;
&lt;li&gt;&lt;b&gt;IGP(Interior Gateway Protocol)&lt;/b&gt;: AS 내부에서 사용하는 라우팅 프로토콜&lt;/li&gt;
&lt;li&gt;&lt;b&gt;EGP(Exterior Gateway Protocol)&lt;/b&gt;: AS 간 통신에 사용되는 라우팅 프로토콜&lt;/li&gt;
&lt;li&gt;AS 내부의 연결은 효율성, AS와의 연결은 조직 간 정책이 더 중요함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동작 원리에 따른 분류&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IGP 라우팅 프로토콜은 동작 원리에 따라 나뉨.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;디스턴스 벡터&lt;/b&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;IGRP, EIGRP&lt;/b&gt; 가 있음&lt;/li&gt;
&lt;li&gt;다른 라우터의 정보는 인접 라우터를 통해 간접적으로 전달 받음&lt;/li&gt;
&lt;li&gt;간단한 네트워크를 구축하는 데 많이 사용되었음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;링크 스테이트&lt;/b&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;li&gt;링크 상태를 교환해 토폴로지 데이터베이스를 만들고 다시 SPF 알고리즘을 이용해 최단 경로 트리를 만듦&lt;/li&gt;
&lt;li&gt;최단 경로 트리를 이용해 최적의 경로를 선정한 후 라우팅 테이블에 정보를 추가함&lt;/li&gt;
&lt;li&gt;경로 파악 작업이 부하로 작용하여 네트워크 규모가 커지면 CPU와 메모리를 많이 소모함&lt;/li&gt;
&lt;li&gt;최적화를 위해 네트워크를 에어리어(AREA) 단위로 분리하고 분리된 에어리어 내에서만 링크 상태 정보를 교환, &lt;b&gt;ex) OSPF&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;에어리어 내부에서는 전체 링크 정보가 공유되고 외부의 라우터는 가공된 라우팅 테이블 형태로 정보를 전달&lt;/li&gt;
&lt;li&gt;AREA 단위로 네트워크를 구분하고 확장하는 OSPF의 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ABR(Area Border Router)&lt;/b&gt;: AREA 간 연결시키는 경계 라우터&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ASBR(Autonomous System Border Router)&lt;/b&gt;: OSPF가 아닌 다른 외부의 정보를 OSPF와 연결시켜주는 외곽 라우터&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 105px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 14.9612%; height: 20px;&quot;&gt;&lt;b&gt;분류 방법&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.3101%; height: 20px;&quot;&gt;&lt;b&gt;분류&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 64.7286%; height: 20px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.9612%; height: 34px;&quot; rowspan=&quot;2&quot;&gt;&lt;b&gt;역할&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.3101%; height: 17px;&quot;&gt;EGP&lt;/td&gt;
&lt;td style=&quot;width: 64.7286%; height: 17px;&quot;&gt;서로 다른 AS 간 정보교환용 라우팅 프로토콜, BGP가 속함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20.3101%; height: 17px;&quot;&gt;IGP&lt;/td&gt;
&lt;td style=&quot;width: 64.7286%; height: 17px;&quot;&gt;AS 내부에서 동작하는 라우팅 프로토콜로 RIP, EIGRP, OSPF, IS-IS 등이 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 14.9612%; height: 51px;&quot; rowspan=&quot;3&quot;&gt;&lt;b&gt;동작원리&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 20.3101%; height: 17px;&quot;&gt;디스턴스 벡터&lt;/td&gt;
&lt;td style=&quot;width: 64.7286%; height: 17px;&quot;&gt;직접 연결된 장비가 보내준 정보를 기반으로 최적의 경로를 선정하는 라우팅 프로토콜로 RIP, BGP가 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20.3101%; height: 17px;&quot;&gt;어드밴스드 디스턴스 벡터&lt;/td&gt;
&lt;td style=&quot;width: 64.7286%; height: 17px;&quot;&gt;디스턴스 벡터보다 다양한 경로 선정을 위한 요소가 있으며 직접 연결된 장비를 지난 장비까지 고려해 경로를 선정할 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20.3101%; height: 17px;&quot;&gt;링크 스테이트&lt;/td&gt;
&lt;td style=&quot;width: 64.7286%; height: 17px;&quot;&gt;네트워크 망에 속한 장비가 보내준 정보를 기반으로 토폴로지 맵을 만들고 SPF 알고리즘을 이용해 최적의 경로를 선정한다. OSPF와 IS-IS가 속함&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RIP: 소형 네트워크에서 많이 쓰였지만 사용되지 않는 추세&lt;/li&gt;
&lt;li&gt;EIGRP: RIP의 단점을 보완했지만 특정 업체(시스코)가 개발한 프로토콜이어서 활용성이 떨어져 대부분 사라짐&lt;/li&gt;
&lt;li&gt;최근에 BGP 사용이 늘어남
&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;AS 외부뿐만 아니라 내부에서도 사용 가능&lt;/li&gt;
&lt;li&gt;정책 기반 라우팅 프로토콜이어서 관리자 의도대로 경로를 변환할 수 있는 장점&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IT 엔지니어를 위한 네트워크 입문 (고재성, 이상훈 저, 2020.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/네트워크</category>
      <category>computer science</category>
      <category>네트워크</category>
      <category>라우터</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/26</guid>
      <comments>https://onyodev.tistory.com/26#entry26comment</comments>
      <pubDate>Wed, 23 Oct 2024 15:21:25 +0900</pubDate>
    </item>
    <item>
      <title>프로세스 관리</title>
      <link>https://onyodev.tistory.com/25</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;이 글은 반효경 저 - &quot;운영체제와 정보기술의 원리&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&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 data-ke-size=&quot;size26&quot;&gt;1. 프로세스의 개념&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.1. 프로세스의 문맥(Context)&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;시분할 시스템 환경에서는 짧은 시간동안 CPU를 점유하고 뺏기는 과정을 반복하며 CPU 관리가 이루어짐&lt;/li&gt;
&lt;li&gt;그렇기 때문에 CPU를 다시 획득했을 때 이전 CPU 시기에서 어디까지 명령이 수행했는지를 재현해야 한다.&lt;/li&gt;
&lt;li&gt;이때 정확한 재현을 위해 필요한 정보가 바로 &lt;b&gt;프로세스의 문맥&lt;/b&gt;이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.2. 프로세스의 문맥 정보&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;729&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tFokQ/btsKeJHfiWW/lHrkWBPcUSgSXVsRqKStS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tFokQ/btsKeJHfiWW/lHrkWBPcUSgSXVsRqKStS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tFokQ/btsKeJHfiWW/lHrkWBPcUSgSXVsRqKStS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtFokQ%2FbtsKeJHfiWW%2FlHrkWBPcUSgSXVsRqKStS0%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;532&quot; height=&quot;354&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;729&quot;/&gt;&lt;/span&gt;&lt;/figure&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;li&gt;시스템 콜 등을 통해 커널에서 수행한 일의 상태&lt;/li&gt;
&lt;li&gt;프로세스와 관련되어 커널이 관리하고 있는 각종 정보&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.3. 프로세스 문맥의 분류&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;하드웨어 문맥&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;CPU의 수행 상태&lt;/li&gt;
&lt;li&gt;프로그램 카운터값과 각종 레지스터에 저장하고 있는 값들을 의미&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로세스의 주소 공간&lt;/b&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;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커널상의 문맥&lt;/b&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;PCB와 커널 스택이 해당&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 프로세스의 상태&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. 프로세스 상태 구분&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;570&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boZISG/btsKeBionvS/tFfF3mTk288biT0x1jNyE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boZISG/btsKeBionvS/tFfF3mTk288biT0x1jNyE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boZISG/btsKeBionvS/tFfF3mTk288biT0x1jNyE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboZISG%2FbtsKeBionvS%2FtFfF3mTk288biT0x1jNyE0%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;570&quot; height=&quot;330&quot; data-origin-width=&quot;570&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;실행(running)&lt;/b&gt;, &lt;b&gt;준비(ready)&lt;/b&gt;, &lt;b&gt;봉쇄(blocked, wait, sleep)&lt;/b&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스가 CPU를 보유하고 기계어 명령을 실행하고 있는 상태&lt;/li&gt;
&lt;li&gt;컴퓨터 내에서 실제 실행 상태에 있는 프로세스는 매 시점 하나이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;준비 상태&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스가 CPU만 보유하면 명령을 실행할 수 있지만 CPU를 할당 받지 못한 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;봉쇄 상태&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU를 할당받더라도 당장 명령을 실행할 수 없는 상태&lt;/li&gt;
&lt;li&gt;ex) 입출력 작업 진행 상황&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. 문맥교환(Context Switch)&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;이때 준비 상태에 있는 프로세스들 중 CPU의 제어권을 넘겨받는 과정을 &lt;b&gt;CPU 디스패치&lt;/b&gt;라고 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.3. 입출력 요청 프로세스의 상태 변화 과정&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;/li&gt;
&lt;/ul&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;그 다음 준비 상태의 프로세스를 하나 선정해 CPU 할당&lt;/li&gt;
&lt;li&gt;입출력을 요청한 프로세스는 디스크 입출력을 기다리는 큐에 줄 서 있음&lt;/li&gt;
&lt;li&gt;그리고 자기 차례 때 디스크 컨트롤러부터 서비스를 받으면 PCU에게 인터럽트를 발생시켜 입출력 완료를 알림&lt;/li&gt;
&lt;li&gt;CPU는 실행 중인 프로세스를 멈추고 인터럽트 처리루틴을 수행&lt;/li&gt;
&lt;li&gt;실행 중인 프로세스는 &lt;b&gt;사용자모드 실행 &amp;rarr; 커널모드 실행&lt;/b&gt;으로 바뀜&lt;/li&gt;
&lt;li&gt;이후 입출력이 완료된 프로세스는 &lt;b&gt;봉쇄 상태 &amp;rarr; 준비상태&lt;/b&gt;로 바꾼 후 장치의 로컬버퍼의 내용을 메모리로 이동시키는 업무를 수행&lt;/li&gt;
&lt;li&gt;인터럽트 처리를 끝낸 후 실행 중이었던 프로세스는 CPU를 다시 할당하여 그 프로세스 직전 수행 시점 이후의 코드 수행
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 입출력이 완료된 프로세스의 우선순위가 더 높다면 문맥교환을 통해 CPU 제어권을 이양할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 프로세스 제어블록&lt;/h2&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;PCB 요소&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로세스의 상태: CPU 할당 여부 결정을 위해 필요한 값&lt;/li&gt;
&lt;li&gt;프로그램 카운터의 값: 다음에 수행할 명령의 위치&lt;/li&gt;
&lt;li&gt;CPU 레지스터의 값: CPU 연산을 위해 현 시점 레지스터값 저장&lt;/li&gt;
&lt;li&gt;CPU 스케줄링 정보&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;/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;1007&quot; data-origin-height=&quot;557&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJkt27/btsKeDtBmpL/meEkKyDLIeU1I180wn5SRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJkt27/btsKeDtBmpL/meEkKyDLIeU1I180wn5SRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJkt27/btsKeDtBmpL/meEkKyDLIeU1I180wn5SRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJkt27%2FbtsKeDtBmpL%2FmeEkKyDLIeU1I180wn5SRK%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;859&quot; height=&quot;475&quot; data-origin-width=&quot;1007&quot; data-origin-height=&quot;557&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 문맥교환&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자 프로세스로부터 다른 사용자 프로세스로 CPU 제어권이 이양되는 과정&lt;/li&gt;
&lt;li&gt;타이머 인터럽트가 발생할 경우 CPU 제어권이 운영체제로 넘어감&lt;/li&gt;
&lt;li&gt;운영체제는 타이머 인터럽트 처리루틴으로 가서 수행 중이던 프로세스 문맥을 저장하고 새로운 프로세스에게 CPU를 이양
&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;실행 상태 &amp;rarr; 준비 상태&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;프로세스의 문맥을 자신의 PCB에 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&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;준비 상태 &amp;rarr; 실행 상태&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;예전에 저장된 프로세스 문맥을 PCB로부터 하드웨어로 복원&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;문맥교환은 실행 중이던 프로세스가 입출력 요청이나 다른 조건을 충족하지 못해 CPU를 회수당하고 봉쇄 상태가 되는 경우에도 발생할 수 있음&lt;/li&gt;
&lt;li&gt;시스템 콜이나 인터럽트에 의해 실행 중인 프로세스가 커널의 코드에서 실행되는 경우에 프로세스 문맥 일부를 PCB에 저장하지만 이 과정은 문맥교환은 아니다.&lt;/li&gt;
&lt;li&gt;(프로세스가 새롭게 바뀌는 것은 아니니깐)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&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;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;CPU 할당 시간을 너무 작게 할 경우 문맥교환이 빈번해져 오버헤드가 상당히 커짐&lt;/li&gt;
&lt;li&gt;반대의 경우 시분할 시스템의 의미가 퇴색되어 적절한 CPU 할당시간을 설정해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 프로세스를 스케줄링하기 위한 큐&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1031&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nipl0/btsKfJ7fDCU/p9QWupnb8UMpTLoJiB0e9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nipl0/btsKfJ7fDCU/p9QWupnb8UMpTLoJiB0e9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nipl0/btsKfJ7fDCU/p9QWupnb8UMpTLoJiB0e9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnipl0%2FbtsKfJ7fDCU%2Fp9QWupnb8UMpTLoJiB0e9K%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;1031&quot; height=&quot;472&quot; data-origin-width=&quot;1031&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.1. 준비 큐&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;준비 큐에 프로세스를 줄 세우는 방법은 CPU 스케줄링 방법에 따라 달라짐&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.2. 장치 큐&lt;/h4&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;/li&gt;
&lt;li&gt;소프트웨어 자원: 공유 데이터 접근 권한&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;공유 데이터 접근에 경우 어떤 프로세스가 사용 중에 다른 프로세스가 같은 자원을 사용하면 일관성이 훼손될 수 있음&lt;/li&gt;
&lt;li&gt;그래서 &lt;b&gt;공유 데이터는 매 시점 하나의 프로세스만이 접근 가능&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;다른 프로세스가 CPU에 할당되어도 해당 프로세스가 다 사용하고 반납할 때까지 동일한 데이터에 접근할 수 없음&lt;/li&gt;
&lt;li&gt;프로세스의 상태 관리는 커널 주소 영역 중 &lt;b&gt;데이터 영역에 다양한 큐를 두어 수행&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.3. 작업 큐&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;/li&gt;
&lt;li&gt;작업 큐가 가장 넓은 개념이고 준비 큐와 장치 큐에 있는 프로세스들은 모두 작업 큐에 속함&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.4. 운영체제의 자료구조 구현&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;큐는 각 프로세스의 PCB를 연결 리스트 형태로 관리하며 포인터를 사용해 순서를 정함&lt;/li&gt;
&lt;li&gt;프로세스가 수행 중 입출력 요청이 발생하면 해당 장치 큐에 줄을 서면서 대기&lt;/li&gt;
&lt;li&gt;장치 큐에 속한 프로세스는 봉쇄 상태에 있다가 서비스를 받고나서 인터럽트를 발생시키면 준비상태로 바뀌면서 준비 큐로 이동&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 스케줄러&lt;/h2&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;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6.1. 스케줄러의 역할&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;장기 스케줄러&lt;/b&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;프로세스가 CPU에서 실행되기 위해서는 메모리를 보유해야 하기 때문에 메모리 할당 문제에 관여&lt;/li&gt;
&lt;li&gt;시작 상태의 프로세스들 중 어떤 프로세스를 준비 큐에 삽입할 지를 결정하는 역할&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단기 스케줄러&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;CPU 스케줄러라고도 하며, 준비 상태의 프로세스 중 실행 상태로 바꿀 프로세스를 결정함&lt;/li&gt;
&lt;li&gt;준비 큐에 있는 프로세스들 중 어떤 프로세스에 CPU를 할당할 지를 결정&lt;/li&gt;
&lt;li&gt;시분할 시스템에서 타이머 인터럽트가 발생하면 단기 스케줄러가 호출&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6.2. 스케줄러의 특성&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;단기 스케줄러&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장기 스케줄러&lt;/b&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;li&gt;시작 상태의 프로세스에서 메모리 할당을 승인할지 여부를 정하기 때문&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;하지만 현대의 시분할 시스템에서는 장기 스케줄러를 두지 않음&lt;/li&gt;
&lt;li&gt;현대 시분할 시스템용 운영체제는 프로세스가 시작되면 곧바로 프로세스에 메모리를 할당해 준비 큐에 넣음&lt;/li&gt;
&lt;li&gt;현대에는 장기 스케줄러 대신 &lt;b&gt;중기 스케줄러&lt;/b&gt;를 두는 경우가 많음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6.3. 중기 스케줄러&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;스왑 아웃(swap out)&lt;/b&gt;을 실행&lt;/li&gt;
&lt;li&gt;스왑 아웃을 시키는 0순위 프로세스는 봉쇄 상태에 있는 프로세스들이다.&lt;/li&gt;
&lt;li&gt;이후에 스왑 아웃이 필요한 경우에는 타이머 인터럽트가 발생해 준비 큐로 이동하는 프로세스를 스왑 아웃시킴&lt;/li&gt;
&lt;li&gt;중기 스케줄러의 등장으로 프로세스의 상태는 실행, 준비, 봉쇄, &lt;b&gt;중지&lt;/b&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;1111&quot; data-origin-height=&quot;610&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSp1R8/btsKgtQevpm/SVeBXQJWOKIyPxUPksA1lk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSp1R8/btsKgtQevpm/SVeBXQJWOKIyPxUPksA1lk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSp1R8/btsKgtQevpm/SVeBXQJWOKIyPxUPksA1lk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSp1R8%2FbtsKgtQevpm%2FSVeBXQJWOKIyPxUPksA1lk%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;1111&quot; height=&quot;610&quot; data-origin-width=&quot;1111&quot; data-origin-height=&quot;610&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;중지(suspended, stopped) 상태&lt;/b&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;li&gt;&lt;b&gt;중지준비 상태&lt;/b&gt;와 &lt;b&gt;중지봉쇄 상태&lt;/b&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;/li&gt;
&lt;li&gt;중지봉쇄 상태이던 프로세스가 봉쇄되었던 조건을 만족하면 중지준비 상태로 바뀜&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 프로세스의 생성&lt;/h2&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;li&gt;이때 프로세스를 생성하면 &lt;b&gt;부모 프로세스&lt;/b&gt;이고 새롭게 생성되는 건 &lt;b&gt;자식 프로세스&lt;/b&gt;라 함.&lt;/li&gt;
&lt;li&gt;부모 프로세스를 종료하려고 하면 그의 자식 프로세스를 연쇄적으로 종료한 후에 종료가 가능함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;7.1. 프로세스 자원 획득과 수행 모델&lt;/h4&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;/li&gt;
&lt;li&gt;부모 프로세스와 자원을 공유해서 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자식과 부모가 CPU를 얻기 위해 경쟁하는 관계가 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&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;/li&gt;
&lt;li&gt;자식 프로세스가 종료되면 부모 프로세스는 준비 상태가 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;7.2. 프로세스의 생성과 종료&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(ex) 유닉스&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;li&gt;자식 프로세스가 다른 프로그램을 수행하면 생성된 주소 공간 위에 덮어씌워 실행&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;fork() &lt;/span&gt;시스템 콜을 통해 자식 프로세스를 생성할 때 부모 프로세스의 내용을 복제 생성&lt;/li&gt;
&lt;li&gt;자식 프로세스는 &lt;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;exec()&lt;/span&gt;시스템 콜을 통해 새로운 프로그램으로 주소 공간을 덮어 씌운다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;7.2.1. 프로세스 종료&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;자발적 종료
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;프로그램이 마쳐지는 코드에 &lt;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;exit()&lt;/span&gt;라는 시스템 콜을 넣게 되어있음.&lt;/li&gt;
&lt;li&gt;프로세스는 시스템 콜을 통해 종료함을 운영체제에게 알림.&lt;/li&gt;
&lt;li&gt;이에 운영체제는 프로세스로부터 자원을 회수하고 프로세스를 정리하게 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;abort()&lt;/span&gt; 함수를 통해 이루어짐&lt;/li&gt;
&lt;li&gt;&lt;b&gt;강제종료가 발생하는 경우&lt;/b&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;/li&gt;
&lt;li&gt;부모 프로세스가 종료되는 경우&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;❓ 로그아웃 후에도 프로그램이 수행되야 하는 경우&lt;/b&gt;&lt;br /&gt;이때에는 모든 자식 프로세스들이 종료되기 때문에 &lt;br /&gt;종료되지 않을 &lt;b&gt;다른 프로세스의 양자로 자식 프로세스를 보내는 작업&lt;/b&gt;을 수행하게 된다. &lt;br /&gt;이러한 방식을 통해 부모가 죽기 전 자식이 먼저 죽게 된다는 원칙을 지키게 됨.&lt;/blockquote&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;7.2.2. 프로세스 생성&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;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;fork()&lt;/span&gt; 시스템 콜을 하게 되면 CPU의 제어권이 커널로 넘어감&lt;/li&gt;
&lt;li&gt;커널은 &lt;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;fork()&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; 를 호출한 프로세스를 복제하여 자식 프로세스를 생성&lt;/li&gt;
&lt;li&gt;복제된 자식 프로세스는 부모의 주소공간, 프로그램 카운터, PCB 및 커널스택 등 문맥 동일함.&lt;/li&gt;
&lt;li&gt;자식 프로세스는 부모 프로세스가 현재 수행한 시점부터 수행하게 됨.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;fork()&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;함수의 결과값이 1이면 원본, 0이면 복제본이 되어 구분할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd; color: #ee2323; text-align: left;&quot;&gt;exec()&lt;/span&gt; 시스템 콜은 프로세스가 지금까지 수행했던 상태를 잊고 새롭게 시작하도록 하는 시스템 콜&lt;/li&gt;
&lt;/ul&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;background-color: #dddddd; color: #ee2323;&quot;&gt;fork()&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; , &lt;span style=&quot;background-color: #dddddd; color: #ee2323; text-align: left;&quot;&gt;exec()&lt;/span&gt;는 특권명령에 해당함.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;wait()&lt;/span&gt; 시스템 콜은 자식 프로세스가 종료되기를 기다리며 부모 프로세스가 봉쇄 상태로 머물게 함.&lt;/li&gt;
&lt;li&gt;자식 프로세스가 종료되면 부모를 준비 상태로 변경하여 프로세스간의 동기화를 가능하게 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 프로세스 간의 협력&lt;/h2&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;8.1. IPC(Inter-Process Communication)&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;IPC(Inter-Process Communication)&lt;/b&gt;: 하나의 컴퓨터 안에서 실행 중인 서로 다른 프로세스 간에 발생하는 통신&lt;/li&gt;
&lt;li&gt;프로세스들 간의 통신과 동기화를 이루기 위한 메커니즘&lt;/li&gt;
&lt;li&gt;공유 데이터를 사용하는가에 따라 &lt;b&gt;메시지 전달 방식&lt;/b&gt;과 &lt;b&gt;공유메모리 방식&lt;/b&gt;로 나뉨&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;8.1.1. 메시지 전달 방식&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;/li&gt;
&lt;li&gt;메시지 통신을 하는 시스템은 커널에 의해 send와 receive 연산을 제공받음&lt;/li&gt;
&lt;li&gt;운영체제는 메시지를 주고받는 연산을 특권명령으로 규정하여 커널을 통해서만 하게 함.&lt;/li&gt;
&lt;li&gt;통신을 원하는 두 프로세스는 &lt;b&gt;커뮤니케이션 링크&lt;/b&gt;를 생성한 후 &lt;b&gt;send&lt;/b&gt;와 &lt;b&gt;receive&lt;/b&gt;를 통해 메시지를 주고받음&lt;/li&gt;
&lt;li&gt;메시지 전송 대상에 따라 &lt;b&gt;직접통신&lt;/b&gt;과 &lt;b&gt;간접통신&lt;/b&gt;으로 나뉨.&lt;/li&gt;
&lt;li&gt;이 두가지 방식의 차이는 연산의 인터페이스에 대한 차이일 뿐, 내부 구현은 동일함.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;직접통신&lt;/b&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;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;send(P, message) &lt;/span&gt;: 프로세스 P에게 메시지 전송&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;receive(Q, message)&lt;/span&gt; : 프로세스 Q로부터 메시지를 전달 받는 것을 말함&lt;/li&gt;
&lt;li&gt;커뮤니케이션 링크는 자동으로 생성되고 하나의 링크는 한 쌍의 프로세스에게 할당&lt;/li&gt;
&lt;li&gt;링크는 단방향성일 수 있지만 &lt;b&gt;대부분 양방향성이다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;간접통신&lt;/b&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;각 메일박스에는 고유 ID가 있고 메일박스를 공유하는 프로세스끼리만 통신함&lt;/li&gt;
&lt;li&gt;하나의 링크가 여러 프로세스들에게 할당될 수 있고 각 프로세스의 쌍은 여러 링크를 공유할 수 있음&lt;/li&gt;
&lt;li&gt;링크는 단방향성 또는 양방향성이다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323; background-color: #dddddd;&quot;&gt;send(P, message)&lt;/span&gt; : P라는 메일박스에 메시지 전송&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323; background-color: #dddddd;&quot;&gt;receive(Q, message)&lt;/span&gt; : 메일박스 Q로부터 메시지를 전달 받음&lt;/li&gt;
&lt;li&gt;메일박스를 공유하는 경우, 메시지를 전달받는 프로세스가 누군지 혼동할 수 있다.&lt;/li&gt;
&lt;li&gt;각 프로세스를 1:1 연결하는 링크들을 메일박스를 생성할 때 구성한다.&lt;/li&gt;
&lt;li&gt;그리고 메시지 내용에 받는 프로세스 대상을 명시하여 전달하도록 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;li&gt;공유메모리 영역은 각자의 주소 공간에 포함되는 영역이므로 여러 프로세스가 읽고 쓰는 것이 가능&lt;/li&gt;
&lt;li&gt;고유메모리 주소영역에 대해서는 동일한 물리적 메모리 주소가 매핑됨&lt;/li&gt;
&lt;li&gt;하지만 서로의 데이터 일관성 문제가 발생할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;/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;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;운영체제와 정보기술의 원리&lt;/span&gt; (&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;반효경&lt;span&gt; &lt;/span&gt;&lt;/span&gt;저, 2020.5)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/운영체제</category>
      <category>computer science</category>
      <category>운영체제</category>
      <category>프로세스</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/25</guid>
      <comments>https://onyodev.tistory.com/25#entry25comment</comments>
      <pubDate>Tue, 22 Oct 2024 22:34:01 +0900</pubDate>
    </item>
    <item>
      <title>프로그램의 구조와 실행</title>
      <link>https://onyodev.tistory.com/24</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;이 글은 반효경 저 - &quot;운영체제와 정보기술의 원리&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 프로그램의 구조와 인터럽트&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그램이 CPU에서 명령을 수행하기 위해선 해당 명령을 담은 프로그램의 주소 영역이 메모리에 올라가 있어야 함.&lt;/li&gt;
&lt;li&gt;프로그램의 주소 영역은 &lt;b&gt;코드(code)&lt;/b&gt;, &lt;b&gt;데이터(data)&lt;/b&gt;, &lt;b&gt;스택(stack)&lt;/b&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;: 사용자가 작성한 프로그램 함수의 코드가 CPU에서 수행할 수 있는 기계어 명령 형태로 변환되어 저장되는 부분&lt;/li&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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ex) X 함수를 수행하는 중에 Y 함수를 호출&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;X 함수에서 Y 함수를 호출한 지점을 스택에 저장&lt;/li&gt;
&lt;li&gt;Y 함수가 수행된 후 스택에 저장된 주소 위치(복귀주소)로 돌아와 코드를 계속 수행&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&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;인터럽트 시에는 CPU를 빼앗긴 위치는 운영체제가 관리하는 PCB에 저장함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 컴퓨터 시스템의 작동 개요&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU는 계산 능력은 빠르지만 어떠한 작업을 수행하는지에 대한 결정은 하진 못한다.&lt;/li&gt;
&lt;li&gt;CPU는 매 시점 메모리의 특정 주소에 존재하는 명령을 실행하고 이때 메모리 주소를 담고 있는 레지스터를 &lt;b&gt;프로그램 카운터(Program Counter)&lt;/b&gt;라 부름.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컴퓨터 시스템 구성 하드웨어&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;1267&quot; data-origin-height=&quot;541&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w8Xjp/btsKecazpqq/cch98Dxr1S2RzgPPtUiFW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w8Xjp/btsKecazpqq/cch98Dxr1S2RzgPPtUiFW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w8Xjp/btsKecazpqq/cch98Dxr1S2RzgPPtUiFW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw8Xjp%2FbtsKecazpqq%2Fcch98Dxr1S2RzgPPtUiFW0%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;1267&quot; height=&quot;541&quot; data-origin-width=&quot;1267&quot; data-origin-height=&quot;541&quot;/&gt;&lt;/span&gt;&lt;/figure&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;CPU는 프로그램 카운터가 가르키는 메모리 위치의 프로그램 수행
&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;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CPU가 수행 중인 명령&lt;/b&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리에서 자료를 읽어와 CPU 에서 계산하고 결과를 메모리에 쓰는 일련의 명령&lt;/li&gt;
&lt;li&gt;모든 프로그램이 수행할 수 있는 명령&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특권명령&lt;/b&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;항상 운영체제만이 수행할 수 있도록 제한&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;사용자 프로그램이 실행할 수 없는 특권명령을 필요로 하여 운영체제에게 대행을 요청하는 것을 &lt;b&gt;시스템 콜(System call)&lt;/b&gt;이라 한다.&lt;/li&gt;
&lt;li&gt;시스템 콜을 하게 되면 운영체제는 커널 영역에 정의된 시스템 콜 처리 코드를 수행함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ex) 디스크 파일 접근&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;CPU가 디스크 컨트롤러에게 데이터를 읽어오라는 명령을 내림&lt;/li&gt;
&lt;li&gt;디스크 컨트롤러는 데이터를 읽고 저장한 후 인터럽트를 발생&lt;/li&gt;
&lt;li&gt;CPU는 인터럽트를 인지하고 인터럽트 처리루틴을 수행&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU는 주변장치의 상태를 지속적으로 파악할 수 없기 때문에 주변장치가 인터럽트를 사용해 CPU에게 서비스를 요청함&lt;/li&gt;
&lt;li&gt;인터럽트를 발생시키기 위해 주변장치는 인터럽트 라인을 세팅하고 CPU는 명령 수행한 직후 인터럽트 라인을 체크하여 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 프로그램의 실행&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;프로그램이 CPU를 할당받고 명령을 수행하고 있는 상태&lt;/li&gt;
&lt;/ol&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;515&quot; data-origin-height=&quot;273&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpLSmI/btsKeFQ1326/kUJfKePQNgc2QKDnrkShl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpLSmI/btsKeFQ1326/kUJfKePQNgc2QKDnrkShl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpLSmI/btsKeFQ1326/kUJfKePQNgc2QKDnrkShl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpLSmI%2FbtsKeFQ1326%2FkUJfKePQNgc2QKDnrkShl1%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;515&quot; height=&quot;273&quot; data-origin-width=&quot;515&quot; data-origin-height=&quot;273&quot;/&gt;&lt;/span&gt;&lt;/figure&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;프로그램의 주소 공간 중 CPU 수행에 필요한 부분만 메모리에 올리고 다른 부분은 스왑 영역에 내려놓는 방식으로 운영&lt;/li&gt;
&lt;li&gt;각각 프로그램마다 프로세스의 주소 공간을 별도로 갖고 이 공간을 &lt;b&gt;가상메모리&lt;/b&gt; 혹은 &lt;b&gt;논리적 메모리&lt;/b&gt;라 부름&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1. 운영체제에서의 프로세스&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;455&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MrOaB/btsKeyEqIlM/21sxLHunDF4t26QO3XLR20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MrOaB/btsKeyEqIlM/21sxLHunDF4t26QO3XLR20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MrOaB/btsKeyEqIlM/21sxLHunDF4t26QO3XLR20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMrOaB%2FbtsKeyEqIlM%2F21sxLHunDF4t26QO3XLR20%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;632&quot; height=&quot;341&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;455&quot;/&gt;&lt;/span&gt;&lt;/figure&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;b&gt;커널의 코드 영역&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU, 메모리 등의 자원을 관리하기 위한 부분&lt;/li&gt;
&lt;li&gt;사용자에게 편리한 인터페이스를 제공하기 위한 부분&lt;/li&gt;
&lt;li&gt;시스템 콜 및 인터럽트를 처리하기 위한 부분&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커널의 데이터 영역&lt;/b&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;CPU나 메모리를 위한 자료구조 뿐만 아니라 현재 수행 중인 프로그램을 관리하기 위한 자료구조도 저장됨&lt;/li&gt;
&lt;li&gt;현재 수행 중인 프로그램을 프로세스라 부르며, 각 프로세스의 상태, CPU 사용 정보, 메모리 사용 정보 등을 유지하기 위한 자료구조인 PCB를 두고 있음&lt;/li&gt;
&lt;li&gt;시스템 내의 모든 자원을 관리하기 위한 자료구조를 유지하고 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커널의 스택 영역&lt;/b&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;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;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2. 정리&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;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;CPU 수행 주체가 운영체제로 바뀔 땐, 프로그램 복귀 정보를 PCB에 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 사용자 프로그램이 사용하는 함수&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;사용자 정의함수&lt;/b&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;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;라이브러리 함수&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;이미 누군가 작성해 놓은 함수를 호출하여 사용하는 함수 ex) sin(), printf()&lt;/li&gt;
&lt;li&gt;프로그램의 코드 영역에 기계어 명령 형태로 존재&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커널함수&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;운영체제 커널의 코드에 정의&lt;/b&gt;된 함수&lt;/li&gt;
&lt;li&gt;시스템 콜 함수 ex) read(), write()&lt;/li&gt;
&lt;li&gt;인터럽트 처리 함수&lt;/li&gt;
&lt;li&gt;운영체제 커널의 주소 공간에 코드가 정의&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 인터럽트&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1258&quot; data-origin-height=&quot;597&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wypTe/btsKesRX0Da/1C2DQdKNqXPjCtYvKLSAM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wypTe/btsKesRX0Da/1C2DQdKNqXPjCtYvKLSAM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wypTe/btsKesRX0Da/1C2DQdKNqXPjCtYvKLSAM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwypTe%2FbtsKesRX0Da%2F1C2DQdKNqXPjCtYvKLSAM1%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;1258&quot; height=&quot;597&quot; data-origin-width=&quot;1258&quot; data-origin-height=&quot;597&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CPU는 매번 프로그램 카운터가 가리키고 있는 지점의 명령을 수행&lt;/li&gt;
&lt;li&gt;다음 명령 수행 직전에 인터럽트 라인이 세팅되었는지 확인&lt;/li&gt;
&lt;li&gt;인터럽트가 발생한 경우 CPU는 현재 수행하던 프로세스를 멈추고 운영체제의 인터럽트 처리루틴으로 이동하여 인터럽트 처리 수행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;만약 인터럽트 처리 중 인터럽트가 다시 발생한다면?&lt;/b&gt;&lt;/li&gt;
&lt;/ul&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;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;하지만 더 우선순위가 높거나 CPU를 당장 사용해야 하는 일이 발생할 경우, 예외를 둔다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 시스템 콜&lt;/h2&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;li&gt;주소 공간 자체가 이동하기 때문에 일반 함수호출과는 다른 방법을 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6.1.&amp;nbsp; (예시) 사용자 프로그램이 CPU에서 명령을 수행하던 중 디스크 파일을 읽어야 할 때&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;464&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsu4Qn/btsKeUtqImR/6udfVt12Kt14Ti8kfZRbQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsu4Qn/btsKeUtqImR/6udfVt12Kt14Ti8kfZRbQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsu4Qn/btsKeUtqImR/6udfVt12Kt14Ti8kfZRbQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbsu4Qn%2FbtsKeUtqImR%2F6udfVt12Kt14Ti8kfZRbQ0%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;975&quot; height=&quot;464&quot; data-origin-width=&quot;975&quot; data-origin-height=&quot;464&quot;/&gt;&lt;/span&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;사용자 프로그램이 시스템 콜로 커널의 함수를 호출&lt;/li&gt;
&lt;li&gt;인터럽트 라인을 세팅하는 명령&lt;/li&gt;
&lt;li&gt;CPU는 인터럽트가 발생했는지 점검&lt;/li&gt;
&lt;li&gt;인터럽트가 발생한 것을 인지하고 프로그램을 멈춘 후 CPU의 제어권을 운영체제에게 넘김&lt;/li&gt;
&lt;li&gt;설정된 인터럽트 라인에 의해 입출력을 요청하는 인터럽트임을 알고 서비스루틴으로 이동해 입출력 작업 수행&lt;/li&gt;
&lt;li&gt;디스크를 읽어오는 작업은 많은 시간이 소요되기 때문에 운영체제는 입출력을 요청한 후 CPU의 제어권을 다른 프로세스로 이양함.&lt;/li&gt;
&lt;li&gt;입출력 과정이 완료되면 디스크 컨트롤러가 CPU에게 인터럽트를 발생시켜 완료를 알림&lt;/li&gt;
&lt;li&gt;CPU는 사용자 프로세스 수행을 멈추고 인터럽트 처리루틴으로 그 제어권이 넘어감
&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;로컬버퍼로 읽어온 내용을 컴퓨터 내 메모리로 복사한 후 디스크 입출력을 요청했던 프로세스에게 다시 CPU 권한을 주는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;해당 프로세스는 CPU를 기다리는 큐에 삽입되고 CPU는 다시 인터럽트를 당한 프로세스로 넘어가하던 작업을 계속 진행&lt;/li&gt;
&lt;/ol&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;프로그램이 CPU를 할당받고 명령을 수행하다가 중간에 CPU를 뺏기는 경우
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;타이머에 의해 인터럽트 발생: CPU 할당시간 만료 시 발생&lt;/li&gt;
&lt;li&gt;입출력 요청을 위해 시스템 콜 발생
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;입출력 작업이 시간이 오래 걸리기 때문에 입출력 작업이 완료되기까지 CPU를 다른 프로세스에 이양함.&lt;/li&gt;
&lt;li&gt;입출력 프로세스는 입출력 요청이 완료되어 인터럽트를 발생시킨 이후 CPU를 얻을 자격을 갖춤&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 프로세스의 두 가지 실행 상태&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1236&quot; data-origin-height=&quot;644&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkdCeX/btsKdeG6ulh/sgHjUEH0AZSLdXVDkt6pRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkdCeX/btsKdeG6ulh/sgHjUEH0AZSLdXVDkt6pRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkdCeX/btsKdeG6ulh/sgHjUEH0AZSLdXVDkt6pRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkdCeX%2FbtsKdeG6ulh%2FsgHjUEH0AZSLdXVDkt6pRK%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;1236&quot; height=&quot;644&quot; data-origin-width=&quot;1236&quot; data-origin-height=&quot;644&quot;/&gt;&lt;/span&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;&lt;b&gt;사용자모드에서의 실행 상태&lt;/b&gt;: 자신의 주소 공간에 정의된 코드를 실행하는 것&lt;/li&gt;
&lt;li&gt;&lt;b&gt;커널모드에서의 실행 상태&lt;/b&gt;: 커널의 시스템 콜 함수를 실행하는 것&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;프로세스의 코드가 시스템 콜이 수행되는 동안 커널이 실행 상태에 있다고 하지 않고 &lt;br /&gt;&lt;b&gt;&amp;ldquo;프로세스가 실행 상태에 있다&amp;rdquo;라고&lt;/b&gt; 말한다.&lt;br /&gt;커널 입장에서는 프로세스가 해야 할 일을 대행하는 것뿐이기 때문에 프로세스가 실행된다고 간주함.&lt;/blockquote&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;&amp;nbsp;&lt;/p&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;br /&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;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;운영체제와 정보기술의 원리&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;반효경&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;저, 2020.5)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/운영체제</category>
      <category>computer science</category>
      <category>시스템콜</category>
      <category>운영체제</category>
      <category>인터럽트</category>
      <category>프로그램</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/24</guid>
      <comments>https://onyodev.tistory.com/24#entry24comment</comments>
      <pubDate>Mon, 21 Oct 2024 16:56:59 +0900</pubDate>
    </item>
    <item>
      <title>스위치: 2계층 장비</title>
      <link>https://onyodev.tistory.com/23</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 고재성, 이상훈 저 - &quot;IT 엔지니어를 위한 네트워크 입문&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;0. 스위치의 역할&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스위치는 2계층 주소인 MAC 주소를 기반으로 동작&lt;/li&gt;
&lt;li&gt;네트워크 중간에서 패킷을 받아 필요한 곳에만 보내주는 역할을 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 계층에서 헤더와 데이터를 합친 부분을 PDU라 함.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;1계층: 비트(bits)&lt;/li&gt;
&lt;li&gt;2계층: 프레임(Frame)&lt;/li&gt;
&lt;li&gt;3계층: 패킷(Packet)&lt;/li&gt;
&lt;li&gt;4계층: 세그먼트(Segment)&lt;/li&gt;
&lt;li&gt;애플리케이션 계층: 데이터(Data)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 스위치 장비 동작&lt;/h2&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;li&gt;여러 단말이 한꺼번에 통신할 수 있고 서로 충돌하거나 낭비되는 문제가 해결되어 통신효율이 향상&lt;/li&gt;
&lt;li&gt;&lt;b&gt;역할: 누가 어느 위치에 있는지 파악하고 자신이 알고 있는 위치로 패킷을 정확히 전송하는 역할&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MAC 주소 테이블&lt;/b&gt;: 단말의 MAC 주소와 인터페이스 정보를 매핑된 테이블&lt;/li&gt;
&lt;li&gt;패킷의 헤더 안에 있는 2계층 목적지 주소를 확인 후, MAC 주소 테이블에서 해당 주소의 포트 번호를 확인하여 해당 포트로 전송&lt;/li&gt;
&lt;li&gt;MAC 주소 테이블에 없는 도착지 주소가 스위치로 들어오는 경우 전체 포트로 패킷을 전송&lt;/li&gt;
&lt;li&gt;스위치의 동작 방식은 크게 &lt;b&gt;플러딩(Flooding)&lt;/b&gt;, &lt;b&gt;어드레스 러닝&lt;/b&gt;, &lt;b&gt;포워딩/필터링&lt;/b&gt;으로 나뉨&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.1. 플러딩(Flooding)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부팅했을 땐 정보가 없는 상황이고 이때에는 중재할 수 없고 허브(Hub)처럼 동작하는 방식&lt;/li&gt;
&lt;li&gt;패킷이 들어온 포트를 제외한 모든 포트로 패킷을 전달&lt;/li&gt;
&lt;li&gt;스위치는 패킷이 들어오면 도착지 MAC 주소를 확인하고 자신이 가진 MAC 주소 테이블과 비교&lt;/li&gt;
&lt;li&gt;MAC 주소 테이블에 없는 경우 모든 포트에 패킷을 전송&lt;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;사실 &lt;b&gt;플러딩 = 스위치가 제 기능을 못한다는 의미&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;스위치가 플러딩을 하게 해서 패킷 정보를 가로채는 수법의 해킹도 존재&lt;/li&gt;
&lt;li&gt;엉뚱한 MAC 주소를 학습시켜 MAC 테이블을 꽉차게 하여 플러딩을 유도&lt;/li&gt;
&lt;li&gt;이외에도 ARP 포이즈닝 기법을 이용해 모니터링해야 할 IP의 MAC 주소가 공격자 자신인 것처럼 속여 통신을 받는 방법도 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.2. 어드레스 러닝&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스위치가 원하는 포트로 포워딩하는 동작을 수행하기 위해 MAC 주소 테이블을 만들고 유지하는 과정&lt;/li&gt;
&lt;li&gt;패킷이 특정 포트에 들어올 때, 패킷의 출발지 MAC 주소와 포트 번호를 기록&lt;/li&gt;
&lt;li&gt;출발지의 MAC 주소 정보를 이용하므로 브로드캐스트나 멀티캐스트에 대한 MAC 주소를 학습할 수 없음
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;두 가지 모두 목적지 MAC 주소 필드만 사용하기 때문&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;사전 정의된 MAC 주소 테이블
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;스위치는 어드레스 러닝 외에도 사전에 미리 정의된 MAC 주소 정보를 갖고 있음&lt;/li&gt;
&lt;li&gt;이 정보는 스위치 간 통신을 위한 주소이고 인접 포트 정보가 없거나 CPU 혹은 관리 모듈을 지칭하는 용어로 표기&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd; color: #ee2323;&quot;&gt;show mac address-table&lt;/span&gt; 명령어를 통해 MAC 주소 테이블을 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.3. 포워딩/필터링&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;패킷이 스위치에 들어온 경우 도착지 MAC 주소를 확인했을 때 맞는 정보가 있으면 해당 포트로 패킷을 &lt;b&gt;포워딩&lt;/b&gt;함.&lt;/li&gt;
&lt;li&gt;이때 다른 포트로는 패킷을 보내지 않기 때문에 이 동작을 &lt;b&gt;필터링&lt;/b&gt;이라고 함.&lt;/li&gt;
&lt;li&gt;통신이 다른 포트에 영향이 가지 않기 위해 다른 포트에서 기존 통신작업으로부터 독립적으로 수행할 수 있음.&lt;/li&gt;
&lt;li&gt;스위치는 일반적인 &lt;b&gt;유니캐스트&lt;/b&gt;로 포워딩과 필터링 작업을 수행&lt;/li&gt;
&lt;li&gt;BUM 트래픽(브로드캐스트, 언노운 유니캐스트, 멀티캐스트)에서는 다르게 동작
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;출발지 MAC 주소로 브로드캐스트나 멀티캐스트 모두 출발지가 사용되지 않으므로 모두 플러딩(Flooding)함.&lt;/li&gt;
&lt;li&gt;언노운 유니캐스트도 MAC 주소 테이블에 없는 주소이므로 동일하게 플러딩&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;LAN 에서의 ARP - 스위치 동작&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;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;이더넷 - TCP/IP에서는 스위치가 플러딩하는 경우는 거의 없음&lt;/li&gt;
&lt;li&gt;단말의 MAC 주소를 알아내기 위해 ARP 브로드캐스트가 먼저 실행&lt;/li&gt;
&lt;li&gt;ARP를 이용한 MAC주소 습득 과정에서 이미 출발지-목적지 MAC 주소 습득이 가능&lt;/li&gt;
&lt;li&gt;실제 유니캐스트가 시작될때는 이미 만들어진 MAC 주소 테이블로 패킷 포워딩/필터링&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. VLAN&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;물리적 배치와 상관없이 LAN을 논리적으로 분할, 구성하는 기술&lt;/li&gt;
&lt;li&gt;단말들의 성능 향상, 보안 향상을 위한 차단 용도, 서비스 성격에 따른 정책 적용 등의 이유로 네트워크를 분리함.&lt;/li&gt;
&lt;li&gt;VLAN을 설정하면 유니캐스트 뿐만 아니라 브로드캐스트로도 다른 VLAN 간 통신이 불가능함.&lt;/li&gt;
&lt;li&gt;다른 VLAN 간 통신을 위해선 3계층 장비가 필요함.&lt;/li&gt;
&lt;li&gt;VLAN을 사용하면 물리적으로 다른 층에 있는 단말끼리 동일한 네트워크로 묶을 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1. VLAN의 종류와 특징&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;포트 기반의 VLAN&lt;/b&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;어떤 단말이 접속하든지 스위치의 특정 포트에 VLAN을 할당하면 해당 VLAN에 속함.&lt;/li&gt;
&lt;li&gt;일반적인 대부분의 VLAN&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MAC 주소 기반의 VLAN&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자들의 자리 이동이 많아지면서 MAC 기반 VLAN이 개발됨.&lt;/li&gt;
&lt;li&gt;스위치에 연결하는 단말의 MAC 주소를 기반으로 VLAN을 할당&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2. VLAN 모드(Trunk/Access) 동작 방식&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서로 다른 VLAN 간 통신을 위해선 3계층 장비를 사용해야 함.&lt;/li&gt;
&lt;li&gt;스위치 포트에 VLAN을 설정하여 네트워크를 분리하면 물리적으로 분리할 때보다 효율적으로 사용할 수 있음.&lt;/li&gt;
&lt;li&gt;여러 개의 VLAN이 존재하는 상황에서 스위치를 서로 연결해야 하는 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;VLAN 개수만큼의 포트가 필요함&lt;/li&gt;
&lt;li&gt;이때 VLAN으로 분할된 스위치는 물리적인 별도의 스위치처럼 취급됨&lt;/li&gt;
&lt;li&gt;장비 간 연결만으로 많은 포트가 낭비됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이 문제를 해결하기 위해 &lt;b&gt;하나의 포트에 여러 개의 VLAN을 함께 전송할 수 있는 기능&lt;/b&gt;이 생김&lt;/li&gt;
&lt;li&gt;이 기능을 &lt;b&gt;태그(Tagged) 포트&lt;/b&gt; 또는 &lt;b&gt;트렁크(Trunk) 포트&lt;/b&gt;라고 함.&lt;/li&gt;
&lt;li&gt;여러개의 VLAN을 동시에 전송하는 태그 포트는 이더넷 프레임 중간에 VLAN ID 필드를 넣어 정보를 이용&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;607&quot; data-origin-height=&quot;316&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DTCPf/btsKchDmInx/dkKoBbohHu2KNf2yfocouk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DTCPf/btsKchDmInx/dkKoBbohHu2KNf2yfocouk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DTCPf/btsKchDmInx/dkKoBbohHu2KNf2yfocouk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDTCPf%2FbtsKchDmInx%2FdkKoBbohHu2KNf2yfocouk%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;607&quot; height=&quot;316&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;316&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;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;태그 포트&lt;/b&gt;가 일반적인 용어, &lt;b&gt;트렁크 포트&lt;/b&gt;는 시스코 사에서 사용하는 명칭&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;태그 포트 기능이 생기면서 MAC 주소 테이블에도 VLAN 필드가 추가됨.&lt;/li&gt;
&lt;li&gt;반대로 일반적인 포트를 &lt;b&gt;언태그(Untagged)&lt;/b&gt; 혹은 &lt;b&gt;액세스(Access) 포트&lt;/b&gt;라고 함.&lt;/li&gt;
&lt;li&gt;태그 포트로 패킷이 들어올 경우, 태그를 벗겨내면서 태그된 VLAN 쪽으로 패킷을 전송&lt;/li&gt;
&lt;li&gt;서버와의 연결된 포트도 가상화 서버가 연결될 때에도 태그 포트로 설정함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. STP&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;SPoF(Single Point of Failure):&lt;/b&gt; 하나의 시스템이나 구성 요소에서 고장이 발생할 때, 전체 시스템의 동작이 멈추는 것&lt;/li&gt;
&lt;li&gt;SPoF로 인한 장애를 피하기 위해 네트워크에서는 이중화, 다중화된 네트워크를 설계하고 구성함.&lt;/li&gt;
&lt;li&gt;그렇지만 SPoF를 피하기 위해 스위치 두 대로 네트워크를 구성하면 패킷이 네트워크를 따라 계속 전송되는 &lt;b&gt;네트워크 루프(Network Loop)&lt;/b&gt;를 발생시켜 네트워크를 마비시킴&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1. Loop&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;3.1.1. 브로드캐스트 스톰&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;2계층에는 3계층처럼 TTL이 없어 쉬지 않고 패킷 하나가 전체 네트워크 대역폭을 차지함.&lt;/li&gt;
&lt;li&gt;모든 단말이 브로드캐스트를 처리하기 위해 자원을 투입하면 스위치-단말 간 통신이 거의 불가한 상태가 됨&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;li&gt;네트워크에 설치된 스위치의 모든 LED가 동시에 빠른 속도로 깜빡임&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.1.2. 스위치 MAC 러닝 중복 문제&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2016&quot; data-origin-height=&quot;1192&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FdSSq/btsKdf532Y0/kwd7PvhGGAQVQi2XP3sOnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FdSSq/btsKdf532Y0/kwd7PvhGGAQVQi2XP3sOnk/img.png&quot; data-alt=&quot;스위치 MAC 러닝 중복 문제&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FdSSq/btsKdf532Y0/kwd7PvhGGAQVQi2XP3sOnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFdSSq%2FbtsKdf532Y0%2Fkwd7PvhGGAQVQi2XP3sOnk%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;626&quot; height=&quot;370&quot; data-origin-width=&quot;2016&quot; data-origin-height=&quot;1192&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스위치 MAC 러닝 중복 문제&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;루프를 돌게 되면 동일한 MAC 주소가 여러 포트에서 학습이 되는 상황이 발생&lt;/li&gt;
&lt;li&gt;이러면 MAC 주소 테이블이 반복 갱신되어 정상적으로 동작하지 않음&lt;/li&gt;
&lt;li&gt;이 현상을 &lt;b&gt;MAC 어드레스 플래핑(MAC Address Flapping)&lt;/b&gt;이라 함.&lt;/li&gt;
&lt;li&gt;이런 현상이 발생하면 포트를 강제로 셧다운하는 방법을 쓰긴 하지만 효율적이지 않아 다른 방법이 필요함&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;그래서 루프를 자동 감지해 포트를 차단하고&lt;br /&gt;장애 때문에 우회로가 없을 때 차단된 포트를 스위치 소스로 풀어주는&lt;br /&gt;&lt;b&gt;스패닝 트리 프로토콜(STP)&lt;/b&gt;가 개발되었다&amp;nbsp;&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2 STP&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;&amp;ldquo;뿌리부터 가지까지 루프가 생기지 않도록&amp;rdquo;&lt;/b&gt; 유지하는 것이 목적&lt;/li&gt;
&lt;li&gt;&lt;b&gt;토폴로지:&lt;/b&gt; 네트워크 장치들이 &lt;b&gt;어떻게 연결되고 동작하는 구조&lt;/b&gt;를 나타내는 개념&lt;/li&gt;
&lt;li&gt;&lt;b&gt;BPDU(Bridge Protocol Data Unit)&lt;/b&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;스위치가 갖고 있는 ID와 같은 고유값이 존재, 이를 스위치 간 서로 교환하면서 루프를 파악하여 예방&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.2.1. 스위치 포트의 상태 및 변경 과정&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;STP가 동작 중인 스위치에서는 루프 예방을 위해 신규 스위치 연결 시 트래픽을 우선 차단함.&lt;/li&gt;
&lt;li&gt;이후 BPDU를 기다려 학습하고 구조를 파악한 후, 트래픽을 흘리거나 루프 구조인 경우 차단 상태를 유지함&lt;/li&gt;
&lt;li&gt;&lt;b&gt; 해당 과정에서의 스위치 포트 4가지 상태&lt;/b&gt;&lt;/li&gt;
&lt;/ul&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Blocking&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;패킷 데이터를 차단한 상태로 BPDU를 기다림&lt;/li&gt;
&lt;li&gt;Max Age(20s) 동안 BPDU를 받지 못하거나 후순위 BPDU를 받는 경우 리스닝 상태로 변경&lt;/li&gt;
&lt;li&gt;BPDU 기본 교환 주기 2초, 10번의 BPDU를 기다림&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Listening&lt;/b&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;자신의 BPDU 정보를 전송하며 총 15초 동안 대기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Learning&lt;/b&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;패킷 포워딩이 일어날 때 스위치가 동작하도록 MAC 주소를 러닝하고 총 15초 동안 대기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Forwarding&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스위치에 신규 장비가 붙을 시 약 50여 초 간의 통신 진행&lt;/li&gt;
&lt;li&gt;이중화된 링크 절체(전환)도 STP 동작대로 진행&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.2.2. STP 동작 방식&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네트워크 상 뿌리가 되는 가장 높은 스위치를 뽑아 모든 BPDU가 그 스위치를 통해 교환되도록 하는데 그 스위치를 &lt;b&gt;루트 스위치&lt;/b&gt;라 부름&lt;/li&gt;
&lt;li&gt;&lt;b&gt;루트 스위치 선정&lt;/b&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;BPDU를 통해 2초마다 자신이 루트 스위치임을 광고&lt;/li&gt;
&lt;li&gt;새로운 스위치가 들어오면 서로 교환된 BPDU에 있는 브릿지 ID값을 비교&lt;/li&gt;
&lt;li&gt;브릿지 ID값이 더 적은 스위치를 루트 스위치로 선정,&amp;nbsp; 해당 스위치가 &lt;b&gt;자신이 루트 스위치라고 적은 BPDU를 다른 스위치 쪽으로 보냄&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;STP 동작 과정&lt;/b&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;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;루트 브릿지로 가는 경로가 가장 짧은 포트를 &lt;b&gt;루트 포트&lt;/b&gt;라 함.&lt;/li&gt;
&lt;li&gt;루트 브릿지에서 보낸 BPDU를 받는 포트&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;하나의 세그먼트에 &lt;b&gt;지정 포트&lt;/b&gt;를 선정
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;스위치 - 스위치 포트는 하나의 &lt;b&gt;지정 포트&lt;/b&gt;를 선정&lt;/li&gt;
&lt;li&gt;스위치 간 연결에서 이미 루트 포트로 선정된 경우, 반대쪽이 지정 포트로 선정되어 양쪽 모두 포워딩 상태&lt;/li&gt;
&lt;li&gt;스위치 간 연결에서 아무도 루트 포트가 아닌 경우, 한쪽은 &lt;b&gt;지정 포트&lt;/b&gt;로 선정, 다른 쪽은 &lt;b&gt;대체 포트&lt;/b&gt;가 되어 차단 상태가 됨&lt;/li&gt;
&lt;li&gt;BPDU가 전달되는 포트&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스패닝 트리 프로토콜 사용 시 대안(Port Fast)&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;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;STP가 동작하면 시간 지연의 문제가 있어 서버나 PC로 연결되는 포트는 이 동작을 생략하거나 빠르게 포워딩 상태로 변경&lt;/li&gt;
&lt;li&gt;이 경우 포트 패스트로 설정하면 BPDU 대기, 습득 과정을 생략하고 포워딩함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.3. 향상된 STP(RSTP, MST)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TCP 기반 애플리케이션은 네트워크가 끊겼을 때는 STP 기반 네트워크에서 기다리지를 못함.&lt;/li&gt;
&lt;li&gt;여러 개의 VLAN이 있는 경우 각 VLAN 별로 STP를 실행하면 부하가 발생하는 문제도 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.3.1. RSTP&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2~3초로 절체 시간이 짧아 일반적인 TCP 기반 애플리케이션이 세션을 유지할 수 있음&lt;/li&gt;
&lt;li&gt;BPDU 메시지 형식이 다양하여 여러가지 상태 메시지를 교환할 수 있음&lt;/li&gt;
&lt;li&gt;RSTP는 8개 비트를 모두 활용해 다양한 정보를 주위 스위치와 교환할 수 있음&lt;/li&gt;
&lt;li&gt;기존 STP는 토폴로지가 변경되면 말단 스위치 - 루트 스위치를 왕복하는 복잡한 과정이 존재&lt;/li&gt;
&lt;li&gt;하지만 RSTP는 토폴로지가 변경되면 스위치 자신이 모든 네트워크에 토폴로지 변경을 전파함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.3.2. MST&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;CST(Common Spanning Tree)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;VLAN 개수와 상관없이 &lt;b&gt;스패닝 트리 한 개만 동작&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;스위치 부하가 적지만 루프가 생기는 토폴로지에서 자원을 효율적으로 사용하지 못함.&lt;/li&gt;
&lt;li&gt;그리고 포트가 하나이기 때문에 최적의 경로를 사용하지 못하는 문제가 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PVST(Per Vlan Spanning Tree)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CST의 문제를 해결하기 위해 개발되었고&lt;b&gt; VLAN마다 다른 프로세스가 동작&lt;/b&gt;하게 하여 최적의 경로를 디자인할 수 있게 됨&lt;/li&gt;
&lt;li&gt;그리고 VLAN마다 별도의 포트를 지정해 &lt;b&gt;네트워크 로드를 셰어링&lt;/b&gt;할 수 있음&lt;/li&gt;
&lt;li&gt;STP 자체가 스위치에 부담을 많이 주는 프로토콜인데 (2초마다 교환) 모든 VLAN마다 별도의 STP를 유지해야 하는 부담이 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MST(Multiple Spanning Tree)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CST와 PVST의 단점을 보완하기 위해 개발&lt;/li&gt;
&lt;li&gt;&lt;b&gt;여러 개의 VLAN을 그룹으로 묶고 그 그룹마다 별도의 스패닝 트리가 동작&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;PVST보다 훨씩 적은 STP 프로세스가 돌게 되고 PVST의 장점인 로드 셰어링 기능도 사용&lt;/li&gt;
&lt;li&gt;대체 경로의 개수나 용도에 따라 STP 프로세스 개수를 정의함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;STP의 대안&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;STP는 스위치 부담이 많은 프로토콜이기 때문에 PortFast, UplinkFast, BackbonFast 등 다수 기능이 있지만 잘못 쓰면 장애 발생에 원인이 되기도 함&lt;/li&gt;
&lt;li&gt;그래서 근본적으로 대체하기 위해 네트워크를 잘게 쪼개 디자인하거나 대체재를 사용하는 경우가 많음&lt;/li&gt;
&lt;li&gt;이런 대체재도 대부분 모두 호환되는 것이 아니라 제작업체 내에서만 동작하거나 호환성이 없는 경우도 많음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SLPP, Extreme STP, Loop Guard, BPDU Guard 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스위치는 관리용 &lt;b&gt;컨트롤 플레인&lt;/b&gt;과 포워딩하는 &lt;b&gt;데이터 플레인&lt;/b&gt;으로 나뉨. &lt;br /&gt;STP나 스위치 원격관리용 텔넷, SSH, 웹 등의 서비스는 &lt;b&gt;컨트롤 플레인&lt;/b&gt;에서 수행&lt;br /&gt;&lt;br /&gt;스위치는 MAC 주소만 이해할 수 있지만 일정 규모 이상의 네트워크에선 관리 목적으로 대부분 IP주소가 할당됩니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IT 엔지니어를 위한 네트워크 입문 (고재성, 이상훈 저, 2020.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/네트워크</category>
      <category>computer science</category>
      <category>stp</category>
      <category>네트워크</category>
      <category>스위치</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/23</guid>
      <comments>https://onyodev.tistory.com/23#entry23comment</comments>
      <pubDate>Sun, 20 Oct 2024 18:59:36 +0900</pubDate>
    </item>
    <item>
      <title>네트워크 통신하기</title>
      <link>https://onyodev.tistory.com/22</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;이 글은 고재성, 이상훈 저 - &quot;IT 엔지니어를 위한 네트워크 입문&quot;를 공부하고 정리하여 작성하였습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 네트워크 통신 방식&lt;/h2&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;출발지와 목적지가 1:1로 통신&lt;/li&gt;
&lt;li&gt;실제 대부분의 통신이 이뤄지는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;브로드캐스트
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동일 네트워크에 존재하는 모든 호스트와 통신하는 1:모든 통신&lt;/li&gt;
&lt;li&gt;유니캐스트 전, 상대방의 정확한 위치를 파악하기 위해 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;멀티캐스트
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 출발지에서 다수의 특정 목적지로 데이터를 전송하는 1: 그룹 통신&lt;/li&gt;
&lt;li&gt;IPTV처럼 다수에게 동시에 같은 내용을 전달해야 할 떄 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;애니캐스트
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다수의 동일 그룹 중 가장 가까운 호스트에서 응답하는 1:1 통신&lt;/li&gt;
&lt;li&gt;가장 가까운 DNS서버나 게이트웨이를 찾는 기능에 사용&lt;/li&gt;
&lt;li&gt;IPv4에서는 일부 사용 가능하고 IPv6에서는 모두 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;BUM 트래픽 &lt;/b&gt;&lt;br /&gt;트래픽 종류에 대한 내용을 다룰 때 사용되는 용어&lt;br /&gt;B(Brodcast), U(Unknown Unicast), M(Multicast)&amp;nbsp;를 지칭함.&lt;br /&gt;- 언노운 유니캐스트: 목적지 주소는 명확히 명시되어 있지만 스위치가 주소를 학습하지 못한 상황이어서 모든 포트로 전송하는 유니캐스트&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. MAC 주소&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MAC(Media Access Control): 2계층에서 통신을 위해 네트워크 인터페이스에 할당된 고유 식별자&lt;/li&gt;
&lt;li&gt;이더넷과 와이파이를 포함한 대두분의 IEEE 802 네트워크 기술에서 2계층 주소로 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.1. MAC 주소 체계&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;877&quot; data-origin-height=&quot;332&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgz9TE/btsJ7OuVbca/K0mhp2ko40yOfadNQxr6w0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgz9TE/btsJ7OuVbca/K0mhp2ko40yOfadNQxr6w0/img.png&quot; data-alt=&quot;MAC 주소 체계&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgz9TE/btsJ7OuVbca/K0mhp2ko40yOfadNQxr6w0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcgz9TE%2FbtsJ7OuVbca%2FK0mhp2ko40yOfadNQxr6w0%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;567&quot; height=&quot;215&quot; data-origin-width=&quot;877&quot; data-origin-height=&quot;332&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;MAC 주소 체계&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;한 제조업체에 하나 이상의 주소 풀을 주고 그 풀 안에서 제조업체가 자체적으로 MAC 주소를 할당&lt;/li&gt;
&lt;li&gt;주소 풀을 &lt;b&gt;제조사 코드(Vendor code)&lt;/b&gt;라 하고 국제기구 IEEE에서 관리&lt;/li&gt;
&lt;li&gt;48비트의 16진수 12자리로 표현됨.&lt;/li&gt;
&lt;li&gt;앞의 24비트는 제조사 코드인 &lt;b&gt;&amp;lsquo;OUI&amp;rsquo;&lt;/b&gt; 값&lt;/li&gt;
&lt;li&gt;뒤의 24비트는 제조사에서 자체적으로 할당하는 네트워크 장비 &lt;b&gt;&amp;lsquo;UAA&amp;rsquo;&lt;/b&gt; 값&lt;/li&gt;
&lt;li&gt;장비를 생산할 때 하드웨어적으로 정해지기 때문에 &lt;b&gt;BIA(Burned-In Address)&lt;/b&gt;라고도 부름&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;윈도우의 경우, Driver 상세 정보에서 MAC 주소 변경을 제공하여 변경이 가능하기도 함.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2.2. MAC 주소 동작&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NIC는 전기신호를 데이터 형태로 변환하여 내용을 구분한 후 도착지 MAC 주소를 확인&lt;/li&gt;
&lt;li&gt;도착지 주소가 자기 자신이거나 멀티캐스트, 브로드캐스트와 같은 그룹 주소이면 상위계층으로 넘김&lt;/li&gt;
&lt;li&gt;이 경우 OS나 애플리케이션에서 처리하기 때문에 시스템에 부하가 작용&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;무차별 모드(Promiscuous Mode)&lt;/b&gt;&lt;br /&gt;다른 목적지를 가진 패킷을 분석하거나 수집해야 하는 경우, 무차별 모드로 NIC 구성&lt;br /&gt;네트워크 패킷 분석 애플리케이션 &lt;b&gt;와이어샤크(Wireshark)&lt;/b&gt;에서 사용&lt;/blockquote&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 data-ke-size=&quot;size26&quot;&gt;3. IP 주소&lt;/h2&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;3.1. IP주소 체계&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k0dhQ/btsJ9mDEBjw/S2vjLqSnw4ykyk4NkhTkbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k0dhQ/btsJ9mDEBjw/S2vjLqSnw4ykyk4NkhTkbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k0dhQ/btsJ9mDEBjw/S2vjLqSnw4ykyk4NkhTkbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk0dhQ%2FbtsJ9mDEBjw%2FS2vjLqSnw4ykyk4NkhTkbK%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;412&quot; height=&quot;211&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IPv4의 경우 32비트, IPv6는 128비트이다.&lt;/li&gt;
&lt;li&gt;IPv4 주소를 표시할 때 4개의 8비트 단위의 옥탯으로 나누고 &amp;ldquo;.&amp;rdquo;로 구분함.&lt;/li&gt;
&lt;li&gt;각 부분은 0 ~ 255 (0 ~ 2^8-1)의 값을 사용할 수 있음&lt;/li&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;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;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;831&quot; data-origin-height=&quot;498&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqYGaB/btsJ8OgoBQ7/Dg9eTn2q8nmO3UWv9yKqPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqYGaB/btsJ8OgoBQ7/Dg9eTn2q8nmO3UWv9yKqPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqYGaB/btsJ8OgoBQ7/Dg9eTn2q8nmO3UWv9yKqPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqYGaB%2FbtsJ8OgoBQ7%2FDg9eTn2q8nmO3UWv9yKqPK%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;577&quot; height=&quot;346&quot; data-origin-width=&quot;831&quot; data-origin-height=&quot;498&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그리고 첫번째 바이트에 있는 맨왼쪽 비트로 클래스를 구분하는데 이를&amp;nbsp;&lt;b&gt;구분 비트&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;라 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 67.5564%; height: 105px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 20.1175%; height: 20px;&quot;&gt;클래스&lt;/td&gt;
&lt;td style=&quot;width: 15.415%; height: 20px;&quot;&gt;구분비트&lt;/td&gt;
&lt;td style=&quot;width: 52.0164%; height: 20px;&quot;&gt;IP 주소 범위&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20.1175%; height: 17px;&quot;&gt;&lt;b&gt;A Class&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.415%; height: 17px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 52.0164%; height: 17px;&quot;&gt;0.0.0.0 ~ 127.255.255.255&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20.1175%; height: 17px;&quot;&gt;&lt;b&gt;B Class&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.415%; height: 17px;&quot;&gt;10&lt;/td&gt;
&lt;td style=&quot;width: 52.0164%; height: 17px;&quot;&gt;128.0.0.0 ~ 191.255.255.255&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20.1175%; height: 17px;&quot;&gt;&lt;b&gt;C Class&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.415%; height: 17px;&quot;&gt;110&lt;/td&gt;
&lt;td style=&quot;width: 52.0164%; height: 17px;&quot;&gt;192.0.0.0 ~ 223.255.255.255&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20.1175%; height: 17px;&quot;&gt;&lt;b&gt;D Class&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.415%; height: 17px;&quot;&gt;1110&lt;/td&gt;
&lt;td style=&quot;width: 52.0164%; height: 17px;&quot;&gt;224.0.0.0 ~ 239.255.255.255&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20.1175%; height: 17px;&quot;&gt;&lt;b&gt;E Class&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.415%; height: 17px;&quot;&gt;1111&lt;/td&gt;
&lt;td style=&quot;width: 52.0164%; height: 17px;&quot;&gt;240.0.0.0 ~ 255.255.255.255&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.2. 클래스풀과 클래스리스&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스 기반의 IP주소 체계를 &lt;b&gt;클래스풀(Classful)이라 부름&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;처음엔 좋았지만 호스트 숫자가 폭발적으로 증가하였음&lt;/li&gt;
&lt;li&gt;IP 주소 부족과 낭비 문제를 해결하기 위해 3가지 보존, 전환전략을 내세움
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;단기대책: 클래스리스, CIDR(Classless Inter-Domain Routing) 기반의 주소 체계&lt;/li&gt;
&lt;li&gt;중기대책: NAT, 사설 IP 주소&lt;/li&gt;
&lt;li&gt;장기대책: IPv6&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;특히 클래스 A를 받은 조직이 남은 호스트 개수만큼의 IP를 사용하지 못하면서 낭비가 커짐&lt;/li&gt;
&lt;li&gt;그래서 그냥 클래스 개념 자체를 버리는데 이를 &lt;b&gt;클래스리스&lt;/b&gt;라 함.&lt;/li&gt;
&lt;li&gt;그로 인해 네트워크 주소와 호스트 주소를 구분할 수 없게 되었는데 이를 구분하기 위해 나온 구분자가 바로 &lt;b&gt;서브넷 마스크(Subnet Mask)&lt;/b&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;848&quot; data-origin-height=&quot;437&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/czu7KO/btsJ8V7o9gM/zQ23EguXoo5PbNYpGuCmS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/czu7KO/btsJ8V7o9gM/zQ23EguXoo5PbNYpGuCmS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/czu7KO/btsJ8V7o9gM/zQ23EguXoo5PbNYpGuCmS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fczu7KO%2FbtsJ8V7o9gM%2FzQ23EguXoo5PbNYpGuCmS0%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;625&quot; height=&quot;322&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;437&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.3. 서브네팅&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 89.3787%; height: 79px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 27px;&quot;&gt;
&lt;td style=&quot;width: 16.5482%; height: 27px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;IP주소&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.0466%; height: 27px;&quot;&gt;103.9.32.146&lt;/td&gt;
&lt;td style=&quot;width: 13.6867%; height: 27px;&quot;&gt;01100111&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.2743%; height: 27px;&quot;&gt;00001001&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 14.9008%; height: 27px;&quot;&gt;00100000&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 48.0936%; height: 27px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;10&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;010010&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 24px;&quot;&gt;
&lt;td style=&quot;width: 16.5482%; height: 24px;&quot;&gt;서브넷&lt;/td&gt;
&lt;td style=&quot;width: 24.0466%; height: 24px;&quot;&gt;255.255.255.192&lt;/td&gt;
&lt;td style=&quot;width: 13.6867%; height: 24px;&quot;&gt;11111111&lt;/td&gt;
&lt;td style=&quot;width: 14.2743%; height: 24px;&quot;&gt;11111111&lt;/td&gt;
&lt;td style=&quot;width: 14.9008%; height: 24px;&quot;&gt;11111111&lt;/td&gt;
&lt;td style=&quot;width: 48.0936%; height: 24px;&quot;&gt;11&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;000000&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 28px;&quot;&gt;
&lt;td style=&quot;width: 16.5482%; height: 28px;&quot;&gt;네트워크 주소&lt;/td&gt;
&lt;td style=&quot;width: 24.0466%; height: 28px;&quot;&gt;103.9.32.128&lt;/td&gt;
&lt;td style=&quot;width: 13.6867%; height: 28px;&quot;&gt;01100111&lt;/td&gt;
&lt;td style=&quot;width: 14.2743%; height: 28px;&quot;&gt;00001001&lt;/td&gt;
&lt;td style=&quot;width: 14.9008%; height: 28px;&quot;&gt;00100000&lt;/td&gt;
&lt;td style=&quot;width: 48.0936%; height: 28px;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;10&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;000000&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;li&gt;서브네팅에서 &lt;b&gt;설계자의 서브네팅&lt;/b&gt;과 &lt;b&gt;사용자의 서브네팅&lt;/b&gt;이 구분된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;네트워크 사용자의 네트워킹&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;네트워크에서 사용할 수 있는 IP 범위 파악&lt;/li&gt;
&lt;li&gt;기본 게이트웨이와 서브넷 마스크 설정이 제대로 되어 있는지 확인&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;네트워크 설계자의 네트워킹&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;서브넷된 하나의 네트워크에 IP를 몇 개나 할당해야 하는가?&lt;/li&gt;
&lt;li&gt;그리고 서브넷된 네트워크가 몇 개나 필요한가?&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3.4. 공인 IP와 사설 IP&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터넷에 접속하고 전 세계에서 유일한 식별자로서의 역할을 하는 IP주소는 &lt;b&gt;공인 IP&lt;/b&gt;라 한다.&lt;/li&gt;
&lt;li&gt;개인적으로 네트워크를 구축하여 사용하는 IP주소를 &lt;b&gt;사설 IP&lt;/b&gt;라 한다.&lt;/li&gt;
&lt;li&gt;인터넷을 사용하지 않거나 NAT(Network Adress Tanslation) 기술을 사용할 경우 사설 IP 주소를 사용할 수 있음&lt;/li&gt;
&lt;li&gt;가정에서 사용하는 공유기가 대표적인 NAT 장비이다.네트워크 주소 IP 범위 클래스 크기&amp;nbsp;&amp;nbsp;
&lt;table style=&quot;border-collapse: collapse; width: 80.314%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.1969%;&quot;&gt;10.0.0.0/8&lt;/td&gt;
&lt;td style=&quot;width: 40.1026%;&quot;&gt;10.0.0.0 ~ 10.255.255.255&lt;/td&gt;
&lt;td style=&quot;width: 20.7729%;&quot;&gt;A클래스 1개&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.1969%;&quot;&gt;172.16.0.0/12&lt;/td&gt;
&lt;td style=&quot;width: 40.1026%;&quot;&gt;172.16.0.0 ~ 172.31.255.255&lt;/td&gt;
&lt;td style=&quot;width: 20.7729%;&quot;&gt;B클래스 16개&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.1969%;&quot;&gt;192.168.0.0/16&lt;/td&gt;
&lt;td style=&quot;width: 40.1026%;&quot;&gt;192.168.0.0 ~ 192.168.255.255&lt;/td&gt;
&lt;td style=&quot;width: 20.7729%;&quot;&gt;C클래스 256개&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;li&gt;회사 내부에서 사설 네트워크를 구축할 때 NAT를 사용하여 인터넷에 연결하더라도 다른 사용자에게 할당된 IP를 사설 네트워크 주소로 사용하면 안됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. TCP와 UDP&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;4계층 프로토콜은 통신해야 할 패킷의 경로와 순서를 정확히 설정하는 역할을 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.1. 4계층 프로토콜(TCP ,UDP)과 서비스 포트&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1251&quot; data-origin-height=&quot;781&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCaC2A/btsJ8NaJ1Cb/wTtkrTa2HukcvrQibPl8LK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCaC2A/btsJ8NaJ1Cb/wTtkrTa2HukcvrQibPl8LK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCaC2A/btsJ8NaJ1Cb/wTtkrTa2HukcvrQibPl8LK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCaC2A%2FbtsJ8NaJ1Cb%2FwTtkrTa2HukcvrQibPl8LK%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;667&quot; height=&quot;416&quot; data-origin-width=&quot;1251&quot; data-origin-height=&quot;781&quot;/&gt;&lt;/span&gt;&lt;/figure&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;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;/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;809&quot; data-origin-height=&quot;749&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/B6V2b/btsJ8Mwakhy/HzhTCNcdtXKEOdeFfkthE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/B6V2b/btsJ8Mwakhy/HzhTCNcdtXKEOdeFfkthE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/B6V2b/btsJ8Mwakhy/HzhTCNcdtXKEOdeFfkthE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FB6V2b%2FbtsJ8Mwakhy%2FHzhTCNcdtXKEOdeFfkthE1%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;648&quot; height=&quot;600&quot; data-origin-width=&quot;809&quot; data-origin-height=&quot;749&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TCP와 UDP가 담당하며 애플리케이션에서 사용하는 프로세스를 정확히 찾아가고 데이터를 분할한 패킷을 잘 쪼개 보내고 잘 조립하는 것이 목적&lt;/li&gt;
&lt;li&gt;이를 위해 시퀀스 번호와 ACK 번호를 사용&lt;/li&gt;
&lt;li&gt;상위 프로토콜 지시자는 Port number로 지정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;웰노운(Well Known) 포트: ~1023번 번호, HTTP TCP(80), HTTPS TCP(443). SMTP TCP(25) 등&lt;/li&gt;
&lt;li&gt;애플리케이션 포트: 1024 ~ 49151번 번호&lt;/li&gt;
&lt;li&gt;동적,사설,임시 포트: 49152 ~ 65535번 번호, 자동 할당되거나 사설용도로 할당&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.2. TCP&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;li&gt;수신자가 잘 받아 처리할 수 있는 전송크기도 고려해 통신&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;패킷 순서, 응답 번호&lt;/b&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;b&gt;응답번호(ACK 번호)&lt;/b&gt;를 부여&lt;/li&gt;
&lt;/ul&gt;
&lt;img src=&quot;https://blog.kakaocdn.net/dn/czibnk/btsJ7bqGwhu/vietgpQVDoiopO3wTQHMrk/img.png&quot; width=&quot;359&quot; height=&quot;315&quot; data-image-src=&quot;https://blog.kakaocdn.net/dn/czibnk/btsJ7bqGwhu/vietgpQVDoiopO3wTQHMrk/img.png&quot; data-origin-width=&quot;529&quot; data-origin-height=&quot;464&quot; /&gt;&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;윈도 사이즈와 슬라이딩 윈도&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;송신자와 수신자 거리가 멀어지면 왕복지연시간(RTT)이 늘어나므로 응답시간이 늘어남&lt;/li&gt;
&lt;li&gt;그래서 많은 패킷을 한꺼번에 보내고 응답을 하나만 받음&lt;/li&gt;
&lt;li&gt;효율적이지만 패킷 유실 가능성이 있음&lt;/li&gt;
&lt;li&gt;한꺼번에 받을 수있는 데이터 크기를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;윈도 사이즈&lt;/b&gt;라 하며 네트워크 상황에 따라 윈도 사이즈를 조절하는 것을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;슬라이딩 윈도&lt;/b&gt;라 함&lt;/li&gt;
&lt;li&gt;TCP 헤더에서 윈도 사이즈로 표현할 수 있는 최대 크기는 2의 16제곱&lt;/li&gt;
&lt;li&gt;TCP에 유실이 발생하면 윈도 사이즈를 절반으로 줄이고 정상적이면 하나씩 늘림&lt;/li&gt;
&lt;li&gt;네트워크 경합이 발생하면 윈도 사이즈가 작아져 속도가 느려짐&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;605&quot; data-origin-height=&quot;491&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/V6jjv/btsJ8WZysUJ/TXhJHSRQf7i3OMM1XVkG00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/V6jjv/btsJ8WZysUJ/TXhJHSRQf7i3OMM1XVkG00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/V6jjv/btsJ8WZysUJ/TXhJHSRQf7i3OMM1XVkG00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FV6jjv%2FbtsJ8WZysUJ%2FTXhJHSRQf7i3OMM1XVkG00%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;416&quot; height=&quot;338&quot; data-origin-width=&quot;605&quot; data-origin-height=&quot;491&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;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;3방향 핸드셰이크&lt;/b&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;li&gt;3번의 패킷을 주고받으면서 통신을 서로 준비하는데 이를 &lt;b&gt;3방향 핸드셰이크&lt;/b&gt;라 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQ1WrM/btsJ7mZKUmI/xOS0M7D8dSi0kZ7XBr5xsK/img.png&quot; width=&quot;576&quot; height=&quot;508&quot; data-image-src=&quot;https://blog.kakaocdn.net/dn/bQ1WrM/btsJ7mZKUmI/xOS0M7D8dSi0kZ7XBr5xsK/img.png&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;646&quot; /&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;SYN 단계:&lt;/b&gt;&amp;nbsp;클라이언트는 서버에 클라이언트의 SIN을 담아 SYN을 보냄&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SYN + ACK 단계:&lt;/b&gt;&amp;nbsp;서버는 클라이언트의 SYN을 수신하고 서버의 ISN을 보내며 승인번호로 클라이언트 &lt;b&gt;ISN + 1&lt;/b&gt;을 보냄&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ACK 단계:&lt;/b&gt;&amp;nbsp;클라이언트는 서버의 &lt;b&gt;ISN + 1&lt;/b&gt;한 값의 승인번호를 담아서 서버에 보냄&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;어떤 유형의 통신인지 구분하기 위해 헤더에 플래그(Flag)를 넣어 통신&lt;/li&gt;
&lt;li&gt;각각 1비트씩 나눠서 할당됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SYN: 연결 시작용도, SYN 플래그에 1로 표시&lt;/li&gt;
&lt;li&gt;ACK: 번호가 유효할 경우 1로 표시&lt;/li&gt;
&lt;li&gt;FIN: 연결 종료 시 1로 표시, 정상적인 양방향 종료 시 사용&lt;/li&gt;
&lt;li&gt;RST: 연결 종료 시 1로 표시, 연결 강제종료를 위해 사용&lt;/li&gt;
&lt;li&gt;URG: 긴급 데이터인 경우 1로 표시&lt;/li&gt;
&lt;li&gt;PSH: 서버 측에서 전송할 데이터가 없거나 데이터를 버퍼링 없이 응용 프로그램으로 전달할 것을 지시할 때 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.3. UDP&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;4계층 프로토콜이 가져야 할 특징을 거의 갖지 않음&lt;/li&gt;
&lt;li&gt;UDP는 데이터 전송을 보장하지 않는 프로토콜로 제한된 용도로 사용&lt;/li&gt;
&lt;li&gt;음성 데이터나 실시간 스트리밍 같이 시간에 민감하거나 멀티캐스트처럼 단방향으로 받기 어려운 경우 사용&lt;/li&gt;
&lt;li&gt;이런 경우 차라리 데이터가 유실되더라도 신소하게 통신하는 것이 더 낫기 때문에 UDP를 사용&lt;/li&gt;
&lt;li&gt;대신 UDP에서 첫 데이터는 리소스 확보를 위해 인터럽트를 거는 용도로 사용되고 유실됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. ARP&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IP주소와 MAC주소를 연계하기 위해 사용되는 프로토콜&lt;/li&gt;
&lt;li&gt;2계층과 3계층의 관계없는 프로토콜에서 물리적 주소와 논리적 주소를 연결&lt;/li&gt;
&lt;li&gt;패킷을 보낼 때마다 ARP 브로드캐스트를 하면 효율이 떨어지기 때문에 메모리에 저장 후 재사용&lt;/li&gt;
&lt;li&gt;다량 ARP 요청을 이용한 공격에 대응하기 위해 ARP 테이블을 정적으로 유지시키는 경우가 많음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.1. ARP 동작&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;송신자 하드웨어 MAC 주소, 송신자 IP 주소, 대상자 MAC 주소, 대상자 IP 주소가 핵심 정보&lt;/li&gt;
&lt;li&gt;패킷의 출발지 IP와 목적지 IP를 알고 출발지(자신)의 MAC주소도 아는 상태.&lt;/li&gt;
&lt;li&gt;그런데 도착지의 MAC주소는 알 수가 없어.. 얘를 알아야 헤더를 달아서 캡슐화를 할텐데 그래서 물어봐야함.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;상대방의 MAC 주소를 알기 위해 ARP 브로드캐스트를 통해 네트워크 전체에 상대의 MAC 주소를 질의&lt;/li&gt;
&lt;li&gt;상대 서버 측에서는 MAC 주소를 채워주고 보낸 IP주소, MAC주소 정보가 이미 있기 때문에 유니캐스트로 응답&lt;/li&gt;
&lt;li&gt;응답을 받으면 자신의 ARP 테이블을 갱신&lt;/li&gt;
&lt;li&gt;정상적인 캡슐화를 해서 상대방에게 전달함.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.2. GARP&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GARP는 자신의 IP와 MAC 주소를 알릴 목적으로 사용&lt;/li&gt;
&lt;li&gt;대상자 IP 필드에 자신의 IP 주소를 채워 ARP 요청을 보냄&lt;/li&gt;
&lt;li&gt;GARP의 목적지 MAC주소는 브로드캐스트 MAC주소를 사용함.&lt;/li&gt;
&lt;li&gt;자신의 IP 주소와 MAC 주소를 알려주는 이유
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;IP 주소 충돌 감지&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;나의 IP를 다른사람이 사용하고 있을 수도 있기 때문에 IP 충돌로 인한 통신 장애를 예방하기 위해 알림&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상대방의 ARP 테이블 갱신&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;가상 MAC 주소를 사용하지 않는 데이터베이스 HA 솔루션에서 주로 사용&lt;/li&gt;
&lt;li&gt;데이터베이스는 보통 한쪽만 가동하고 한쪽은 액티브-스탠바이 상태로 대기&lt;/li&gt;
&lt;li&gt;마스터 장비가 동작하지 않아 대기 장비를 사용하게 되었을 때, MAC 주소가 변경됐음을 미리 알림&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;HA(고가용성) 용도의 클러스터링, VRRP, HSRP
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;가상 MAC을 사용하는 솔루션에서도 사용됨.&lt;/li&gt;
&lt;li&gt;네트워크에 있는 스위치 장비의 MAC 테이블 갱신이 목적&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;클러스터링: 데이터를 비슷한 특성을 가진 그룹으로 묶는 데이터 분석 기법&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5.3. RARP&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;반대로 동작하는 ARP로 MAC 주소를 활용해서 정해져 있지 않은 IP주소를 찾을 때 사용&lt;/li&gt;
&lt;li&gt;요즘은 BOOTP나 DHCP로 대체되어 사용되지 않음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;BOOTP:&lt;/b&gt; 네트워크 장치가 IP 주소와 기본 설정 정보를 수동으로 할당받는 초기 프로토콜&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DHCP:&lt;/b&gt; BOOTP를 확장하여 IP 주소와 네트워크 설정을 자동으로 동적으로 할당하는 프로토콜입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 서브넷과 게이트웨이&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6.1. 서브넷과 게이트웨이의 용도&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;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;프록시 ARP&lt;/b&gt;&lt;br /&gt;: ARP를 대행해주는 기능 수행&lt;br /&gt;서로 다른 네트워크에 있는 장치들이 같은 네트워크에 있는 것처럼 통신할 수 있도록 도와줌&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;6.2. 2계층 통신 vs 3계층 통신&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;L2 통신&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로컬 네트워크에서 통신하는 경우, 3계층의 네트워크 장비가 필요하지 않음&lt;/li&gt;
&lt;li&gt;ARP 브로드캐스트를 하고 상대방의 MAC 주소를 알아내자마자 캡슐화되어 통신을 시작함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;L3 통신&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원격 네트워크에서 통신할 경우, 해당 패킷을 전송하는 네트워크 장비에서 3계층 정보까지 확인해야 함&lt;/li&gt;
&lt;li&gt;목적지의 위치를 파악하고 ARP 요청을 게이트웨이 IP 주소로 요청&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IT 엔지니어를 위한 네트워크 입문 (고재성, 이상훈 저, 2020.10)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>[컴퓨터 과학자 스터디]/네트워크</category>
      <category>computer science</category>
      <category>네트워크</category>
      <author>Frinee</author>
      <guid isPermaLink="true">https://onyodev.tistory.com/22</guid>
      <comments>https://onyodev.tistory.com/22#entry22comment</comments>
      <pubDate>Wed, 16 Oct 2024 17:53:41 +0900</pubDate>
    </item>
  </channel>
</rss>