<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>stat_kwon.log</title>
        <link>https://velog.io/</link>
        <description>백엔드 개발자를 목표로 공부하고 있습니다.</description>
        <lastBuildDate>Tue, 29 Jun 2021 18:09:38 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>stat_kwon.log</title>
            <url>https://images.velog.io/images/stat_wkon/profile/0b1ad6da-65e2-4ed9-9ca7-2e82b2254b75/social.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. stat_kwon.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/stat_wkon" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[CS] API와 REST API]]></title>
            <link>https://velog.io/@stat_wkon/CS-API%EC%99%80-REST-API</link>
            <guid>https://velog.io/@stat_wkon/CS-API%EC%99%80-REST-API</guid>
            <pubDate>Tue, 29 Jun 2021 18:09:38 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolorwhite-background-colorblack1-api"><span style="color:white; background-color:black;">1. API</h1>
<p><img src="https://images.velog.io/images/stat_wkon/post/cfd2da6b-22ef-4daf-8ae0-1242a29b1c4a/image.png" alt=""></p>
<ul>
<li>쉽게 비유를 들어서 위의 그림으로 설명 가능</li>
<li>손님과 요리사 사이에서 점원의 역할이 프로그램과 프로그램 사이의 API 역할이라고 생각하면 됨</li>
<li>즉, 프로그램간의 요청을 편리하게 처리하기 위해 존재한다.</li>
</ul>
<blockquote>
<p><strong>Application Program Interface ( API )</strong>의 사전적 정의</p>
<p>프로그램을 작성하기 위한 일련의 부(Sub) 프로그램, 프로토콜 등을 정의하여 상호 작용을 하기 위한 인터페이스 사양</p>
</blockquote>
<h1 id="span-stylecolorwhite-background-colorblack2-rest-api-restful-api"><span style="color:white; background-color:black;">2. REST API (RESTful API)</h1>
<h2 id="span-stylecolorwhite-background-colorblack1-rest-api-란"><span style="color:white; background-color:black;">1) REST API 란?</h2>
<blockquote>
<p>REST ( Representational State Transfer )</p>
<ul>
<li>표현 가능한 상태에서의 전달 ( 직역 )</li>
</ul>
</blockquote>
<ul>
<li>자원을 이름(자원의 표현)으로 구분하여 해당 자원의 상태(정보)를 주고 받는 모든 것을 의미</li>
<li>REST는 기본적으로 웹의 기존 기술과 HTTP 프로토콜을 그대로 활용하기 때문에 웹의 장점을 최대한 활용할 수 있는 아키텍처 스타일이다.</li>
</ul>
<h2 id="span-stylecolorwhite-background-colorblack2-rest-api-설계-기본-규칙"><span style="color:white; background-color:black;">2) REST API 설계 <strong>기본 규칙</strong></h2>
<ul>
<li>URI는 정보의 자원을 표현해야 한다.</li>
<li>자원에 대한 행위는 HTTP Method(GET, PUT, POST, DELETE 등)로 표현한다. <ul>
<li>URI에 HTTP Method가 들어가면 안된다. <ul>
<li>Ex) <code>GET /members/delete/1</code> -&gt; <code>DELETE /members/1</code></li>
</ul>
</li>
<li>경로 부분 중 변하는 부분은 유일한 값으로 대체한다.(즉, :id는 하나의 특정 resource를 나타내는 고유값이다.) <pre><code>    Ex) student를 생성하는 route: POST /students
    Ex) id=12인 student를 삭제하는 route: DELETE /students/12</code></pre></li>
</ul>
</li>
</ul>
<h2 id="span-stylecolorwhite-background-colorblack3-rest-api-설계-규칙"><span style="color:white; background-color:black;">3) REST API 설계 규칙</h2>
<ol>
<li>슬래시 구분자(/ )는 계층 관계를 나타내는데 사용한다. <ul>
<li>Ex) <code>http://restapi.example.com/houses/apartments</code></li>
</ul>
</li>
</ol>
<ol start="2">
<li><p>URI 마지막 문자로 슬래시(/ )를 포함하지 않는다. </p>
<ul>
<li>URI에 포함되는 모든 글자는 리소스의 유일한 식별자로 사용되어야 하며 URI가 다르다는 것은 리소스가 다르다는 것이고, 역으로 리소스가 다르면 URI도 달라져야 한다.</li>
<li>REST API는 분명한 URI를 만들어 통신을 해야 하기 때문에 혼동을 주지 않도록 URI 경로의 마지막에는 슬래시(/)를 사용하지 않는다.</li>
<li>Ex) <code>http://restapi.example.com/houses/apartments/ (X)</code></li>
</ul>
</li>
<li><p>하이픈(- )은 URI 가독성을 높이는데 사용 </p>
<ul>
<li>불가피하게 긴 URI경로를 사용하게 된다면 하이픈을 사용해 가독성을 높인다.</li>
</ul>
</li>
<li><p>밑줄(_ )은 URI에 사용하지 않는다. </p>
</li>
<li><p>URI 경로에는 소문자가 적합하다. </p>
</li>
<li><p>파일확장자는 URI에 포함하지 않는다. </p>
</li>
<li><p>리소스 간에는 연관 관계가 있는 경우 </p>
<ul>
<li>/리소스명/리소스 ID/관계가 있는 다른 리소스명</li>
<li>Ex) <code>GET : /users/{userid}/devices</code>(일반적으로 소유 ‘has’의 관계를 표현할 때)</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] Memo API 만들기 (CRUD 기능 구현)]]></title>
            <link>https://velog.io/@stat_wkon/Spring-Memo-API-%EB%A7%8C%EB%93%A4%EA%B8%B0-CRUD-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84</link>
            <guid>https://velog.io/@stat_wkon/Spring-Memo-API-%EB%A7%8C%EB%93%A4%EA%B8%B0-CRUD-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84</guid>
            <pubDate>Mon, 28 Jun 2021 15:18:51 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolorwhite-background-colorblack1-목표"><span style="color:White; background-color:black;">1. 목표</h1>
