<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>솔</title>
    <link>https://sol248.tistory.com/</link>
    <description>c++기반 개발 공부기록 블로그입니다.</description>
    <language>ko</language>
    <pubDate>Wed, 1 Jul 2026 00:36:16 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>S0LL</managingEditor>
    <item>
      <title>4. Lexical and Syntax Analysis</title>
      <link>https://sol248.tistory.com/156</link>
      <description>&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4.1 Introduction&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #000000; text-align: start;&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;컴파일러를 제대로 배우려면 한 학기 정도의 집중적인 설계&amp;middot;구현 경험이 필요하다.&lt;/li&gt;
&lt;li&gt;그 과정의 첫 파트가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;어휘 분석(lexical analysis)&lt;/b&gt;&amp;middot;구문 분석(syntax analysis)이다.&lt;/li&gt;
&lt;li&gt;특히 구문 분석기(parser)는 컴파일러의 &amp;ldquo;심장&amp;rdquo; 역할을 하며, 이후 단계인 의미 분석기(semantic analyzer)와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;중간 코드 생성기&lt;/b&gt;가 파서의 결과에 의존한다.&lt;/li&gt;
&lt;li&gt;&amp;rArr; &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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;문법(grammar)의 자연스러운 응용&lt;/b&gt;: 3장에서 배운 BNF 등 문법 이론을 실제로 쓰는 가장 직접적인 예시가 파서 설계이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;응용 범위의 확장성&lt;/b&gt;: 컴파일러를 쓰지 않는 프로그램(예: 소스코드 포매터, 복잡도 측정 도구, 설정 파일 분석기 등)도 어휘&amp;middot;구문 분석을 필요로 한다.&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;즉, 컴파일러를 작성하지 않더라도 소프트웨어 개발자라면 어휘&amp;middot;구문 분석 기법을 알아야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로그래밍 언어 구현 방식 3가지&lt;/b&gt;방식특징대표 활용
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Compilation&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;전체 소스 &amp;rarr; 기계어로 번역 후 실행&lt;/td&gt;
&lt;td&gt;대규모 시스템(C/C++ 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Pure Interpretation&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;번역 없이 인터프리터가 원본 소스를 직접 실행&lt;/td&gt;
&lt;td&gt;스크립트&amp;middot;내장 스크립트(JavaScript in HTML)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Hybrid Implementation&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;소스 &amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;중간 형태&lt;/b&gt;로 변환 후 인터프리트&lt;/td&gt;
&lt;td&gt;Java, .NET 등 (JIT 컴파일 시&lt;span&gt;&amp;nbsp;&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;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;어휘&amp;middot;구문 분석&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;단계를 공통적으로 사용한다는 점이 중요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구문 분석기의 이론적 기반 &amp;ndash; BNF&lt;/b&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;BNF(Backus&amp;ndash;Naur Form)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;같은&lt;span&gt;&amp;nbsp;&lt;/span&gt;형식 문법에 기반한다.&lt;/li&gt;
&lt;li&gt;BNF 사용 이점
&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;: 사람&amp;middot;소프트웨어 모두 이해하기 쉬움.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;직접 활용&lt;/b&gt;: BNF 자체가 파서 생성기의 입력이 됨.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모듈성&lt;/b&gt;: 문법이 모듈화되어 유지보수가 용이.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;어휘 분석 vs. 구문 분석의 분리&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;어휘 분석기(lexer)&lt;/b&gt;: 토큰 단위(식별자, 숫자 리터럴 등)처럼&lt;span&gt;&amp;nbsp;&lt;/span&gt;소규모&lt;span&gt;&amp;nbsp;&lt;/span&gt;요소를 처리.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구문 분석기(parser)&lt;/b&gt;: 표현식&amp;middot;문장&amp;middot;프로그램 단위의&lt;span&gt;&amp;nbsp;&lt;/span&gt;대규모&lt;span&gt;&amp;nbsp;&lt;/span&gt;구조를 처리.&lt;/li&gt;
&lt;li&gt;교재 구조: 4.2 (lexer) &amp;rarr; 4.3&amp;ndash;4.5 (parser) 순서로 상세 설명.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;어휘 분석을 별도 모듈로 두는 3가지 이유&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;span&gt;&amp;nbsp;&lt;/span&gt;&amp;ndash; 렉서 기술은 파서보다 단순하므로 분리 시 파서가 작고 이해하기 쉬워진다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;효율성&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;ndash; 전체 컴파일 시간 중 상당 부분이 렉서에 쓰이므로, 파서와 독립적으로 최적화하기 좋다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이식성&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;ndash; 렉서는 파일 입출력&amp;middot;버퍼링 등 플랫폼 의존 요소가 많다. 이를 분리하면 파서는 플랫폼 독립적으로 유지할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&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;b&gt;어휘 분석&lt;/b&gt;은 문장을 단어(토큰)로&lt;span&gt;&amp;nbsp;&lt;/span&gt;띄어쓰기&lt;span&gt;&amp;nbsp;&lt;/span&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;/li&gt;
&lt;li&gt;&lt;b&gt;JIT(Just‑in‑Time) 컴파일러&lt;/b&gt;는 하이브리드 시스템의 단점을 보완하기 위해, &amp;ldquo;필요한 순간&amp;rdquo;에만 바이트코드&amp;rarr;기계어 번역을 수행하여 실행 속도를 끌어올린다.&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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4.2 Lexical Analysis&lt;/b&gt;&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;  서론 (Introduction)&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Lexical analyzer의 개념&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Lexical analyzer&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(어휘 분석기, 렉서)는 본질적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;패턴 매칭기&lt;/b&gt;(pattern matcher)이다.&lt;/li&gt;
&lt;li&gt;입력된 문자열에서 특정한 문자 패턴과 일치하는 하위 문자열(substring)을 찾는 역할을 한다.&lt;/li&gt;
&lt;li&gt;패턴 매칭은 컴퓨팅에서 오래된 전통적인 기법이며, 초창기 Unix의&lt;span&gt;&amp;nbsp;&lt;/span&gt;ed&lt;span&gt;&amp;nbsp;&lt;/span&gt;편집기에서도 사용되었고 Perl, JavaScript 등의 언어에도 포함되어 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;  Lexical Analyzer의 역할&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;어휘 분석기의 기능적 위치&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어휘 분석기는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Syntax analyzer(구문 분석기)의 앞단&lt;/b&gt;(front-end)에 위치하여, 프로그램 구조의 가장 낮은 수준(lowest level)의 분석을 수행한다.&lt;/li&gt;
&lt;li&gt;컴파일러 입장에서는 전체 프로그램이 단순히&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;문자(character)의 나열&lt;/b&gt;로 보인다.&lt;/li&gt;
&lt;li&gt;어휘 분석기는 이 문자들을 모아서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;의미 있는 그룹&lt;/b&gt;(lexeme)으로 구분하고, 내부적으로 코드화(token)하여 분류한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심 용어의 구분&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Lexeme (렉심)&lt;/b&gt;: 문법적으로 의미 있는 최소 단위의 문자 집합.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Token (토큰)&lt;/b&gt;: 렉심의 분류(category)에 대한 내부적 코드.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;  예시를 통한 개념 이해&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다음 예시를 통해 렉심과 토큰의 차이를 이해할 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예시 코드:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;ini&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;result = oldsum - value / 100;
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; 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;TokenLexeme&lt;/p&gt;
&lt;table style=&quot;color: #000000; text-align: start; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;IDENT&lt;/td&gt;
&lt;td&gt;result&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ASSIGN_OP&lt;/td&gt;
&lt;td&gt;=&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IDENT&lt;/td&gt;
&lt;td&gt;oldsum&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SUB_OP&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IDENT&lt;/td&gt;
&lt;td&gt;value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DIV_OP&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;INT_LIT&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SEMICOLON&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; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 예시에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&quot;result&quot;라는 문자열이 하나의&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;은 식별자(IDENT)로 분류된다.&lt;/li&gt;
&lt;li&gt;마찬가지로 연산자와 정수 리터럴도 각각의 렉심과 토큰으로 분류된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;  Lexical Analyzer의 동작 방식&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;초기에는 어휘 분석기가 프로그램 전체를 한 번에 처리하여 모든 토큰과 렉심을 미리 뽑아냈다. 그러나 현대 컴파일러는 다음과 같은 방식으로 동작한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&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;/li&gt;
&lt;li&gt;따라서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;구문 분석기가 보는 입력은 토큰의 연속&lt;/b&gt;으로 구성된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;어휘 분석기는 주석(comment)이나 공백(space)과 같이 의미 없는 문자들은 건너뛴다. 또한, 사용자 정의 식별자(user-defined identifier)는 이후의 컴파일러 단계에서 사용되는 심볼 테이블(symbol table)에 저장한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;  Lexical Analyzer 구축 방법 (3가지 접근법)&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;어휘 분석기를 설계하는 대표적 방법은 다음 세 가지다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;정규 표현식(regular expression)을 이용한 자동화&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대표적 도구: Unix의&lt;span&gt;&amp;nbsp;&lt;/span&gt;lex&lt;/li&gt;
&lt;li&gt;토큰 패턴을 정의하면 소프트웨어가 자동으로 어휘 분석기를 생성해 준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상태 전이 다이어그램(state transition diagram)을 설계 후, 이를 코드로 구현하는 방법&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상태 전이 다이어그램을 설계 후, 테이블(table-driven)로 직접 구현하는 방법&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;  상태 다이어그램 (State Diagram)&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;상태 다이어그램&lt;/b&gt;은 어휘 분석기가 문자 입력을 처리하면서 상태를 변화시킬 때의 흐름을 시각적으로 나타낸다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;노드는 상태(state), 화살표는 문자 입력(input)을 나타낸다.&lt;/li&gt;
&lt;li&gt;상태 다이어그램은 이론적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;유한 오토마타(Finite Automata)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;에 해당하며, 이는 정규 언어(Regular Language)를 인식하는 기계이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; 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-filename=&quot;Screenshot 2025-04-05 at 22.10.26.png&quot; data-origin-width=&quot;1570&quot; data-origin-height=&quot;966&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rLkJd/btsNa5svVfC/bt64CBO9mePPuepK4Eq9H0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rLkJd/btsNa5svVfC/bt64CBO9mePPuepK4Eq9H0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rLkJd/btsNa5svVfC/bt64CBO9mePPuepK4Eq9H0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrLkJd%2FbtsNa5svVfC%2Fbt64CBO9mePPuepK4Eq9H0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1570&quot; height=&quot;966&quot; data-filename=&quot;Screenshot 2025-04-05 at 22.10.26.png&quot; data-origin-width=&quot;1570&quot; data-origin-height=&quot;966&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Letter&lt;span&gt;&amp;nbsp;&lt;/span&gt;입력으로 시작하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;id(식별자),&lt;span&gt;&amp;nbsp;&lt;/span&gt;Digit&lt;span&gt;&amp;nbsp;&lt;/span&gt;입력으로 시작하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;int(정수 리터럴) 상태로 전환된다.&lt;/li&gt;
&lt;li&gt;알파벳/숫자 조합으로 식별자나 정수 리터럴을 계속 읽고, 그 외 문자는 즉시 토큰을 반환하고 종료한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;  예제 코드 분석 (C 구현)&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;교재에서는 상태 다이어그램을 C로 구현한 실제 예제 코드(front.c)를 제시했다.&lt;/p&gt;
&lt;pre id=&quot;code_1743858749597&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* Function declarations */
void addChar();
void getChar();
void getNonBlank();
int lex();
/* Character classes */
#define LETTER 0
#define DIGIT 1
#define UNKNOWN 99
/* Token codes */
#define INT_LIT 10
#define IDENT 11
#define ASSIGN_OP 20
#define ADD_OP 21
#define SUB_OP 22
#define MULT_OP 23
#define DIV_OP 24
#define LEFT_PAREN 25
#define RIGHT_PAREN 26

/******************************************************/
/* main driver */
main() {
  /* Open the input data file and process its contents */
  if ((in_fp = fopen(&quot;front.in&quot;, &quot;r&quot;)) == NULL)
    printf(&quot;ERROR - cannot open front.in \n&quot;);
  else {
    getChar();
    do {
      lex();
    } while (nextToken != EOF);
  }
}
/*****************************************************/
/* lookup - a function to lookup operators and parentheses
and return the token */
int lookup(char ch) {
  switch (ch) {
    case '(':
      addChar();
      nextToken = LEFT_PAREN;
      break;
    case ')':
      addChar();
      nextToken = RIGHT_PAREN;
      break;
    case '+':
      addChar();
      nextToken = ADD_OP;
      break;
    case '-':
      addChar();
      nextToken = SUB_OP;
      break;
    case '*':
      addChar();
      nextToken = MULT_OP;
      break;
    case '/':
      addChar();
      nextToken = DIV_OP;
      break;
    default:
      addChar();
      nextToken = EOF;
      break;
  }
  return nextToken;
}
/*****************************************************/
/* addChar - a function to add nextChar to lexeme */
void addChar() {
  if (lexLen &amp;lt;= 98) {
    lexeme[lexLen++] = nextChar;
    lexeme[lexLen] = 0;
  } else
    printf(&quot;Error - lexeme is too long \n&quot;);
}
/*****************************************************/
/* getChar - a function to get the next character of
input and determine its character class */
void getChar() {
  if ((nextChar = getc(in_fp)) = EOF) {
    if (isalpha(nextChar))
      charClass = LETTER;
    else if (isdigit(nextChar))
      charClass = DIGIT;
    else
      charClass = UNKNOWN;
  } else
    charClass = EOF;
}
/*****************************************************/
/* getNonBlank - a function to call getChar until it
returns a non-whitespace character */
void getNonBlank() {
  while (isspace(nextChar)) getChar();
}
/ *****************************************************/
    /* lex - a simple lexical analyzer for arithmetic
    expressions */
    int lex() {
  lexLen = 0;
  getNonBlank();
  switch (charClass) {
    /* Parse identifiers */
    case LETTER:
      addChar();
      getChar();
      while (charClass == LETTER || charClass == DIGIT) {
        addChar();
        getChar();
      }
      nextToken = IDENT;
      break;
    /* Parse integer literals */
    case DIGIT:
      addChar();
      getChar();
      while (charClass == DIGIT) {
        addChar();
        getChar();
      }
      nextToken = INT_LIT;
      break;
    /* Parentheses and operators */
    case UNKNOWN:
      lookup(nextChar);
      getChar();
      break;
    /* EOF */
    case EOF:
      nextToken = EOF;
      lexeme[0] = 'E';
      lexeme[1] = 'O';
      lexeme[2] = 'F';
      lexeme[3] = 0;
      break;
  } /* End of switch */
  printf(&quot;Next token is: %d, Next lexeme is %s\n&quot;, nextToken, lexeme);
  return nextToken;
} /* End of function lex */&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;주요 함수의 역할을 요약하면 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;getChar(): 다음 문자를 입력에서 읽어오고 문자의 클래스(letter/digit/unknown)를 정한다.&lt;/li&gt;
&lt;li&gt;addChar(): 현재 문자를 렉심 배열에 추가한다.&lt;/li&gt;
&lt;li&gt;getNonBlank(): 공백 문자를 건너뛰고 다음 의미 있는 문자를 찾는다.&lt;/li&gt;
&lt;li&gt;lookup(): 연산자나 괄호 같은 단일 문자 토큰을 식별하여 반환한다.&lt;/li&gt;
&lt;li&gt;lex(): 메인 분석 함수로, 입력된 문자 클래스를 확인하여 렉심을 구성하고 적절한 토큰을 결정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실행 예시:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;stata&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;입력: (sum + 47) / total
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;출력:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;vbnet&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Next token is: LEFT_PAREN    Lexeme is (
Next token is: IDENT         Lexeme is sum
Next token is: ADD_OP        Lexeme is +
Next token is: INT_LIT       Lexeme is 47
Next token is: RIGHT_PAREN   Lexeme is )
Next token is: DIV_OP        Lexeme is /
Next token is: IDENT         Lexeme is total
Next token is: EOF           Lexeme is EOF
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;  예약어(Reserved Word) 처리와 심볼 테이블&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그램의 이름(변수명 등)과 예약어(if, else 등)는 패턴이 유사하다. 모든 예약어를 각각 별도로 상태 다이어그램에 넣으면 복잡해진다.&lt;/li&gt;
&lt;li&gt;따라서 이름과 예약어는 일단 같은 방식으로 인식하고, 이후 심볼 테이블에 저장된 예약어 테이블에서 확인하여 구분한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;심볼 테이블(Symbol Table)&lt;/b&gt;: 변수 이름과 그 속성(예: 자료형 등)을 저장하여 이후 컴파일 단계에서 활용하는 데이터베이스이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;  요약 및 정리&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Lexical Analysis(어휘 분석)는 프로그램의 텍스트에서 문자를 읽어 의미 있는 최소단위(Lexeme)로 나누고, 이를 추상화된 분류(Token)로 변환하는 작업이다.&lt;/li&gt;
&lt;li&gt;Lexical Analyzer는 컴파일러의 front-end로서 패턴 매칭을 기반으로 작동하며, 유한 오토마타 형태의 상태 전이 다이어그램으로 모델링된다.&lt;/li&gt;
&lt;li&gt;실무에서는 도구를 사용하거나 정규 표현식을 기반으로 어휘 분석기를 구축하고 관리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;4.3 The Parsing Problem (구문 분석 문제)&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로그래밍 언어의 구문을 분석하는 작업을 흔히 구문 분석(parsing)이라고 부른다.&lt;br /&gt;구문 분석이란 프로그래밍 언어의 문법적 구조를 확인하고 분석하여 의미를 이해할 수 있도록 트리를 생성하는 과정이다.&lt;br /&gt;이 섹션에서는 구문 분석 문제를 다루며, 주요 알고리즘 종류와 그 복잡도를 소개한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;4.3.1 Introduction to Parsing (구문 분석 소개)&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로그래밍 언어를 위한 파서는 입력된 프로그램에 대해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;구문 트리(parse tree)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;를 구성한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;때때로 구문 트리를 명시적으로 만들지 않고, 트리를 순회(traversal)하는 과정만으로 충분한 경우도 있다.&lt;/li&gt;
&lt;li&gt;하지만 어떤 방식으로든 파서는 반드시 구문 트리를 만들거나, 최소한 그 구조 정보를 파악해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;구문 분석의 목적은 크게 두 가지로 나뉜다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;① 입력된 프로그램이 문법적으로 올바른지 확인하기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문법 오류를 발견하면, 진단 메시지를 출력하고 분석을 계속 진행할 수 있도록 정상 상태로 복구(recovery)해야 한다.&lt;/li&gt;
&lt;li&gt;잘 만든 구문 분석기는 한 번의 분석에서 최대한 많은 오류를 찾아내야 효율적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;② 문법적으로 올바른 입력에 대해서 구문 트리를 생성(혹은 트리의 구조를 추적)하기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이렇게 만들어진 구문 트리(혹은 그 흔적)는 이후 번역 과정(translation)의 기반이 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;구문 분석 알고리즘은 트리를 구축하는 방향에 따라 두 가지로 나눌 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;하향식 (Top-down)&lt;/b&gt;: 루트에서부터 출발하여 잎(leaf) 노드까지 내려가면서 트리를 구축한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상향식 (Bottom-up)&lt;/b&gt;: 잎(leaf) 노드에서부터 출발하여 루트 노드로 올라가면서 트리를 구축한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 섹션에서 사용되는 기호 규칙을 명확하게 설명해두고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구분표기방식예시&lt;/p&gt;
&lt;table style=&quot;color: #000000; text-align: start; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;종단 기호 (Terminal)&lt;/td&gt;
&lt;td&gt;소문자 (a, b, &amp;hellip;)&lt;/td&gt;
&lt;td&gt;a, b, c&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;비종단 기호 (Nonterminal)&lt;/td&gt;
&lt;td&gt;대문자 (A, B, &amp;hellip;)&lt;/td&gt;
&lt;td&gt;A, B, C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;종단 또는 비종단 기호&lt;/td&gt;
&lt;td&gt;대문자 (W, X, Y, Z)&lt;/td&gt;
&lt;td&gt;X, Y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;종단 기호의 문자열&lt;/td&gt;
&lt;td&gt;소문자 (w, x, y, z)&lt;/td&gt;
&lt;td&gt;xyz&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;혼합 문자열&lt;/td&gt;
&lt;td&gt;소문자 그리스 문자 (&amp;alpha;, &amp;beta;, &amp;gamma;, &amp;delta;)&lt;/td&gt;
&lt;td&gt;&amp;alpha;, &amp;beta;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;4.3.2 Top-Down Parsers (하향식 파서)&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하향식 파서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;전위 순회(preorder traversal)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;방식으로 구문 트리를 구축한다.&lt;br /&gt;즉, 루트 노드부터 시작해서 가지(branch)를 탐색하기 전에 각 노드를 방문한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하향식 파서의 기본적인 원리는 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Leftmost derivation (좌측 최우선 유도)&lt;/b&gt;&lt;br /&gt;좌측 최우선 유도는 항상 가장 왼쪽에 위치한 비종단(nonterminal) 기호를 확장(expand)하면서 진행한다.&lt;/li&gt;
&lt;li&gt;하향식 파서가 해결해야 할 핵심 문제는 바로 &quot;어떤 문법 규칙을 다음에 적용할지 선택하는 것&quot;이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주어진 sentential form(문장 형태, 문법 기호들로 이루어진 문자열)에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;가장 왼쪽에 위치한 비종단 기호&lt;/b&gt;가 선택의 기준이 된다.&lt;/li&gt;
&lt;li&gt;일반적으로 다음 입력 토큰을 보고 어떤 규칙(RHS)을 선택할지 결정한다. 이러한 방식의 하향식 파서를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;LL 파서&lt;/b&gt;라 부른다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LL: Left-to-right(왼쪽에서 오른쪽 입력 탐색), Leftmost derivation(좌측 최우선 유도) 방식.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;가장 흔히 쓰이는 하향식 파서의 구현 방식은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;재귀 하강(recursive-descent)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;파서이며, 이것은 주어진 문법의 BNF(Backus-Naur Form) 정의를 거의 그대로 코드로 구현한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;4.3.3 Bottom-Up Parsers (상향식 파서)&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;상향식 파서는 하향식 파서와 반대로, 구문 트리를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;아래쪽 잎 노드에서 시작하여 위로 루트까지 올라가며 구축한다.&lt;/b&gt;&lt;br /&gt;구체적으로 말하면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;우측 최우선 유도(rightmost derivation)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;를 역방향으로 수행한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;상향식 파서의 핵심 아이디어는 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Handle(핸들)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;찾기:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문장 형태(오른쪽 최우선 유도된 형태)에서 문법 규칙의 우측(RHS)에 정확히 매칭되는 하위 문자열을 찾는다.&lt;/li&gt;
&lt;li&gt;찾은 핸들을 문법 규칙의 좌측(LHS)으로 축약(reduce)하며, 이를 반복하여 문장 형태를 최종적으로 시작 기호(start symbol)로 되돌린다.&lt;/li&gt;
&lt;li&gt;예를 들어, 주어진 문장 형태에서 어떤 부분 문자열이 규칙의 RHS에 대응하는지 정확히 찾아야 한다. 이것을 handle이라고 하며, 이 handle을 LHS로 대체하는 과정이 reduction(축약)이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;상향식 파서의 대표적 구현 방식은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;LR 파서&lt;/b&gt;이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LR: Left-to-right(왼쪽에서 오른쪽 입력 탐색), Rightmost derivation(우측 최우선 유도) 방식.&lt;/li&gt;
&lt;li&gt;LR 계열 파서는 대부분의 실제 상용 컴파일러에서 널리 쓰이는 방식이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;4.3.4 The Complexity of Parsing (구문 분석의 복잡도)&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;모든 가능한 문법(특히 모호하지 않은 문법)을 파싱할 수 있는 알고리즘의 복잡도는 일반적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;O(n&amp;sup3;)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이다.&lt;br /&gt;이런 높은 복잡도는 알고리즘이 오류가 발생했을 때 문장을 반복적으로 되돌아가면서 재분석(reparse)을 해야하기 때문이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 실제로 많이 쓰이는 문법을 사용하는 컴파일러의 구문 분석 알고리즘은 대부분 **O(n)**의 복잡도를 가진다.&lt;br /&gt;즉, 입력 문자열의 길이에 비례하는 시간만큼 걸리며, 이로 인해 매우 효율적이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;실무에서 효율성을 중시하기 때문에, 실제 컴파일러 구현에서는 모든 문법을 다루는 범용적인 알고리즘보다 효율적인 특수 목적의 알고리즘이 주로 선택된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;정리 및 핵심 개념:&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구문 분석(parsing)이란 문법 구조를 트리 형태로 분석하여 의미적 처리를 돕는 과정.&lt;/li&gt;
&lt;li&gt;하향식 파서(LL)는 루트에서 잎으로, 상향식 파서(LR)는 잎에서 루트로 트리를 구성.&lt;/li&gt;
&lt;li&gt;실무적으로 사용되는 구문 분석 알고리즘의 효율은 선형 시간 O(n).&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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;b&gt;4.4 Recursive-Descent Parsing (재귀 하향식 파싱)&lt;/b&gt;&lt;/h1&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4.4.1 The Recursive-Descent Parsing Process (재귀 하향식 파싱 과정)&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;재귀 하향식 파서(recursive-descent parser)는 이름 그대로 재귀 호출(recursion)을 이용하여 문법 규칙(grammar rules)을 구현하는 방식이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특징 및 이유:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그래밍 언어는 종종 중첩(nested)된 구조(예: if문 내부의 if문 또는 중첩된 괄호 표현식)를 가지는데, 이런 구조를 표현하기에 가장 적합한 문법 형식이 바로 재귀적인 문법(recursive grammar rules)이다.&lt;/li&gt;
&lt;li&gt;Extended BNF(EBNF)는 재귀 하향식 파서를 구현할 때 자주 사용되는데, 이는 선택적(optional)이고 반복되는 구조(repeated)를 편하게 표현할 수 있기 때문이다. 예를 들어,&lt;span&gt;&amp;nbsp;&lt;/span&gt;{}는 0회 이상 반복을 의미하고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;[]는 선택적(optional)을 의미한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;예시 문법:&lt;/h3&gt;
&lt;pre class=&quot;dts&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;&amp;lt;if_statement&amp;gt; &amp;rarr; if &amp;lt;logic_expr&amp;gt; &amp;lt;statement&amp;gt; [else &amp;lt;statement&amp;gt;]
&amp;lt;ident_list&amp;gt; &amp;rarr; ident {, ident}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 첫 문법에서 else는 옵션이며, 두 번째 문법에서 식별자는 하나 이상 쉼표로 반복된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;재귀 하향식 파서 동작 원리&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;재귀 하향식 파서는 문법에서 정의된 각 비단말 기호(nonterminal)마다 서브프로그램(함수)을 작성하여 파싱한다. 파싱 과정은 다음과 같다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;입력 문자열이 주어지면 해당 문자열을 문법의 규칙에 따라 **재귀적으로 분석하여 파스 트리(parse tree)**를 생성한다.&lt;/li&gt;
&lt;li&gt;이 때, 각 서브프로그램은 해당 비단말 기호로 시작하는 문자열 집합을 분석할 수 있는 파서 역할을 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다음은 간단한 산술 표현식(arithmetic expression)의 EBNF 문법 예시이다:&lt;/p&gt;
&lt;pre class=&quot;xml&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;&amp;lt;expr&amp;gt; &amp;rarr; &amp;lt;term&amp;gt; {( + | - ) &amp;lt;term&amp;gt;}
&amp;lt;term&amp;gt; &amp;rarr; &amp;lt;factor&amp;gt; {( * | / ) &amp;lt;factor&amp;gt;}
&amp;lt;factor&amp;gt; &amp;rarr; id | int_constant | ( &amp;lt;expr&amp;gt; )
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 문법은 *산술 표현식을 +, -,&lt;span&gt;&amp;nbsp;&lt;/span&gt;, /&lt;span&gt;&amp;nbsp;&lt;/span&gt;연산자를 포함해 표현한 것이다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;코드 예시 및 설명&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;실제 코드로 구현할 때 다음과 같이 작성한다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;①&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;expr&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;파싱 함수:&lt;/h4&gt;
&lt;pre class=&quot;less&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;void expr() {
    printf(&quot;Enter &amp;lt;expr&amp;gt;\n&quot;);
    term();
    while (nextToken == ADD_OP || nextToken == SUB_OP) {
        lex(); // 토큰을 하나 가져온다.
        term();
    }
    printf(&quot;Exit &amp;lt;expr&amp;gt;\n&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 코드는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;expr&amp;gt;을 분석하며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;term&amp;gt;을 최소 한번 호출하고, 그 뒤에 연속적인 + 또는 - 가 나오는 동안 계속&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;term&amp;gt;을 호출한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;②&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;term&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;파싱 함수:&lt;/h4&gt;
&lt;pre class=&quot;less&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;void term() {
    printf(&quot;Enter &amp;lt;term&amp;gt;\n&quot;);
    factor();
    while (nextToken == MULT_OP || nextToken == DIV_OP) {
        lex();
        factor();
    }
    printf(&quot;Exit &amp;lt;term&amp;gt;\n&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;lt;term&amp;gt;은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;factor&amp;gt;를 최소 한 번 호출하고, 이후 * 또는 / 연산자가 있는 경우 반복해서 호출한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;③&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;factor&amp;gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;파싱 함수:&lt;/h4&gt;
&lt;pre class=&quot;less&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;void factor() {
    printf(&quot;Enter &amp;lt;factor&amp;gt;\n&quot;);
    if (nextToken == IDENT || nextToken == INT_LIT) {
        lex();
    }
    else if (nextToken == LEFT_PAREN) {
        lex();
        expr();
        if (nextToken == RIGHT_PAREN) lex();
        else error();
    }
    else error();
    printf(&quot;Exit &amp;lt;factor&amp;gt;\n&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;lt;factor&amp;gt;는 변수 이름이나 정수 상수, 혹은 괄호로 감싸진 표현식을 처리한다. 에러 처리를 명확히 수행한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;예제 파싱 결과 (Trace)&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;표현식&lt;span&gt;&amp;nbsp;&lt;/span&gt;(sum + 47) / total&lt;span&gt;&amp;nbsp;&lt;/span&gt;의 파싱 과정을 예시(trace)로 제공하였다. 여기서 핵심은 파서가 재귀적으로 문법 규칙을 따라가면서 분석한다는 것이다. trace의 각 &quot;Enter&quot;와 &quot;Exit&quot; 메시지는 서브프로그램이 호출되고 종료될 때 찍히는 로그이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-05 at 23.36.17.png&quot; data-origin-width=&quot;1526&quot; data-origin-height=&quot;802&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcEpCW/btsM9UMAXJS/OogrpWTyoRhyrbGrhPMmB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcEpCW/btsM9UMAXJS/OogrpWTyoRhyrbGrhPMmB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcEpCW/btsM9UMAXJS/OogrpWTyoRhyrbGrhPMmB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcEpCW%2FbtsM9UMAXJS%2FOogrpWTyoRhyrbGrhPMmB0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1526&quot; height=&quot;802&quot; data-filename=&quot;Screenshot 2025-04-05 at 23.36.17.png&quot; data-origin-width=&quot;1526&quot; data-origin-height=&quot;802&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;또한 trace에 따라 생성된&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;파스 트리&lt;/b&gt;도 나타나 있다. 트리는 분석 과정에서 어떤 규칙이 적용되었는지 명확하게 나타낸다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;추가 예시 (if&lt;span&gt;&amp;nbsp;&lt;/span&gt;문 예제)&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;추가적으로 자바의&lt;span&gt;&amp;nbsp;&lt;/span&gt;if문을 표현한 문법과 재귀 하향식 서브프로그램을 예로 들고 있다. 여기서도 같은 재귀 하향식 접근법으로 각 비단말 기호를 파싱한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-05 at 23.36.44.png&quot; data-origin-width=&quot;1242&quot; data-origin-height=&quot;688&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p3EOg/btsNa7X86Hy/O5O6mqdspF2HWWkNeshJh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p3EOg/btsNa7X86Hy/O5O6mqdspF2HWWkNeshJh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p3EOg/btsNa7X86Hy/O5O6mqdspF2HWWkNeshJh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp3EOg%2FbtsNa7X86Hy%2FO5O6mqdspF2HWWkNeshJh1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1242&quot; height=&quot;688&quot; data-filename=&quot;Screenshot 2025-04-05 at 23.36.44.png&quot; data-origin-width=&quot;1242&quot; data-origin-height=&quot;688&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-05 at 23.36.55.png&quot; data-origin-width=&quot;1234&quot; data-origin-height=&quot;1206&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WNrbY/btsM98qhfxM/kkBYQhaptdDYkdeEZYONUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WNrbY/btsM98qhfxM/kkBYQhaptdDYkdeEZYONUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WNrbY/btsM98qhfxM/kkBYQhaptdDYkdeEZYONUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWNrbY%2FbtsM98qhfxM%2FkkBYQhaptdDYkdeEZYONUk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1234&quot; height=&quot;1206&quot; data-filename=&quot;Screenshot 2025-04-05 at 23.36.55.png&quot; data-origin-width=&quot;1234&quot; data-origin-height=&quot;1206&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4.4.2 The LL Grammar Class (LL 문법 클래스)&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;재귀 하향식 파싱(Recursive-descent parsing)은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;LL 파서&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;범주에 속하며, LL 문법 규칙에 적합해야 한다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;LL 파싱 문제: 왼쪽 재귀(Left Recursion)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LL 파서는 왼쪽 재귀(Left recursion)가 포함된 문법을 파싱할 수 없다.&lt;/li&gt;
&lt;li&gt;왼쪽 재귀란 문법의 규칙에서 자기 자신을 제일 처음에 호출하는 규칙을 의미한다. 예를 들어:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;dns&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;A &amp;rarr; A + B
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 경우 파싱 함수가 무한 재귀에 빠진다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해결 방법으로는 왼쪽 재귀 제거(Left recursion elimination)를 수행한다. 이를 위해 다음과 같이 문법을 재구성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;gherkin&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;A &amp;rarr; &amp;beta;1A' | &amp;beta;2A' | ... | &amp;beta;nA'
A' &amp;rarr; &amp;alpha;1A' | &amp;alpha;2A' | ... | &amp;alpha;mA' | &amp;epsilon;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여기서 &amp;epsilon;는 empty(빈 문자열)이다. 이런 변형을 통해 문법이 LL 문법으로 바뀐다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Pairwise Disjointness Test (쌍별로 분리성 테스트)&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;LL 파서의 다른 조건은 각 규칙의 오른쪽 부분(RHS)이 서로 분리(disjoint)되어야 한다는 것이다. 즉, 다음과 같은 두 규칙이 있다고 할 때:&lt;/p&gt;
&lt;pre class=&quot;1c&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;A &amp;rarr; &amp;alpha; | &amp;beta;
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;두 규칙 &amp;alpha;와 &amp;beta;가 시작하는 첫 토큰의 집합이 겹치지 않아야 한다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Left Factoring (왼쪽 인수분해)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위에서 설명한 Pairwise Disjointness 조건을 만족시키기 위해 문법을 수정하는 것이 Left Factoring이다. 이는 공통된 앞부분을 따로 떼어내 새로운 비단말을 만드는 과정이다. 예:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;fsharp&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;변경 전:
&amp;lt;variable&amp;gt; &amp;rarr; identifier | identifier[&amp;lt;expression&amp;gt;]

변경 후 (Left Factoring 적용):
&amp;lt;variable&amp;gt; &amp;rarr; identifier &amp;lt;new&amp;gt;
&amp;lt;new&amp;gt; &amp;rarr; &amp;epsilon; | [&amp;lt;expression&amp;gt;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;b&gt;4.5 Bottom-Up Parsing (상향식 파싱)&lt;/b&gt;&lt;/h1&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4.5.1 The Parsing Problem for Bottom-Up Parsers (상향식 파서의 파싱 문제)&lt;/b&gt;&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;상향식 파싱의 개념&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;상향식 파서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;오른쪽 최단 유도(rightmost derivation)를 역으로 진행&lt;/b&gt;하면서 파싱을 수행한다. 즉, 주어진 입력에서부터 시작하여 점진적으로 문법의 시작 심볼(start symbol)로 역추적하는 방식이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예시 문법 (산술 표현식):&lt;/p&gt;
&lt;pre class=&quot;r&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;E &amp;rarr; E + T | T
T &amp;rarr; T * F | F
F &amp;rarr; (E) | id
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 문법은 앞서 본 재귀 하향식 파싱 문법과 동일한 표현식을 생성하지만, **좌측 재귀(left recursion)**를 포함하여 상향식 파싱에 적합하도록 작성된 문법이다. 이때 사용된 유도 과정은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;오른쪽 최단 유도&lt;/b&gt;이며, 역순으로 따라가면 바로 상향식 파싱 과정이다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Handle의 개념과 정의&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;상향식 파싱의 핵심 개념 중 하나는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;핸들(handle)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핸들(handle)이란?&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주어진 sentential form(유도된 문자열)에서 다음으로 축소(reduce)될 부분 문자열이다.&lt;/li&gt;
&lt;li&gt;공식적 정의는 다음과 같다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;stata&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;정의: &amp;beta;가 sentential form &amp;gamma;의 핸들(handle)인 경우는 다음과 같다.
S &amp;rArr;*rm &amp;alpha;Aw &amp;rArr;rm &amp;alpha;&amp;beta;w
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 정의는 '핸들'이란 특정 부분(&amp;beta;)을 축소하면 이전 형태(sentential form)로 돌아갈 수 있는 유일한 문자열을 의미한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Phrase와 Simple Phrase&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Phrase:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;sentential form에서 하나 이상의 유도 과정을 거쳐서 나타난 비단말 기호로부터 생성된 문자열이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Simple Phrase:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;오직 한 단계의 유도만을 거쳐서 생성된 phrase이다.&lt;/li&gt;
&lt;li&gt;핸들은 항상 가장 왼쪽의 simple phrase이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예시 파스트리(Parse Tree)를 통해 이해할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-05 at 23.44.35.png&quot; data-origin-width=&quot;1514&quot; data-origin-height=&quot;488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JljAh/btsM97dQgbf/Eby0sxuDnMKZnW4wDbBzN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JljAh/btsM97dQgbf/Eby0sxuDnMKZnW4wDbBzN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JljAh/btsM97dQgbf/Eby0sxuDnMKZnW4wDbBzN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJljAh%2FbtsM97dQgbf%2FEby0sxuDnMKZnW4wDbBzN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1514&quot; height=&quot;488&quot; data-filename=&quot;Screenshot 2025-04-05 at 23.44.35.png&quot; data-origin-width=&quot;1514&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; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Phrase:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;파스트리의 하위 트리에서 생성된 문자열 전체&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Simple Phrase:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;파스트리에서 단 한 단계의 유도만 거쳐 나온 문자열 (예:&lt;span&gt;&amp;nbsp;&lt;/span&gt;id)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4.5.2 Shift-Reduce Algorithms (Shift-Reduce 알고리즘)&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;상향식 파서는 흔히&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Shift-Reduce 알고리즘&lt;/b&gt;으로 불린다. 두 가지 기본 동작을 수행하기 때문이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Shift:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;입력에서 다음 토큰을 파서의 스택으로 옮김.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Reduce:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;스택 상단의 핸들(RHS, 우측 부분)을 축소하여 해당하는 문법 규칙의 LHS(좌측 부분)으로 변경함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Pushdown Automaton (푸시다운 오토마타, PDA)&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;모든 파서는 일종의 푸시다운 오토마타(PDA)이며, 상향식 파서 역시 PDA로 볼 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PDA는 입력 심볼을 왼쪽에서 오른쪽으로 한 번씩만 스캔하며 스택을 사용하여 처리하는 단순한 기계이다.&lt;/li&gt;
&lt;li&gt;상향식 파서는 입력 문자열을 왼쪽에서 오른쪽으로 순차적으로 읽으며 핸들을 찾아 축소한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4.5.3 LR Parsers (LR 파서)&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;상향식 파싱 알고리즘은 다양하지만, 대표적으로 LR 알고리즘 계열이 있다.&lt;br /&gt;&lt;b&gt;LR은 다음의 의미를 가진다:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Left-to-right scanning (좌에서 우로 스캔)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Rightmost derivation (오른쪽 최단 유도)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;LR 알고리즘은 Donald Knuth에 의해 개발되었으며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;LR parsing table&lt;/b&gt;을 기반으로 한다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;LR Parsing의 장점:&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;대부분의 프로그래밍 언어 문법에 적용 가능하다.&lt;/li&gt;
&lt;li&gt;구문 오류(syntax error)를 신속히 찾아낼 수 있다.&lt;/li&gt;
&lt;li&gt;LL 문법보다 더 넓은 문법 클래스(LR 문법 클래스)를 지원한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;LR 파서 구조&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;LR 파서는 다음과 같은 형태의 스택을 사용한다.&lt;/p&gt;
&lt;pre class=&quot;sas&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;S₀ X₁ S₁ X₂ S₂ ... Xₘ Sₘ
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;S&lt;/b&gt;는 상태(state),&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;X&lt;/b&gt;는 문법 심볼(grammar symbol)이다.&lt;/li&gt;
&lt;li&gt;상태(state)는 파싱 테이블(parsing table)에서의 위치를 나타내며, 심볼은 실제 문법에서 등장하는 토큰이나 비단말 기호이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;LR 파서 동작 구조 (그림 4.4 참고)&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-05 at 23.45.15.png&quot; data-origin-width=&quot;1608&quot; data-origin-height=&quot;562&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dgU1fJ/btsM9xqCT2T/jepWCykyt5YyY1ULOyOXq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dgU1fJ/btsM9xqCT2T/jepWCykyt5YyY1ULOyOXq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dgU1fJ/btsM9xqCT2T/jepWCykyt5YyY1ULOyOXq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdgU1fJ%2FbtsM9xqCT2T%2FjepWCykyt5YyY1ULOyOXq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1608&quot; height=&quot;562&quot; data-filename=&quot;Screenshot 2025-04-05 at 23.45.15.png&quot; data-origin-width=&quot;1608&quot; data-origin-height=&quot;562&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;gherkin&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;Parse Stack       Input
| S₀ X₁ S₁ ... Xₘ Sₘ | aᵢ aᵢ₊₁ ... aₙ $ |
&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;파서는 다음 구성요소를 갖는다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Parsing Table:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;파싱을 제어하는 ACTION과 GOTO 테이블로 구성.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Parser Code:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;파싱 테이블의 내용을 이용하여 입력을 분석하는 코드.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;LR Parsing Table (LR 파싱 테이블)&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;LR 파싱 테이블은 다음 두 부분으로 구성된다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ACTION 테이블:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;현재 상태(state)와 입력 토큰(token)에 따라 다음 행동을 결정한다 (shift, reduce, accept, error).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GOTO 테이블:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;reduce 후 어떤 상태로 이동할지를 결정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;LR 파서의 행동(action):&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Shift:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;입력에서 토큰을 하나 스택으로 옮기고 새 상태로 전환.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Reduce:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;핸들을 스택에서 제거하고 LHS로 축소한 뒤, 해당 상태로 이동.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Accept:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;입력이 성공적으로 파싱됨을 의미.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Error:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;구문 오류가 발생하여 오류 처리 루틴 호출.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예시 문법을 통한 실제 파싱 테이블이 제공된다(그림 4.5 참고).&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;LR Parsing 예시 (예시 문자열:&lt;span&gt;&amp;nbsp;&lt;/span&gt;id + id * id)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-05 at 23.45.39.png&quot; data-origin-width=&quot;1540&quot; data-origin-height=&quot;1008&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZtUM3/btsM90eTczW/OamtPgiEPptZ9wKnIOuzv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZtUM3/btsM90eTczW/OamtPgiEPptZ9wKnIOuzv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZtUM3/btsM90eTczW/OamtPgiEPptZ9wKnIOuzv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZtUM3%2FbtsM90eTczW%2FOamtPgiEPptZ9wKnIOuzv1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1540&quot; height=&quot;1008&quot; data-filename=&quot;Screenshot 2025-04-05 at 23.45.39.png&quot; data-origin-width=&quot;1540&quot; data-origin-height=&quot;1008&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-05 at 23.46.04.png&quot; data-origin-width=&quot;1196&quot; data-origin-height=&quot;738&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GWP5F/btsNaBemTxi/QYQ3L9GydtcsMP3HITXDbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GWP5F/btsNaBemTxi/QYQ3L9GydtcsMP3HITXDbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GWP5F/btsNaBemTxi/QYQ3L9GydtcsMP3HITXDbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGWP5F%2FbtsNaBemTxi%2FQYQ3L9GydtcsMP3HITXDbk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1196&quot; height=&quot;738&quot; data-filename=&quot;Screenshot 2025-04-05 at 23.46.04.png&quot; data-origin-width=&quot;1196&quot; data-origin-height=&quot;738&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제 LR 테이블을 이용해 입력 문자열을 파싱하는 과정 예시(trace)를 보여준다.&lt;/li&gt;
&lt;li&gt;스택(Stack), 입력(Input), 행동(Action)을 단계별로 추적하여 최종적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;Accept&lt;span&gt;&amp;nbsp;&lt;/span&gt;상태에 이르는 과정을 명확히 보여준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Parsing Table 자동 생성&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제 프로그래밍 언어를 위한 문법의 LR 테이블을 손으로 만드는 것은 비효율적이다. 따라서, yacc와 같은 자동화된 소프트웨어 도구를 사용하여 자동으로 생성한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;b&gt;Summary&lt;/b&gt;&lt;/h1&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;구문 분석(Syntax analysis)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;은 프로그래밍 언어 구현에 필수적인 요소이며, 보통 언어의 문법(grammar)을 기반으로 이루어진다.
&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;BNF(Backus-Naur Form)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;형태로 나타낸다.&lt;/li&gt;
&lt;li&gt;문법 분석은 보통&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Lexical analysis(어휘 분석)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Syntax analysis(구문 분석)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;로 나눈다.&lt;/li&gt;
&lt;li&gt;이유는 단순성, 효율성, 이식성 때문이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;어휘 분석기(Lexical Analyzer)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;는 소스코드를 토큰(Token)으로 나누는 작업을 한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;토큰은 식별자, 리터럴 등으로 나누며, 각 토큰은 숫자 코드(token code)로 표현된다.&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;자동 생성 소프트웨어 도구 사용 (예: lex)&lt;/li&gt;
&lt;li&gt;수동으로 상태 전이표(State transition table)를 구성하여 제작&lt;/li&gt;
&lt;li&gt;상태 다이어그램(State diagram)을 직접 코드로 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구문 분석기(Syntax Analyzer)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;는 두 가지 목표가 있다:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문장의 구문 오류를 찾아내는 것&lt;/li&gt;
&lt;li&gt;파스트리(Parse Tree)를 만들어내는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;파싱 방법&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;은 크게 **하향식(Top-down)**과 **상향식(Bottom-up)**으로 나뉜다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하향식은 문법의 왼쪽에서 오른쪽으로 전개하며, 파스트리를 위에서 아래로 만든다.&lt;/li&gt;
&lt;li&gt;상향식은 오른쪽 유도(rightmost derivation)를 역순으로 진행하며, 파스트리를 아래에서 위로 만든다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;재귀 하향식 파서(Recursive-descent parser)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;는 EBNF 문법을 기반으로 만들어진 LL 파서이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 비단말(nonterminal)에 대응되는 서브 프로그램을 만들어 처리한다.&lt;/li&gt;
&lt;li&gt;왼쪽 재귀(Left recursion)와 pairwise disjointness(서로 구분 가능한 RHS) 문제가 있을 수 있다.&lt;/li&gt;
&lt;li&gt;왼쪽 재귀는 제거가 가능하고, pairwise disjointness 문제는 left factoring(왼쪽 인수분해)을 통해 해결 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상향식 파싱(Bottom-up parsing)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;은 핸들(Handle)을 찾아 문법의 왼쪽 부분(LHS)으로 축소(Reduce)하는 과정을 반복한다.
&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;LR 파서 테이블은 ACTION과 GOTO로 구성되며 shift와 reduce를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1 style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;b&gt;&amp;nbsp;Review Questions&lt;/b&gt;&lt;/h1&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;1. BNF가 비공식적 설명보다 장점이 있는 이유&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정확성, 명료성, 일관성&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;때문. 비공식적 설명은 애매할 수 있지만 BNF는 모호성을 없앤 형식적인 방법이기 때문이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;2. 어휘 분석기가 구문 분석기의 프론트 엔드인 이유&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&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;3. Finite automata와 Regular grammar의 정의&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Finite Automata:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;유한한 개수의 상태(state)를 가진 기계로, 입력 문자열을 읽으며 상태 전이를 통해 입력 문자열의 유효성을 검사한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Regular grammar:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;정규 언어를 생성하는 가장 간단한 형태의 문법으로, 하나의 비단말 기호에서 단말 기호 또는 단말 기호와 비단말 기호의 결합 형태로 표현된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;4. 상태 다이어그램을 이용한 어휘 분석기 구축 방법&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&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;5. 어휘 분석기 구축의 세 가지 접근법&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자동화 도구 사용 (예: lex)&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;6. 형식 언어의 다양한 문법 심볼&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;**비단말(nonterminal)**과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;단말(terminal)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;심볼이 있다. 비단말은 추가로 전개 가능한 문법 요소이며, 단말은 최종적으로 코드에 직접 등장하는 요소이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;7. 상태 다이어그램에서 개별 문자 대신 문자 클래스를 사용하는 이유&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&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;8. 구문 분석의 두 가지 목표&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구문 오류의 탐지&lt;/li&gt;
&lt;li&gt;파스 트리 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;9. 파싱 알고리즘의 복잡도 설명&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반적으로 문법의 복잡도는 O(n&amp;sup3;)이지만, 프로그래밍 언어에 쓰이는 문법은 O(n)으로 더 효율적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;10. 재귀 하향식 파서 설명&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 비단말마다 재귀적으로 호출되는 파서이며 EBNF와 잘 맞는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;11. LL 알고리즘의 두 L의 의미&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Left-to-right scan(왼쪽부터 읽기)과 Leftmost derivation(왼쪽부터 유도 전개)을 의미한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;12. 재귀 하향식 서브프로그램 작성 규칙&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서브프로그램이 시작할 때 다음 입력 토큰(nextToken)이 항상 미리 준비되어 있다고 가정하고 시작한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;13. 토큰 코드로 숫자 대신 이름 붙인 상수를 쓰는 이유&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&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;14. 하나의 RHS를 가진 규칙의 재귀 하향식 서브프로그램 작성법&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RHS의 심볼을 차례로 비교 및 호출하며, 일치하지 않으면 구문 오류를 리턴한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;15. 하향식 파서를 어렵게 하는 두 가지 문법적 특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;왼쪽 재귀(left recursion)&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;pairwise disjointness 조건 위배&lt;/b&gt;이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;16. 직접 왼쪽 재귀 정의&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문법 규칙의 왼쪽에서 자기 자신을 바로 다시 호출하는 형태 (예:&lt;span&gt;&amp;nbsp;&lt;/span&gt;A &amp;rarr; A &amp;alpha;)이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;17. Pairwise disjointness 테스트 설명&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 nonterminal의 각 RHS의 첫 번째 심볼 집합이 겹치지 않아야 하는 조건이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;18. Left factoring의 한계&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 pairwise disjointness 문제를 해결하지는 못한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;19~20. Phrase와 Simple Phrase 정의 및 차이&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Phrase는 파스트리의 한 노드에서 나온 모든 문자열, Simple Phrase는 오직 한 단계만의 유도로 생성된 phrase이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;21. Handle의 특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;항상 sentential form에서 가장 왼쪽에 위치한 simple phrase이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;22. 모든 파서의 기반이 되는 수학적 기계&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Pushdown Automaton(PDA)이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;23. LR 파서의 단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&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;24. 상향식 파서를 Shift-Reduce 알고리즘이라 하는 이유&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;shift와 reduce 동작을 주로 수행하기 때문이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;25. LR 파서에서 Parse stack의 목적&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&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;26. Canonical LR 파싱 테이블 변형의 속성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&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;27. 모든 프로그래밍 언어 파서가 PDA인 이유&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스택을 이용한 구문 처리 능력을 제공하기 때문이다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Book/Concepts of Programming Language</category>
      <category>pl</category>
      <category>Programming Language</category>
      <author>S0LL</author>
      <guid isPermaLink="true">https://sol248.tistory.com/156</guid>
      <comments>https://sol248.tistory.com/156#entry156comment</comments>
      <pubDate>Sat, 5 Apr 2025 23:58:37 +0900</pubDate>
    </item>
    <item>
      <title>Chapter3: Describing Syntax and Semantics</title>
      <link>https://sol248.tistory.com/155</link>
      <description>&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3.1 Introduction (서론)&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로그래밍 언어를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;간결하면서도 이해하기 쉽게 기술&lt;/b&gt;&lt;/span&gt;하는 작업은 매우 어렵지만, 그 언어의 성공을 위해 반드시 필요하다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;과거 ALGOL 60과 ALGOL 68이라는 언어는 매우 간결하고 형식적인 설명을 사용했으나, 당시 사람들에게 익숙하지 않은 새로운 표기법(notation) 때문에 오히려 이해하기가 어려웠고 그 결과 두 언어 모두 널리 받아들여지지 못했다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;반대로, 어떤 언어는 너무 간략하고 비형식적인 설명 때문에 조금씩 다른 여러 방언(dialect)이 생겨 혼란이 발생하기도 했다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;언어를 설명하는 과정에서 중요한 어려움 중 하나는 이 언어 설명을 읽고 이해해야 하는 사람들이 매우 다양하다는 점이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;초기 평가자(initial evaluators)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;언어의 초기 평가를 담당하는 사람들이다. 새로운 프로그래밍 언어는 설계가 끝나기 전 여러 단계에서 여러 사람의 평가를 받게 되며, 이러한 평가에서 이해하기 쉬운 언어 기술이 중요하다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;언어 구현자(implementors)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로그래밍 언어를 실제로 구현하는 사람들이다. 이들은 언어의 표현식(expression), 문장(statement), 프로그램 단위(program unit)의 구조뿐 아니라, 그것들이 실행될 때의 의도된 효과(intended effect)까지 정확히 이해해야 한다. 언어의 설명이 명확하고 정확할수록 구현자들의 작업 난이도가 낮아진다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;언어 사용자(users)&lt;/b&gt;&lt;/span&gt;: 실제 프로그래밍 언어로 소프트웨어를 개발하는 프로그래머들이다. 이들은 프로그래밍 문제에 대한 해결책을 만들기 위해 언어 매뉴얼을 참고한다. 따라서 교재나 매뉴얼은 이들에게 있어 언어를 배우고 활용하는 유일한 권위적인 정보원이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로그래밍 언어를 공부할 때에는 자연어(natural languages)를 공부할 때와 마찬가지로 크게 두 가지 측면으로 나누어 볼 수 있다:&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Syntax (구문)&lt;/b&gt;&lt;/span&gt;: 언어의 표현식, 문장, 프로그램 단위와 같은 구조적 형태를 말한다. 쉽게 말해 언어가 작성되는 형식을 의미한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Semantics (의미)&lt;/b&gt;&lt;/span&gt;: 표현식, 문장, 프로그램 단위가 가지고 있는 의미, 즉 언어의 문장들이 실제로 수행할 동작을 의미한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;Example (예시)&lt;/b&gt;&lt;/span&gt;: Java의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;while&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;문을 보면,&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;while (boolean_expr) statement&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위는 syntax(구문)이다. 이 구문에 대한 semantics(의미)는 다음과 같다:&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;이 문장의 Boolean 표현식(boolean_expr)이 참(true)이라면, 안쪽에 있는 statement가 수행된다. 그런 다음 다시 Boolean 표현식으로 돌아가 반복 여부를 판단한다. Boolean 표현식이 거짓(false)이면, 프로그램의 흐름이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;while&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;구문 다음에 오는 문장으로 넘어간다.&lt;/blockquote&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;종종 설명을 위해 syntax와 semantics를 분리하지만, 실제로는 이 둘이 밀접하게 연관되어 있다. 잘 설계된 프로그래밍 언어에서는 구문이 그 자체로 의미를 강력히 암시하는 경향이 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;일반적으로 semantics를 설명하는 것은 syntax를 설명하는 것보다 훨씬 어렵다. 그 이유는 syntax에 대해서는 간결하고 보편적으로 인정된 표기법(notation)이 존재하지만, semantics에 대해서는 아직 그러한 표기법이 만들어지지 않았기 때문이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3.2 The General Problem of Describing Syntax (구문을 기술하는 일반적 문제점)&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;언어(자연어든, 인공 언어든)는 특정 알파벳(alphabet)에서 나오는 문자열의 집합(set of strings)으로 볼 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이런 문자열들을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;문장(sentence)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;또는 명령문(statement)이라고 한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;언어의 syntax 규칙은 어떤 문자열들이 그 언어의 알파벳으로 구성되어 언어에 포함되는지를 결정한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 영어는 복잡한 구문 규칙을 가지고 있지만, 프로그래밍 언어의 syntax는 이보다 훨씬 간단하다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로그래밍 언어의 syntax를 공식적으로 기술할 때, 자주 낮은 단계의 작은 단위들을 생략하고 기술한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;가장 낮은 단계의 문법적 단위(syntactic unit)는 lexeme(어휘소)라고 한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;lexeme의 기술은 일반적으로 언어의 구문적 설명과는 별도의 lexical specification(어휘 규격)에서 다룬다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로그래밍 언어의 lexeme은 숫자 리터럴(numeric literals), 연산자(operators), 예약어(special words) 등을 포함한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Lexeme들은 비슷한 특징을 가진 그룹으로 나뉘는데, 예를 들어 변수, 메서드, 클래스의 이름들은 모두 identifier(식별자)라는 그룹으로 분류될 수 있다. 이 그룹을 나타내는 이름을 token(토큰)이라고 한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;Example (예시)&lt;/b&gt;&lt;/span&gt;: Java의 아래와 같은 문장이 있다고 하자.&lt;/p&gt;
&lt;pre class=&quot;ini&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;index = 2 * count + 17;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 문장의 lexeme과 token은 다음과 같다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Lexeme&lt;/b&gt;&lt;b&gt;Token&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;color: #000000; text-align: start; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;index&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;identifier&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;=&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;equal_sign&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;2&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;int_literal&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;*&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;mult_op&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;count&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;identifier&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;+&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;plus_op&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;17&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;int_literal&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;semicolon&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.2.1 Language Recognizers (언어 인식자)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;언어를 공식적으로 정의하는 방식 중 하나는 인식(recognition)을 이용하는 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;인식을 이용하면, 언어에 속하는 문자열을 판별하는 기계(device) R을 만든다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;즉, R은 입력된 문자열이 해당 언어에 속하는지 아닌지를 판단하여 수락(accept) 또는 거부(reject)하는 역할을 한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;컴파일러의 구문 분석기(syntax analyzer)는 대표적인 language recognizer이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;모든 가능한 문장을 다 테스트하지 않고, 단지 주어진 프로그램이 그 언어의 구문 규칙에 맞는지만 검사한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이런 구조를 parser(파서)라고 부른다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.2.2 Language Generators (언어 생성기)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다른 방법은 언어의 문장을 생성(generation)하는 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이것은 마치 버튼을 누를 때마다 문장이 생성되는 장치를 의미한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;언어 생성기는 사용자가 syntax를 이해하기 쉽게 만든다는 장점이 있지만, 컴파일러와 같이 syntax가 올바른지 검사하는 데에는 효율적이지 않다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;언어 생성기와 인식자는 본질적으로 밀접하게 연결되어 있으며, 이것이 컴파일러 이론과 프로그래밍 언어 설계에 있어서 중요한 발견이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3.3 Formal Methods of Describing Syntax (구문 기술의 형식적 방법)&lt;/b&gt;&lt;/h3&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3.3.1 Backus-Naur Form and Context-Free Grammars (배커스-나우어 형식과 문맥 자유 문법)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1950년대 중후반에 언어학자인 노암 촘스키(Noam Chomsky)와 프로그래밍 언어 연구자인 존 배커스(John Backus)는 독립적인 연구를 통해 같은 문법 기술 방식을 발견했다. 이것이 현재 가장 널리 사용되는 구문 기술 방식으로 자리 잡았다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.3.1.1 Context-Free Grammars (문맥 자유 문법)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1950년대 중반 촘스키는 문법을 네 가지 클래스로 구분했다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그중 정규 문법(regular grammars)과 문맥 자유 문법(context-free grammars)이 프로그래밍 언어 기술에 매우 유용하게 쓰이게 되었다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;정규 문법&lt;/b&gt;&lt;/span&gt;은 주로 언어의 토큰(token)을 기술하는 데 사용된다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;문맥 자유 문법&lt;/b&gt;&lt;/span&gt;은 프로그래밍 언어 전체의 구문 기술에 사용된다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;촘스키는 언어학자였기 때문에 처음부터 컴퓨터 언어에 관심이 있었던 것은 아니다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그러나 후에 그의 이론이 프로그래밍 언어 기술에 적용되었다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.3.1.2 Origins of Backus-Naur Form (BNF의 기원)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;ALGOL 58을 설계하던 중, 배커스가 처음으로 새로운 구문 기술 방식을 발표했다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이후 피터 나우어(Peter Naur)가 ALGOL 60을 기술할 때 이를 조금 수정했고, 그 결과 나온 것이 배커스-나우어 형식(BNF)이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;BNF는 자연스럽고 간결한 구문 표기법이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로그래밍 언어의 구문을 기술하는 가장 보편적인 방법이 되었으며, 사실상 촘스키가 제안한 문맥 자유 문법과 거의 같다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이후부터 이 책에서 문법(grammar)은 문맥 자유 문법을 지칭한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.3.1.3 Fundamentals (기본 개념)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;BNF는 다른 언어를 설명하는 언어인 메타언어(metalanguage)이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;BNF 문법에서 정의하는 규칙을 다음과 같은 형식으로 표현한다:&lt;/p&gt;
&lt;pre class=&quot;xml&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;&amp;lt;assign&amp;gt; &amp;rarr; &amp;lt;var&amp;gt; = &amp;lt;expression&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;왼쪽(LHS)은 정의되는 추상 구조를 의미한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;오른쪽(RHS)은 이 구조를 정의하는 구성 요소들이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위 규칙은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;lt;assign&amp;gt;&lt;/span&gt;이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;lt;var&amp;gt;&lt;/span&gt;라는 변수 뒤에 등호(=)가 오고 그 뒤에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;lt;expression&amp;gt;&lt;/span&gt;이 따라오는 구조로 정의된다는 의미이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;BNF에서는 추상적 요소들을 nonterminals(비단말 기호)라 부르고, lexeme과 token은 terminals(단말 기호)라 부른다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.3.1.4 Describing Lists (목록의 표현)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;BNF는 수학에서 쓰이는 생략 부호(&lt;span&gt;...&lt;/span&gt;)를 사용하지 않는다. 대신, 재귀(recursion)를 통해 목록을 정의한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예:&lt;/p&gt;
&lt;pre class=&quot;xml&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;&amp;lt;ident_list&amp;gt; &amp;rarr; identifier | identifier, &amp;lt;ident_list&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이는 identifier들의 목록을 나타낸다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.3.1.5 Grammars and Derivations (문법과 유도)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;문법은 언어의 문장을 생성하는 규칙들의 집합이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;문장을 생성하는 과정을 유도(derivation)라고 한다. 유도는 시작 기호(start symbol)에서 시작하여 비단말 기호를 규칙에 따라 대체하는 과정이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;EXAMPLE 3.1 (작은 언어 문법)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.26.41.png&quot; data-origin-width=&quot;958&quot; data-origin-height=&quot;670&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vn12Y/btsM6FU11R8/qrho7nQzPMutiLOvjQdUJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vn12Y/btsM6FU11R8/qrho7nQzPMutiLOvjQdUJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vn12Y/btsM6FU11R8/qrho7nQzPMutiLOvjQdUJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvn12Y%2FbtsM6FU11R8%2Fqrho7nQzPMutiLOvjQdUJ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;958&quot; height=&quot;670&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.26.41.png&quot; data-origin-width=&quot;958&quot; data-origin-height=&quot;670&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 예제는 간단한 할당 언어를 정의하며, 문장 생성 과정을 단계별로 보여준다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.3.1.6 Parse Trees (파스 트리)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;유도 과정은 계층적 구조로 나타낼 수 있는데, 이것을 파스 트리(parse tree)라 부른다. 그림 3.1은 문장&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;A = B * (A + C)&lt;/span&gt;의 파스 트리를 나타낸다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.27.37.png&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;732&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9Z4qJ/btsM5lwKRdB/j2lVf7ojiP1DK2ZmErmWKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9Z4qJ/btsM5lwKRdB/j2lVf7ojiP1DK2ZmErmWKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9Z4qJ/btsM5lwKRdB/j2lVf7ojiP1DK2ZmErmWKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9Z4qJ%2FbtsM5lwKRdB%2Fj2lVf7ojiP1DK2ZmErmWKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;950&quot; height=&quot;732&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.27.37.png&quot; data-origin-width=&quot;950&quot; data-origin-height=&quot;732&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.3.1.7 Ambiguity (모호성)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하나의 문장에 여러 파스 트리가 존재하면 모호(ambiguous)하다고 한다. 예제 3.3과 그림 3.2에서 모호성을 보여준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.28.51.png&quot; data-origin-width=&quot;1030&quot; data-origin-height=&quot;1888&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2xN3M/btsM4SuO7Ai/EW7WsyssiHZ49zLkzJySr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2xN3M/btsM4SuO7Ai/EW7WsyssiHZ49zLkzJySr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2xN3M/btsM4SuO7Ai/EW7WsyssiHZ49zLkzJySr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2xN3M%2FbtsM4SuO7Ai%2FEW7WsyssiHZ49zLkzJySr0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1030&quot; height=&quot;1888&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.28.51.png&quot; data-origin-width=&quot;1030&quot; data-origin-height=&quot;1888&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.3.1.8 Operator Precedence (연산자 우선순위)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;모호성을 피하려면 문법에 연산자 우선순위(precedence)를 반영해야 한다. 예제 3.4와 그림 3.3이 이를 보여준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.29.39.png&quot; data-origin-width=&quot;878&quot; data-origin-height=&quot;184&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0Gncb/btsM6hHaciW/XcOBwP7BVMM97i6UvCLxQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0Gncb/btsM6hHaciW/XcOBwP7BVMM97i6UvCLxQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0Gncb/btsM6hHaciW/XcOBwP7BVMM97i6UvCLxQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0Gncb%2FbtsM6hHaciW%2FXcOBwP7BVMM97i6UvCLxQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;878&quot; height=&quot;184&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.29.39.png&quot; data-origin-width=&quot;878&quot; data-origin-height=&quot;184&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.29.46.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;1294&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJGdn7/btsM6qKw4RB/h9ByxxmPuU9hPzBmXavqtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJGdn7/btsM6qKw4RB/h9ByxxmPuU9hPzBmXavqtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJGdn7/btsM6qKw4RB/h9ByxxmPuU9hPzBmXavqtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJGdn7%2FbtsM6qKw4RB%2Fh9ByxxmPuU9hPzBmXavqtk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;962&quot; height=&quot;1294&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.29.46.png&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;1294&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.30.50.png&quot; data-origin-width=&quot;908&quot; data-origin-height=&quot;1684&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k3H4l/btsM4Q4P36M/bJddVwtnpFW2ZjLZk6bKKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k3H4l/btsM4Q4P36M/bJddVwtnpFW2ZjLZk6bKKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k3H4l/btsM4Q4P36M/bJddVwtnpFW2ZjLZk6bKKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk3H4l%2FbtsM4Q4P36M%2FbJddVwtnpFW2ZjLZk6bKKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;908&quot; height=&quot;1684&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.30.50.png&quot; data-origin-width=&quot;908&quot; data-origin-height=&quot;1684&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.3.1.9 Associativity of Operators (연산자 결합성)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;동일한 연산자의 연속적 표현에서 어느 쪽부터 평가할지 정하는 규칙을 결합성(associativity)이라 한다. 그림 3.4는 왼쪽 결합성을 보여준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.31.18.png&quot; data-origin-width=&quot;868&quot; data-origin-height=&quot;1640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dt3hxv/btsM51xKZAJ/XZjoZItAhCu3Dx3N6p46o0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dt3hxv/btsM51xKZAJ/XZjoZItAhCu3Dx3N6p46o0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dt3hxv/btsM51xKZAJ/XZjoZItAhCu3Dx3N6p46o0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdt3hxv%2FbtsM51xKZAJ%2FXZjoZItAhCu3Dx3N6p46o0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;868&quot; height=&quot;1640&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.31.18.png&quot; data-origin-width=&quot;868&quot; data-origin-height=&quot;1640&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.3.1.10 An Unambiguous Grammar for if-else (if-else를 위한 모호하지 않은 문법)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;if-else&lt;/span&gt;의 모호성을 해결하는 문법을 소개한다. 예제와 그림 3.5로 그 문제점과 해결 방안을 제시한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.31.39.png&quot; data-origin-width=&quot;964&quot; data-origin-height=&quot;1370&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cacYpW/btsM6gBuMTA/k4KljYd2PvotAl8zR1YqOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cacYpW/btsM6gBuMTA/k4KljYd2PvotAl8zR1YqOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cacYpW/btsM6gBuMTA/k4KljYd2PvotAl8zR1YqOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcacYpW%2FbtsM6gBuMTA%2Fk4KljYd2PvotAl8zR1YqOK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;964&quot; height=&quot;1370&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.31.39.png&quot; data-origin-width=&quot;964&quot; data-origin-height=&quot;1370&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3.3.2 Extended BNF (확장된 BNF, EBNF)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;BNF를 보다 명확하고 편리하게 확장한 것이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;EBNF&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;주요한 확장 요소는 다음과 같다:&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;대괄호[]&lt;/b&gt;&lt;/span&gt;: 선택적 요소(optional)&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;중괄호{}&lt;/b&gt;&lt;/span&gt;: 반복 요소(iteration)&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;괄호와 &amp;lsquo;|&amp;rsquo;&lt;/b&gt;&lt;/span&gt;: 선택적 목록(multiple-choice options)&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;EXAMPLE 3.5&lt;/b&gt;&lt;/span&gt;: BNF와 EBNF의 표현 비교를 보여준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.32.20.png&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;2484&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PtDlh/btsM68Cro0v/yk9qHJznVVORQrzlBcwqK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PtDlh/btsM68Cro0v/yk9qHJznVVORQrzlBcwqK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PtDlh/btsM68Cro0v/yk9qHJznVVORQrzlBcwqK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPtDlh%2FbtsM68Cro0v%2Fyk9qHJznVVORQrzlBcwqK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;2484&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.32.20.png&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;2484&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;EBNF는 다양한 변형이 있으며, ISO 표준(ISO/IEC 14977)도 존재하지만 실제로 자주 사용되진 않는다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.3.3 Grammars and Recognizers (문법과 인식자)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이전에 설명한 것처럼 문법과 인식자(recognizer)는 밀접한 관계가 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;문법이 주어지면 그것을 인식하는 기계적 인식자를 자동으로 구성할 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;대표적인 도구로는 yacc(yet another compiler compiler)가 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3.4 Attribute Grammars (속성 문법)&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;속성 문법(Attribute Grammar)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;은 문맥 자유 문법(context-free grammar)보다 프로그래밍 언어의 구조를 더 자세히 설명하기 위해 사용하는 기술이다. 문맥 자유 문법의 확장판이라 볼 수 있으며, 특히 언어의 타입 호환성(type compatibility) 같은 규칙을 명료하게 기술할 수 있게 해준다. 속성 문법의 구체적 정의에 앞서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;정적 의미론(Static Semantics)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;의 개념을 명확히 할 필요가 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;역사적 배경(history note)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;속성 문법은 광범위한 분야에서 사용되어 왔다. 구문과 정적 의미론에 대한 완전한 설명을 제공하거나, 컴파일러 생성 시스템의 입력으로 사용되었으며, 문법 기반 편집 시스템(syntax-directed editing systems), 자연어 처리 시스템 등에도 활용되었다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.4.1 Static Semantics (정적 의미론)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;정적 의미론(static semantics)은 BNF로 설명하기 어렵거나 불가능한 언어 규칙을 다룬다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, Java에서는 부동소수점 타입의 값을 정수 타입의 변수에 넣을 수 없다(반대는 가능하다).&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이러한 규칙을 BNF로 설명하려면 지나치게 복잡한 문법이 필요해진다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;BNF로 아예 불가능한 규칙의 또 다른 예로는, &amp;ldquo;모든 변수는 사용되기 전에 반드시 선언되어야 한다&amp;rdquo;라는 규칙이 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;정적 의미론은 프로그램 실행 중의 의미와는 간접적인 관계만을 가지며, 주로 프로그램의 타입 제한 같은 구문적 제약에 초점을 맞춘다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;정적 의미론이라 불리는 이유는 컴파일 시간(compile time)에 이 분석이 이루어지기 때문이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;정적 의미론을 기술하기 위해 보다 강력한 방법으로 도널드 크누스(Donald Knuth)가 속성 문법을 제안하였다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;속성 문법은 프로그램의 구문과 정적 의미론을 모두 기술할 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.4.2 Basic Concepts (기본 개념)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;속성 문법은 문맥 자유 문법에 다음 요소를 추가한 것이다:&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;속성(Attributes)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 문법 기호에 연결되어 있고 변수처럼 값이 할당될 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;속성 계산 함수(Attribute computation functions)&lt;/b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 문법 규칙과 연결되어 속성의 값을 계산한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;술어 함수(Predicate functions)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 정적 의미론 규칙을 기술하는 데 사용되는 불리언(Boolean) 표현이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.4.3 Attribute Grammars Defined (속성 문법의 정의)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;속성 문법은 다음의 특성을 추가로 가진 문법이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;각 문법 기호 X에는 속성 집합 A(X)가 연결된다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;A(X)는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;합성 속성(synthesized attributes)&lt;/b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;상속 속성(inherited attributes)&lt;/b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;으로 구성된다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;합성 속성&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 파스 트리의 아래에서 위로(자식에서 부모 방향으로) 의미 정보를 전달한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;상속 속성&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 위에서 아래로(부모에서 자식 방향으로), 혹은 형제 간 의미 정보를 전달한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;각 문법 규칙에는 속성을 계산하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;의미 함수(semantic functions)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;가 연결되어 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;술어 함수(predicate function)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;는 속성들이 언어의 정적 의미 규칙을 만족하는지 여부를 검사하며, false면 구문이나 정적 의미 규칙에 어긋난다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;속성 값을 모두 계산한 파스 트리를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;fully attributed&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라고 부른다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.4.4 Intrinsic Attributes (고유 속성)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;고유 속성(Intrinsic attributes)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;은 파스 트리 외부에서 결정되는 리프 노드의 합성 속성이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 변수의 타입이 심볼 테이블(symbol table)에서 정해진다. 파스 트리의 초기 단계에서는 오직 리프 노드의 고유 속성만 값이 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.4.5 Examples of Attribute Grammars (속성 문법의 예제)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다음은 속성 문법을 사용하여 정적 의미론을 표현하는 간단한 예제이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Ada 프로시저 이름 검사 예제:&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Ada 언어에서 프로시저 이름과 끝나는 이름이 일치해야 한다는 규칙은 BNF로 표현할 수 없으며, 속성 문법으로 표현할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;delphi&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;&amp;lt;proc_def&amp;gt; &amp;rarr; procedure &amp;lt;proc_name&amp;gt;[1] &amp;lt;proc_body&amp;gt; end &amp;lt;proc_name&amp;gt;[2];
Predicate: &amp;lt;proc_name&amp;gt;[1].string == &amp;lt;proc_name&amp;gt;[2].string&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;간단한 할당문의 타입 검사 예제 (EXAMPLE 3.6):&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.36.23.png&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;1208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctzGxw/btsM7eCCFaS/VT4rg9rrM2kXt7Q2eMNiJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctzGxw/btsM7eCCFaS/VT4rg9rrM2kXt7Q2eMNiJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctzGxw/btsM7eCCFaS/VT4rg9rrM2kXt7Q2eMNiJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctzGxw%2FbtsM7eCCFaS%2FVT4rg9rrM2kXt7Q2eMNiJk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;684&quot; height=&quot;1208&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.36.23.png&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;1208&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;속성 문법으로 타입을 검사하는 할당문의 예시이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;문법 규칙과 의미 규칙, 술어를 정의하여 표현하였다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;파스 트리 예시 (&lt;span&gt;A = A + B&lt;/span&gt;)가 그림 3.6에 나타나 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.36.37.png&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;636&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/J1gDQ/btsM5vsw0fY/HsH7uuYYxaptniQes1HeDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/J1gDQ/btsM5vsw0fY/HsH7uuYYxaptniQes1HeDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/J1gDQ/btsM5vsw0fY/HsH7uuYYxaptniQes1HeDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJ1gDQ%2FbtsM5vsw0fY%2FHsH7uuYYxaptniQes1HeDk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;710&quot; height=&quot;636&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.36.37.png&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;636&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.4.6 Computing Attribute Values (속성 값의 계산)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;속성 값 계산 과정을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;파스 트리를 꾸미기(decorating)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라고 한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;상속 속성은 위에서 아래 방향으로, 합성 속성은 아래에서 위 방향으로 계산된다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;실제로는 문법 규칙에 따라 다양한 방향에서 값이 계산된다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;속성 계산의 흐름이 그림 3.7에 표현되어 있으며, 최종적으로 모든 속성이 계산된 파스 트리가 그림 3.8에 나와있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.37.20.png&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kyWJA/btsM42qz4Jg/xbqD8FapERV3mKxeW8uxZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kyWJA/btsM42qz4Jg/xbqD8FapERV3mKxeW8uxZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kyWJA/btsM42qz4Jg/xbqD8FapERV3mKxeW8uxZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkyWJA%2FbtsM42qz4Jg%2FxbqD8FapERV3mKxeW8uxZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;630&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.37.20.png&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;630&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.37.26.png&quot; data-origin-width=&quot;738&quot; data-origin-height=&quot;488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qMlJS/btsM7bFTZRp/fdy8S39iJ6D53MiLH7QxFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qMlJS/btsM7bFTZRp/fdy8S39iJ6D53MiLH7QxFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qMlJS/btsM7bFTZRp/fdy8S39iJ6D53MiLH7QxFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqMlJS%2FbtsM7bFTZRp%2Ffdy8S39iJ6D53MiLH7QxFk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;738&quot; height=&quot;488&quot; data-filename=&quot;Screenshot 2025-04-03 at 01.37.26.png&quot; data-origin-width=&quot;738&quot; data-origin-height=&quot;488&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3.4.7 Evaluation (속성 문법 평가)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;정적 의미론 규칙을 검사하는 일은 모든 컴파일러에서 필수적이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;속성 문법을 사용하여 언어의 모든 구문 및 정적 의미를 기술하는 주된 어려움은 복잡성과 크기이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;실제 프로그래밍 언어를 모두 표현하려면 매우 큰 문법이 필요하며, 큰 파스 트리에서의 속성 값 계산 또한 비용이 많이 든다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 덜 형식적인 속성 문법은 컴파일러 개발자에게 강력하고 일반적으로 사용되는 도구가 된다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3.5 Describing the Meanings of Programs: Dynamic Semantics&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;Dynamic semantics(동적 의미론)은 프로그램 실행 시(런타임에) 각 구문이 어떻게 동작하고 결과적으로 어떤 상태(state) 변화를 일으키는지에 대한 의미를 설명한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;정적 의미론(static semantics)과 달리, 동적 의미론은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;프로그램이 실제로 &amp;ldquo;실행&amp;rdquo;되었을 때 벌어지는 모든 과정&lt;/b&gt;&lt;/span&gt;을 모델링하려고 한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;이 절은 크게&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;조작적 의미론(operational semantics)&lt;/b&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;의미론적 의미론(denotational semantics)&lt;/b&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;공리적 의미론(axiomatic semantics)&lt;/b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이 세 가지 대표적인 기술 방법을 다룬다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.5.1 Operational Semantics (조작적 의미론)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심 아이디어&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;프로그램의 실행 과정을 &amp;ldquo;기계(또는 가상 기계)&amp;rdquo;가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;한 단계씩&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;상태를 변화시키는 모습으로 모델링한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;예: 표현식&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;E&lt;/span&gt;를 실행(평가)했을 때, 기계 상태(S)가 어떻게&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;(S &amp;rarr; S')&lt;/span&gt;로 변하는지, 또는 문장&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;C&lt;/span&gt;가 어떤 식으로 상태를 바꾸는지를 규칙화한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;두 가지 접근&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;Natural operational semantics(큰 단위 조작적 의미론)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;프로그램 전체의 실행을 큰 단위로 묘사한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;예를 들어, &amp;ldquo;이 프로그램을 한 번에 실행시켰을 때 최종 상태는 무엇인가?&amp;rdquo; 에 집중한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;주로 증명이나 간결한 설명에 유리하다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;Structural operational semantics(구조적 조작적 의미론)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;프로그램을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;구문 단위별&lt;/b&gt;&lt;/span&gt;로 쪼개어, 각 문장(혹은 표현식)이 어떤 식으로 상태를 변환하는지를 세부적으로 규정한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;프로그램의 구조와 평행하게 &amp;ldquo;작은 단계&amp;rdquo;로 상태 전이가 이루어지며, 이를 일련의 규칙들로 제시한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점 &amp;amp; 단점&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/span&gt;: 실제 컴퓨터에서 일어나는 실행 과정을 가장 직관적&amp;middot;직접적으로 나타낸다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/span&gt;: 복잡한 언어 전체에 대해 모든 단계를 세밀하게 정의하면 상당히 방대해져서, 문서화&amp;middot;이해가 어려울 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예시/그림&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;책에서는 간단한 조건문, 반복문 등에 대한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;조작적 의미 규칙&lt;/b&gt;&lt;/span&gt;을 예로 든다. 예컨대&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;if b then S1 else S2&lt;/span&gt;에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;b&lt;/span&gt;가 참인지 거짓인지에 따라 실행 경로가 어떻게 변하는지를 단계별로 나타낸 도표나 그림이 수록되어 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;어떤 표현식이 스택 머신에서 평가되는 과정을 &amp;ldquo;스택 상태 변화&amp;rdquo;로 보여주는 식의 예제도 등장할 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3.5.2 Denotational Semantics (의미론적 의미론)&lt;/b&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심 아이디어&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;프로그램의 구문 요소(표현식, 문장, 프로그램 단위 등)를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;수학적 객체&lt;/b&gt;&lt;/span&gt;(함수나 도메인)로 대응시켜, 그 &amp;ldquo;뜻(denotation)&amp;rdquo;을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;함수&lt;/b&gt;&lt;/span&gt;처럼 정의한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;예:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;E&lt;/span&gt;라는 표현식을 평가하는 함수를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;\mathcal{M}(\cdot)&lt;/span&gt;라고 두고, 입력 상태를 받아서 결과값(또는 새 상태)을 산출하는 형태로 구성한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;정의 방식&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;보통은 구문 분할(문맥 자유 문법의 구조)에 맞춰, 각 비단말 기호(nonterminal)별로 의미 함수를 정의한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;재귀&lt;/b&gt;&lt;/span&gt;적으로 정의되므로, 복잡한 프로그램도 하위 요소들의 의미 함수를 모아서 전체 의미가 결정된다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점 &amp;amp; 단점&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/span&gt;: 엄밀한 수학적 기초 위에 있기 때문에, 프로그램의 성질(예: 동등성, 종료, 불변식 등)을 논리적으로 증명하기 쉽다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/span&gt;: 추상화 수준이 높아, 실제 구현이나 직관적인 면에서는 접근성이 떨어질 수 있다. 큰 언어 전체를 전부 의미론적 의미론으로 기술하려면 매우 복잡해진다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예시/그림&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;책에서는 간단한 산술 표현식을 예로 들어, &amp;ldquo;덧셈 표현식&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;E1 + E2&lt;/span&gt;의 의미는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;\mathcal{M}(E1)&lt;/span&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;\mathcal{M}(E2)&lt;/span&gt;를 각각 구해 더한 값&amp;rdquo;이라는 식으로 정의하는 재귀 규칙을 보인다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;도식화 그림은 &amp;lsquo;문법 구조&amp;rsquo;와 &amp;lsquo;의미 함수&amp;rsquo;를 짝지어 보여주며, 최종적으로 프로그램 전체를 수학적 도메인으로 사상(mapping)하는 과정을 소개한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3.5.3 Axiomatic Semantics (공리적 의미론)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심 아이디어&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;프로그램 문장을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;논리식&lt;/b&gt;&lt;/span&gt;(Hoare triple)으로 표현하고, 프로그램의 &amp;ldquo;정확성(correctness)&amp;rdquo;을 증명하기 위한 공리 및 추론 규칙을 정의한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;대표적으로,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;{P} S {Q}&lt;/span&gt;라는 형태로 &amp;ldquo;문장 S를 실행하기 전 조건이 P라면, 실행 후에는 Q가 성립한다&amp;rdquo;는 논리를 쓴다. 이를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Hoare logic&lt;/b&gt;&lt;/span&gt;이라고 부른다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주요 개념&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;전제조건(Precondition) P&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;문장을 실행하기 전 프로그램 상태가 만족해야 하는 논리적 조건.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;후조건(Postcondition) Q&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;문장을 실행한 뒤 프로그램 상태가 만족해야 하는 논리적 조건.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;약한 선행 조건(Weakest precondition)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;어떤 후조건 Q가 주어졌을 때, 그 Q를 만족하게 하는 가장 일반적인(&amp;ldquo;약한&amp;rdquo;) P를 의미한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점 &amp;amp; 단점&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/span&gt;: 논리 체계가 완비되어 있으면, 프로그램에 대한 **정확성 증명(formal verification)**이 가능하다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/span&gt;: 실제 구현 수준에서 전제/후조건을 설정하거나 복잡한 언어 기능(예: 포인터, 병행성 등)에 대해 공리적 의미론을 적용하는 일은 매우 어려울 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예시/그림&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;책에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;if b then S1 else S2&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;while b do S&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;같은 구문에 대해 어떤 전제와 후조건이 필요한지를 예시로 든다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;그림/표에서 &amp;ldquo;조건 b가 참일 때 S1의 전후조건이 유지되는지, 거짓일 때 S2가 어떻게 작동하는지&amp;rdquo; 등을 논리 규칙으로 나타낸다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3.5 결론 &amp;amp; 비교&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;조작적 의미론&lt;/b&gt;&lt;/span&gt;은 &amp;ldquo;실행 단계&amp;rdquo;를 직관적으로 추적하므로 이해하기는 쉽지만, 완전한 기술 시 상당히 방대해질 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;의미론적 의미론&lt;/b&gt;&lt;/span&gt;은 프로그램을 수학 함수로 대응시켜 엄밀하게 다룰 수 있으나 추상화가 높고 복잡해질 위험이 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;공리적 의미론&lt;/b&gt;&lt;/span&gt;은 프로그램의 정확성 증명에 특화되어 있으나, 실제로 모든 부분을 증명하기 위한 작업량이 매우 클 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Summary (장 전체 요약)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;Syntax(구문) 기술&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;BNF(Backus-Naur Form)와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;EBNF(Extended BNF)&lt;/b&gt;&lt;/span&gt;, 문맥 자유 문법을 사용하여 프로그래밍 언어의 구조를 정의한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;모호성(ambiguity)을 해소하기 위해 연산자 우선순위와 결합성 규칙을 적용하거나, 문법을 재설계한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;Attribute Grammars(속성 문법)&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;문맥 자유 문법에 속성(Attributes)과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;의미 함수&lt;/b&gt;&lt;/span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;술어(Predicate)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;등을 추가해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;정적 의미론&lt;/b&gt;&lt;/span&gt;(타입 검사 등 BNF로 표현하기 어려운 규칙)을 기술한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;속성은 합성 속성(Synthesized)과 상속 속성(Inherited)이 있어, 파스 트리(parse tree)에서 상&amp;middot;하위 노드 간 정보를 교환한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;Dynamic Semantics(동적 의미론)&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;3.5절에서 다룬&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Operational/Denotational/Axiomatic&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;접근법 모두, 프로그램을 실행했을 때의 &amp;ldquo;의미&amp;rdquo;를 정의하려는 시도다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;각 접근법은 구체적인 실행 모델, 수학적 함수 대응, 논리적 증명 등 서로 다른 관점과 장단점을 가진다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Review Questions&lt;/b&gt;&lt;/h3&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Define syntax and semantics.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Syntax (구문)&lt;/b&gt;&lt;/span&gt;: 프로그래밍 언어의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;형식&lt;/b&gt;&lt;/span&gt;(form)을 정의하는 규칙들. 즉, &amp;ldquo;문법적으로 어떤 구조가 올바른 프로그램 문장인지&amp;rdquo;를 결정한다. 예: 변수 선언, 식의 구성, 구두점(semicolon), 괄호의 배치 등.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Semantics (의미)&lt;/b&gt;&lt;/span&gt;: 구문으로 표현된&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;프로그램이 실행될 때의 의미&lt;/b&gt;&lt;/span&gt;(의도, 동작, 결과)를 정의한다. 즉, &amp;ldquo;이 프로그램이 실제로 무엇을 하는지&amp;rdquo;를 설명한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Who are language descriptions for?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프로그래밍 언어를 기술한 문서는 다음을 위해 필요하다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;언어 디자이너(Designer)&lt;/b&gt;&lt;/span&gt;: 새로운 언어를 설계할 때, 정확하고 일관성 있게 정의하기 위해.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;언어 구현자(Implementor)&lt;/b&gt;&lt;/span&gt;: 컴파일러나 인터프리터를 만들 때, 언어 규칙에 따라 구문 분석, 의미 분석, 실행 방식을 구현하기 위해.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;초기 평가자(Evaluator)&lt;/b&gt;&lt;/span&gt;: 언어가 충분히 표현력이 있는지, 설계가 타당한지 피드백하기 위해.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;4.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;언어 사용자(User)&lt;/b&gt;&lt;/span&gt;: 실제 프로그래머들이 프로그램 작성 시, 언어의 정확한 문법과 기능을 이해하기 위해.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Describe the operation of a general language generator.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;언어 생성기(Language generator)는 해당 언어의 &amp;ldquo;문장들을 생성&amp;rdquo;하는 장치 혹은 모델이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;예: 문맥 자유 문법에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;생성기&lt;/b&gt;&lt;/span&gt;는 시작 기호(start symbol)부터 적용 가능한 규칙을 선택해가며 문자열을 만들어낸다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;이 장치는 버튼을 누를 때마다 그 언어의 합법적인 문장을 하나씩 &amp;ldquo;생성&amp;rdquo;한다고 생각할 수 있지만, 실제론 무작위성이 높아 실무적 유용성은 낮다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;그래도 언어 생성기는 언어를 기술할 때, &amp;ldquo;이 규칙들로부터 만들어지는 문자열들의 집합 = 언어&amp;rdquo;라는 관점으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;정의에 명확성&lt;/b&gt;&lt;/span&gt;을 부여한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. Describe the operation of a general language recognizer.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;언어 인식기(Language recognizer)는 주어진 문자열이 언어에 속하는지(합법적인 문장인지)를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;판별&lt;/b&gt;&lt;/span&gt;(accept/reject)하는 장치다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;컴파일러의 구문 분석기(parser)가 대표적 예시. 프로그램 소스(문자열) 입력 &amp;rarr; 문법 규칙에 맞으면 accept, 아니면 reject.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;이 장치는 언어의 문장들을 분류(filter)하며, 올바른 문장인지 아닌지 식별해낸다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. What is the difference between a sentence and a sentential form?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Sentence(문장)&lt;/b&gt;&lt;/span&gt;: 한 언어의 문법으로부터 완전히 유도(fully derived)된 문자열(terminal 심볼만 남은 형태). 즉, 실제로 &amp;ldquo;언어에 속하는&amp;rdquo; 최종 문자열.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Sentential form(문장형)&lt;/b&gt;&lt;/span&gt;: 유도 과정 중간에 등장할 수 있는 임의의 문자열(비단말 + 단말 기호 섞여 있음). 즉, 파생(derivation) 도중의 상태.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. Define a left-recursive grammar rule.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Left recursion(좌측 재귀)&lt;/b&gt;&lt;/span&gt;: 문법 규칙에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;왼쪽&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;비단말이 자신의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;오른쪽 가장 앞&lt;/b&gt;&lt;/span&gt;에 재귀적으로 등장하는 경우.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;예:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&amp;lt;expr&amp;gt; &amp;rarr; &amp;lt;expr&amp;gt; + &amp;lt;term&amp;gt; | &amp;lt;term&amp;gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;이런 규칙은 파서를 작성할 때, 특히 상향식 파싱(LL 파서)에서는 문제가 될 수 있어 보통 회피하거나 변환한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7. What three extensions are common to most EBNFs?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;EBNF(Extended Backus-Naur Form)는 BNF를 좀 더 간결하게 쓰기 위한 확장.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;대괄호 [ ]&lt;/b&gt;&lt;/span&gt;: 선택적(optional) 부분을 나타낸다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;중괄호 { }&lt;/b&gt;&lt;/span&gt;: 반복(0회 이상)을 나타낸다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;괄호 및 파이프(|)&lt;/b&gt;&lt;/span&gt;: 여러 선택사항(multiple-choice)을 묶을 때 종종 사용한다. 예:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;( x | y )&lt;/span&gt;.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8. Distinguish between static and dynamic semantics.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;정적 의미론(Static semantics)&lt;/b&gt;&lt;/span&gt;: 프로그램 실행 전(컴파일 시점)에 검사할 수 있는 언어 규칙. 예: 타입 호환성, 변수 선언 여부 등. 속성 문법(attribute grammar) 등으로 기술할 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;동적 의미론(Dynamic semantics)&lt;/b&gt;&lt;/span&gt;: 프로그램이 실제로 &amp;ldquo;실행&amp;rdquo;될 때 나타나는 동작이나 상태 변화를 다룬다. Operational, Denotational, Axiomatic semantics 등 기법을 통해 정의한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;9. What purpose do predicates serve in an attribute grammar?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Predicate&lt;/b&gt;&lt;/span&gt;는 속성 문법에서 &amp;ldquo;조건식(불리언 표현)&amp;rdquo;으로,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;해당 문법 규칙이 유효하려면 참이어야 하는 조건&lt;/b&gt;&lt;/span&gt;을 명시한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;예:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;expr.type == term.type&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;같은 식.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;이를 통해 정적 의미 규칙(예: 타입 검사, 선언 규칙 등)을 기술하고, 위배되면 문법적으로는 맞아도 의미론적 오류가 발생했다고 판단한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;10. What is the difference between a synthesized and an inherited attribute?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Synthesized attribute (합성 속성)&lt;/b&gt;&lt;/span&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;자식 &amp;rarr; 부모&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;방향으로 정보 전달. 예: 하위 노드(표현식)의 결과 타입이나 값이 상위 노드에 합성됨.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Inherited attribute (상속 속성)&lt;/b&gt;&lt;/span&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;부모(또는 형제) &amp;rarr; 자식&lt;/b&gt;&lt;/span&gt;으로 정보가 내려가는 형태. 예: 어떤 스코프 정보나 기대하는 타입 등 상위 문맥이 하위 노드에 전수.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;11. How is the order of evaluation of attributes determined for the trees of a given attribute grammar?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;파스 트리에서 속성 값을 올바르게 계산하기 위해서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;의존성&lt;/b&gt;&lt;/span&gt;(dependency)을 분석한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;보통은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;위상 정렬(topological sort)&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;개념을 사용. 즉, 특정 속성이 계산되기 전에 필요한 다른 속성들이 모두 계산된 상태여야 한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;실무적으로는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;L-속성 문법&lt;/b&gt;&lt;/span&gt;(상속 속성이 왼쪽에서 오른쪽으로만 흐르는)이나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;S-속성 문법&lt;/b&gt;&lt;/span&gt;(합성 속성만 사용하는) 등을 사용하면, 계산 순서가 단순화된다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;12. What is the primary use of attribute grammars?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;정적 의미론&lt;/b&gt;&lt;/span&gt;(static semantics)을 기술하고 검사하기 위해 쓴다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;즉, BNF만으로는 표현하기 어려운 타입 규칙, 선언 규칙 등을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;속성과 술어&lt;/b&gt;&lt;/span&gt;로 작성하여,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;컴파일 시점&lt;/b&gt;&lt;/span&gt;에 검사할 수 있도록 한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;13. Explain the primary uses of a methodology and notation for describing the semantics of programming languages.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;프로그래밍 언어의 의미(semantics)를 공식적으로 기술하면,&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;언어 사용자/구현자&lt;/b&gt;&lt;/span&gt;가 정확한 동작을 이해할 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;컴파일러 설계&lt;/b&gt;&lt;/span&gt;에서 구현을 체계화하거나 오류를 줄일 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;3.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;프로그램 검증&lt;/b&gt;&lt;/span&gt;(correctness proof)이나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;언어 설계&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;시, 논리적&amp;middot;수학적 근거를 제시할 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;14. Why can machine languages not be used to define statements in operational semantics?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;전형적인 기계어(machine language)나 실제 컴퓨터의 상태는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;너무 세부적&lt;/b&gt;&lt;/span&gt;이고 복잡(메모리, 레지스터, 하드웨어 구조 등)하므로, 언어의 의미를 간결하게 설명하기엔 비효율적이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Operational semantics는 보통 &amp;ldquo;이상적인 가상 기계(abstract machine)&amp;rdquo;나 &amp;ldquo;단순화된 중간 언어&amp;rdquo;를 사용해 정의한다. 실제 기계어를 사용하면 단계가 지나치게 많고, 개념이 복잡해져 버린다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;15. Describe the two levels of uses of operational semantics.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Natural(큰 단위) Operational Semantics&lt;/b&gt;&lt;/span&gt;: 프로그램 전체를 한 번에(또는 큰 구문 단위별) 평가해 최종 결과 상태를 기술.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Structural(작은 단위) Operational Semantics&lt;/b&gt;&lt;/span&gt;: 구문 구조에 따라 단계별로(작은 조각) 상태 전이를 정의. 제어 흐름과 데이터 흐름을 미세하게 추적한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;16. In denotational semantics, what are the syntactic and semantic domains?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Syntactic domain&lt;/b&gt;&lt;/span&gt;: 프로그램 구문의 구조를 나타내는 집합. 예:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;lt;expr&amp;gt;&lt;/span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;lt;stmt&amp;gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;등이 표현하는 추상 구문 구조(트리).&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Semantic domain&lt;/b&gt;&lt;/span&gt;: 구문이 매핑되는 수학적 객체의 집합. 예: 정수 집합 ℤ, 불리언 집합 {true, false}, 상태(&amp;sigma;)의 집합 등.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;17. What is stored in the state of a program for denotational semantics?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;프로그램의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;변수와 그 값&lt;/b&gt;&lt;/span&gt;(variable &amp;rarr; value)들이 저장된다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;즉, 상태(state)는 일반적으로 &amp;ldquo;메모리&amp;rdquo;를 추상화한 것으로, 각 변수 이름에 대응되는 현재 값이 담겨 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;18. Which semantics approach is most widely known?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;세 가지(Operational, Denotational, Axiomatic) 중,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Operational semantics&lt;/b&gt;&lt;/span&gt;가 가장 직관적&amp;middot;널리 알려져 있다고 볼 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;그러나 &amp;ldquo;가장 엄밀한&amp;rdquo; 측면에서는 Denotational이, &amp;ldquo;프로그램 증명&amp;rdquo; 측면에선 Axiomatic이 사용된다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;일반적으로 교과서에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Operational semantics&lt;/b&gt;&lt;/span&gt;가 많이 소개된다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;19. What two things must be defined for each language entity in order to construct a denotational description of the language?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;수학적 객체&lt;/b&gt;&lt;/span&gt;(Mathematical object): 그 언어 구문이 나타내는 의미 대상(예: 정수, 불리언, 함수 등).&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;의미 함수(semantic mapping function)&lt;/b&gt;&lt;/span&gt;: 구문을 해당 수학적 객체로 사상시키는 규칙(재귀적으로 정의).&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;20. Which part of an inference rule is the antecedent?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Inference rule&lt;/b&gt;&lt;/span&gt;(추론 규칙)에서, 위쪽 부분(조건들, premises)이 antecedent(전제)이고, 아래쪽(결론)이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;consequent&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;pre class=&quot;gcode&quot; style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;code&gt;  ──────── (조건)
  결론&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위 &amp;ldquo;조건&amp;rdquo;이 antecedent, 아래 &amp;ldquo;결론&amp;rdquo;이 consequent.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;21. What is a predicate transformer function?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;프로그램 구문의 의미를 &amp;ldquo;전후조건&amp;rdquo; 관점에서 다룰 때, 전제조건을 후제조건과 구문에 따라 &amp;ldquo;변환&amp;rdquo;하는 함수이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;예: Hoare logic에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;weakest precondition&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;함수&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;wp&lt;/span&gt;는 후조건 Q와 문장 S를 입력받아, 이를 만족하기 위한 전제조건 P를 산출한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;즉, P =&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;wp(S, Q)&lt;/span&gt;이다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;22. What does partial correctness mean for a loop construct?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;부분적 올바름(partial correctness)&lt;/b&gt;&lt;span&gt;: 프로그램(또는 루프)이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;중단(termination)을 가정하지 않고&lt;/b&gt;&lt;span&gt;, 실행 종료 시에 올바른 결과를 낸다는 것을 의미한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;즉, 프로그램이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;멈춘다면&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;결과가 맞음. (멈출지 여부는 별도)&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;23. On what branch of mathematics is axiomatic semantics based?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Axiomatic semantics&lt;/b&gt;&lt;/span&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;수리 논리(Mathematical logic)&lt;/b&gt;&lt;/span&gt;, 구체적으로는 술어 논리(predicate calculus)에 기반한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Hoare logic 등에서 전제조건, 후조건을 논리식으로 표현하고 추론 규칙으로 다루기 때문.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;24. On what branch of mathematics is denotational semantics based?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;Denotational semantics&lt;/b&gt;&lt;span&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;재귀함수 이론&lt;/b&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;집합론&lt;/b&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&amp;lambda;-계산(람다 미적분)&lt;/b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;등 수학적 함수를 다루는 이론에 기반한다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;구체적으로는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;재귀적 정의, 고정점 이론&lt;/b&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;함수형 수학 모델&lt;/b&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;등이 핵심이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;25. What is the problem with using a software pure interpreter for operational semantics?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;소프트웨어 순수 해석기&lt;/b&gt;&lt;/span&gt;로 실제 기계 단위 동작을 전부 시뮬레이션하면,&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;1.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;효율성 면에서 너무 느리거나&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;하드웨어 구조(메모리, I/O 등)가 너무 복잡해서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;언어 정의&lt;/b&gt;&lt;/span&gt;를 간단히 보이기 어려울 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;또한, 기계어 레벨의 모든 세부 단계를 명시해야 하므로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;조작적 의미론&lt;/b&gt;&lt;/span&gt;을 단순 명료하게 기술하기가 힘들다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;26. Explain what the preconditions and postconditions of a given statement mean in axiomatic semantics.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Precondition&lt;/b&gt;&lt;/span&gt;: 문장 실행 전, 프로그램 상태(변수 값들)가 만족해야 할 논리적 조건.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Postcondition&lt;/b&gt;&lt;/span&gt;: 문장 실행 후, 프로그램 상태가 만족해야 할 논리적 조건.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Axiomatic semantics에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;{P} S {Q}&lt;/span&gt;는 &amp;ldquo;P가 참인 상태에서 S를 실행하면, Q가 참이 된다&amp;rdquo;는 의미다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;27. Describe the approach of using axiomatic semantics to prove the correctness of a given program.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;프로그램을 여러 구문 단위(문장, 블록, 루프)로 나누고, 각 문장에 대해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Hoare triple&lt;/b&gt;&lt;/span&gt;(또는 공리, 추론 규칙)을 적용하여 전제조건에서 후조건이 어떻게 유지되는지 증명한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;루프의 경우 루프 불변식(loop invariant)을 찾아 증명.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;모든 경로가 최종적으로 원하는 전제조건&amp;rarr;후조건이 성립하면 프로그램이 &amp;ldquo;정확하다&amp;rdquo;고 증명된다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;28. Describe the basic concept of denotational semantics.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;프로그램의 각 구문(비단말 기호)을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;수학적 의미 대상&lt;/b&gt;&lt;/span&gt;(집합, 함수)에 매핑시키는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;함수&lt;/b&gt;&lt;/span&gt;를 정의한다(재귀적으로).&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;이 매핑 함수는 &amp;ldquo;상태&amp;rdquo;를 입력받아 &amp;ldquo;새로운 상태&amp;rdquo; 또는 &amp;ldquo;값&amp;rdquo;을 반환한다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;이렇게 전체 프로그램을 순수 수학적 객체로 변환하면, 이론적인 분석&amp;middot;증명이 가능해진다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;29. In what fundamental way do operational semantics and denotational semantics differ?&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Operational semantics&lt;/b&gt;&lt;/span&gt;: 프로그램을 어떤 추상 기계(또는 단계적 기계)에서 실제로 실행시키는 과정을 &amp;ldquo;상태 전이&amp;rdquo;로 모델링한다. (실행 절차를 중시)&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Denotational semantics&lt;/b&gt;&lt;/span&gt;: 프로그램의 구문을 &amp;ldquo;수학적 함수&amp;rdquo;로 대응시켜, 최종 결과(또는 재귀적 평가)로 나타낸다. (수학적 매핑을 중시)&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;둘 다 런타임 동작을 다루지만,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Operational&lt;/b&gt;&lt;/span&gt;은 &amp;ldquo;어떻게&amp;rdquo; 실행되는지(단계적),&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Denotational&lt;/b&gt;&lt;/span&gt;은 &amp;ldquo;무엇&amp;rdquo;으로 귀결되는지(함수적) 관점이 다르다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Book/Concepts of Programming Language</category>
      <category>pl</category>
      <category>Programming Language</category>
      <author>S0LL</author>
      <guid isPermaLink="true">https://sol248.tistory.com/155</guid>
      <comments>https://sol248.tistory.com/155#entry155comment</comments>
      <pubDate>Thu, 3 Apr 2025 01:54:40 +0900</pubDate>
    </item>
    <item>
      <title>위상 정렬 (Topological Sorting)</title>
      <link>https://sol248.tistory.com/152</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;위상 정렬이란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위상 정렬은 그래프 알고리즘 중 DAG(Directed Acyclic Graph), 즉 방향성이 있으면서 싸이클이 없는 그래프에서 정점들을 순서대로 정렬하는 방법이다.&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;위상 정렬은 다음과 같은 상황에서 유용하다.&lt;/p&gt;
&lt;pre id=&quot;code_1737119676275&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;- 작업 스케쥴링
- 선수 과목에 대한 문제
- 데이터 처리 파이프라인&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;위상 정렬의 조건&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위상 정렬을 사용하기 위해선 위에서 언급한 것처럼&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. edge(간선) 에 방향이 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 비순환 그래프 즉, 싸이클이 없어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두가지 조건을 만족해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위상 정렬은 큐 기반 위상 정렬과 dfs 기반 위상 정렬로 나뉜다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 방식에 대해 각각 알아보자.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;큐 기반 위상정렬&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큐 기반 위상정렬은 다음과 같은 단계를 따른다.&lt;/p&gt;
&lt;pre id=&quot;code_1737119995717&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1.
각 정점의 진입 차수(inDegree)를 계산한다.

2.
진입 차수가 0인 정점을 큐에 삽입한다.

3.
큐에서 정점을 하나씩 꺼내면서 해당 정점에서 나가는 간선을 제거한다.
간선을 제거하며 새롭게 진입 차수가 0이 되는 정점을 큐에 삽입한다.

4.
큐가 빌 때까지 이를 반복한다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;lt;예시 코드&amp;gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737120014583&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;queue&amp;gt;
using namespace std;

void topologicalSort(int V, vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt;&amp;amp; adj) {
    vector&amp;lt;int&amp;gt; indegree(V, 0); // 각 정점의 진입 차수 계산
    for (int u = 0; u &amp;lt; V; u++) {
        for (int v : adj[u]) {
            indegree[v]++;
        }
    }

    queue&amp;lt;int&amp;gt; q;
    for (int i = 0; i &amp;lt; V; i++) {
        if (indegree[i] == 0) q.push(i); // 진입 차수가 0인 정점을 큐에 추가
    }

    while (!q.empty()) {
        int u = q.front();
        q.pop();
        cout &amp;lt;&amp;lt; u &amp;lt;&amp;lt; &quot; &quot;; // 정렬된 순서 출력

        for (int v : adj[u]) {
            indegree[v]--;
            if (indegree[v] == 0) q.push(v); // 새롭게 진입 차수가 0이 된 정점 추가
        }
    }
}

int main() {
    int V = 6;
    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj(V);

    adj[5].push_back(2);
    adj[5].push_back(0);
    adj[4].push_back(0);
    adj[4].push_back(1);
    adj[2].push_back(3);
    adj[3].push_back(1);

    topologicalSort(V, adj);
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;DFS기반 위상정렬&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dfs기반 위상정렬은 다음과 같은 단계를 따른다.&lt;/p&gt;
&lt;pre id=&quot;code_1737120090587&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1.
모든 정점에 대해 dfs를 수행한다.

2.
탐색이 끝나는 순서대로 정점을 스택에 추가한다.

3.
스택에 저장된 순서대로 정점을 출력한다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;lt;예시 코드&amp;gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737120100631&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;stack&amp;gt;
using namespace std;

void dfs(int u, vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt;&amp;amp; adj, vector&amp;lt;bool&amp;gt;&amp;amp; visited, stack&amp;lt;int&amp;gt;&amp;amp; s) {
    visited[u] = true; // 현재 정점 방문 처리
    for (int v : adj[u]) {
        if (!visited[v]) dfs(v, adj, visited, s); // 이웃 정점 방문
    }
    s.push(u); // 방문이 끝난 정점을 스택에 추가
}

void topologicalSort(int V, vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt;&amp;amp; adj) {
    vector&amp;lt;bool&amp;gt; visited(V, false); // 방문 여부 체크
    stack&amp;lt;int&amp;gt; s;

    for (int i = 0; i &amp;lt; V; i++) {
        if (!visited[i]) dfs(i, adj, visited, s); // 방문하지 않은 정점에 대해 DFS 수행
    }

    while (!s.empty()) {
        cout &amp;lt;&amp;lt; s.top() &amp;lt;&amp;lt; &quot; &quot;; // 스택에서 정점을 꺼내며 출력
        s.pop();
    }
}

int main() {
    int V = 6;
    vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt; adj(V);

    adj[5].push_back(2);
    adj[5].push_back(0);
    adj[4].push_back(0);
    adj[4].push_back(1);
    adj[2].push_back(3);
    adj[3].push_back(1);

    topologicalSort(V, adj);
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;큐 기반 &amp;nbsp;vs &amp;nbsp;DFS기반&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737120243638&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;큐 기반
-간단하고 효율적
-O(V+E)의 시간 복잡도를 가진다
-노드의 순서를 점진석으로 생성해 사용하기 쉽다.


DFS 기반
-재귀적으로 동작하여 구현이 간결하다.
-그래프를 탐색하면서 동시에 위상정렬을 수행할 수 있다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737120316497&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;큐 기반
-진입 차수를 계산할 추가적인 메모리가 필요하다.
-순서를 생성하는 과정이 재귀에 비해 직관적이지 않을 수 있음.


DFS 기반
-재귀 호출 스택이 추가적으로 필요함.
-순서 생성 과정이 명시적이지 않아 DFS종료 후에만 결과를 알 수 있음&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 장단점에 따라,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큐 기반 위상정렬은 작업 스케쥴링과 같은 간단한 순서 계산에 적합하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DFS 기반 위상정렬은 그래프 분석 작업이나 탐색과 동시에 위상 정렬이 필요한 경우에 적합하다.&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;&lt;b&gt;위상 정렬의 결과는 유일하지 않을 수 있으니 유의해야 한다.&lt;/b&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;&amp;nbsp;&lt;/h2&gt;</description>
      <category>DataStructure/Algorithm</category>
      <category>Algorithm</category>
      <category>honglab</category>
      <category>sorting</category>
      <category>topologicalsorting</category>
      <category>위상정렬</category>
      <category>정렬</category>
      <author>S0LL</author>
      <guid isPermaLink="true">https://sol248.tistory.com/152</guid>
      <comments>https://sol248.tistory.com/152#entry152comment</comments>
      <pubDate>Fri, 17 Jan 2025 22:28:26 +0900</pubDate>
    </item>
    <item>
      <title>백준11689_GCD(n, k) = 1</title>
      <link>https://sol248.tistory.com/151</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/11689&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/11689&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-01-10 at 23.41.12.png&quot; data-origin-width=&quot;2368&quot; data-origin-height=&quot;2548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Xtzk2/btsLJlydl7V/sF8WXkVTIpkjTQ1Ig7rSR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Xtzk2/btsLJlydl7V/sF8WXkVTIpkjTQ1Ig7rSR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Xtzk2/btsLJlydl7V/sF8WXkVTIpkjTQ1Ig7rSR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXtzk2%2FbtsLJlydl7V%2FsF8WXkVTIpkjTQ1Ig7rSR1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2368&quot; height=&quot;2548&quot; data-filename=&quot;Screenshot 2025-01-10 at 23.41.12.png&quot; data-origin-width=&quot;2368&quot; data-origin-height=&quot;2548&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자연수 n이 주어졌을 때, 1~n 의 자연수 중 n 과 서로소인 숫자의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;접근 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오일러 파이 함수를 이용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 1부터 n까지의 수 중에서 n과 서로소인 수의 개수를 계산하는 함수이므로 이 문제를 해결하기에 적합하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2386&quot; data-origin-height=&quot;1491&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Mm4PZ/btsLKM2p9dX/wgNSmghHsFa1kbiajKoKe0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Mm4PZ/btsLKM2p9dX/wgNSmghHsFa1kbiajKoKe0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Mm4PZ/btsLKM2p9dX/wgNSmghHsFa1kbiajKoKe0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMm4PZ%2FbtsLKM2p9dX%2FwgNSmghHsFa1kbiajKoKe0%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;2386&quot; height=&quot;1491&quot; data-origin-width=&quot;2386&quot; data-origin-height=&quot;1491&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, n의 소인수만 찾으면 효율적으로 계산이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오일러 피 함수의 원리는 에라토스테네스의 체와 비슷하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게, 소수를 찾아서 순차적으로 p[i] = p[i] - (p[i]/2) 연산을 반복적으로 수행해주면 최종 결과는 오일러 피 함수의 결괏값이 배열에 남게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2386&quot; data-origin-height=&quot;1491&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCzfzW/btsLJe63ISe/a72J7Wx6u58SkZG1Mx1vyk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCzfzW/btsLJe63ISe/a72J7Wx6u58SkZG1Mx1vyk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCzfzW/btsLJe63ISe/a72J7Wx6u58SkZG1Mx1vyk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCzfzW%2FbtsLJe63ISe%2Fa72J7Wx6u58SkZG1Mx1vyk%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;2386&quot; height=&quot;1491&quot; data-origin-width=&quot;2386&quot; data-origin-height=&quot;1491&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;코드&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1736520952393&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;cmath&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;string&amp;gt;
#include &amp;lt;vector&amp;gt;

// 오일러 파이 함수 구현
long long euler_totient(long long n) {
  long long result = n; // 초기값은 n

  // 소인수 찾기
  for (long long i = 2; i * i &amp;lt;= n; i++) {
    if (n % i == 0) { // 소인수 발견
      while (n % i == 0) { // n에서 i의 배수를 제거
        n /= i;
      }
      result -= result / i; // 결과 갱신
    }
  }

  // 마지막 남은 소수가 있으면 처리
  if (n &amp;gt; 1) {
    result -= result / n;
  }

  return result;
}

int main(void) {
  std::ios::sync_with_stdio(false); // 입출력 최적화
  std::cin.tie(NULL);
  std::cout.tie(NULL);

  long long n;
  std::cin &amp;gt;&amp;gt; n;

  std::cout &amp;lt;&amp;lt; euler_totient(n) &amp;lt;&amp;lt; '\n'; // 결과 출력
  return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;시간 복잡도&lt;/b&gt;&lt;/h3&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;2386&quot; data-origin-height=&quot;445&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOvWVz/btsLKAVkjUJ/UxMZEpbp8UH08LPHOzMfk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOvWVz/btsLKAVkjUJ/UxMZEpbp8UH08LPHOzMfk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOvWVz/btsLKAVkjUJ/UxMZEpbp8UH08LPHOzMfk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOvWVz%2FbtsLKAVkjUJ%2FUxMZEpbp8UH08LPHOzMfk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2386&quot; height=&quot;445&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2386&quot; data-origin-height=&quot;445&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>백준</category>
      <category>11689</category>
      <category>백준</category>
      <category>백준11689</category>
      <category>오일러</category>
      <category>오일러 피함수</category>
      <author>S0LL</author>
      <guid isPermaLink="true">https://sol248.tistory.com/151</guid>
      <comments>https://sol248.tistory.com/151#entry151comment</comments>
      <pubDate>Sat, 11 Jan 2025 00:01:32 +0900</pubDate>
    </item>
    <item>
      <title>백준1016_제곱 ㄴㄴ수</title>
      <link>https://sol248.tistory.com/150</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1016&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1016&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-01-10 at 22.06.57.png&quot; data-origin-width=&quot;2368&quot; data-origin-height=&quot;2076&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FypEb/btsLKIMwWgh/kvsJ1ZK952Hq1QAvcDc4kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FypEb/btsLKIMwWgh/kvsJ1ZK952Hq1QAvcDc4kK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FypEb/btsLKIMwWgh/kvsJ1ZK952Hq1QAvcDc4kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFypEb%2FbtsLKIMwWgh%2FkvsJ1ZK952Hq1QAvcDc4kK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2368&quot; height=&quot;2076&quot; data-filename=&quot;Screenshot 2025-01-10 at 22.06.57.png&quot; data-origin-width=&quot;2368&quot; data-origin-height=&quot;2076&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;문제 정의&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;min 과 max 가 주어졌을 때, 제곱수로 나누어지지 않는 정수의 개수를 찾아야 한다.&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;예제 입력 1에서 min=1 , max=10 이 주어졌을 떄, 1보다 큰 제곱수(4,9)로 나누어지지 않는 정수의 개수는 1,2,3,5,6,7,10 으로 7개이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2386&quot; data-origin-height=&quot;880&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1M9kW/btsLJx6hnXs/TMK23ZzHqWuKKVUPrDWHn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1M9kW/btsLJx6hnXs/TMK23ZzHqWuKKVUPrDWHn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1M9kW/btsLJx6hnXs/TMK23ZzHqWuKKVUPrDWHn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1M9kW%2FbtsLJx6hnXs%2FTMK23ZzHqWuKKVUPrDWHn1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2386&quot; height=&quot;880&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2386&quot; data-origin-height=&quot;880&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림과 같이 2부터 제곱수가 max값을 넘기 전까지 제곱수로 나누어지는 수들을 하나씩 제거해주면 된다.&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;b&gt;배열 초기화&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력받은 min, max 값에 따라 범위를 설정해주고 배열을 초기화한다.&lt;/p&gt;
&lt;pre id=&quot;code_1736515517431&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;long long range = max - min + 1;
std::vector&amp;lt;bool&amp;gt; is_power(range, false);&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;b&gt;제곱수로 나누어지는 수 순차적으로 탐색&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;i^2 형태의 제곱수를 순회하며 해당 제곱수로 나눌 수 있는 숫자들을 범위 내에서 표시한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제곱수로 나누어지면 true로, 나누어지지 않으면 처음 초기화한 false 그대로 남는다.&lt;/p&gt;
&lt;pre id=&quot;code_1736515628794&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for (long long i = 2; i * i &amp;lt;= max; i++) {
  long long p = i * i;
  long long sIdx = min / p;

  if (min % p != 0) sIdx++;
  for (long long j = sIdx; p * j &amp;lt;= max; j++) {
    is_power[(int)((j * p) - min)] = true;
  }
}&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;b&gt;결과 계산&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;탐색 이후, false로 남아있는 값의 개수를 세면 문제의 답을 구할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1736515685189&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;long count = 0;
for (int i = 0; i &amp;lt; range; i++) {
  if (!is_power[i]) count++;
}
std::cout &amp;lt;&amp;lt; count &amp;lt;&amp;lt; '\n';&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;b&gt;시간 복잡도&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2386&quot; data-origin-height=&quot;1491&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KQIN5/btsLI5PU5UO/klOATcwyxM2A1jeQkfBJfK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KQIN5/btsLI5PU5UO/klOATcwyxM2A1jeQkfBJfK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KQIN5/btsLI5PU5UO/klOATcwyxM2A1jeQkfBJfK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKQIN5%2FbtsLI5PU5UO%2FklOATcwyxM2A1jeQkfBJfK%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;2386&quot; height=&quot;1491&quot; data-origin-width=&quot;2386&quot; data-origin-height=&quot;1491&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;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1736515947844&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;cmath&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

int main(void) {
  std::ios::sync_with_stdio(false);
  std::cin.tie(NULL);
  std::cout.tie(NULL);

  long long min, max;
  std::cin &amp;gt;&amp;gt; min &amp;gt;&amp;gt; max;
  long long range = max - min + 1;

  std::vector&amp;lt;bool&amp;gt; is_power(range, false);

  for (long long i = 2; i * i &amp;lt;= max; i++) {
    long long p = i * i;
    long long sIdx = min / p;

    if (min % p != 0) sIdx++;
    for (long long j = sIdx; p * j &amp;lt;= max; j++) {
      is_power[(int)((j * p) - min)] = true;
    }
  }

  long count = 0;
  for (int i = 0; i &amp;lt; range; i++) {
    if (!is_power[i]) count++;
  }
  std::cout &amp;lt;&amp;lt; count &amp;lt;&amp;lt; '\n';
  return 0;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>백준</category>
      <category>1016</category>
      <category>백준</category>
      <category>백준1016</category>
      <category>제곱</category>
      <author>S0LL</author>
      <guid isPermaLink="true">https://sol248.tistory.com/150</guid>
      <comments>https://sol248.tistory.com/150#entry150comment</comments>
      <pubDate>Fri, 10 Jan 2025 22:35:59 +0900</pubDate>
    </item>
    <item>
      <title>백준1931_회의실 배정</title>
      <link>https://sol248.tistory.com/149</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1931&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1931&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-01-09 at 21.22.53.png&quot; data-origin-width=&quot;2252&quot; data-origin-height=&quot;1754&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hl1hD/btsLJv69LWR/rTAl7Q1wYS9UJhGaSKCaXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hl1hD/btsLJv69LWR/rTAl7Q1wYS9UJhGaSKCaXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hl1hD/btsLJv69LWR/rTAl7Q1wYS9UJhGaSKCaXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHl1hD%2FbtsLJv69LWR%2FrTAl7Q1wYS9UJhGaSKCaXk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2252&quot; height=&quot;1754&quot; data-filename=&quot;Screenshot 2025-01-09 at 21.22.53.png&quot; data-origin-width=&quot;2252&quot; data-origin-height=&quot;1754&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 시간대가 주어지고, 시간이 겹치지 않으면서 가능한 한 많은 회의실 사용 횟수를 구하려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 구하기 위해서는, 가장 빨리 끝나는 회의를 찾고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 이후에 시작하는 회의 중 가장 빨리 끝나는 회의를 찾고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 찾아나가면 될 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 회의 시간을 찾기 위해서는, 끝나는 시간을 기준으로 정렬되어 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해 다음과 같은 구조체와 배열을 만들어 주고,&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2386&quot; data-origin-height=&quot;1491&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmF9Mz/btsLJM8Fiow/g9FfMgWg6dYjdMyRx2QHn0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmF9Mz/btsLJM8Fiow/g9FfMgWg6dYjdMyRx2QHn0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmF9Mz/btsLJM8Fiow/g9FfMgWg6dYjdMyRx2QHn0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmF9Mz%2FbtsLJM8Fiow%2Fg9FfMgWg6dYjdMyRx2QHn0%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;2386&quot; height=&quot;1491&quot; data-origin-width=&quot;2386&quot; data-origin-height=&quot;1491&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 끝나는 시간을 기준으로 정렬해주는 cmp함수까지 완성해주면 준비는 끝났다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(끝나는 시간이 같은 경우 시작 시간을 기준으로 정렬)&lt;/p&gt;
&lt;pre id=&quot;code_1736425711662&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bool cmp(const t&amp;amp; a, const t&amp;amp; b) {
  if (a.eTime != b.eTime) return a.eTime &amp;lt; b.eTime;

  return a.sTime &amp;lt; b.sTime;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정렬이 완료되었다면, 배열의 처음부터 끝까지 돌며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가능한 회의의 개수를 세어주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1736425827878&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int count = 0;
  int end = 0;

  for (int i = 0; i &amp;lt; N; i++) {
    if (v[i].sTime &amp;gt;= end) {
      count++;
      end = v[i].eTime;
    }
  }

  std::cout &amp;lt;&amp;lt; count &amp;lt;&amp;lt; '\n';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1736425841671&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

struct t {
  int sTime;
  int eTime;
};

bool cmp(const t&amp;amp; a, const t&amp;amp; b) {
  if (a.eTime != b.eTime) return a.eTime &amp;lt; b.eTime;

  return a.sTime &amp;lt; b.sTime;
}

int main(void) {
  std::ios::sync_with_stdio(false);
  std::cin.tie(NULL);
  std::cout.tie(NULL);

  int N;
  std::cin &amp;gt;&amp;gt; N;

  std::vector&amp;lt;t&amp;gt; v(N, {0, 0});

  for (int i = 0; i &amp;lt; N; i++) {
    std::cin &amp;gt;&amp;gt; v[i].sTime &amp;gt;&amp;gt; v[i].eTime;
  }

  std::sort(v.begin(), v.end(), cmp);

  int count = 0;
  int end = 0;

  for (int i = 0; i &amp;lt; N; i++) {
    if (v[i].sTime &amp;gt;= end) {
      count++;
      end = v[i].eTime;
    }
  }

  std::cout &amp;lt;&amp;lt; count &amp;lt;&amp;lt; '\n';

  return 0;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>백준</category>
      <category>1931</category>
      <category>Algorithm</category>
      <category>Greedy</category>
      <category>백준</category>
      <category>백준1931</category>
      <author>S0LL</author>
      <guid isPermaLink="true">https://sol248.tistory.com/149</guid>
      <comments>https://sol248.tistory.com/149#entry149comment</comments>
      <pubDate>Thu, 9 Jan 2025 21:31:05 +0900</pubDate>
    </item>
    <item>
      <title>백준 1300_K번째 수</title>
      <link>https://sol248.tistory.com/148</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1300&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.acmicpc.net/problem/1300&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2025-01-08 at 14.02.25.png&quot; data-origin-width=&quot;2338&quot; data-origin-height=&quot;1158&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CSlbY/btsLF1Gjmv3/wQ0GPYjprxTY0Cmwr08Z70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CSlbY/btsLF1Gjmv3/wQ0GPYjprxTY0Cmwr08Z70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CSlbY/btsLF1Gjmv3/wQ0GPYjprxTY0Cmwr08Z70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCSlbY%2FbtsLF1Gjmv3%2FwQ0GPYjprxTY0Cmwr08Z70%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2338&quot; height=&quot;1158&quot; data-filename=&quot;Screenshot 2025-01-08 at 14.02.25.png&quot; data-origin-width=&quot;2338&quot; data-origin-height=&quot;1158&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 풀 때 N의 최댓값이 10^5 이므로 이차원 배열(N x N)을 만들어 문제를 풀면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;100억의 메모리가 필요하고, 10^10(log(10^10)) 의 시간이 필요한데 사실상 불가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1736314496906&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;메모리
O(N^2)

시간
O(N^2 log(N^2))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제에서 요구하는 것은&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;정렬된 배열에서 k번째로 작은 값&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 어떤 값 x를 기준으로 배열(B) 에서 x 이하의 원소가 몇 개인지만 구하면&amp;nbsp;&lt;/p&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 style=&quot;color: #000000;&quot;&gt;&amp;ldquo;&lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이하가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;개 이상이면 &amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;B[k]&lt;/span&gt;&lt;/span&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이하여야 함&amp;rdquo;&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot;&gt;&amp;ldquo;&lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이하가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;개 미만이면 &amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;B[k]&lt;/span&gt;&lt;/span&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;span&gt;x&amp;nbsp;&lt;/span&gt;&lt;/span&gt;보다 커야 함&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 기준을 얻을 수 있고, 이분탐색을 이용해 원하는 B[k]를 빠르게 구할 수 있다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2386&quot; data-origin-height=&quot;869&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSjm61/btsLGiupEl1/j0PJoifxVP9w6q4C4fSuo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSjm61/btsLGiupEl1/j0PJoifxVP9w6q4C4fSuo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSjm61/btsLGiupEl1/j0PJoifxVP9w6q4C4fSuo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSjm61%2FbtsLGiupEl1%2Fj0PJoifxVP9w6q4C4fSuo0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2386&quot; height=&quot;869&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2386&quot; data-origin-height=&quot;869&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 보면 이론상으론&lt;/p&gt;
&lt;pre id=&quot;code_1736315188816&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1 &amp;lt;= B[k] &amp;lt;= N * N&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이지만, 사실 B[k]는 k보다 커질 수 없다. (배열을 직접 그려보면 더 쉽게 알 수 있다..)&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;따라서, 이분 탐색의 시작 범위를 1, 마지막 범위를 k로 설정하고 이분탐색을 진행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1736315629618&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

int main(void) {
  std::ios::sync_with_stdio(false);
  std::cin.tie(NULL);
  std::cout.tie(NULL);

  int N, K;
  std::cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; K;

  int start = 1;
  int end = K;
  int ans = 0;

  while (start &amp;lt;= end) {
    int mid = (start + end) / 2;

    long long sum = 0;
    for (int i = 1; i &amp;lt;= N; i++) {
      sum += std::min(mid / i, N);
    }

    if (sum &amp;lt; K)
      start = mid + 1;
    else {
      end = mid - 1;
      ans = mid;
    }
  }
  std::cout &amp;lt;&amp;lt; start &amp;lt;&amp;lt; '\n';

  return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이분 탐색으로 문제를 풀어야겠다는 생각하기까지가 어려운 문제였던 것 같다.&lt;/p&gt;</description>
      <category>백준</category>
      <category>binarysearch</category>
      <category>Search</category>
      <category>백준</category>
      <category>백준1300</category>
      <category>이분탐색</category>
      <author>S0LL</author>
      <guid isPermaLink="true">https://sol248.tistory.com/148</guid>
      <comments>https://sol248.tistory.com/148#entry148comment</comments>
      <pubDate>Wed, 8 Jan 2025 14:55:06 +0900</pubDate>
    </item>
    <item>
      <title>기본개념</title>
      <link>https://sol248.tistory.com/147</link>
      <description>&lt;pre id=&quot;code_1735304391450&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int main()
{
    const int width = 1280, height = 960;
    const int canvasWidth = width / 80, canvasHeight = height / 80;
    ...&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;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;width, height&lt;/b&gt;: 실제 윈도우가 갖게 될 해상도(픽셀 수).&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;canvasWidth, canvasHeight&lt;/b&gt;: 우리가 직접 그릴 &amp;lsquo;캔버스&amp;rsquo; 크기를 단순히 줄여서 사용할 수 있음. 위 예시 코드에서는 80으로 나누어, 예를 들어 16x12 정도의 작은 캔버스를 만듦(계산값에 따라 다름). 이 캔버스 크기만큼의 텍스처를 생성해서, 그 텍스처를 풀스크린 사각형에 맵핑하는 구조.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735304438955&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;WNDCLASSEX wc = {
    sizeof(WNDCLASSEX),
    CS_CLASSDC,
    WndProc,
    0L,
    0L,
    GetModuleHandle(NULL),
    NULL,
    NULL,
    NULL,
    NULL,
    L&quot;HongLabGraphics&quot;,
    NULL
};
RegisterClassEx(&amp;amp;wc);

RECT wr = { 0, 0, width, height };
AdjustWindowRect(&amp;amp;wr, WS_OVERLAPPEDWINDOW, FALSE);

HWND hwnd = CreateWindow(
    wc.lpszClassName,
    L&quot;HongLabGraphics Example&quot;,
    WS_OVERLAPPEDWINDOW,
    100, 100,
    wr.right - wr.left,
    wr.bottom - wr.top,
    NULL,
    NULL,
    wc.hInstance,
    NULL
);

ShowWindow(hwnd, SW_SHOWDEFAULT);
UpdateWindow(hwnd);&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;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;WNDCLASSEX&lt;/b&gt;를 통해 윈도우 클래스를 정의한 뒤,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;RegisterClassEx&lt;/span&gt;로 등록.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CreateWindow&lt;/span&gt;를 통해 실제 윈도우 핸들(&lt;span&gt;HWND&lt;/span&gt;)을 얻고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;ShowWindow&lt;/span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;UpdateWindow&lt;/span&gt;로 화면에 표시.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이런 Win32 API는 그래픽스보다는 Windows 창을 다루는 부분.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;(&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;참고&lt;/b&gt;: 다양한 프레임워크/엔진에선 이 과정을 숨겨주므로 직접 볼 일은 많지 않을 수 있음. )&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735304510326&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;auto example = std::make_unique&amp;lt;Example&amp;gt;(hwnd, width, height, canvasWidth, canvasHeight);&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&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;여기서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Example&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;클래스 생성자 내부에서 D3D11 디바이스와 스왑체인 초기화를 모두 진행.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;unique_ptr&lt;/span&gt;은 C++ 스마트 포인터(자동으로 메모리를 해제).&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735304543674&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO&amp;amp; io = ImGui::GetIO(); (void)io;
io.DisplaySize = ImVec2(width, height);
ImGui::StyleColorsLight();

// Setup Platform/Renderer backends
ImGui_ImplDX11_Init(example-&amp;gt;device, example-&amp;gt;deviceContext);
ImGui_ImplWin32_Init(hwnd);&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&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;ImGui&lt;/b&gt;는 UI를 빠르게 그릴 수 있도록 도와주는 라이브러리.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;DirectX 11과 Win32에 연동하기 위한 초기화 로직이 있음( _ImplDX11_Init, _ImplWin32_Init 등).&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735304582452&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;MSG msg = {};
while (WM_QUIT != msg.message)
{
    if (PeekMessage(&amp;amp;msg, NULL, 0, 0, PM_REMOVE))
    {
        TranslateMessage(&amp;amp;msg);
        DispatchMessage(&amp;amp;msg);
    }
    else
    {
        // 실제 로직(업데이트 / 렌더링)
        example-&amp;gt;Update();
        example-&amp;gt;Render();

        // 더블 버퍼링 스왑
        example-&amp;gt;swapChain-&amp;gt;Present(1, 0);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;PeekMessage&lt;/b&gt;: Windows 메시지를 확인하고, 있으면 전달(DispatchMessage)하여 WinProc(=WndProc)으로 보냄.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;Update&lt;/b&gt;: 매 프레임마다 로직 갱신. 예제에서는 텍스처에 픽셀 데이터를 복사해 넣는 과정을 담당.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;Render&lt;/b&gt;: D3D 렌더링 호출(사각형에 텍스처를 그려서 화면에 표시).&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;swapChain-&amp;gt;Present(1, 0)&lt;/b&gt;: 더블 버퍼를 스왑하여 화면에 최종 그림을 표시.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735304616430&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;example-&amp;gt;Clean();
DestroyWindow(hwnd);
UnregisterClass(wc.lpszClassName, wc.hInstance);&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&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;Clean()에서 D3D 리소스를 모두 해제(Release).&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;DestroyWindow&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;UnregisterClass&lt;/b&gt;는 Win32 창 리소스를 해제.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;pre id=&quot;code_1735304657271&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
        return true;

    switch (msg)
    {
    case WM_SIZE:
        // TODO: 창 크기 변경 시 스왑체인 리사이즈
        return 0;
    case WM_SYSCOMMAND:
        ...
    case WM_MOUSEMOVE:
        ...
    case WM_LBUTTONUP:
        ...
    case WM_RBUTTONUP:
        ...
    case WM_KEYDOWN:
        ...
    case WM_DESTROY:
        ::PostQuitMessage(0);
        return 0;
    }

    return ::DefWindowProc(hWnd, msg, wParam, lParam);
}&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&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;메시 종류에 따라 분기 처리&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;WM_SIZE&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;같은 메시지는 창 크기가 변경될 때 발생. 일반적으로 D3D11에서는 스왑체인 Resize 작업을 해주어야 함.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;ImGui를 사용하면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;ImGui_ImplWin32_WndProcHandler&lt;/span&gt;가 먼저 입력 이벤트(마우스, 키보드)를 받아 처리할 수 있도록 함.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;pre id=&quot;code_1735304705961&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ID3D11Device* device;
ID3D11DeviceContext* deviceContext;
IDXGISwapChain* swapChain;
D3D11_VIEWPORT viewport;
ID3D11RenderTargetView* renderTargetView;
ID3D11VertexShader* vertexShader;
ID3D11PixelShader* pixelShader;
ID3D11InputLayout* layout;
ID3D11Buffer* vertexBuffer = nullptr;
ID3D11Buffer* indexBuffer = nullptr;
ID3D11Texture2D* canvasTexture = nullptr;
ID3D11ShaderResourceView* canvasTextureView = nullptr;
ID3D11RenderTargetView* canvasRenderTargetView = nullptr;
ID3D11SamplerState* colorSampler;
UINT indexCount;
int canvasWidth, canvasHeight;
float backgroundColor[4] = { 0.8f, 0.8f, 0.8f, 1.0f };&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&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;device&lt;/b&gt;: 그래픽 하드웨어와 리소스 생성 등의 작업을 할 수 있는 핵심 객체&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;deviceContext&lt;/b&gt;: 실제 파이프라인 상태, 그리기 명령을 내리는 객체&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;swapChain&lt;/b&gt;: 더블 버퍼링, 프런트/백 버퍼 교체 관리&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;renderTargetView&lt;/b&gt;: 화면에 그릴 때, 어떤 버퍼(텍스처)에 그릴지를 지정&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;vertexShader, pixelShader&lt;/b&gt;: 간단히 말해, 정점 처리(위치 변환)와 픽셀 처리(색상 결정) 로직이 담긴 프로그램&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;layout&lt;/b&gt;: 정점 버퍼의 구조(예: (x, y, z, w), (u, v))를 정의&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;vertexBuffer, indexBuffer&lt;/b&gt;: GPU 메모리에 올려둔 정점 데이터와 그 정점의 그리기 순서(인덱스)&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;canvasTexture&lt;/b&gt;: 우리가 CPU에서 만든 픽셀 데이터를 복사해 넣을 수 있는 텍스처(동적(Dynamic) 사용)&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;canvasTextureView&lt;/b&gt;: 셰이더에서 텍스처를 접근하기 위한 뷰&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;canvasRenderTargetView&lt;/b&gt;: 텍스처 자체를 랜더링 대상(RenderTarget)으로도 쓸 수 있도록 하는 뷰&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;colorSampler&lt;/b&gt;: 텍스처를 샘플링할 때 보간(필터링) 방법, UV 범위가 넘어섰을 때 보더나 랩(반복) 등을 어떻게 처리하는지 결정&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;canvasWidth, canvasHeight&lt;/b&gt;: 캔버스 텍스처의 크기&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;backgroundColor&lt;/b&gt;: (r, g, b, a) 형태의 클리어 색상&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735304722722&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Example(HWND window, int width, int height, int canvasWidth, int canvasHeight)
{
    Initialize(window, width, height, canvasWidth, canvasHeight);
}&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&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;객체 생성 시 즉시&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;Initialize&lt;/span&gt;를 통해 D3D 환경을 구축.&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;pre id=&quot;code_1735304742934&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;DXGI_SWAP_CHAIN_DESC swapChainDesc;
ZeroMemory(&amp;amp;swapChainDesc, sizeof(swapChainDesc));
swapChainDesc.BufferDesc.Width = width;
swapChainDesc.BufferDesc.Height = height;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferCount = 2;
swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.OutputWindow = window;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.Windowed = TRUE;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

UINT createDeviceFlags = 0;
// createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;

const D3D_FEATURE_LEVEL featureLevelArray[1] = { D3D_FEATURE_LEVEL_11_0};

if (FAILED(D3D11CreateDeviceAndSwapChain(...)))
{
    std::cout &amp;lt;&amp;lt; &quot;D3D11CreateDeviceAndSwapChain() error&quot; &amp;lt;&amp;lt; std::endl;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;DXGI_SWAP_CHAIN_DESC&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;구조체로 스왑체인의 특성을 설정:&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Width/Height&lt;/span&gt;: 백 버퍼 크기(창 크기와 동일)&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Format&lt;/span&gt;: 픽셀 형식(여기서는 RGBA 8비트)&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;BufferCount = 2&lt;span&gt;: 더블 버퍼링&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;RefreshRate&lt;/span&gt;: 60fps로 맞출 수 있도록 60/1&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;Windowed = TRUE&lt;span&gt;: 창 모드&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;SwapEffect = DXGI_SWAP_EFFECT_DISCARD&lt;span&gt;: 가장 기본적인 교체 방식&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;D3D11CreateDeviceAndSwapChain&lt;/b&gt;:&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;device&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;deviceContext&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;swapChain&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;객체가 생성됨&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;D3D_DRIVER_TYPE_HARDWARE&lt;/span&gt;를 사용하면 실제 GPU를 사용하게 됨.(소프트웨어 대신).&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735304780920&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ID3D11Texture2D* pBackBuffer;
swapChain-&amp;gt;GetBuffer(0, IID_PPV_ARGS(&amp;amp;pBackBuffer));
device-&amp;gt;CreateRenderTargetView(pBackBuffer, NULL, &amp;amp;renderTargetView);
pBackBuffer-&amp;gt;Release();&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&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;GetBuffer(0)&lt;/b&gt;: 스왑체인의 0번(백버퍼) 텍스처를 가져옴.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CreateRenderTargetView&lt;/span&gt;: 그 텍스처를 &amp;ldquo;화면 렌더링 대상으로 쓸 수 있는 뷰&amp;rdquo;로 만듦.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735304793911&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = float(width);
viewport.Height = float(height);
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
deviceContext-&amp;gt;RSSetViewports(1, &amp;amp;viewport);&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&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;화면에 그릴 좌표계를 설정. (0,0)은 왼쪽 상단, (width, height)는 오른쪽 하단, 깊이 범위(0~1).&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;pre id=&quot;code_1735304808673&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void InitShaders()
{
    ID3DBlob* vertexBlob = nullptr;
    ID3DBlob* pixelBlob = nullptr;
    ID3DBlob* errorBlob = nullptr;

    D3DCompileFromFile(L&quot;VS.hlsl&quot;, 0, 0, &quot;main&quot;, &quot;vs_5_0&quot;, 0, 0, &amp;amp;vertexBlob, &amp;amp;errorBlob);
    D3DCompileFromFile(L&quot;PS.hlsl&quot;, 0, 0, &quot;main&quot;, &quot;ps_5_0&quot;, 0, 0, &amp;amp;pixelBlob, &amp;amp;errorBlob);

    device-&amp;gt;CreateVertexShader(vertexBlob-&amp;gt;GetBufferPointer(), vertexBlob-&amp;gt;GetBufferSize(), NULL, &amp;amp;vertexShader);
    device-&amp;gt;CreatePixelShader(pixelBlob-&amp;gt;GetBufferPointer(), pixelBlob-&amp;gt;GetBufferSize(), NULL, &amp;amp;pixelShader);

    // 인풋 레이아웃 정의
    D3D11_INPUT_ELEMENT_DESC ied[] =
    {
        {&quot;POSITION&quot;, 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0},
        {&quot;TEXCOORD&quot;, 0, DXGI_FORMAT_R32G32_FLOAT,       0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0},
    };

    device-&amp;gt;CreateInputLayout(ied, 2, vertexBlob-&amp;gt;GetBufferPointer(), vertexBlob-&amp;gt;GetBufferSize(), &amp;amp;layout);
    deviceContext-&amp;gt;IASetInputLayout(layout);
}&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&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;**HLSL(High Level Shading Language)**로 작성된 셰이더(VS.hlsl, PS.hlsl)를 컴파일하여,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;vertexBlob&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;pixelBlob&lt;/b&gt;을 얻어옴.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;CreateVertexShader&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;CreatePixelShader&lt;span&gt;로 셰이더 객체 생성.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;정점 버퍼 구조는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;POSITION&lt;/span&gt;(float4)와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;TEXCOORD&lt;/span&gt;(float2)로 구성됨.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IASetInputLayout&lt;/span&gt;으로 정점 입력 구조를 GPU 파이프라인에 설정.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735304829528&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;D3D11_SAMPLER_DESC sampDesc;
ZeroMemory(&amp;amp;sampDesc, sizeof(sampDesc));
sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
...
device-&amp;gt;CreateSamplerState(&amp;amp;sampDesc, &amp;amp;colorSampler);

D3D11_TEXTURE2D_DESC textureDesc;
ZeroMemory(&amp;amp;textureDesc, sizeof(textureDesc));
textureDesc.Width = canvasWidth;
textureDesc.Height = canvasHeight;
textureDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
textureDesc.Usage = D3D11_USAGE_DYNAMIC;
textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
...
device-&amp;gt;CreateTexture2D(&amp;amp;textureDesc, nullptr, &amp;amp;canvasTexture);
device-&amp;gt;CreateShaderResourceView(canvasTexture, nullptr, &amp;amp;canvasTextureView);&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&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;SamplerState&lt;/b&gt;: 텍스처 읽기 시 보간(POINT 필터) 및 범위 밖 주소(Clamp) 설정.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;Texture2D&lt;/b&gt;: RGBA 32bit float로 구성된 canvas 텍스처를 CPU가 수정할 수 있도록(D3D11_USAGE_DYNAMIC &amp;amp; CPUAccessFlags=WRITE).&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;CreateShaderResourceView&lt;/span&gt;를 통해 이 텍스처를 픽셀 셰이더에서 접근 가능하도록 설정.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735304850177&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Vertex
std::vector&amp;lt;Vertex&amp;gt; vertices = {
    {{-1.0f, -1.0f, 0.0f, 1.0f}, {0.f,1.f}},
    {{ 1.0f, -1.0f, 0.0f, 1.0f}, {1.f,1.f}},
    {{ 1.0f,  1.0f, 0.0f, 1.0f}, {1.f,0.f}},
    {{-1.0f,  1.0f, 0.0f, 1.0f}, {0.f,0.f}},
};

D3D11_BUFFER_DESC bufferDesc = {};
bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
bufferDesc.ByteWidth = sizeof(Vertex)* vertices.size();
bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
device-&amp;gt;CreateBuffer(&amp;amp;bufferDesc, &amp;amp;vertexBufferData, &amp;amp;vertexBuffer);

// Index
std::vector&amp;lt;uint16_t&amp;gt; indices = {3,1,0, 2,1,3};
indexCount = indices.size();
...
device-&amp;gt;CreateBuffer(&amp;amp;bufferDesc, &amp;amp;indexBufferData, &amp;amp;indexBuffer);&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&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;화면 전체를 덮는 정사각형(Quad)을 구성하는 정점 4개를 만듦.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;정점0: (-1,-1)&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;정점1: ( 1,-1)&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;정점2: ( 1, 1)&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;정점3: (-1, 1)&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;텍스처 좌표(UV)는 (0,1) ~ (1,0) 사이로 지정하여, 이미지가 뒤집히지 않도록 세심하게 설정.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;인덱스는 삼각형 2개로 정사각형을 그립니다. (총 6개 인덱스)&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735304866972&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Update()
{
    std::vector&amp;lt;Vec4&amp;gt; pixels(canvasWidth * canvasHeight, Vec4{0.8f, 0.8f, 0.8f, 1.0f});
    pixels[0 + canvasWidth * 0] = Vec4{ 1.0f, 0.0f, 0.0f, 1.0f };
    pixels[1 + canvasWidth * 0] = Vec4{ 1.0f, 1.0f, 0.0f, 1.0f };

    D3D11_MAPPED_SUBRESOURCE ms;
    deviceContext-&amp;gt;Map(canvasTexture, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &amp;amp;ms);
    memcpy(ms.pData, pixels.data(), pixels.size() * sizeof(Vec4));
    deviceContext-&amp;gt;Unmap(canvasTexture, 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&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;(canvasWidth x canvasHeight) 크기의 CPU 메모리 배열을 만들어, 각각의 픽셀에 대해 RGBA 색상값을 지정(여기서는 회색(0.8,0.8,0.8)으로 초기화).&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;임의로 (0,0) 위치엔 빨간색, (1,0) 위치엔 노랑색을 넣어봄.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;deviceContext-&amp;gt;Map&lt;/span&gt;을 통해 텍스처 리소스를 CPU가 쓸 수 있게 잠금(Map).&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;memcpy&lt;/span&gt;로 CPU에서 만든 픽셀 데이터를 GPU 텍스처에 복사.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Unmap&lt;/span&gt;으로 잠금 해제.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735304894110&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Render()
{
    float clearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
    deviceContext-&amp;gt;RSSetViewports(1, &amp;amp;viewport);
    deviceContext-&amp;gt;OMSetRenderTargets(1, &amp;amp;renderTargetView, nullptr);
    deviceContext-&amp;gt;ClearRenderTargetView(renderTargetView, clearColor);

    deviceContext-&amp;gt;VSSetShader(vertexShader, 0, 0);
    deviceContext-&amp;gt;PSSetShader(pixelShader, 0, 0);

    UINT stride = sizeof(Vertex);
    UINT offset = 0;
    deviceContext-&amp;gt;IASetVertexBuffers(0, 1, &amp;amp;vertexBuffer, &amp;amp;stride, &amp;amp;offset);
    deviceContext-&amp;gt;IASetIndexBuffer(indexBuffer, DXGI_FORMAT_R16_UINT, 0);

    deviceContext-&amp;gt;PSSetSamplers(0, 1, &amp;amp;colorSampler);
    deviceContext-&amp;gt;PSSetShaderResources(0, 1, &amp;amp;canvasTextureView);
    deviceContext-&amp;gt;IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    deviceContext-&amp;gt;DrawIndexed(indexCount, 0, 0);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;&lt;span&gt;ClearRenderTargetView&lt;/span&gt;로 현재 렌더 타겟(백버퍼)을 검은색(0,0,0,1)으로 지움.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;정점 셰이더와 픽셀 셰이더를 바인딩.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;3.&lt;span&gt; &lt;/span&gt;정점/인덱스 버퍼 연결 + PS 샘플러 &amp;amp; 텍스처 뷰 연결.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;4.&lt;span&gt; &lt;/span&gt;삼각형 리스트로 인덱스의 개수(indexCount)만큼 Draw 호출.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;결국은 Quad(사각형) 1개를 그립니다. 이 사각형은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;canvasTexture&lt;/span&gt;를 텍스처로 갖는다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1735304918746&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Clean()
{
    if (layout) layout-&amp;gt;Release();
    if (vertexShader) vertexShader-&amp;gt;Release();
    if (pixelShader) pixelShader-&amp;gt;Release();
    if (vertexBuffer) vertexBuffer-&amp;gt;Release();
    ...
    // 모든 D3D 리소스 메모리 해제
}&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&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;D3D11에서 생성한 객체는 COM(Reference Counting) 기반이므로, 사용 후에는 반드시&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;Release()&lt;/span&gt;로 참조를 줄여야 함.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;이 코드가 없다면, 프로그램 종료 시 리소스 누수가 발생할 수 있음.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;흐름 요약&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;&lt;b&gt;main.cpp&lt;/b&gt;에서 Win32 윈도우를 생성&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;&lt;b&gt;Example&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;객체 생성 시, D3D11 초기화, 셰이더 컴파일, 버퍼/텍스처 생성&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;3.&lt;span&gt; &lt;/span&gt;매 프레임&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;Update()&lt;/span&gt;에서 캔버스 텍스처 메모리를 CPU로부터 갱신&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;4.&lt;span&gt; &lt;/span&gt;매 프레임&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;Render()&lt;/span&gt;에서 검은 화면을 클리어 후, 사각형에 캔버스 텍스처를 그려서 출력&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;5.&lt;span&gt; &lt;/span&gt;메시 루프에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;Present()&lt;/span&gt;로 GPU가 그린 결과를 화면에 표시&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;6.&lt;span&gt; &lt;/span&gt;종료 시&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;Clean()&lt;/span&gt;으로 리소스 정리&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;추가 학습/연습 아이디어&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;&lt;b&gt;픽셀 데이터 변경&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;Update()에서 특정 위치의 색을 바꾸는 대신, 간단한 패턴(예: 그라디언트, 체크무늬)을 만들기.&lt;/p&gt;
&lt;pre id=&quot;code_1735305008821&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for(int y = 0; y &amp;lt; canvasHeight; y++) {
    for(int x = 0; x &amp;lt; canvasWidth; x++) {
        float r = float(x) / canvasWidth;   // 0.0 ~ 1.0
        float g = float(y) / canvasHeight; // 0.0 ~ 1.0
        float b = 0.5f;
        pixels[x + y * canvasWidth] = {r, g, b, 1.0f};
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;&lt;b&gt;마우스로 클릭해서 점찍기&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;WM_LBUTTONUP에서 좌표를 얻어, Update()에 반영.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&amp;ldquo;화면 해상도&amp;rdquo;와 &amp;ldquo;캔버스 해상도&amp;rdquo;가 다르므로, 클릭된 좌표를 canvasWidth, canvasHeight에 맞게 변환이 필요. 예를 들어,&lt;/p&gt;
&lt;pre id=&quot;code_1735305041467&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// mouse_x, mouse_y는 화면(0~width, 0~height)
int canvas_x = (mouse_x * canvasWidth)  / width;
int canvas_y = (mouse_y * canvasHeight) / height;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>graphics</category>
      <category>c++</category>
      <category>Graphics</category>
      <category>그래픽스</category>
      <author>S0LL</author>
      <guid isPermaLink="true">https://sol248.tistory.com/147</guid>
      <comments>https://sol248.tistory.com/147#entry147comment</comments>
      <pubDate>Fri, 27 Dec 2024 22:12:09 +0900</pubDate>
    </item>
    <item>
      <title>Setting</title>
      <link>https://sol248.tistory.com/146</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Install the visual studio 2022 community&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;To get started, download Visual Studio 2022 Community Edition using the link below.&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;a href=&quot;https://visualstudio.microsoft.com/ko/vs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://visualstudio.microsoft.com/ko/vs/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1734354195103&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Visual Studio 2022 | 무료 다운로드&quot; data-og-description=&quot;Visual Studio에서 코드 완성, 디버깅, 테스트, Git 관리, 클라우드 배포를 사용하여 코드를 작성합니다. 지금 무료로 커뮤니티를 다운로드하세요.&quot; data-og-host=&quot;visualstudio.microsoft.com&quot; data-og-source-url=&quot;https://visualstudio.microsoft.com/ko/vs/&quot; data-og-url=&quot;https://visualstudio.microsoft.com/ko/vs/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/czm3af/hyXKj2vSv8/NDdyhtkceOVmxBTGkxlFz1/img.gif?width=500&amp;amp;height=280&amp;amp;face=0_0_500_280,https://scrap.kakaocdn.net/dn/bA6dwe/hyXOlEn2aO/cpOKebwGKCTokBYkEFFQK1/img.gif?width=500&amp;amp;height=280&amp;amp;face=0_0_500_280&quot;&gt;&lt;a href=&quot;https://visualstudio.microsoft.com/ko/vs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://visualstudio.microsoft.com/ko/vs/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/czm3af/hyXKj2vSv8/NDdyhtkceOVmxBTGkxlFz1/img.gif?width=500&amp;amp;height=280&amp;amp;face=0_0_500_280,https://scrap.kakaocdn.net/dn/bA6dwe/hyXOlEn2aO/cpOKebwGKCTokBYkEFFQK1/img.gif?width=500&amp;amp;height=280&amp;amp;face=0_0_500_280');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Visual Studio 2022 | 무료 다운로드&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Visual Studio에서 코드 완성, 디버깅, 테스트, Git 관리, 클라우드 배포를 사용하여 코드를 작성합니다. 지금 무료로 커뮤니티를 다운로드하세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;visualstudio.microsoft.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;For this study, we only need the C++ development environment.&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;&lt;b&gt;2. Install ImGui using Vcpkg&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;Next, install Vcpkg, a C/C++ package manager, by following the instructions provided in the link below.&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;a href=&quot;https://learn.microsoft.com/ko-kr/vcpkg/get_started/overview&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://learn.microsoft.com/ko-kr/vcpkg/get_started/overview&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1734354302164&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;vcpkg 개요&quot; data-og-description=&quot;vcpkg C/C++ 패키지 관리자가 종속성을 획득하고 관리하는 데 어떻게 도움이 되는지 알아봅니다.&quot; data-og-host=&quot;learn.microsoft.com&quot; data-og-source-url=&quot;https://learn.microsoft.com/ko-kr/vcpkg/get_started/overview&quot; data-og-url=&quot;https://learn.microsoft.com/ko-kr/vcpkg/get_started/overview&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/byKVoy/hyXOkFs7AG/Slr0vCfqHxQxkIcFuOyPUK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/ko-kr/vcpkg/get_started/overview&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://learn.microsoft.com/ko-kr/vcpkg/get_started/overview&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/byKVoy/hyXOkFs7AG/Slr0vCfqHxQxkIcFuOyPUK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;vcpkg 개요&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;vcpkg C/C++ 패키지 관리자가 종속성을 획득하고 관리하는 데 어떻게 도움이 되는지 알아봅니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;learn.microsoft.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;&lt;b&gt;3. Install ImGui&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;You can get ImGui from the GitHub repository below.&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;a href=&quot;https://github.com/ocornut/imgui&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/ocornut/imgui&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1734355095330&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - ocornut/imgui: Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies&quot; data-og-description=&quot;Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies - ocornut/imgui&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/ocornut/imgui&quot; data-og-url=&quot;https://github.com/ocornut/imgui&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cyWiHc/hyXKjO0f0u/xC7tIRo5gwHxy7BAzyC721/img.jpg?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640,https://scrap.kakaocdn.net/dn/blCAov/hyXOfxomCM/bSAPMSztxzBPLdbXecCtv0/img.jpg?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640&quot;&gt;&lt;a href=&quot;https://github.com/ocornut/imgui&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/ocornut/imgui&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cyWiHc/hyXKjO0f0u/xC7tIRo5gwHxy7BAzyC721/img.jpg?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640,https://scrap.kakaocdn.net/dn/blCAov/hyXOfxomCM/bSAPMSztxzBPLdbXecCtv0/img.jpg?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - ocornut/imgui: Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies - ocornut/imgui&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Alternatively, you can install ImGui more easily using Vcpkg.&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;To search for ImGui versions, use the following command in your terminal.&lt;/p&gt;
&lt;pre id=&quot;code_1734360347296&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;./vcpkg search imgui&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;This will display a list of available ImGui versions.&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;Since I am using DirectX11(dx11) and my operating system is Windows11, I will install ImGui using the following command.&lt;/p&gt;
&lt;pre id=&quot;code_1734360495569&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; ./vcpkg install imgui[win32-binding,dx11-binding]:x64-windows&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;Finally, integrate Vcpkg into your Visual Studio environment by entering:&lt;/p&gt;
&lt;pre id=&quot;code_1734452640410&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;./vcpkg integrate install&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;The setup is now complete! You can use ImGui in Visual Studio 2022 Community Edition.&lt;/p&gt;</description>
      <category>graphics</category>
      <category>Graphics</category>
      <category>IMGUI</category>
      <category>vcpkg</category>
      <category>Visual Studio</category>
      <author>S0LL</author>
      <guid isPermaLink="true">https://sol248.tistory.com/146</guid>
      <comments>https://sol248.tistory.com/146#entry146comment</comments>
      <pubDate>Wed, 18 Dec 2024 01:32:23 +0900</pubDate>
    </item>
    <item>
      <title>CH8. More Computational Complexity: The Searching Problem</title>
      <link>https://sol248.tistory.com/144</link>
      <description>&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.1 Lower Bounds for Searching Only by Comparisons of Keys&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 섹션에서는 키 비교만을 사용하여 배열에서 특정 키를 검색할 때 소모되는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;최악의 경우 비교 횟수의 하한&lt;/b&gt;을 다룹니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;특히,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Binary Search&lt;/b&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Sequential Search&lt;/b&gt;의 의사결정 트리(Decision Tree)를 사용하여 검색 과정의 효율성을 분석합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;의사결정 트리 (Decision Tree)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;정의&lt;/b&gt;:&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;의사결정 트리는 키&lt;span&gt;&amp;nbsp;&lt;/span&gt;를 배열에서 검색하는 과정에서 발생하는 모든 비교를 나타냅니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;각&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;내부 노드&lt;/b&gt;는 키 비교를 나타냅니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;각&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;리프 노드&lt;/b&gt;는 검색 결과를 나타냅니다 (성공적으로 검색된 위치 또는 실패).&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;예시:&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;Figure 8.1&lt;/b&gt;: 정렬된 배열에서 이진 탐색(Binary Search)의 의사결정 트리를 나타냅니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;Figure 8.2&lt;/b&gt;: 순차 탐색(Sequential Search)의 의사결정 트리를 나타냅니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.28.01.png&quot; data-origin-width=&quot;794&quot; data-origin-height=&quot;992&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgGCWi/btsLeifYtMe/SBOy9kVE70C8D8kLCKsfnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgGCWi/btsLeifYtMe/SBOy9kVE70C8D8kLCKsfnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgGCWi/btsLeifYtMe/SBOy9kVE70C8D8kLCKsfnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgGCWi%2FbtsLeifYtMe%2FSBOy9kVE70C8D8kLCKsfnk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;794&quot; height=&quot;992&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.28.01.png&quot; data-origin-width=&quot;794&quot; data-origin-height=&quot;992&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;검색 알고리즘과 의사결정 트리의 관계&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;검색 알고리즘이&lt;span&gt;&amp;nbsp;&lt;/span&gt;개의 키를 처리한다고 가정할 때:&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;개의 키를 검색하는 모든 알고리즘에는 유효한 의사결정 트리가 존재합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;최악의 경우 비교 횟수는 트리의 최대 깊이 (트리의 루트에서 리프까지의 가장 긴 경로)로 표현됩니다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.1.1 Lower Bounds for Worst-Case Behavior&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Lemma 8.1&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.29.41.png&quot; data-origin-width=&quot;872&quot; data-origin-height=&quot;408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKMlVs/btsLcrTnJEG/DwsbwaHoexVCiKDoPB2LsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKMlVs/btsLcrTnJEG/DwsbwaHoexVCiKDoPB2LsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKMlVs/btsLcrTnJEG/DwsbwaHoexVCiKDoPB2LsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKMlVs%2FbtsLcrTnJEG%2FDwsbwaHoexVCiKDoPB2LsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/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;408&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.29.41.png&quot; data-origin-width=&quot;872&quot; data-origin-height=&quot;408&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Lemma 8.2&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.30.18.png&quot; data-origin-width=&quot;930&quot; data-origin-height=&quot;598&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/laaU8/btsLcuoS26A/Kh6ieuslsQZvF1jAy3IScK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/laaU8/btsLcuoS26A/Kh6ieuslsQZvF1jAy3IScK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/laaU8/btsLcuoS26A/Kh6ieuslsQZvF1jAy3IScK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlaaU8%2FbtsLcuoS26A%2FKh6ieuslsQZvF1jAy3IScK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;930&quot; height=&quot;598&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.30.18.png&quot; data-origin-width=&quot;930&quot; data-origin-height=&quot;598&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Theorem 8.1&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.30.52.png&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;660&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0FVfT/btsLdcnA60F/aEqkyHc7w6kL6YAEIK8mt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0FVfT/btsLdcnA60F/aEqkyHc7w6kL6YAEIK8mt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0FVfT/btsLdcnA60F/aEqkyHc7w6kL6YAEIK8mt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0FVfT%2FbtsLdcnA60F%2FaEqkyHc7w6kL6YAEIK8mt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;910&quot; height=&quot;660&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.30.52.png&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;660&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.1.2 평균 성능에 대한 하한 (Lower Bounds for Average-Case Behavior)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 정의와 개념&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;거의 완전 이진 트리(Nearly Complete Binary Tree):&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;한 이진 트리가 깊이가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;d - 1&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;까지 채워져 있으면 &amp;ldquo;거의 완전 이진 트리&amp;rdquo;라고 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;예를 들어, Figure 8.3(a)는 완전 이진 트리, Figure 8.3(b)는 거의 완전 이진 트리입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.34.17.png&quot; data-origin-width=&quot;992&quot; data-origin-height=&quot;376&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDkcDD/btsLdxrpZUJ/LpuJZL7OfapYTuRepj0uGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDkcDD/btsLdxrpZUJ/LpuJZL7OfapYTuRepj0uGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDkcDD/btsLdxrpZUJ/LpuJZL7OfapYTuRepj0uGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDkcDD%2FbtsLdxrpZUJ%2FLpuJZL7OfapYTuRepj0uGk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;992&quot; height=&quot;376&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.34.17.png&quot; data-origin-width=&quot;992&quot; data-origin-height=&quot;376&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;Binary Search의 결정 트리(Decision Tree)는 거의 완전 이진 트리로 나타낼 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Lemma 8.3&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내용:&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;Binary Search의 결정 트리는 &amp;ldquo;거의 완전 이진 트리&amp;rdquo;입니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;증명:&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;기초:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;노드가 1개일 때, 이는 명백히 &amp;ldquo;거의 완전 이진 트리&amp;rdquo;입니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;귀납 가정:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;노드가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;k&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;개일 때, 이진 트리가 &amp;ldquo;거의 완전 이진 트리&amp;rdquo;라고 가정합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;귀납 증명:&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;노드가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;n&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;개일 때:&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;n&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;이 홀수일 경우, Binary Search는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;n - 1&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;/2로 두 서브트리를 나눕니다. 이 두 서브트리는 구조적으로 동일하며, 귀납 가정에 의해 거의 완전합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;n&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;이 짝수일 경우에도, 좌우 서브트리 중 하나가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;n/2&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;, 나머지가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(n/2) - 1&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;이며, 두 서브트리도 귀납 가정에 의해 거의 완전합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;따라서 결정 트리는 &amp;ldquo;거의 완전 이진 트리&amp;rdquo;입니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Algorithm 8.1: Binary Search 평균 시간 분석&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기본 동작:&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0e0e0e;&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;x&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #0e0e0e;&quot;&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;S[{mid}]&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #0e0e0e;&quot;&gt;의 비교.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;분석:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.37.18.png&quot; data-origin-width=&quot;894&quot; data-origin-height=&quot;816&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P0BlU/btsLepeZBmu/xiaeITzbN5GaP2KYuZCcq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P0BlU/btsLepeZBmu/xiaeITzbN5GaP2KYuZCcq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P0BlU/btsLepeZBmu/xiaeITzbN5GaP2KYuZCcq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FP0BlU%2FbtsLepeZBmu%2FxiaeITzbN5GaP2KYuZCcq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;894&quot; height=&quot;816&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.37.18.png&quot; data-origin-width=&quot;894&quot; data-origin-height=&quot;816&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.37.32.png&quot; data-origin-width=&quot;874&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tDn85/btsLddUoXU2/IIN1oaxJ0Q6OJkfZ8rIF30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tDn85/btsLddUoXU2/IIN1oaxJ0Q6OJkfZ8rIF30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tDn85/btsLddUoXU2/IIN1oaxJ0Q6OJkfZ8rIF30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtDn85%2FbtsLddUoXU2%2FIIN1oaxJ0Q6OJkfZ8rIF30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;874&quot; height=&quot;456&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.37.32.png&quot; data-origin-width=&quot;874&quot; data-origin-height=&quot;456&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. Lemma 8.4&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내용:&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;TND&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;가 최소(&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;minTND(n)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;)가 되려면 결정 트리가 &amp;ldquo;거의 완전 이진 트리&amp;rdquo;여야 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;증명:&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;TND&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;가 최소가 아닌 경우, 트리의 마지막 레벨에서 노드를 제거하고 위로 이동시켜&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;TND&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;를 줄일 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;따라서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;minTND(n)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;를 가지려면 트리가 &amp;ldquo;거의 완전 이진 트리&amp;rdquo;여야 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. Lemma 8.5&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내용:&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0e0e0e;&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;평균 시간 복잡도는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;\text{minTND(n)} / n&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #0e0e0e;&quot;&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;증명:&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;Binary Search의 평균 시간은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;TND / n&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;에서 도출됩니다. Lemma 8.3과 8.4에 의해 이 결과를 얻을 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. Lemma 8.6&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내용:&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;결정 트리에서 각 키&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;s_i&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;는 최소 한 번 비교되어야 하므로, 평균 시간 복잡도의 하한은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt; &lt;/span&gt;{minTND(n)} / n&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.38.40.png&quot; data-origin-width=&quot;896&quot; data-origin-height=&quot;530&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vZgx1/btsLc0ucfBQ/CuGYQxYgk7KKWP7WhIHHa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vZgx1/btsLc0ucfBQ/CuGYQxYgk7KKWP7WhIHHa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vZgx1/btsLc0ucfBQ/CuGYQxYgk7KKWP7WhIHHa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvZgx1%2FbtsLc0ucfBQ%2FCuGYQxYgk7KKWP7WhIHHa0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;896&quot; height=&quot;530&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.38.40.png&quot; data-origin-width=&quot;896&quot; data-origin-height=&quot;530&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.2 Interpolation Search&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기본 개념&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;Interpolation Search는 **키 값(key value)**이 균등하게 분포되어 있다고 가정할 때 Binary Search보다 효율적으로 동작할 수 있는 탐색 알고리즘입니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;Binary Search는 중간(mid) 위치를 항상 배열의 가운데로 설정하지만, Interpolation Search는 키 값의 분포에 따라&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;예상 위치&lt;/b&gt;를 계산해 중간값을 동적으로 결정합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;이를 통해 데이터가 균일하게 분포된 경우 Binary Search보다 적은 비교 횟수로 원하는 값을 찾을 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.41.00.png&quot; data-origin-width=&quot;896&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMLwMd/btsLdgcn2F3/qP5I9ycXcbKqMFvXaFZFq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMLwMd/btsLdgcn2F3/qP5I9ycXcbKqMFvXaFZFq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMLwMd/btsLdgcn2F3/qP5I9ycXcbKqMFvXaFZFq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMLwMd%2FbtsLdgcn2F3%2FqP5I9ycXcbKqMFvXaFZFq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;896&quot; height=&quot;456&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.41.00.png&quot; data-origin-width=&quot;896&quot; data-origin-height=&quot;456&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.41.32.png&quot; data-origin-width=&quot;870&quot; data-origin-height=&quot;592&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCSbiR/btsLeoUIb7X/eR3zdWxVYf1IfRKUE8pPG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCSbiR/btsLeoUIb7X/eR3zdWxVYf1IfRKUE8pPG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCSbiR/btsLeoUIb7X/eR3zdWxVYf1IfRKUE8pPG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCSbiR%2FbtsLeoUIb7X%2FeR3zdWxVYf1IfRKUE8pPG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;870&quot; height=&quot;592&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.41.32.png&quot; data-origin-width=&quot;870&quot; data-origin-height=&quot;592&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.41.57.png&quot; data-origin-width=&quot;896&quot; data-origin-height=&quot;862&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/05A6p/btsLdWLbWFz/SFhhTaNakkkECRkE22ANp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/05A6p/btsLdWLbWFz/SFhhTaNakkkECRkE22ANp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/05A6p/btsLdWLbWFz/SFhhTaNakkkECRkE22ANp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F05A6p%2FbtsLdWLbWFz%2FSFhhTaNakkkECRkE22ANp0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;896&quot; height=&quot;862&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.41.57.png&quot; data-origin-width=&quot;896&quot; data-origin-height=&quot;862&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.3 Searching in Trees&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 부분은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;트리 구조를 활용한 탐색&lt;/b&gt;에 대해 설명합니다. Binary Search(이진 탐색)와 Interpolation Search(보간 탐색)는 효율적이지만, 동적 데이터 추가나 삭제가 자주 이루어지는 경우에는 적합하지 않을 수 있습니다. 트리 구조는 이러한 상황에서 효율적인 해결책을 제공합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.3.1 Binary Search Trees (이진 탐색 트리)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 정적 탐색 vs 동적 탐색&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;정적 탐색&lt;/b&gt;: 데이터가 추가되거나 삭제되지 않고 고정된 경우. 이진 탐색(Binary Search)이 적합.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;동적 탐색&lt;/b&gt;: 데이터가 자주 추가되고 삭제되는 경우. 이진 탐색 트리는 데이터 추가 및 삭제가 용이.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 이진 탐색 트리 구조&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;트리의 노드는 데이터 값을 저장하고, 왼쪽 자식은 더 작은 값, 오른쪽 자식은 더 큰 값을 저장.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;In-order Traversal(중위 순회)&lt;/b&gt;:&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;왼쪽 서브트리를 탐색 &amp;rarr; 루트 방문 &amp;rarr; 오른쪽 서브트리 탐색.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;이 방법을 통해 정렬된 순서로 데이터에 접근 가능.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 이진 탐색 트리와 이진 탐색의 관계&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;이진 탐색 트리에서 탐색 과정은 이진 탐색(Binary Search)와 동일.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;예를 들어, 트리 구조에서 특정 값을 찾기 위해 키 값과 비교를 반복하며 좌우 서브트리로 이동.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 문제점&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;트리가 불균형(Skewed Tree) 상태가 되면 성능이 선형 시간&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;O(n)&lt;/span&gt;으로 저하될 수 있음.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;예: 값이 정렬된 순서로 추가될 경우 트리가 리스트처럼 한쪽으로 치우침.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. Theorem 8.3&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;평균적으로, 이진 탐색 트리를 사용하는 탐색 시간은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;A(n) &amp;asymp; 1.38 \log n&lt;/span&gt;.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;트리가 무작위로 구성된다고 가정하면, 효율적인 탐색 성능을 보장.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.3.2 B-Trees (B-트리)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;B-트리는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;대규모 데이터베이스&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;및 외부 저장소 검색에서 주로 사용되는 트리입니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 특징&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;B-트리는 항상 균형을 유지하며, 모든 리프 노드가 같은 깊이에 있음.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;데이터를 추가하거나 삭제해도 트리의 균형이 깨지지 않음.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 3-2 트리 (3-2 Tree)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;특성&lt;/b&gt;:&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;각 노드는 1개 또는 2개의 키를 포함.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;키는 항상 정렬된 상태로 저장됨.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;각 노드의 자식은 키 값에 따라 구분됨.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;모든 리프 노드는 같은 깊이에 있음.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 추가 동작&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;키를 추가할 때:&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;노드가 가득 차면, 가운데 키를 부모로 올림.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;리프 노드에 새 키를 추가하거나, 부모 노드로 분리.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 장점&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;항상 균형이 유지되므로 탐색, 삽입, 삭제 모두&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;O(\log n)&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;시간 복잡도를 가짐.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;B-트리는 대규모 데이터 처리에 적합하며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;대부분의 현대 데이터베이스 시스템&lt;/b&gt;에서 활용됨.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;Figure 8.5&lt;/b&gt;: 이진 탐색 트리의 구성 및 탐색 방법.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;Figure 8.6&lt;/b&gt;: 스큐드(Skewed) 트리 예시. 키가 정렬된 순서로 삽입될 경우.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.55.57.png&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;806&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6hnmV/btsLeuN3vR9/mIrESsEp99vKYfPOlbimTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6hnmV/btsLeuN3vR9/mIrESsEp99vKYfPOlbimTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6hnmV/btsLeuN3vR9/mIrESsEp99vKYfPOlbimTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6hnmV%2FbtsLeuN3vR9%2FmIrESsEp99vKYfPOlbimTK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;784&quot; height=&quot;806&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.55.57.png&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;806&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;Figure 8.7&lt;/b&gt;: 3-2 트리에서 데이터 추가 예제.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.56.13.png&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;850&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QnZgu/btsLbWMJUOS/2SwHMhT03hwBxPgdcgh4tK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QnZgu/btsLbWMJUOS/2SwHMhT03hwBxPgdcgh4tK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QnZgu/btsLbWMJUOS/2SwHMhT03hwBxPgdcgh4tK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQnZgu%2FbtsLbWMJUOS%2F2SwHMhT03hwBxPgdcgh4tK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;790&quot; height=&quot;850&quot; data-filename=&quot;Screenshot 2024-12-10 at 14.56.13.png&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;850&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;(a): 리프 노드에 새로운 키 추가.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;(b): 리프 노드가 가득 찬 경우 부모로 키 이동.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;(c): 루트 노드가 가득 찬 경우 새로운 루트 생성.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 B-트리는 데이터베이스 시스템에서 효율적으로 활용될 수 있는 매우 유용한 트리 구조를 설명합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.4 Hashing&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Hashing 개요&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Hashing은 키를 특정 값으로 변환하여 데이터를 효율적으로 저장하고 검색하는 기법입니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;문제 상황&lt;/b&gt;: 1부터 100까지의 키와 약 100개의 데이터를 다룰 때, 배열에 데이터를 저장하면 키가 곧 인덱스가 되어 검색이 빠르지만, 메모리 낭비가 발생할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;해결 방법&lt;/b&gt;: 키를 특정 범위(예: 0~99)로 변환하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;해시 함수&lt;/b&gt;를 사용해 메모리를 절약하면서도 효율적인 검색을 가능하게 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Hash Function&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;해시 함수&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;h(key) = key mod 100&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;는 키를 100으로 나눈 나머지를 반환합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;이 함수는 키를 특정 인덱스(0~99)로 변환하여 배열&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;S[i]&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;에 저장합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;조건&lt;/b&gt;: 키가 유일한 인덱스로 매핑되지 않을 가능성(충돌)이 존재합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Collision (충돌)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;충돌&lt;/b&gt;이란 두 키가 동일한 해시 값으로 변환되는 경우를 뜻합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;예를 들어, 키가 100개인 경우 충돌이 없는 확률은 매우 낮습니다 (&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;9.3 * 10^{-43}&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;).&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;충돌 해결 방법: Open Hashing (열린 해싱)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;각 해시 값에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;버킷(bucket)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;을 생성하고, 해당 해시 값에 매핑된 키들을 연결 리스트 형태로 저장합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;그림 8.8에서는 동일한 해시 값을 가지는 키들이 하나의 버킷에 저장된 예를 보여줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-10 at 15.00.57.png&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Nak1W/btsLddUsLYc/rHOSD6lVzKPnCIE4r5ubQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Nak1W/btsLddUsLYc/rHOSD6lVzKPnCIE4r5ubQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Nak1W/btsLddUsLYc/rHOSD6lVzKPnCIE4r5ubQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNak1W%2FbtsLddUsLYc%2FrHOSD6lVzKPnCIE4r5ubQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1090&quot; height=&quot;480&quot; data-filename=&quot;Screenshot 2024-12-10 at 15.00.57.png&quot; data-origin-width=&quot;1090&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;버킷과 검색&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;버킷 개수와 키 수&lt;/b&gt;: 버킷이 많을수록 충돌 확률이 줄어들지만, 메모리 낭비가 증가합니다. 일반적으로 키 수와 동일한 버킷을 사용하는 것이 적절합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;순차 검색&lt;/b&gt;: 충돌이 발생하면 연결 리스트를 순회해야 하므로 검색 시간이 증가할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-10 at 15.01.40.png&quot; data-origin-width=&quot;860&quot; data-origin-height=&quot;936&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4efDI/btsLdzpi6Fe/CzKQBhP9z0ibk8QwFLUmwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4efDI/btsLdzpi6Fe/CzKQBhP9z0ibk8QwFLUmwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4efDI/btsLdzpi6Fe/CzKQBhP9z0ibk8QwFLUmwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4efDI%2FbtsLdzpi6Fe%2FCzKQBhP9z0ibk8QwFLUmwK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;860&quot; height=&quot;936&quot; data-filename=&quot;Screenshot 2024-12-10 at 15.01.40.png&quot; data-origin-width=&quot;860&quot; data-origin-height=&quot;936&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-10 at 15.01.57.png&quot; data-origin-width=&quot;914&quot; data-origin-height=&quot;860&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LABdA/btsLedMIGNy/T1yKwoyJ7l3COZ9XQGsCU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LABdA/btsLedMIGNy/T1yKwoyJ7l3COZ9XQGsCU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LABdA/btsLedMIGNy/T1yKwoyJ7l3COZ9XQGsCU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLABdA%2FbtsLedMIGNy%2FT1yKwoyJ7l3COZ9XQGsCU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;914&quot; height=&quot;860&quot; data-filename=&quot;Screenshot 2024-12-10 at 15.01.57.png&quot; data-origin-width=&quot;914&quot; data-origin-height=&quot;860&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-10 at 15.02.28.png&quot; data-origin-width=&quot;988&quot; data-origin-height=&quot;324&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pE7Vl/btsLdO7CAmH/kKdQu3xZ3qIKNLnR9TkjPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pE7Vl/btsLdO7CAmH/kKdQu3xZ3qIKNLnR9TkjPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pE7Vl/btsLdO7CAmH/kKdQu3xZ3qIKNLnR9TkjPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpE7Vl%2FbtsLdO7CAmH%2FkKdQu3xZ3qIKNLnR9TkjPK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;988&quot; height=&quot;324&quot; data-filename=&quot;Screenshot 2024-12-10 at 15.02.28.png&quot; data-origin-width=&quot;988&quot; data-origin-height=&quot;324&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Table 8.1&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;테이블 8.1은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;k = \log n&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;또는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;k = 2 \log n&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;일 때, 충돌 확률을 보여줍니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;예를 들어,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;n = 1024&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;일 때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;k = \log n&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;에 대해 충돌 확률은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;0.00027&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;로 매우 낮습니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;Hashing은 키가 균등하게 분포된 경우 Binary Search보다 훨씬 빠릅니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;그러나 최악의 경우를 대비하여 해시 함수를 신중히 설계해야 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;테이블을 참조하여 현실적인 키와 버킷 수에 따라 해싱 전략을 선택할 수 있습니다&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.5.1 Finding the Largest Key&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;&lt;b&gt;문제 정의&lt;/b&gt;:&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;주어진 배열&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;S&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;에서 가장 큰 키&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;\text{large}&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;를 찾습니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;입력:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;n&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;, 배열&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;S&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(크기&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;n&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;).&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;출력:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;\text{large}&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(가장 큰 값).&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;&lt;b&gt;알고리즘&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(Algorithm 8.2):&lt;/p&gt;
&lt;pre id=&quot;code_1733811414256&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void find_largest (int n, const keytype S[], keytype&amp;amp; large) {
    index i;
    large = S[1]; // 초기화
    for (i = 2; i &amp;lt;= n; ++i) { 
        if (S[i] &amp;gt; large)
            large = S[i];
    }
}&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;bull;&lt;span&gt; &lt;/span&gt;배열의 각 값을 순회하며 현재까지 발견된 가장 큰 값과 비교해 업데이트합니다.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0e0e0e;&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;비교 연산 수:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;T(n) = n - 1&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #0e0e0e;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;3.&lt;span&gt; &lt;/span&gt;&lt;b&gt;이론적 최적성&lt;/b&gt;:&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;직관적으로, 배열의 모든 값을 비교해야 가장 큰 값을 찾을 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;Theorem 8.7&lt;/b&gt;: 어떤 결정적 알고리즘이라도 모든 입력에 대해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;n-1&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;번 이상의 비교를 수행해야 가장 큰 키를 찾을 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;증명:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;n-1&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;번보다 적게 비교하면 두 키를 비교하지 않아 잘못된 결과를 낼 수 있는 입력이 존재.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.5.2 Finding Both the Smallest and Largest Keys&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;&lt;b&gt;문제 정의&lt;/b&gt;:&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;배열&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;S&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;에서 동시에 가장 큰 값&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;\text{large}&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;와 가장 작은 값&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;\text{small}&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;을 찾습니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;&lt;b&gt;알고리즘&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(Algorithm 8.3):&lt;/p&gt;
&lt;pre id=&quot;code_1733811438906&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void find_both (int n, const keytype S[], keytype&amp;amp; small, keytype&amp;amp; large) {
    index i;
    small = S[1];
    large = S[1];
    for (i = 2; i &amp;lt;= n; ++i) {
        if (S[i] &amp;lt; small)
            small = S[i];
        else if (S[i] &amp;gt; large)
            large = S[i];
    }
}&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: #0e0e0e;&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;각 배열 요소를 순회하며&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;\text{small}&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #0e0e0e;&quot;&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;\text{large}&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #0e0e0e;&quot;&gt;를 업데이트.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0e0e0e;&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;비교 연산 수:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;W(n) = 2(n-1)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #0e0e0e;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;3.&lt;span&gt; &lt;/span&gt;&lt;b&gt;향상된 방법&lt;/b&gt;:&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;한 번의 비교로 두 값을 동시에 판단하는 방식.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;Algorithm 8.4&lt;/b&gt;:&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;두 개씩 쌍을 이루어 비교.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;n/2&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;번의 비교로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;\text{small}&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;\text{large}&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;후보군 생성.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;추가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;n/2&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;번의 비교로 최종 값 선택.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;최적 비교 수:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;3n/2 - 2&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(짝수일 때).&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-12-10 at 15.17.41.png&quot; data-origin-width=&quot;1086&quot; data-origin-height=&quot;1064&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzJZP4/btsLdiuA4Co/OpGsvVAHiP7evnmPoTq4F1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzJZP4/btsLdiuA4Co/OpGsvVAHiP7evnmPoTq4F1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzJZP4/btsLdiuA4Co/OpGsvVAHiP7evnmPoTq4F1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzJZP4%2FbtsLdiuA4Co%2FOpGsvVAHiP7evnmPoTq4F1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1086&quot; height=&quot;1064&quot; data-filename=&quot;Screenshot 2024-12-10 at 15.17.41.png&quot; data-origin-width=&quot;1086&quot; data-origin-height=&quot;1064&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Adversary Argument (대항 논증)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;&lt;b&gt;목적&lt;/b&gt;:&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;알고리즘의 최악의 성능에 대해 하한선을 증명.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;대항자가 알고리즘이 최대한 많은 비교를 수행하도록 설계된 입력을 동적으로 만듦.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;&lt;b&gt;예제&lt;/b&gt;:&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;n = 5&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;일 때,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;8&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;번의 비교가 필요함을 대항자가 증명.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.5.4 Finding the k-th Smallest Key&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제 설명&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;배열&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;S&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;k&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;-번째로 작은 키를 찾는 문제를 다룹니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;단순히 배열을 정렬하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;k&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;-번째 값을 반환하는 방법은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;O(n \log n)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;시간이 걸립니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;더 적은 비교로 해결하기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;분할 및 정복(divide and conquer)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;방법을 사용합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;알고리즘 설명 (Algorithm 8.5)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;Partition Procedure&lt;/b&gt;: 배열을 분할합니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;pivotpoint&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;는 기준 값입니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;pivotpoint&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;를 기준으로, 작은 값들은 왼쪽, 큰 값들은 오른쪽으로 배치합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;재귀 호출&lt;/b&gt;:&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0e0e0e;&quot;&gt;&lt;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;만약&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;k = pivotpoint&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #0e0e0e;&quot;&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;S[pivotpoint]&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #0e0e0e;&quot;&gt;를 반환합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;k &amp;lt; pivotpoint&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;: 왼쪽 부분 배열에서 다시 찾습니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;3.&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;k &amp;gt; pivotpoint&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;: 오른쪽 부분 배열에서 다시 찾습니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;시간 복잡도&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;최악의 경우: 모든 재귀 호출이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;n-1&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;길이로 이어질 때,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;O(n^2)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;시간이 걸립니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;평균의 경우: 대부분&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;n/2&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;로 분할되므로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;O(n)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;에 가깝습니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Median of Medians (Algorithm 8.6)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;개선 방법&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;분할 과정에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;pivot&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;을 임의로 선택하지 않고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Median of Medians&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;방법을 사용합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;배열을 5개씩 나눠서 각 그룹의 중간값을 찾습니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;이 중간값들의 중간값을 구합니다(즉, &amp;ldquo;중간값들의 중간값&amp;rdquo;).&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;이를 기준으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;pivot&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;을 설정합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;알고리즘 수행 방식&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;배열을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;n/5&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;그룹으로 나눕니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;각 그룹의 중간값을 계산합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;3.&lt;span&gt; &lt;/span&gt;중간값들의 배열에서 다시&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;k번째 중간값&lt;/b&gt;을 찾습니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;4.&lt;span&gt; &lt;/span&gt;이 값을 기준으로 분할합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;시간 복잡도&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;최악의 경우에도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;O(n)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;을 보장합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;이유: 매 재귀 호출마다 배열 크기가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;n/5&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;로 감소하기 때문입니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Probabilistic Selection Algorithm (Algorithm 8.7)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;확률적 접근법&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;Sherwood 알고리즘&lt;/b&gt;: 분할 기준인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;pivot&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;을 랜덤하게 선택합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;이 방식은 평균적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;O(n)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;시간에 동작합니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;최악의 경우는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;O(n^2)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;이지만, 랜덤 선택으로 인해 발생 확률이 매우 낮습니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;시간 복잡도 분석&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;기대값 계산을 통해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;O(n)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;임을 보입니다.&lt;/p&gt;
&lt;p style=&quot;color: #0e0e0e; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;재귀적으로 기대값을 계산하며, 반복적으로 모든 가능성을 고려합니다.&lt;/p&gt;</description>
      <category>Book/Foundations Of Algorithms</category>
      <category>Algorithm</category>
      <category>알고리즘</category>
      <author>S0LL</author>
      <guid isPermaLink="true">https://sol248.tistory.com/144</guid>
      <comments>https://sol248.tistory.com/144#entry144comment</comments>
      <pubDate>Tue, 10 Dec 2024 15:33:35 +0900</pubDate>
    </item>
  </channel>
</rss>