<ul>
<li><p>End to End 프로젝트</p>
</li>
<li><p>3계층에 대한 이해</p>
</li>
<li><p>API 설계하기 (CRUD) 와 구현</p>
</li>
</ul>
<hr>
<h1 id="span-stylecolorwhite-background-colorblack2-repository-만들기"><span style="color:White; background-color:black;">2. Repository 만들기</h1>
<h2 id="span-stylecolorwhite-background-colorblack1-memo-클래스-만들기"><span style="color:White; background-color:black;">1) Memo 클래스 만들기</h2>
<blockquote>
<p><strong>왜 필요할가?</strong>
Memo라는 것을 구현하려면 필요한 Table을 만들어야 함
  → 이러한 기능을 <span style="color:red;">Repository에서 domain이 담당하게됨</span>
→ domain &gt; Memo.java 클래스를 만들어 준다.</p>
</blockquote>
<ul>
<li>메모는 1) 익명의 작성자 이름(username), 2) 메모내용(contents)로 이루어져 있다.</li>
<li>Memo.java</li>
</ul>
<pre><code class="language-java">    @NoArgsConstructor // 기본생성자를 만듭니다.
    @Getter // getter를 lombok으로 쉽게 표현
    @Entity // 테이블과 연계됨을 스프링에게 알려줍니다. DB설계도로 할거야를 알려줌
    public class Memo extends Timestamped { // 생성,수정 시간을 자동으로 만들어줍니다.
    // Timestamped를 상속받아 기능을 추가(생성시간, 수정시간 변수화)

        @GeneratedValue(strategy = GenerationType.AUTO) // 1씩 증가하게 자동생성
        @Id // Primary key를 지정
        private Long id;                // 인스턴스 변수 1

        @Column(nullable = false)
        private String username;        // 인스턴스 변수 2

        @Column(nullable = false)
        private String contents;        // 인스턴스 변수 3

        public Memo(String username, String contents) { // 생성자를 만들어줌
            this.username = username; // 기본 생성자가 필요하지만 어노테이션 처리함
            this.contents = contents;
        }

        public Memo(MemoRequestDto requestDto) {
            this.username = requestDto.getUsername();
            this.contents = requestDto.getContents();
        }

        public void update(MemoRequestDto requestDto){ // 업데이트 메소드
            this.username = requestDto.getUsername();  // return 없음
            this.contents = requestDto.getContents();  // DTO를 통해서 update하게 됨
        }

    }</code></pre>
<pre><code>- DB를 직접 바꿀일은 없으므로 Setter는 필요 없음, Getter만 필요
- record를 생성할때 정해진 파라미터가 필요하므로 생성자가 필요함
- requestsDto를 통해서 데이터를 이동시키므로 생성자의 파라미터 타입 MemoRequestDto</code></pre><h2 id="span-stylecolorwhite-background-colorblack2-memorepository-인터페이스-만들기"><span style="color:White; background-color:black;">2) MemoRepository 인터페이스 만들기</h2>
<blockquote>
<p><strong>왜 필요할가?</strong>
SQL과 같은 기능을 하는 것은 Repository 따라서 MemoRepository를 만들어 줌
  이때 <span style="color:red;">JpaRepository의 메서드만 사용할 것</span>이므로 상속후 인터페이스로 만들어 줌</p>
</blockquote>
<ul>
<li>MemoRepository.java</li>
</ul>
<pre><code class="language-java">
    public interface MemoRepository extends JpaRepository&lt;Memo, Long&gt; { // 상속 후 JPA 메서드 사용
        List&lt;Memo&gt; findAllByOrderByModifiedAtDesc(); // 수정시간 기준 오름차순으로 List안에 Memo 객체를 넣어줌
    }</code></pre>
<pre><code>- JPA 메서드만을 사용하는 인터페이스를 만드는데 Memo DB이므로 MemoRepository를 만듬</code></pre><h2 id="span-stylecolorwhite-background-colorblack3-memorequestdto-클래스-만들기"><span style="color:White; background-color:black;">3) MemoRequestDto 클래스 만들기</h2>
<blockquote>
<p><strong>왜 필요할가?</strong>
DB에 직접 접근하여 값을 수정하는 것은 데이터 분석에도 금기 되어 있는 사실!
  따라서 <span style="color:red;">값의 이동이 있을 때 DTO를 사용</span></p>
</blockquote>
<ul>
<li>MemoRequestDto.java</li>
</ul>
<pre><code class="language-java">
    @Getter
    public class MemoRequestDto {
        private String username;     // 컬럼 중 하나
        private String contents;     // 컬럼 중 하나

    }</code></pre>
<pre><code>- 자동생성되는 ID는 제외하고 memo table의 column을 멤버 변수로 갖는다.
- 또한 private 멤버 변수를 조회하기 위해 Getter 옵션을 사용한다.</code></pre><h1 id="span-stylecolorwhite-background-colorblack3-memoservice-클래스-만들기"><span style="color:White; background-color:black;">3. MemoService 클래스 만들기</h1>
<blockquote>
<p><strong>왜 필요할가?</strong>
  일단은 <span style="color:red;">Client에서 DB로 넘어가서 update를 해준다는 점</span>에서 Service에 해당이 됨
추후 DB 관련 update는 모두 Service에서 구현하는지 궁금함
또한, 서비스에 대한 이해가 진짜 필요함</p>
</blockquote>
<ul>
<li>MemoService.java</li>
</ul>
<pre><code class="language-java">
    @RequiredArgsConstructor  // final은 꼭 필요한 녀석으로 생성자도 필요로 함
    @Service // Service임을 알려주고 있음
    public class MemoService {

        private final MemoRepository memoRepository;  //꼭 필요한 녀석

        @Transactional // 트랜젝션 기능
        public Long update(Long id, MemoRequestDto requestDto) {
            Memo memo = memoRepository.findById(id).orElseThrow(
                    () -&gt; new IllegalArgumentException(&quot;아이디가 존재하지 않습니다.&quot;)
            );
            memo.update(requestDto);
            return memo.getId();
        }
    }</code></pre>
<pre><code>- 일단 Client단에서 DB로 데이터의 이동이기 때문에 Service에 update를 만들어 놓는 것임</code></pre><h1 id="span-stylecolorwhite-background-colorblack4-controller-클래스-만들기"><span style="color:White; background-color:black;">4. Controller 클래스 만들기</h1>
<blockquote>
<p><strong>왜 필요할가?</strong>
  <span style="color:red;">API 요청을 처리하기 위해 필요하다.</span>
즉, API 설계도에 따라 적절한 GET, PUT, DELETE, POST에 따라 반환되는 값이 무엇인지 설정해주게 됨</p>
</blockquote>
<ul>
<li>MemoContoller.java</li>
</ul>
<pre><code class="language-java">@RequiredArgsConstructor // final에 꼭 필요한 녀석들은 생성자를 필요로 함
@RestController // Json 형태로 객체 데이터를 반환하기 위함
public class MemoController {

    private final MemoRepository memoRepository; // 꼭 필요한 녀석들을 멤버 변수로 설정
    private final MemoService memoService;

    @PostMapping(&quot;/api/memos&quot;) // Post요청
    public Memo createMemo(@RequestBody MemoRequestDto requestDto) { // Json으로 입력받으면 
        Memo memo = new Memo(requestDto); // Memo 객체 생성 후
        return memoRepository.save(memo); // DB에 저장
    }

    @GetMapping(&quot;/api/memos&quot;) // Get 요청
    public List&lt;Memo&gt; getMemos() { // GET이므로 BODY에 json은 없음
        return memoRepository.findAllByOrderByModifiedAtDesc(); // 조회해줌
    }

    @DeleteMapping(&quot;/api/memos/{id}&quot;)
    public Long deleteMemo(@PathVariable Long id) { //URL path로 부터 파라미터를 받음
        memoRepository.deleteById(id);
        return id;
    }

    @PutMapping (&quot;/api/memos/{id}&quot;)
    public Long updateMemo(@PathVariable Long id,@RequestBody MemoRequestDto requestDto){
        memoService.update(id,requestDto); //Service인 update를 이용
        return id;
    }
}</code></pre>
<ul>
<li><p>Client로 부터 시작되는 요청에 따라 어떻게 stack되는지 흐름을 파악할 필요가 있음</p>
</li>
<li><p>Client 요청으로 부터 해야될 일들이 Controller에 만들어져 있음을 확인</p>
<blockquote>
<p><strong>느낀점!</strong></p>
<ol>
<li>객체 지향 개념을 모두 이해하면서 Spring에 대입하는 것이 완벽하게 되지 않는다는 것
(기초가 부족)</li>
<li>아직도 Service의 모호한 개념이 머리에 있어서 추가 공부가 필요함</li>
<li>Annotation은 그때그때 쓰임새를 알아둘 것</li>
<li>기본적으로 CRUD를 구현할 자신감은 생김!!</li>
</ol>
</blockquote>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JAVA] 객체지향 언어(클래스와 객체)]]></title>
            <link>https://velog.io/@stat_wkon/JAVA-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%EC%96%B8%EC%96%B4%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EA%B0%9D%EC%B2%B4</link>
            <guid>https://velog.io/@stat_wkon/JAVA-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-%EC%96%B8%EC%96%B4%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EA%B0%9D%EC%B2%B4</guid>
            <pubDate>Sun, 27 Jun 2021 06:14:08 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolorwhite-background-colorblack객체지향-언어"><span style="color:white; background-color:black;">객체지향 언어</h1>
<ul>
<li>80년 초 소프트웨어의 위기 ⇒ 빠른 변화를 못 쫒아감</li>
<li>해결책으로 <strong>객체지향 언어</strong>를 도입 ( 절차적 ⇒ 객체지향 )</li>
<li>코드의 재사용성이 높고 유지보수가 용이, 중복 코드 제거</li>
<li>프로그래밍 언어 + 객체지향개념 ( 규칙 ) ⇒ <span style="color:red;">규칙이라서 외워야 함!<blockquote>
<ul>
<li>OOP의 4가지 핵심 개념</li>
</ul>
</blockquote>
<ol>
<li>캡슐화</li>
<li>상속</li>
<li>추상화</li>
<li><span style="color:red;">다형성</li>
</ol>
</li>
<li>객체지향 개념은 설계에 해당해서 처음에 하기 힘들다</li>
</ul>
<hr>
<h1 id="span-stylecolorwhite-background-colorblack클래스와-객체"><span style="color:white; background-color:black;">클래스와 객체</h1>
<h2 id="1-클래스와-객체란">1. 클래스와 객체란?</h2>
<ul>
<li>클래스의 정의 : 객체를 정의해 놓은 것</li>
<li>클래스의 용도 : 객체를 생성하는데 사용</li>
<li>객체의 정의 : 실제로 존재하는 것. 사물 또는 개념</li>
<li>객체의 용도 : 객체가 가지고 있는 기능과 속성에 따라 다름</li>
</ul>
<h2 id="2-객체의-구성-요소---속성과-기능">2. 객체의 구성 요소 - 속성과 기능</h2>
<ul>
<li>거시적 관점 : 하드웨어를 소프트웨어화(프로그램 화 = 코드) 시키는 것에서 시작<ul>
<li>따라서 하드웨어를 분석 &amp; 관찰이 필요함</li>
</ul>
</li>
<li>객체 = 속성(변수) + 기능(메서드)  ⇒ TV로 예를 들면<ul>
<li>속성 : 크기, 길이, 높이, 색상, 볼륨, 채널</li>
<li>기능 : 끄기, 켜기, 볼륨 높이기, 볼륨 낮추기, 채널 변경하기 등등</li>
</ul>
</li>
</ul>
<h2 id="3-객체와-인스턴스">3. 객체와 인스턴스</h2>
<ul>
<li>객체 : 모든 인스턴스를 대표하는 일반적인 용어</li>
<li>인스턴스 : 특정 클래스로부터 생성된 객체 ( 예 : TV인스턴스 )</li>
<li>객체와 인스턴스는 같은 의미다라고 생각해도 됨</li>
<li>클래스 ⇒ 인스턴스(객체) , 인스턴스화 한다라고 표현</li>
</ul>
<blockquote>
<p>Q. 클래스가 왜 필요한가?
A. 객체를 생성하기 위해</p>
</blockquote>
<blockquote>
<p>Q. 객체가 왜 필요한가?
A. 객체를 사용하기 위해</p>
</blockquote>
<blockquote>
<p>Q. 객체를 사용한다는 것은?
A. 객체가 가진 속성(변수)과 기능(메서드)을 사용하려고</p>
</blockquote>
<hr>
<h1 id="span-stylecolorwhite-background-colorblack하나의-소스파일에-여러-클래스-작성"><span style="color:white; background-color:black;">하나의 소스파일에 여러 클래스 작성</h1>
<pre><code class="language-java">// hello2.java로 소스 파일 이름을 해야함
public class Hello2 {}
       class Hello3 {}

// Hello2.java or Hello3.java 둘다 가능
class Hello2 {}
class Hello3 {}</code></pre>
<ul>
<li>java 파일 이름과 Public class 이름과 일치해야 한다.</li>
<li>심지어 대소문자도 일치해야 함</li>
<li>가능하면 하나의 소스파일에는 하나의 클래스만 작성하는 것이 바람직</li>
</ul>
<hr>
<h1 id="span-stylecolorwhite-background-colorblack객체의-생성과-사용"><span style="color:white; background-color:black;">객체의 생성과 사용</h1>
<h2 id="1-객체의-생성">1. 객체의 생성</h2>
<blockquote>
<p>*<em>클래스명 변수명;       *</em>           // 클래스의 객체를 참조하기 위한 참조변수 선언
*<em>변수명 = new 클래스명();  *</em>  // 클래스의 객체를 생성 후, 객체의 주소를 참조변수에 저장</p>
</blockquote>
<pre><code class="language-java">//예를 들면
Tv t;             // Tv클래스 타입의 참조변수 t를 선언 (t를 리모콘으로 비유)
t = new Tv();     // Tv인스턴스를 생성한 후, 생성된 Tv 인스턴스의 주소를 t에 저장

//이를 한번에 표현하면
Tv t = new Tv();</code></pre>
<h2 id="2-객체의-사용">2. 객체의 사용</h2>
<pre><code class="language-java">t.channel = 7;     // Tv인스턴스의 멤버변수 channel의 값을 7로 한다.
t.channelDown();   // Tv인스턴스의 메서드 channelDown()을 호출한다.
System.out.println(&quot;현재 채널은 &quot; + t.channel + &quot; 입니다.&quot;);</code></pre>
<blockquote>
<p><strong>순서</strong></p>
</blockquote>
<ol>
<li>클래스 작성</li>
<li>객체의 생성</li>
<li>객체의 사용<blockquote>
</blockquote>
3단계로 사용할 것</li>
</ol>
<p><img src="https://images.velog.io/images/stat_wkon/post/f4dabd99-ae82-41f8-a2b9-e498c9b0cf15/image.png" alt=""></p>
<ul>
<li>Tv 인스턴스 중 하나인 t를 print해보면 주소가 찍히는 이유</li>
<li>대입 연산자로 공간에 객체 주소를 대입해주는 것</li>
</ul>
<hr>
<p>  <strong><em>생각 해보기</em></strong></p>
<p>  Java 언어를 접하면서 왜? 객체지향에 특화되어있는 지, 고민과 함께 공부를 하고 있음
일단, 기본적으로 객체지향 개념 (규칙)을 어느 정도 암기가 필요하다는 사실도 알게 됨
Python도 그렇고 JAVA도 class를 print했을 때 주소값이 나오는게 이해가 되지않았는데
강의를 듣고 메모리 측면과 함께 생각하니 당연하다고 생각이 들었음 
( 접근을 통해 이해가 되서 많이 놀램 )
추후, 남궁성님 유튜브 강의를 공부하고 체화 시킨 후 지속적인 업로드를 할 예정</p>
<hr>
<p> <strong>Reference</strong></p>
<p>  남궁성님 유튜브 강의를 보고 작성하였습니다.
<a href="https://www.youtube.com/watch?v=p1ZZnM715ao&amp;list=PLW2UjW795-f5JPTsYHGAawAck9cQRw5TD&amp;index=4&amp;ab_channel=%EB%82%A8%EA%B6%81%EC%84%B1%EC%9D%98%EC%A0%95%EC%84%9D%EC%BD%94%EB%94%A9">https://www.youtube.com/watch?v=p1ZZnM715ao&amp;list=PLW2UjW795-f5JPTsYHGAawAck9cQRw5TD&amp;index=4&amp;ab_channel=남궁성의정석코딩</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-2] BFS와 DFS 이해]]></title>
            <link>https://velog.io/@stat_wkon/TIL-2-BFS%EC%99%80-DFS-%EC%9D%B4%ED%95%B4</link>
            <guid>https://velog.io/@stat_wkon/TIL-2-BFS%EC%99%80-DFS-%EC%9D%B4%ED%95%B4</guid>
            <pubDate>Fri, 18 Jun 2021 15:48:04 GMT</pubDate>
            <description><![CDATA[<h1 id="span-stylecolorwhite-background-colorblack1-why"><span style="color:white; background-color:black;">1. WHY?</h1>
<ul>
<li>왜 쓰는지에 대해 이해하는 것이 중요하다.</li>
<li>BFS, DFS 용어에서 유추가 되듯이 먼저, <code>탐색(Search)</code>에 대해 생각해 볼 필요가 있다.</li>
</ul>
<h2 id="span-stylecolorwhite-background-colorblack11-탐색search"><span style="color:white; background-color:black;">1.1 탐색(Search)</h2>
<ul>
<li>알고리즘을 시작하면서 쉽게 접하게 되는 주제이다.</li>
<li>단순히 이름 그대로 원하는 데이터를 검색하는데 최적으로 도달하기 위한 기법이라고 하기에는 다양한 문제(분야)에 접목이 된다.  ( 위키피디아 - <a href="https://ko.wikipedia.org/wiki/%EA%B2%80%EC%83%89_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98">검색 알고리즘</a> )</li>
<li>여러 탐색 알고리즘 ( 현재 정확히 알고 있는 알고리즘 기준)<ul>
<li>완전탐색</li>
<li>이진탐색 (Binary search)</li>
<li>깊이우선탐색 ( Depth-First Search )</li>
<li>너비우선탐색 ( Breadth-First Search)</li>
<li>해시탐색 (아직 잘 모르는 개념 - 시간이 가장 빠른 것만 알고 있음)</li>
</ul>
</li>
</ul>
<p><a href="https://www.notion.so/96da74a5f5cc4c9ea2066c41fbf7a2fc">Search Algorithm 특징</a></p>
<blockquote>
<p>여기까지 보았을 때 탐색 알고리즘에는 각 특징들이 있고 왜? 쓰는지에 대해 대략적으로 해소는 되지만 실제 코딩 문제에 봉착했을 때 DFS를 쓸 지 BFS에 대해서는 판단 기준은 서지 않는다. 일단은 DFS와 BFS에 대해 자세히 알아보자!</p>
</blockquote>
<h1 id="span-stylecolorwhite-background-colorblack2-depth-first-search-dfs"><span style="color:white; background-color:black;">2. depth-first search (DFS)</h1>
<h2 id="span-stylecolorwhite-background-colorblack21-dfs란"><span style="color:white; background-color:black;">2.1 DFS란?</h2>
<ul>
<li>먼저, input으로 들어가게 되는 인접행렬, 인접 리스트와 같은 개념은 생략하였다.</li>
<li>백문이 불여일견이다.</li>
</ul>
<p><img src="https://upload.wikimedia.org/wikipedia/commons/7/7f/Depth-First-Search.gif" alt="https://upload.wikimedia.org/wikipedia/commons/7/7f/Depth-First-Search.gif"></p>
<ul>
<li>왼쪽부터 계층을 모두 거쳐 오른쪽으로 탐색을 진행한다.</li>
<li>위의 그림을 보았을 때 깊이 우선 탐색이라는 말이 와닿는다.</li>
<li>다시 말하면, 갈 수 있는 만큼 <strong>계속해서</strong> 탐색하다가 갈 수 없게 되면 다른 방향으로 다시 탐색하는 구조입니다.</li>
<li>실행 과정<ol>
<li>노드를 방문하고 <strong>깊이 우선으로 인접한</strong> 노드를 방문한다. ( 1 → 2 ) </li>
<li>또 그 노드를 방문해서 <strong>깊이 우선으로 인접한</strong> 노드를 방문한다. ( 2 → 3 → 4 )</li>
<li>만약 <strong>끝에 도달했다면</strong> 리턴한다. ( 4 → X )</li>
</ol>
</li>
</ul>
<blockquote>
<p>반복하다가 → 갈 수가 없게 되면 → 탈출 조건
즉, 재귀함수를 이용해서 구현할 수 있음
재귀함수는 stack 특성을 가짐 즉, stack을 이용해 DFS를 구현한다는 것을 의미</p>
</blockquote>
<blockquote>
<p>재귀함수는 F(n+1) = ? X F(n) 구조를 찾는 것이 중요! (TIL-1 재귀함수 참고)
DFS(node) = node + DFS(node와 인접하지만 방문하지 않은 다른 node)로 생각해 볼 수 있음</p>
</blockquote>
<h2 id="span-stylecolorwhite-background-colorblack22-dfs-구현"><span style="color:white; background-color:black;">2.2 DFS 구현</h2>
<ul>
<li>예시 1) 인접 리스트가 주어질 때, 모든 노드를 DFS 순서대로 방문하시오.</li>
</ul>
<h3 id="span-stylecolorwhite-background-colorblack221-인접-리스트-adjacent-list"><span style="color:white; background-color:black;">2.2.1 인접 리스트 (Adjacent list)</h3>
<pre><code class="language-python">graph = {
    1: [2, 5, 9],
    2: [1, 3],
    3: [2, 4],
    4: [3],
    5: [1, 6, 8],
    6: [5, 7],
    7: [6],
    8: [5],
    9: [1, 10],
    10: [9]
}

graph = [[],
         [2, 5, 9],
         [1, 3],
         [2, 4],
         [3],
         [1, 6, 8],
         [5, 7],
         [6],
         [5],
         [1, 10],
         [9]]</code></pre>
<ul>
<li>인접리스트를 딕셔너리로 표현하느냐, 리스트로 표현하느냐에 따른 표현의 차이 ( 접근하는 슬라이싱만 제대로하면 문제될게 없음)</li>
<li>짧지만 코딩 문제 경험상 이중 리스트 구조로 표현하는 것이 괜찮을 것으로 보인다. ( [ [] *len()])과 같은 표현으로 쉽게 구성 가능 )</li>
<li>graph[i] 에서 i의 의미는 &quot;i에서&quot;라는 시작의 의미이므로 graph[0]은 빈 리스트를 가진다.</li>
<li>위의 그림의 예제를 이용한 것이다. 따라서 DFS에 의해 방문 순서를 구하게 되면 [1,2,3,4,5,6,7,8,9,10]이 정답이 된다.</li>
</ul>
<h3 id="span-stylecolorwhite-background-colorblack222-구현을-위한-생각"><span style="color:white; background-color:black;">2.2.2 구현을 위한 생각</h3>
<ul>
<li><p><strong>구현 방법</strong></p>
<ol>
<li>루트 노드부터 시작한다.</li>
<li>현재 방문한 노드를 visted =[] 에 추가한다.</li>
<li>현재 방문한 노드와 인접한 노드 중 방문하지 않은 노드에 방문한다.</li>
<li>2, 3을 반복하며 계층 끝에 도달한다.</li>
</ol>
</li>
<li><p>*<em>왜 stack을 이용하는지에 대한 생각 *</em>
  stack은 FILO인 선입후출 개념
  따라서 처음 시작 노드와 인접한 노드를 모두 저장해두고
  가장 왼쪽의 노드의 모든 계층을 탐색한 이후
  되돌아와 저장해 둔 노드 중 방문하지 않은 다음 노드로 넘어감
  → 이런 논리는 stack으로 구현하면 알맞음</p>
</li>
<li><p><strong>예시를 통한 이해</strong>
  1과 인접한 (2, 5, 9) 저장
  → 2와 인접한 3
  → 3과 인접한 4
  → 다시 돌아와 1과 인접한 5를 탐색 이후 반복</p>
</li>
</ul>
<h3 id="span-stylecolorwhite-background-colorblack223-구현"><span style="color:white; background-color:black;">2.2.3 구현</h3>
<ul>
<li><strong>구현 방법에 따른 코드</strong></li>
</ul>
<pre><code class="language-python">visited = []

# dictionary의 경우
def dfs_recursion(adjacent_graph, cur_node, visited_array):
    visited_array.append(cur_node)
    for adjacent_node in adjacent_graph:
        if adjacent_node not in visited_array:
            dfs_recursion(adjacent_graph, adjacent_node, visited_array)
    return

# list의 경우
def dfs_recursion(adjacent_graph, cur_node, visited_array):
    visited_array.append(cur_node) # (1)
    for adjacent_node in adjacent_graph[cur_node]: # (2)
        if adjacent_node not in visited_array: # (2)
            dfs_recursion(adjacent_graph,adjacent_node,visited_array) # (3)
    return visited_array # (4)

dfs_recursion(graph, 1, visited)
print(visited)</code></pre>
<blockquote>
<blockquote>
<p>(result)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]</p>
</blockquote>
</blockquote>
<ul>
<li>(1) : 현재 노드를 visted에 추가</li>
<li>(2) : 인접 리스트를 통해 추가된 노드와 인접한 노드를 찾은 후, visited에 없는지 확인</li>
<li>(3) : (1)과(2)는 반복적인 작업이므로 재귀함수를 통해 cur_node만 바꿔줌</li>
<li>(4) visted_array는 방문 순서를 나타냄</li>
</ul>
<blockquote>
<p>위의 예제는 DFS의 가장 뼈대가 되는 것으로 이해가 중요!</p>
</blockquote>
<h1 id="span-stylecolorwhite-background-colorblack3-breadth-first-search-bfs"><span style="color:white; background-color:black;">3. Breadth-first search (BFS)</h1>
<h2 id="span-stylecolorwhite-background-colorblack31-bfs란"><span style="color:white; background-color:black;">3.1 BFS란?</h2>
<ul>
<li>백문이 불여일견</li>
</ul>
<p><img src="https://upload.wikimedia.org/wikipedia/commons/5/5d/Breadth-First-Search-Algorithm.gif" alt="https://upload.wikimedia.org/wikipedia/commons/5/5d/Breadth-First-Search-Algorithm.gif"></p>
<ul>
<li>같은 계층을 모두 탐색한 이후 다음 계층을 탐색하는 과정을 거침</li>
<li>1에 인접한 [2, 3, 4] 노드를 모두 queue에 저장한 이후 가장 처음에 넣은 노드를 꺼내서 탐색을 시작함</li>
<li>&quot;가장 처음에 넣은 노드&quot;가 의미하는 것이 큐를 이용하여 BFS를 구현할 수 있음</li>
</ul>
<h2 id="span-stylecolorwhite-background-colorblack32-bfs-구현"><span style="color:white; background-color:black;">3.2 BFS 구현</h2>
<h3 id="span-stylecolorwhite-background-colorblack321-인접-리스트"><span style="color:white; background-color:black;">3.2.1 인접 리스트</h3>
<pre><code class="language-python">graph = [[],
         [2, 3, 4],
         [1,5],
         [1,6, 7],
         [1,8],
         [2,9],
         [3,10],
         [3],
         [4],
         [5],
         [6]]</code></pre>
<ul>
<li>이중 리스트로 결과가 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]이 나올 수 있도록 구성</li>
</ul>
<h3 id="span-stylecolorwhite-background-colorblack322-구현-방법"><span style="color:white; background-color:black;">3.2.2 구현 방법</h3>
<ol>
<li>루트 노드를 큐에 넣습니다.</li>
<li>현재 큐의 노드를 빼서 visited에 추가한다.</li>
<li>현재 방문한 노드와 인접한 노드 중 방문하지 않은 노드를 큐에 추가한다.</li>
<li>2와 3을 반복한다.</li>
<li>queue가 비면 탐색을 종료한다.</li>
</ol>
<h3 id="span-stylecolorwhite-background-colorblack323-구현"><span style="color:white; background-color:black;">3.2.3 구현</h3>
<ul>
<li>구현 방법에 따른 코드</li>
</ul>
<pre><code class="language-python">from collections import deque

def bfs_queue(adj_graph, start_node):
    queue = deque([start_node]) # (1)
    visited = [] # (1)
    while queue: # (2)
        current_node = queue.popleft() #(3)
        visited.append(current_node) #(3)
        for adj_node in adj_graph[current_node]:
            if adj_node not in visited:# (4)
                queue.append(adj_node) 
    return visited</code></pre>
<ul>
<li>리스트로 구현할 수 있지만 실제 프로젝트에서 queue를 구현한다고 했을 때 내장된 자료구조인 deque를 이용하는 것이 좋음</li>
<li>(1) : 시작 노드를 queue에 넣어주고 방문 정보 역할을 하는 visited라는 빈 리스트를 생성한다.</li>
<li>(2) : queue에 원소가 없을 때 까지 while을 돌린다.</li>
<li>(3) : <code>queue.popleft()</code> 를 이용해 첫번째 인덱스의 원소를 꺼낸 후 visited에 추가한다.</li>
<li>(4) : current_node와 인접해 있는 노드 중 visited에 있지 않은 노드를 queue에 추가한다.</li>
</ul>
<blockquote>
<p>확실히, 재귀함수를 이용하는 DFS보다 이해하기는 쉬움!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL-1]  재귀함수]]></title>
            <link>https://velog.io/@stat_wkon/TIL-21.06.17-%EC%9E%AC%EA%B7%80%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@stat_wkon/TIL-21.06.17-%EC%9E%AC%EA%B7%80%ED%95%A8%EC%88%98</guid>
            <pubDate>Wed, 16 Jun 2021 16:58:18 GMT</pubDate>
            <description><![CDATA[<h2 id="1-span-stylecolorwhite-background-colorblackrecursive-functionspan-❤">1. <span style="color:white; background-color:black;">Recursive function</span> ❤</h2>
<blockquote>
<p>영어 뜻에서 유추가 가능하듯 <strong>자기 자신을 호출하는 함수</strong>를 의미</p>
</blockquote>
<hr>
<h2 id="2-span-stylecolorwhite-background-colorblack이해를-위한-example">2. <span style="color:white; background-color:black;">이해를 위한 Example</h2>
<pre><code class="language-python">def count_down(number):
    print(number)          # number를 출력하고
    count_down(number - 1) # count_down 함수를 number - 1 인자를 주고 다시 호출한다!

count_down(60)</code></pre>
<blockquote>
<ul>
<li>숫자를 Count 하는 함수를 재귀함수로 구현한 것</li>
</ul>
</blockquote>
<ul>
<li>함수 내의 함수가 호출된 것을 보고 재귀함수로 이루어져 있구나 생각할 수 있음</li>
<li>여기서 중요한 점은 <strong>재귀 함수가 언제 끝날지를 알려줘야 함</strong></li>
<li>끝나는 조건을 주지 않을 경우 <code>RecursionError</code> 가 발생함</li>
</ul>
<pre><code class="language-python">def count_down(number):
    **if number &lt; 0:
        return**
    print(number)          # number를 출력하고
    count_down(number - 1) # count_down 함수를 number - 1 인자를 주고 다시 호출한다!

count_down(60)</code></pre>
<blockquote>
<ul>
<li>종료조건은 if , return을 통해 단순히 빠져나올 수 있음</li>
</ul>
</blockquote>
<p><span style="color:blue; font-size:25px;"><strong>코드를 간결하고 명확하게 만들 수 있다는 장점이 있음!!</strong></p>
<hr>
<h2 id="3-span-stylecolorwhite-background-colorblack재귀함수를-이용한-대표적인-example">3. <span style="color:white; background-color:black;">재귀함수를 이용한 대표적인 Example</h2>
<h3 id="31-span-stylecolorwhite-background-colorblackexample---factorial">3.1 <span style="color:white; background-color:black;">Example - Factorial</h3>
<pre><code class="language-python">def factorial(n):
    if n == 1:
        return 1
    return n * factorial(n - 1)

print(factorial(5))</code></pre>
<ul>
<li>매우 간단하게 Factorial을 구현할 수 있음</li>
<li>여기서 중요한 점은 반복되는 것이 무엇인지 수식을 생각할 수 있어야 한다는 점</li>
<li>수식을 생각했을 때 코드의 구현까지 이루어 질 수 있음</li>
</ul>
<h3 id="32-span-stylecolorwhite-background-colorblackexample---회문-검사">3.2 <span style="color:white; background-color:black;">Example - 회문 검사</h3>
<blockquote>
<p>회문은 똑바로 읽으나 거꾸로 읽으나 똑같은 단어나 문장을 의미함
Ex) 토마토, 오디오, 아시아, 일요일, 소주만병만주소 등등</p>
</blockquote>
<blockquote>
<ul>
<li>먼저 def를 이용해 회문이면 True, 아니면 False를 반환하는 함수를 만들 수 있음</li>
</ul>
</blockquote>
<pre><code class="language-python">input = &quot;토마토&quot;

def is_palindrome(string):
    n = len(string)
        rule = n//2
    for i in range(rule):
        if input[i]!= input[-1-i]:
            return False
    return True

print(is_palindrome(input))</code></pre>
<blockquote>
<blockquote>
<p>(result)
True</p>
</blockquote>
</blockquote>
<blockquote>
<ul>
<li>쉽게 구현이 가능하지만 이를 재귀함수로도 구현이 가능함</li>
</ul>
</blockquote>
<ul>
<li>재귀함수의 목적은 문제를 점점 좁혀가는 것</li>
<li>즉, 반복되는 구조로 문제가 점점 작아지는 것을 인식할 수 있어야 함</li>
</ul>
<pre><code class="language-python">input1 = &quot;tomato&quot;
input2 = &#39;소주반병반주소&#39;

def is_palindrome(string):
    if len(string) &lt;= 1:
        return True
    if string[0] != string[-1]:
        return False

    return is_palindrome(string[1:-1])

print(is_palindrome(input1))
print(is_palindrome(input2))</code></pre>
<blockquote>
<blockquote>
<p>(result)
False
True</p>
</blockquote>
</blockquote>
<blockquote>
<ul>
<li>구조가 축소되는 양상을 보이고, 특정 구조가 반복되는 것 같은 양상을 보이면 재귀함수로 풀어볼 생각을 하면 좋다.</li>
</ul>
</blockquote>
<ul>
<li>반드시 종료조건을 생각해야 함</li>
</ul>
<hr>
<h2 id="4-span-stylecolorwhite-background-colorblack재귀함수-더-알아보자">4. <span style="color:white; background-color:black;">재귀함수 더 알아보자!</h2>
<blockquote>
<ul>
<li>컴퓨터 내부에서 재귀 함수의 수행은 스택 자료구조를 이용한다.</li>
</ul>
</blockquote>
<ul>
<li>함수를 계속 호출했을 때 가장 마지막에 호출한 함수가 먼저 수행을 끝내야 그 앞의 함수 호출이 종료되기 때문이다.</li>
<li>컴퓨터 구조 측면에서 보자면 연속해서 호출되는 함수는 메인 메모리의 스택 공간에 적재되므로 재귀 함수는 스택 자료구조와 같다는 말이 틀린 말이 아니다.</li>
<li>1줄 요약 : <strong>재귀 함수는 내부적으로 스택 자료구조와 동일하다</strong></li>
</ul>
<h3 id="41-span-stylecolorwhite-background-colorblack재귀함수가-왜-스택-구조-인지-증명을-해봄">4.1 <span style="color:white; background-color:black;">재귀함수가 왜 스택 구조 인지 증명을 해봄</h3>
<pre><code class="language-python">input2 = &#39;123454321&#39;  # string

cnt = 0

def is_palindrome(string):
    global cnt
    if len(string) &lt;= 1:
        return True
    if string[0] != string[-1]:
        return False
    print(&#39;스택 IN -&gt; string:{} cnt:{}&#39;.format(string, cnt))
    is_palindrome(string[1:-1])
    cnt += 1
    print(&#39;스택 OUT -&gt; string:{} cnt:{}&#39;.format(string, cnt))

print(is_palindrome(input2))</code></pre>
<blockquote>
<blockquote>
<p>(result)
스택 IN -&gt; string:123454321 cnt:0
스택 IN -&gt; string:2345432 cnt:0
스택 IN -&gt; string:34543 cnt:0
스택 IN -&gt; string:454 cnt:0
스택 OUT -&gt; string:454 cnt:1
스택 OUT -&gt; string:34543 cnt:2
스택 OUT -&gt; string:2345432 cnt:3
스택 OUT -&gt; string:123454321 cnt:4</p>
</blockquote>
</blockquote>
<blockquote>
<ul>
<li>먼저 재귀함수를 만나기 전까지(스택 IN) 모두 쌓이는 것을 확인할 수 있었음</li>
</ul>
</blockquote>
<ul>
<li>이후 모든 재귀함수가 쌓이고 나서 선입후출(First IN Last OUT)이 되는 것을 확인할 수 있었음</li>
<li>이러한 개념은 자연스럽게 DFS 개념으로 확장되는 것을 확인할 수 있음</li>
</ul>
<p><span style="color:blue; font-size:25px;"><strong>Stack 구조 + 재귀함수</strong> ⇒ <span style="color:black;">두가지 개념을 이해해야 <span style="color:red;">DFS</span>를 이해할 수 있음</p>
]]></description>
        </item>
    </channel>
</rss>