<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>mh_kim.log</title>
        <link>https://velog.io/</link>
        <description>안녕하세요. 블로그를 시작하게 되었습니다! 앞으로 유용한 정보와 좋은 내용을 많이 공유할게요:)</description>
        <lastBuildDate>Mon, 07 Oct 2024 15:02:02 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>mh_kim.log</title>
            <url>https://velog.velcdn.com/images/mh_kim/profile/1a6aae92-76c2-4808-b359-265a1b0ca420/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. mh_kim.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/mh_kim" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[JPA, JPQL, QueryDSL, NativeQuery 비교]]></title>
            <link>https://velog.io/@mh_kim/JPA-JPQL-QueryDSL-NativeQuery-%EB%B9%84%EA%B5%90</link>
            <guid>https://velog.io/@mh_kim/JPA-JPQL-QueryDSL-NativeQuery-%EB%B9%84%EA%B5%90</guid>
            <pubDate>Mon, 07 Oct 2024 15:02:02 GMT</pubDate>
            <description><![CDATA[<p>Java 애플리케이션에서 데이터베이스와 상호작용하기 위해 다양한 기술이 존재하며, 그중 대표적인 것이 JPA, JPQL, QueryDSL, 그리고 Native Query입니다. 각 기술은 고유한 장점과 단점을 가지고 있으며, 상황에 맞게 적절한 방법을 선택하는 것이 중요합니다. 이 글에서는 각 기술의 특징, 장단점, 예제 코드, 그리고 활용할 때의 주의점에 대해 설명합니다.</p>
<h3 id="1-jpa-java-persistence-api">1. JPA (Java Persistence API)</h3>
<h4 id="특징">특징</h4>
<p>JPA는 ORM(객체-관계 매핑) 표준으로, 자바 객체와 데이터베이스 테이블을 자동으로 매핑하여 데이터베이스 작업을 더 쉽게 처리할 수 있도록 합니다. 기본적인 CRUD(Create, Read, Update, Delete) 작업은 SQL을 직접 작성하지 않고도 처리할 수 있습니다.</p>
<h4 id="장점">장점</h4>
<ul>
<li><p>생산성: SQL을 작성하지 않고도 객체를 다루듯 데이터베이스와 상호작용할 수 있어 개발 속도가 빠릅니다.</p>
</li>
<li><p>유지보수 용이: 객체 중심의 코드로 가독성이 높아 유지보수가 용이합니다.</p>
</li>
<li><p>데이터베이스 독립성: 다양한 DBMS에서 사용이 가능하며 데이터베이스에 종속적이지 않습니다.</p>
<h4 id="단점">단점</h4>
</li>
<li><p>성능 문제 가능성: 복잡한 쿼리에서 자동 생성된 SQL이 최적화되지 않으면 성능 이슈가 발생할 수 있습니다. 특히 N+1 Select 문제와 같은 성능 저하를 일으킬 수 있으며, 이를 해결하기 위해선 fetch join이나 batch fetching을 사용할 수 있습니다.</p>
</li>
<li><p>학습 곡선: ORM과 JPA의 개념을 이해하는 데 시간이 걸립니다.</p>
<pre><code class="language-java">@Entity
public class Product {
  @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  private String name;
  private int price;

  // getters and setters
}
</code></pre>
</li>
</ul>
<p>// EntityManager 사용 예시
Product product = new Product();
product.setName(&quot;Laptop&quot;);
product.setPrice(1500);
entityManager.persist(product);</p>
<pre><code>
&gt; JPA는 위와 같이 Entity를 기반으로 데이터를 다룹니다. 별도의 SQL을 작성하지 않아도 기본적인 CRUD 작업을 쉽게 처리할 수 있습니다.

### 2. JPQL (Java Persistence Query Language)
#### 특징
JPQL은 SQL과 유사하지만 객체를 대상으로 쿼리를 작성하는 언어입니다. SQL과 달리 JPQL은 데이터베이스 테이블이 아닌 엔티티(Entity)를 대상으로 하므로 객체 지향적인 쿼리 작성이 가능합니다.
#### 장점
- 객체 중심 쿼리: 테이블이 아닌 객체(Entity)를 대상으로 작업하므로 객체 지향적으로 데이터를 다룰 수 있습니다.
- 데이터베이스 독립성: 특정 DBMS에 종속되지 않으며, 다양한 데이터베이스에서 동일한 쿼리를 사용할 수 있습니다.
#### 단점
- 제한된 기능: SQL이 제공하는 모든 기능을 지원하지 않으며, 복잡한 쿼리나 데이터베이스 고유의 기능은 사용할 수 없습니다.
- 성능 문제: 복잡한 조인이나 서브쿼리 작업 시 성능 이슈가 발생할 수 있습니다.

```java
@Query(&quot;SELECT p FROM Product p WHERE p.price &gt; :minPrice&quot;)
List&lt;Product&gt; findProductsWithPriceGreaterThan(@Param(&quot;minPrice&quot;) int price);
</code></pre><blockquote>
<p>JPQL은 객체를 기준으로 쿼리를 작성하므로, SQL과는 달리 테이블이 아닌 Product 클래스에 대해 쿼리합니다. :minPrice는 파라미터 바인딩을 사용하여 안전한 쿼리 작성이 가능합니다.</p>
</blockquote>
<h3 id="3-querydsl">3. QueryDSL</h3>
<h4 id="특징-1">특징</h4>
<p>QueryDSL은 동적 쿼리를 안전하게 작성할 수 있도록 지원하는 타입 세이프한 쿼리 빌더입니다. 동적 쿼리 작성이 필요할 때 매우 유용하며, SQL, JPQL 등 다양한 쿼리 언어와 호환됩니다.</p>
<h4 id="장점-1">장점</h4>
<ul>
<li>타입 세이프: 컴파일 시점에 쿼리 오류를 잡아낼 수 있어 런타임 오류를 줄입니다.</li>
<li>동적 쿼리 작성 편리: 복잡한 조건이나 동적 쿼리 작성을 더 쉽고 안전하게 할 수 있습니다.</li>
<li>유지보수성: 코드로 쿼리를 관리할 수 있어 가독성이 좋고 유지보수하기 쉽습니다.<h4 id="단점-1">단점</h4>
</li>
<li>초기 설정 복잡: QueryDSL을 사용하려면 별도의 설정이 필요하며, 기본 JPA만 사용하는 것보다 복잡할 수 있습니다.</li>
<li>복잡한 쿼리 성능 문제: 동적 쿼리가 많아지면 쿼리 생성 및 실행 시간이 길어질 수 있습니다<pre><code class="language-java">QProduct product = QProduct.product;
List&lt;Product&gt; products = queryFactory.selectFrom(product)
  .where(product.price.gt(1000))
  .fetch();</code></pre>
<blockquote>
<p>QueryDSL은 타입 세이프한 쿼리 작성이 가능합니다. QProduct는 Product 엔티티에 대한 메타 모델 클래스입니다. QueryDSL은 메소드 체이닝을 통해 쿼리를 직관적으로 작성할 수 있으며, 조건문 등을 동적으로 구성할 수 있어 유연성이 높습니다.</p>
</blockquote>
</li>
</ul>
<h3 id="4-native-query">4. Native Query</h3>
<h4 id="특징-2">특징</h4>
<p>Native Query는 데이터베이스 고유의 SQL을 직접 사용하여 쿼리를 작성하는 방법입니다. 데이터베이스에 직접 SQL을 작성하여 더 높은 성능 최적화를 할 수 있습니다.</p>
<h4 id="장점-2">장점</h4>
<ul>
<li>성능 최적화: SQL을 직접 작성함으로써 데이터베이스에 맞춘 최적화가 가능해 성능을 극대화할 수 있습니다.</li>
<li>고급 기능 사용 가능: 데이터베이스의 고유 기능이나 복잡한 SQL 문법을 자유롭게 사용할 수 있습니다.<h4 id="단점-2">단점</h4>
</li>
<li>데이터베이스 종속성: 특정 DBMS에 종속적이므로 데이터베이스가 변경되면 쿼리도 다시 작성해야 합니다.</li>
<li>유지보수 어려움: 직접 SQL을 작성하고 관리해야 하므로 코드 복잡성이 증가할 수 있습니다.</li>
<li>동적 정렬 및 페이징 한계: Native Query는 동적 정렬을 지원하지 않으며, 페이징을 위해서는 별도의 카운트 쿼리를 작성해야 합니다<pre><code class="language-java">@Query(value = &quot;SELECT * FROM Product p WHERE p.price &gt; :price&quot;, nativeQuery = true)
List&lt;Product&gt; findByNativeQuery(@Param(&quot;price&quot;) int price);
}
</code></pre>
</li>
</ul>
<p>```</p>
<blockquote>
<p>Native Query는 데이터베이스의 SQL을 그대로 사용할 수 있습니다. 이를 통해 JPA와 JPQL로는 처리하기 어려운 복잡한 쿼리를 직접 작성할 수 있으며, 성능 최적화를 위해 DBMS의 고유 기능을 활용할 수 있습니다. 그러나 데이터베이스에 종속적이라는 단점이 있습니다.</p>
</blockquote>
<p>[비교 정리]</p>
<table>
<thead>
<tr>
<th align="center">구분</th>
<th align="left">장점</th>
<th align="left">단점</th>
<th align="left">사용</th>
</tr>
</thead>
<tbody><tr>
<td align="center">JPA</td>
<td align="left">SQL 작성 불필요</td>
<td align="left">성능 문제 발생 가능</td>
<td align="left">기본 CRUD 작업에 적합</td>
</tr>
<tr>
<td align="center"></td>
<td align="left">객체 지향적 코드</td>
<td align="left">학습 곡선 있음</td>
<td align="left"></td>
</tr>
<tr>
<td align="center">JPQL</td>
<td align="left">객체 중심 쿼리 작성</td>
<td align="left">복잡한 SQL 기능 지원 제한</td>
<td align="left">간단한 조회나 객체 기반 쿼리 시 적합</td>
</tr>
<tr>
<td align="center"></td>
<td align="left">데이터베이스 독립성</td>
<td align="left">성능 문제 가능</td>
<td align="left"></td>
</tr>
<tr>
<td align="center">QueryDSL</td>
<td align="left">동적 쿼리 작성 편리</td>
<td align="left">초기 설정 복잡</td>
<td align="left">복잡한 조건의 동적 쿼리가 필요할 때 적합</td>
</tr>
<tr>
<td align="center"></td>
<td align="left">타입 세이프</td>
<td align="left">동적 쿼리 성능 문제 가능</td>
<td align="left"></td>
</tr>
<tr>
<td align="center">Native Query</td>
<td align="left">성능 최적화 가능</td>
<td align="left">데이터베이스 종속성</td>
<td align="left">성능 최적화가 필요한 복잡한 쿼리 작성 시 적합</td>
</tr>
<tr>
<td align="center"></td>
<td align="left">데이터베이스 고유 기능 사용 가능</td>
<td align="left">동적 정렬 및 페이징 한계 있음</td>
<td align="left"></td>
</tr>
</tbody></table>
<hr>
<p>Reference
<a href="https://sproutinghye.tistory.com/63">https://sproutinghye.tistory.com/63</a>
<a href="https://velog.io/@simgyuhwan/%EC%BF%BC%EB%A6%AC-%EB%A9%94%EC%86%8C%EB%93%9C-JPQL-Querydsl-%EC%9A%94%EC%95%BD">https://velog.io/@simgyuhwan/%EC%BF%BC%EB%A6%AC-%EB%A9%94%EC%86%8C%EB%93%9C-JPQL-Querydsl-%EC%9A%94%EC%95%BD</a>
<a href="https://www.baeldung.com/spring-data-jpa-vs-jpa">https://www.baeldung.com/spring-data-jpa-vs-jpa</a> </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[기능 테스트와 구조 테스트, 그리고 개발 프로세스 기반 테스트]]></title>
            <link>https://velog.io/@mh_kim/%EA%B8%B0%EB%8A%A5-%ED%85%8C%EC%8A%A4%ED%8A%B8%EC%99%80-%EA%B5%AC%EC%A1%B0-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EA%B0%9C%EB%B0%9C-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EA%B8%B0%EB%B0%98-%ED%85%8C%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@mh_kim/%EA%B8%B0%EB%8A%A5-%ED%85%8C%EC%8A%A4%ED%8A%B8%EC%99%80-%EA%B5%AC%EC%A1%B0-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EA%B0%9C%EB%B0%9C-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EA%B8%B0%EB%B0%98-%ED%85%8C%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Tue, 17 Sep 2024 15:00:32 GMT</pubDate>
            <description><![CDATA[<h3 id="1-기능-테스트-functional-testing">1. 기능 테스트 (Functional Testing)</h3>
<p>소프트웨어가 요구되는 기능을 정확하게 수행하는지 확인하는 테스트 방식입니다. 사용자의 관점에서 시스템의 입력과 출력만을 검증합니다.</p>
<ul>
<li><p>Black-Box Testing (블랙박스 테스트):
소프트웨어의 내부 구조를 고려하지 않고 외부 동작만으로 테스트를 진행합니다.
요구사항이나 명세에 따른 기능 검증을 목표로 합니다.</p>
</li>
<li><p>Behavior-Driven Development (BDD, 행동 주도 개발):
시스템의 행동을 자연어로 설명하고 그에 맞춰 테스트를 진행합니다.
비즈니스 측면의 기능을 테스트하는 방식입니다. Given-When-Then 구조를 따릅니다.</p>
</li>
</ul>
<h3 id="2-구조-테스트-structural-testing">2. 구조 테스트 (Structural Testing)</h3>
<p>소프트웨어의 내부 로직이나 구조를 기반으로 테스트하는 방법입니다. 소스 코드를 분석하여 기능이 의도대로 동작하는지 확인합니다.</p>
<ul>
<li>White-Box Testing (화이트박스 테스트):
코드의 내부 구조와 논리 흐름을 바탕으로 테스트합니다.
경로 커버리지, 조건 커버리지, 루프 테스트 등을 포함합니다.</li>
</ul>
<h3 id="3-단위-테스트-unit-testing">3. 단위 테스트 (Unit Testing)</h3>
<p>정의: 소프트웨어의 가장 작은 단위(함수, 클래스 등)를 독립적으로 테스트합니다.</p>
<ul>
<li><p>Unit Testing (단위 테스트):
개별 메소드나 클래스가 정상적으로 동작하는지 확인합니다.
Mocking 등을 사용하여 외부 의존성을 제거하고 테스트합니다.</p>
</li>
<li><p>Arrange-Act-Assert (AAA 패턴):
단위 테스트 작성 시 사용하는 패턴으로, 테스트의 흐름을 명확하게 나누는 방식입니다.
테스트는 준비(Arrange), 실행(Act), 확인(Assert)의 세 단계로 나뉘어 구조적으로 작성됩니다.</p>
</li>
</ul>
<h3 id="4-통합-테스트-integration-testing">4. 통합 테스트 (Integration Testing)</h3>
<p>개별 모듈들이 상호작용하며 통합될 때, 이들이 잘 연동되는지 테스트하는 방식입니다.</p>
<ul>
<li>Integration Testing (통합 테스트):
여러 모듈을 통합하여 그들이 함께 올바르게 동작하는지 확인합니다.
데이터베이스나 외부 API와의 연동을 포함하는 실제 의존성을 테스트합니다.</li>
</ul>
<h3 id="5-개발-프로세스-기반-테스트-development-process-based-testing">5. 개발 프로세스 기반 테스트 (Development Process-Based Testing)</h3>
<p>개발 방식 자체에서 테스트를 중시하며, 개발과 테스트가 밀접하게 연관된 프로세스를 따르는 방식입니다.</p>
<ul>
<li><p>Test-Driven Development (TDD, 테스트 주도 개발):
테스트를 먼저 작성하고, 그 테스트를 통과할 수 있는 코드를 작성하는 개발 방식입니다.
작은 단위로 코드를 작성하고 지속적인 리팩토링을 통해 코드 품질을 유지합니다.</p>
</li>
<li><p>Behavior-Driven Development (BDD, 행동 주도 개발):
요구 사항을 테스트 사례로 변환해 개발하는 방법입니다. TDD에서 발전된 형태로, 비개발자도 이해할 수 있는 테스트 사례를 사용합니다.
기능 요구 사항에 초점을 맞추고 테스트를 개발의 일부분으로 다룹니다.</p>
</li>
</ul>
<p>전체 요약</p>
<table>
<thead>
<tr>
<th align="center">대분류</th>
<th align="center">중분류</th>
<th align="center">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">기능 테스트</td>
<td align="center">Black-Box Testing</td>
<td align="center">내부 구조를 알지 못한 상태에서 기능 및 요구사항이 제대로 동작하는지 테스트.</td>
</tr>
<tr>
<td align="center">BDD</td>
<td align="center"></td>
<td align="center">Given-When-Then 패턴을 사용하여 비즈니스 요구사항을 자연어로 설명하고 테스트.</td>
</tr>
<tr>
<td align="center">구조 테스트</td>
<td align="center">White-Box Testing</td>
<td align="center">내부 코드의 구조와 논리 흐름을 기반으로 테스트. 코드 커버리지를 확인함.</td>
</tr>
<tr>
<td align="center">단위 테스트</td>
<td align="center">Unit Testing</td>
<td align="center">소프트웨어의 작은 단위(메소드, 클래스)를 독립적으로 테스트.</td>
</tr>
<tr>
<td align="center"></td>
<td align="center">AAA 패턴</td>
<td align="center">테스트의 준비, 실행, 결과 확인의 단계를 명확하게 나누어 작성하는 패턴.</td>
</tr>
<tr>
<td align="center">통합 테스트</td>
<td align="center">Integration Testing</td>
<td align="center">여러 모듈이 통합되어 잘 연동되고 동작하는지 확인하는 테스트. 외부 의존성을 포함하는 경우가 많음.</td>
</tr>
<tr>
<td align="center">개발 프로세스 기반 테스트</td>
<td align="center">TDD</td>
<td align="center">테스트를 먼저 작성하고, 이를 통과하는 코드를 작성하는 방식의 개발 프로세스.</td>
</tr>
<tr>
<td align="center"></td>
<td align="center">BDD</td>
<td align="center">행동 기반으로 기능을 설명하고 테스트 사례로 변환하여 개발하는 방식.TDD에서 발전된 형태.</td>
</tr>
</tbody></table>
<p>이렇게 분류하면 각 테스트 방법이 어떤 범주에 속하며, 어떤 목적으로 사용하는지 명확히 이해할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 다이나믹 프로그래밍]]></title>
            <link>https://velog.io/@mh_kim/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EB%8B%A4%EC%9D%B4%EB%82%98%EB%AF%B9%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</link>
            <guid>https://velog.io/@mh_kim/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EB%8B%A4%EC%9D%B4%EB%82%98%EB%AF%B9%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</guid>
            <pubDate>Tue, 17 Sep 2024 11:35:27 GMT</pubDate>
            <description><![CDATA[<h4 id="다이나믹-프로그래밍dp란">다이나믹 프로그래밍(DP)란?</h4>
<p>다이나믹 프로그래밍(DP, Dynamic Programming)은 문제를 해결하기 위한 하나의 접근 방식으로, 복잡한 문제를 더 작은 하위 문제로 나누어 해결하고 그 결과를 저장하여 반복적인 계산을 피하는 최적화 기법입니다. 주로 재귀적 또는 반복적 방식으로 문제를 해결하며, 이미 계산된 값을 재사용함으로써 중복 계산을 방지하는 것이 특징입니다.</p>
<h4 id="다이나믹-프로그래밍dp-핵심-개념">다이나믹 프로그래밍(DP) 핵심 개념</h4>
<ul>
<li>재귀적 사고: 큰 문제를 더 작은 하위 문제로 나누고, 이미 해결된 작은 문제들이 있다는 믿음 아래 큰 문제를 해결합니다. 이때, 큰 문제와 작은 문제를 명확히 구분하는 것이 중요합니다. 작은 문제는 최소한의 정보만으로도 해결 가능한 문제를 의미하며, 이를 잘 구분해야 합니다.</li>
<li>불필요한 계산 제거: 동일한 하위 문제를 여러 번 계산하지 않기 위해 메모이제이션(Memoization) 기법을 사용합니다. 즉, 한 번 계산된 결과를 저장해 두고, 다시 계산이 필요할 때 저장된 값을 재사용하여 성능을 극대화합니다.</li>
<li>밑에서부터 계산하기: 문제를 해결할 때 꼭 재귀적 방식만 사용할 필요는 없습니다. 작은 문제부터 차례대로 해결해나가는 반복적 방식도 사용할 수 있습니다. 예를 들어, 팩토리얼을 계산할 때 가장 작은 값인 1부터 차례대로 계산해 나가듯, DP 문제에서도 하위 문제부터 차근차근 풀어나가는 방식이 효과적입니다.</li>
</ul>
<h4 id="다이나믹-프로그래밍dp로-풀-수-있는-대표적인-문제들">다이나믹 프로그래밍(DP)로 풀 수 있는 대표적인 문제들</h4>
<ol>
<li>피보나치 수열(Fibonacci Sequence):
문제: n번째 피보나치 수를 구하는 문제
설명: 이전 두 개의 피보나치 수를 이용해 n번째 피보나치 수를 계산합니다.<pre><code class="language-java">import java.util.HashMap;
</code></pre>
</li>
</ol>
<p>public class Fibonacci {
    private static HashMap&lt;Integer, Integer&gt; memo = new HashMap&lt;&gt;();</p>
<pre><code>public static int fib(int n) {
    if (n &lt;= 1) return n;
    if (memo.containsKey(n)) return memo.get(n);
    int result = fib(n - 1) + fib(n - 2);
    memo.put(n, result);
    return result;
}

public static void main(String[] args) {
    System.out.println(fib(10));  // Output: 55
}</code></pre><p>}</p>
<pre><code>
2. 최장 공통 부분 수열(Longest Common Subsequence, LCS):
문제: 두 문자열의 최장 공통 부분 수열을 찾는 문제
설명: 두 문자열 사이에서 순서를 유지하면서 가장 긴 공통 부분을 찾습니다.
```java
public class LCS {
    public static int lcs(String s1, String s2) {
        int[][] dp = new int[s1.length() + 1][s2.length() + 1];

        for (int i = 1; i &lt;= s1.length(); i++) {
            for (int j = 1; j &lt;= s2.length(); j++) {
                if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }

        return dp[s1.length()][s2.length()];
    }

    public static void main(String[] args) {
        System.out.println(lcs(&quot;ABCBDAB&quot;, &quot;BDCAB&quot;));  // Output: 4
    }
}</code></pre><ol start="3">
<li>최장 증가 부분 수열(Longest Increasing Subsequence, LIS):
문제: 주어진 수열에서 가장 긴 증가하는 부분 수열을 찾는 문제
설명: 수열에서 연속적으로 증가하는 부분을 찾아 그 길이를 구합니다.<pre><code class="language-java">import java.util.Arrays;
</code></pre>
</li>
</ol>
<p>public class LIS {
    public static int lis(int[] arr) {
        int[] dp = new int[arr.length];
        Arrays.fill(dp, 1);</p>
<pre><code>    for (int i = 1; i &lt; arr.length; i++) {
        for (int j = 0; j &lt; i; j++) {
            if (arr[i] &gt; arr[j]) {
                dp[i] = Math.max(dp[i], dp[j] + 1);
            }
        }
    }

    return Arrays.stream(dp).max().orElse(1);
}

public static void main(String[] args) {
    int[] arr = {10, 22, 9, 33, 21, 50, 41, 60, 80};
    System.out.println(lis(arr));  // Output: 6
}</code></pre><p>}</p>
<pre><code>4. 배낭 문제(Knapsack Problem):
문제: 제한된 무게를 가진 배낭에 최대 가치를 가지도록 물건들을 넣는 문제
설명: 각 물건의 무게와 가치를 고려하여 최대 가치를 구합니다.
```java
public class Knapsack {
    public static int knapsack(int[] weights, int[] values, int capacity) {
        int n = weights.length;
        int[][] dp = new int[n + 1][capacity + 1];

        for (int i = 1; i &lt;= n; i++) {
            for (int w = 0; w &lt;= capacity; w++) {
                if (weights[i - 1] &lt;= w) {
                    dp[i][w] = Math.max(dp[i - 1][w], dp[i - 1][w - weights[i - 1]] + values[i - 1]);
                } else {
                    dp[i][w] = dp[i - 1][w];
                }
            }
        }

        return dp[n][capacity];
    }

    public static void main(String[] args) {
        int[] weights = {1, 3, 4, 5};
        int[] values = {1, 4, 5, 7};
        int capacity = 7;
        System.out.println(knapsack(weights, values, capacity));  // Output: 9
    }
}</code></pre><ol start="5">
<li><p>최소 편집 거리(Edit Distance, Levenshtein Distance):
문제: 하나의 문자열을 다른 문자열로 변환하는데 필요한 최소 편집 작업(삽입, 삭제, 교체)의 수를 구하는 문제
설명: 두 문자열을 비교하여 변환 비용을 최소화하는 방법을 찾습니다.</p>
<pre><code class="language-java">public class EditDistance {
 public static int editDistance(String s1, String s2) {
     int[][] dp = new int[s1.length() + 1][s2.length() + 1];

     for (int i = 0; i &lt;= s1.length(); i++) {
         for (int j = 0; j &lt;= s2.length(); j++) {
             if (i == 0) {
                 dp[i][j] = j;
             } else if (j == 0) {
                 dp[i][j] = i;
             } else if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
                 dp[i][j] = dp[i - 1][j - 1];
             } else {
                 dp[i][j] = 1 + Math.min(dp[i - 1][j - 1], Math.min(dp[i - 1][j], dp[i][j - 1]));
             }
         }
     }

     return dp[s1.length()][s2.length()];
 }

 public static void main(String[] args) {
     System.out.println(editDistance(&quot;kitten&quot;, &quot;sitting&quot;));  // Output: 3
 }
}</code></pre>
</li>
<li><p>동전 거스름돈 문제(Coin Change Problem):
문제: 주어진 동전들로 특정 금액을 만드는 방법의 수를 구하거나 최소 동전 개수를 구하는 문제
설명: 다양한 금액을 만들기 위해 가능한 동전 조합을 계산합니다.</p>
<pre><code class="language-java">public class CoinChange {
 public static int coinChange(int[] coins, int amount) {
     int[] dp = new int[amount + 1];
     Arrays.fill(dp, amount + 1);
     dp[0] = 0;

     for (int coin : coins) {
         for (int i = coin; i &lt;= amount; i++) {
             dp[i] = Math.min(dp[i], dp[i - coin] + 1);
         }
     }

     return dp[amount] &gt; amount ? -1 : dp[amount];
 }

 public static void main(String[] args) {
     int[] coins = {1, 2, 5};
     int amount = 11;
     System.out.println(coinChange(coins, amount));  // Output: 3
 }
}</code></pre>
</li>
<li><p>최대 부분 배열 합(Maximum Subarray Sum, Kadane&#39;s Algorithm):
문제: 주어진 배열에서 연속된 부분 배열의 합 중 가장 큰 값을 찾는 문제
설명: 배열 내에서 가장 큰 합을 가지는 부분 배열을 찾습니다.</p>
<pre><code class="language-java">public class MaximumSubarraySum {
 public static int maxSubArray(int[] nums) {
     int maxSoFar = nums[0];
     int currentMax = nums[0];

     for (int i = 1; i &lt; nums.length; i++) {
         currentMax = Math.max(nums[i], currentMax + nums[i]);
         maxSoFar = Math.max(maxSoFar, currentMax);
     }

     return maxSoFar;
 }

 public static void main(String[] args) {
     int[] nums = {-2, 1, -3, 4, -1, 2, 1, -5, 4};
     System.out.println(maxSubArray(nums));  // Output: 6
 }
}</code></pre>
</li>
<li><p>최단 경로 찾기(Path Finding Problem, 다익스트라)
문제: 주어진 그래프에서 특정 출발점에서 도착점까지의 최단 경로를 찾는 문제
설명: 그래프에서 각 경로를 탐색하여 출발점에서 도착점까지의 최소 거리를 구합니다. 다익스트라(Dijkstra) 알고리즘이나 벨만-포드(Bellman-Ford) 알고리즘 같은 DP 기반의 최단 경로 알고리즘이 자주 사용됩니다.</p>
<pre><code class="language-java">import java.util.*;
</code></pre>
</li>
</ol>
<p>public class Dijkstra {
    public static int[] dijkstra(int[][] graph, int src) {
        int n = graph.length;
        int[] dist = new int[n];
        boolean[] visited = new boolean[n];
        Arrays.fill(dist, Integer.MAX_VALUE);
        dist[src] = 0;</p>
<pre><code>    PriorityQueue&lt;int[]&gt; pq = new PriorityQueue&lt;&gt;(Comparator.comparingInt(a -&gt; a[1]));
    pq.add(new int[]{src, 0});

    while (!pq.isEmpty()) {
        int[] node = pq.poll();
        int u = node[0];

        if (visited[u]) continue;
        visited[u] = true;

        for (int v = 0; v &lt; n; v++) {
            if (graph[u][v] != 0 &amp;&amp; !visited[v] &amp;&amp; dist[u] + graph[u][v] &lt; dist[v]) {
                dist[v] = dist[u] + graph[u][v];
                pq.add(new int[]{v, dist[v]});
            }
        }
    }

    return dist;
}

public static void main(String[] args) {
    int[][] graph = {
        {0, 10, 0, 30, 100},
        {10, 0, 50, 0, 0},
        {0, 50, 0, 20, 10},
        {30, 0, 20, 0, 60},
        {100, 0, 10, 60, 0}
    };
    int[] dist = dijkstra(graph, 0);
    System.out.println(Arrays.toString(dist));  // Output: [0, 10, 50, 30, 60]
}</code></pre><p>}</p>
<pre><code></code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Electron vs Neutralino.js: 데스크톱 애플리케이션 개발을 위한 프레임워크 비교
]]></title>
            <link>https://velog.io/@mh_kim/Electron-vs-Neutralino.js-%EB%8D%B0%EC%8A%A4%ED%81%AC%ED%86%B1-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EA%B0%9C%EB%B0%9C%EC%9D%84-%EC%9C%84%ED%95%9C-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC-%EB%B9%84%EA%B5%90</link>
            <guid>https://velog.io/@mh_kim/Electron-vs-Neutralino.js-%EB%8D%B0%EC%8A%A4%ED%81%AC%ED%86%B1-%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98-%EA%B0%9C%EB%B0%9C%EC%9D%84-%EC%9C%84%ED%95%9C-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC-%EB%B9%84%EA%B5%90</guid>
            <pubDate>Tue, 03 Sep 2024 15:56:57 GMT</pubDate>
            <description><![CDATA[<p>  크로스 플랫폼 데스크톱 애플리케이션중 하나인 Electron은 널리 사용되는 프레임워크로, 많은 인기 있는 애플리케이션(예: Visual Studio Code, Slack)이 이를 기반으로 만들어졌습니다. 하지만 최근 들어 Electron의 대안으로 경량화된 프레임워크인 Neutralino.js가 주목받고 있습니다. </p>
<h3 id="1-electron-강력한-기능성과-확장성">1. Electron: 강력한 기능성과 확장성</h3>
<p>Electron이란?
Electron은 Chromium(구글 크롬의 오픈소스 버전)과 Node.js를 결합하여 웹 기술을 사용해 크로스 플랫폼 데스크톱 애플리케이션을 개발할 수 있는 프레임워크입니다. Windows, macOS, Linux에서 모두 동작하며, HTML, CSS, JavaScript를 사용하여 데스크톱 앱을 개발할 수 있습니다.</p>
<h4 id="장점">장점</h4>
<p>풍부한 기능성: Electron은 파일 시스템 접근, 네이티브 메뉴, 알림, 데스크톱 통합 기능 등 다양한 API를 제공합니다. 이를 통해 개발자는 브라우저 기반의 애플리케이션을 네이티브 데스크톱 애플리케이션처럼 동작하도록 만들 수 있습니다.
광범위한 생태계: Electron은 매우 널리 사용되는 프레임워크로, 커뮤니티와 생태계가 잘 발달되어 있습니다. 따라서 다양한 문제에 대한 해결책을 쉽게 찾을 수 있으며, 많은 오픈소스 플러그인과 라이브러리를 활용할 수 있습니다.
웹 개발 기술 재사용: 웹 개발자라면 기존에 익숙한 기술 스택을 활용해 데스크톱 애플리케이션을 개발할 수 있어, 학습 곡선이 낮습니다.</p>
<h4 id="단점">단점</h4>
<p>무거운 애플리케이션: Electron은 Chromium 엔진을 포함하기 때문에, 애플리케이션 크기가 수십 MB 이상으로 커집니다. 작은 기능을 제공하는 애플리케이션에도 불필요하게 많은 리소스를 소비하게 됩니다.
높은 메모리 사용량: Chromium을 사용하면서 각 Electron 애플리케이션은 높은 메모리를 사용하게 됩니다. 특히 여러 개의 창을 동시에 열거나, 복잡한 웹 앱을 데스크톱에서 구동할 때 이 문제가 두드러집니다.
성능 저하: 웹 뷰를 내장하고 있어 CPU 사용량이 높고, 저사양 기기에서는 성능 저하가 발생할 수 있습니다.</p>
<h3 id="2-neutralinojs-경량화와-빠른-성능">2. Neutralino.js: 경량화와 빠른 성능</h3>
<p>Neutralino.js란?
Neutralino.js는 Electron과 유사한 목적을 지닌 경량 프레임워크로, 운영 체제의 기본 웹뷰를 사용하여 애플리케이션을 실행합니다. Node.js를 사용하지 않고, 자체 내장 서버를 통해 네이티브 기능에 접근합니다. 이로 인해 애플리케이션 크기가 매우 작고, 리소스 사용량이 최소화됩니다.</p>
<h4 id="장점-1">장점</h4>
<p>경량화된 애플리케이션: Neutralino.js는 Chromium과 같은 브라우저 엔진을 포함하지 않기 때문에, 애플리케이션 크기가 매우 작습니다. 보통 몇 MB 수준으로 유지되며, 작은 기능을 가진 앱에 적합합니다.
낮은 리소스 사용량: 운영 체제의 기본 웹뷰를 활용하기 때문에 메모리와 CPU 사용량이 적습니다. 저사양 기기에서도 원활하게 동작할 수 있으며, 전반적인 성능이 향상됩니다.
빠른 로딩 속도: 경량화된 구조 덕분에 애플리케이션의 로딩 시간이 매우 짧고, 사용자에게 빠른 응답성을 제공합니다.</p>
<h4 id="단점-1">단점</h4>
<p>제한된 기능: Electron에 비해 제공하는 API와 기능이 제한적입니다. 복잡한 애플리케이션을 개발하기에는 기능이 부족할 수 있습니다.
미성숙한 생태계: Neutralino.js는 비교적 새로운 프레임워크로, Electron만큼의 커뮤니티 지원이나 플러그인이 부족할 수 있습니다.
플랫폼 종속성: Neutralino.js는 운영 체제의 기본 웹뷰에 의존하기 때문에, 운영 체제마다 약간의 차이가 있을 수 있으며, 모든 기능이 동일하게 지원되지 않을 수 있습니다.</p>
<h3 id="3-electron과-neutralinojs의-주요-비교">3. Electron과 Neutralino.js의 주요 비교</h3>
<table>
<thead>
<tr>
<th align="center">특징</th>
<th align="center">Electron</th>
<th align="center">Neutralino.js</th>
</tr>
</thead>
<tbody><tr>
<td align="center">기본 구조</td>
<td align="center">Chromium(웹 브라우저 엔진) + Node.js</td>
<td align="center">운영 체제의 기본 웹뷰 + 경량화된 내장 서버</td>
</tr>
<tr>
<td align="center">애플리케이션 크기</td>
<td align="center">수십 MB 이상 (Chromium 포함)</td>
<td align="center">몇 MB 수준 (경량화된 구조)</td>
</tr>
<tr>
<td align="center">메모리 사용량</td>
<td align="center">상대적으로 높음 (다중 창 사용 시 더욱 증가)</td>
<td align="center">낮음 (운영 체제의 기본 웹뷰 활용)</td>
</tr>
<tr>
<td align="center">성능</td>
<td align="center">로딩 시간 및 응답 속도가 상대적으로 느림</td>
<td align="center">빠른 로딩 시간과 응답 속도</td>
</tr>
<tr>
<td align="center">기능성</td>
<td align="center">매우 풍부한 API 제공 (파일 시스템 접근, 네이티브 기능 등)</td>
<td align="center">제한된 API 제공 (기본적인 기능만 지원)</td>
</tr>
<tr>
<td align="center">생태계</td>
<td align="center">광범위한 커뮤니티와 플러그인 생태계</td>
<td align="center">비교적 작은 커뮤니티와 제한된 플러그인</td>
</tr>
<tr>
<td align="center">개발 편의성</td>
<td align="center">복잡한 설정과 기능 지원 (다양한 확장성)</td>
<td align="center">간단한 설치 및 설정 (기본적인 기능에 적합)</td>
</tr>
<tr>
<td align="center">사용 사례</td>
<td align="center">복잡한 데스크톱 애플리케이션 (VS Code, Slack 등)</td>
<td align="center">경량화된 도구형 애플리케이션 (작은 크기의 단순 앱)</td>
</tr>
<tr>
<td align="center">호환성</td>
<td align="center">높은 플랫폼 간 호환성 (Windows, macOS, Linux)</td>
<td align="center">플랫폼 간 호환성은 좋지만, 기본 웹뷰에 따라 다소 차이 발생 가능</td>
</tr>
<tr>
<td align="center">리소스 소비</td>
<td align="center">높은 CPU와 메모리 소비</td>
<td align="center">낮은 리소스 소비</td>
</tr>
<tr>
<td align="center">로드맵 및 지원</td>
<td align="center">널리 사용되며, 지속적인 업데이트와 지원</td>
<td align="center">상대적으로 덜 성숙하지만 경량화 및 단순화에 집중</td>
</tr>
</tbody></table>
<h3 id="4-어떤-상황에서-무엇을-선택할-것인가">4. 어떤 상황에서 무엇을 선택할 것인가?</h3>
<h4 id="electron을-선택해야-할-때">Electron을 선택해야 할 때</h4>
<p>복잡한 기능이 필요한 경우: Electron은 풍부한 API와 기능을 제공하기 때문에, 복잡한 데스크톱 애플리케이션을 개발할 때 유리합니다. 예를 들어, 고급 그래픽 처리, 멀티미디어 기능, 또는 확장 가능한 플러그인 시스템이 필요한 경우 Electron이 더 적합합니다.
강력한 생태계를 활용하고 싶을 때: 이미 확립된 커뮤니티와 방대한 플러그인, 라이브러리를 활용하여 개발 속도를 높이고자 할 때 Electron이 좋은 선택입니다.
플랫폼 간 호환성이 중요한 경우: Electron은 Windows, macOS, Linux에서 동일한 코드를 실행할 수 있는 높은 호환성을 제공합니다.</p>
<h4 id="neutralinojs를-선택해야-할-때">Neutralino.js를 선택해야 할 때</h4>
<p>경량화가 중요한 경우: 애플리케이션 크기와 메모리 사용량을 최소화하고, 성능 최적화가 중요한 경우 Neutralino.js가 적합합니다. 특히, 작은 도구형 애플리케이션이나 리소스가 제한된 환경에서 실행되는 애플리케이션에 적합합니다.
단순한 애플리케이션 개발: 복잡한 기능이 필요하지 않고, 기본적인 UI/UX 기능을 가진 애플리케이션을 빠르고 효율적으로 개발하고자 할 때 Neutralino.js가 유리합니다.
빠른 로딩과 낮은 리소스 사용이 필요한 경우: 빠른 로딩 시간과 낮은 리소스 사용량이 중요한 경우, Neutralino.js를 선택하여 더 나은 사용자 경험을 제공할 수 있습니다.</p>
<h3 id="5-결론">5. 결론</h3>
<p>Electron과 Neutralino.js는 각각 다른 요구사항에 맞게 사용될 수 있는 데스크톱 애플리케이션 개발 프레임워크입니다. Electron은 풍부한 기능과 강력한 생태계를 제공하며, 복잡한 애플리케이션 개발에 적합합니다. 반면, Neutralino.js는 경량화와 성능 최적화가 중요한 프로젝트에 적합한 선택이 될 수 있습니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Queue,  Stack,  Deque의 차이와 사용법]]></title>
            <link>https://velog.io/@mh_kim/Queue-Stack-Deque%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%99%80-%EC%82%AC%EC%9A%A9%EB%B2%95</link>
            <guid>https://velog.io/@mh_kim/Queue-Stack-Deque%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%99%80-%EC%82%AC%EC%9A%A9%EB%B2%95</guid>
            <pubDate>Thu, 29 Aug 2024 08:06:37 GMT</pubDate>
            <description><![CDATA[<h3 id="1-queue">1. Queue</h3>
<ul>
<li><strong>정의</strong>: Queue는 &quot;선입선출(First-In-First-Out, FIFO)&quot; 방식의 자료구조입니다. 즉, 먼저 들어온 데이터가 먼저 나가는 구조입니다.</li>
<li><strong>사용 방법</strong>: add() 또는 offer() 메서드로 큐의 끝에 요소를 추가하고, remove() 또는 poll() 메서드로 큐의 앞에서 요소를 제거합니다.</li>
<li><strong>대표적 구현체</strong>: LinkedList, PriorityQueue, ArrayBlockingQueue</li>
<li><strong>주요 메서드</strong>
add(): 큐의 끝에 요소를 추가합니다. 큐의 크기가 제한되어 있고 가득 찬 경우 예외를 던집니다.
offer(): 큐의 끝에 요소를 추가합니다. 큐의 크기가 제한되어 있고 가득 찬 경우 false를 반환합니다.
remove(): 큐의 앞에서 요소를 제거하고 반환합니다. 큐가 비어있으면 예외를 던집니다.
poll(): 큐의 앞에서 요소를 제거하고 반환합니다. 큐가 비어있으면 null을 반환합니다.
peek(): 큐의 앞에 있는 요소를 반환하되, 큐에서 제거하지 않습니다.</li>
<li><strong>사용 사례</strong>
작업 대기열(Task Queue): 작업을 순차적으로 처리해야 할 때, 예를 들어 프린터 작업 대기열이나 요청 처리 대기열에서 사용합니다.
BFS 알고리즘: 너비 우선 탐색(Breadth-First Search) 알고리즘에서 노드를 탐색할 때 Queue를 사용합니다.<pre><code class="language-java">import java.util.LinkedList;
import java.util.Queue;
</code></pre>
</li>
</ul>
<p>public class QueueExample {
    public static void main(String[] args) {
        Queue<Integer> queue = new LinkedList&lt;&gt;();</p>
<pre><code>    queue.offer(1);
    queue.offer(2);
    queue.offer(3);

    System.out.println(queue.poll()); // 출력: 1
    System.out.println(queue.peek()); // 출력: 2
}</code></pre><p>}</p>
<pre><code>### 2. Stack
- **정의**: Stack은 &quot;후입선출(Last-In-First-Out, LIFO)&quot; 방식의 자료구조입니다. 즉, 나중에 들어온 데이터가 먼저 나가는 구조입니다.
- **사용 방법**: push() 메서드로 스택의 맨 위에 요소를 추가하고, pop() 메서드로 스택의 맨 위에서 요소를 제거합니다.
- **대표적 구현체**: java.util.Stack 클래스
- **주요 메서드**
push(): 스택의 맨 위에 요소를 추가합니다.
pop(): 스택의 맨 위에서 요소를 제거하고 반환합니다. 스택이 비어있으면 예외를 던집니다.
peek(): 스택의 맨 위에 있는 요소를 반환하되, 스택에서 제거하지 않습니다.
empty(): 스택이 비어있는지를 반환합니다.
- **사용 사례**
수식 계산기: 수식을 후위 표기법(Reverse Polish Notation)으로 변환하여 계산할 때 스택을 사용합니다.
재귀적인 알고리즘: 재귀적인 문제를 반복 구조로 풀 때, 호출 스택을 모방하여 스택을 사용합니다.
브라우저의 뒤로 가기 기능: 사용자가 방문한 페이지를 스택에 저장해 두었다가 뒤로 가기 요청 시 pop하여 페이지를 보여주는 기능에 사용됩니다.
``` java
import java.util.Stack;

public class StackExample {
    public static void main(String[] args) {
        Stack&lt;Integer&gt; stack = new Stack&lt;&gt;();

        stack.push(1);
        stack.push(2);
        stack.push(3);

        System.out.println(stack.pop()); // 출력: 3
        System.out.println(stack.peek()); // 출력: 2
    }
}
</code></pre><h3 id="3-deque">3. Deque</h3>
<ul>
<li><strong>정의</strong>: Deque는 &quot;양방향 큐(Double-Ended Queue)&quot;의 약자로, 큐의 앞과 뒤 양쪽에서 삽입과 삭제가 모두 가능한 자료구조입니다. 따라서 Deque는 Queue와 Stack의 특성을 모두 가질 수 있습니다.</li>
<li><strong>사용 방법</strong>: Deque 인터페이스는 큐의 양쪽에서 삽입과 삭제를 처리할 수 있는 여러 메서드를 제공합니다.</li>
<li><strong>대표적 구현체</strong>: ArrayDeque, LinkedList</li>
<li><strong>주요 메서드</strong>
addFirst(): 덱의 앞에 요소를 추가합니다.
addLast(): 덱의 뒤에 요소를 추가합니다.
removeFirst(): 덱의 앞에서 요소를 제거하고 반환합니다.
removeLast(): 덱의 뒤에서 요소를 제거하고 반환합니다.
getFirst(): 덱의 앞에 있는 요소를 반환하되, 덱에서 제거하지 않습니다.
getLast(): 덱의 뒤에 있는 요소를 반환하되, 덱에서 제거하지 않습니다.</li>
<li><strong>사용 사례</strong>
덱을 사용한 큐 또는 스택 대체: Deque는 큐와 스택의 역할을 모두 할 수 있으므로, 이 두 가지 기능을 모두 필요로 하는 경우에 유용합니다.
이중 끝 스택 알고리즘: 양방향에서 삽입 및 삭제가 필요한 알고리즘에 사용됩니다.
Sliding Window: 특정 범위 내에서 최대값이나 최소값을 찾는 슬라이딩 윈도우 알고리즘에서 유용하게 사용할 수 있습니다.<pre><code class="language-java">import java.util.ArrayDeque;
import java.util.Deque;
</code></pre>
</li>
</ul>
<p>public class DequeAsStack {
    public static void main(String[] args) {
        Deque<Integer> stack = new ArrayDeque&lt;&gt;();</p>
<pre><code>    stack.push(1);
    stack.push(2);
    stack.push(3);

    System.out.println(stack.pop()); // 출력: 3
    System.out.println(stack.peek()); // 출력: 2
}</code></pre><p>}</p>
<pre><code>### 4. Stack vs Deque: 무엇을 사용할까?
#### Stack을 사용하는 이점
- 간단한 API: Stack 클래스는 간단한 API를 제공하여 사용이 직관적입니다.
- 레거시 코드와의 호환성: 기존에 작성된 코드에서 Stack을 사용하고 있다면 호환성을 유지할 수 있습니다.
#### Deque를 사용하는 이유
- 더 나은 성능 및 유연성: Deque는 큐와 스택의 모든 기능을 지원하며, 더 나은 성능을 제공합니다.
- 현대적인 설계: Deque는 API가 일관되고 설계가 현대적이어서 유지보수성이 높습니다.
- 양방향 기능 제공: 스택과 큐의 기능을 모두 필요로 하는 경우 유용합니다.

### 5. Stack의 동시성 문제(성능 저하)와 대안
Stack 클래스는 동기화 메서드를 통해 스레드 안전성을 보장하지만, 이는 성능 저하를 초래할 수 있습니다. 따라서, 멀티스레드 환경에서 스택이 필요하다면, 동시성을 제공하는 다른 컬렉션을 고려하는 것이 좋습니다.
ConcurrentLinkedDeque: 스레드 안전한 Deque 구현체로, Deque의 양방향 기능을 그대로 사용하면서도 동시성을 보장합니다.
``` java
import java.util.concurrent.ConcurrentLinkedDeque;

public class ConcurrentDequeExample {
    public static void main(String[] args) {
        ConcurrentLinkedDeque&lt;Integer&gt; deque = new ConcurrentLinkedDeque&lt;&gt;();

        deque.push(1);
        deque.push(2);
        deque.push(3);

        System.out.println(deque.pop()); // 출력: 3
    }
}</code></pre><h3 id="deque의-구현체-arraydeque와-linkedlist-비교">Deque의 구현체 ArrayDeque와 LinkedList 비교</h3>
<ul>
<li><strong>메모리 효율성</strong>: ArrayDeque는 내부적으로 크기가 가변적인 배열을 사용하여 요소를 저장합니다. 이 배열은 요소가 추가됨에 따라 동적으로 확장됩니다. 반면, LinkedList는 각 요소를 저장할 때 추가적인 객체(노드)와 그 안에 두 개의 포인터(이전 노드와 다음 노드)를 사용해야 하므로 메모리 사용량이 더 많습니다. 이로 인해 ArrayDeque는 일반적으로 더 적은 메모리를 사용합니다.</li>
<li><strong>캐시 적중률</strong>: ArrayDeque는 배열을 사용하기 때문에 요소가 메모리 상에서 연속적으로 저장됩니다. 이는 CPU 캐시의 효율성을 높이고, 메모리 접근 속도를 향상시킬 수 있습니다. 반면, LinkedList의 노드는 메모리 상에 분산되어 저장되기 때문에 캐시 적중률이 낮아질 수 있습니다.</li>
<li><strong>상수 시간 복잡도</strong>: ArrayDeque는 요소의 추가와 제거 작업에서 상수 시간(Amortized O(1))이 걸립니다. 특히, 양쪽 끝에서의 추가 및 제거 작업이 빠릅니다. 반면, LinkedList는 특정 위치에 있는 요소를 추가하거나 제거할 때 양방향으로 리스트를 탐색해야 하는 경우 O(n)의 시간이 소요될 수 있습니다.</li>
<li><strong>더 나은 성능</strong>: 실제 사용에서 ArrayDeque는 대부분의 작업에서 LinkedList보다 더 나은 성능을 보입니다. 특히 중간에서의 삽입, 삭제 작업이 많이 일어나지 않는 경우에는 ArrayDeque가 압도적으로 빠릅니다.</li>
</ul>
<h3 id="6-결론-언제-어떤-자료구조를-선택해야-할까">6. 결론: 언제 어떤 자료구조를 선택해야 할까?</h3>
<ul>
<li>FIFO 구조가 필요할 때: 순차적으로 작업을 처리해야 하는 경우 Queue를 사용</li>
<li>LIFO 구조가 필요할 때: 최근에 추가된 데이터를 먼저 처리해야 하는 경우 Stack을 사용하거나, 더 현대적이고 유연한 대안으로 Deque를 사용</li>
<li>양방향 삽입/삭제가 필요할 때: Deque를 사용하여 양쪽에서 데이터를 효율적으로 처리</li>
</ul>
<p>대부분의 새로운 개발에서는 Deque를 사용하는 것이 권장됩니다. Deque는 큐와 스택의 기능을 모두 제공하며, 성능과 유연성 면에서 Stack보다 우수하기 때문입니다. 그러나 간단한 스택 기능이 필요하거나 레거시 코드와의 호환성이 중요한 경우에는 Stack을 사용할 수 있습니다. 각 자료구조의 특성을 잘 이해하고, 구체적인 요구 사항에 맞춰 적절한 자료구조를 선택하는 것이 중요합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 왜 Java에서 BigDecimal을 사용해야 할까? ]]></title>
            <link>https://velog.io/@mh_kim/%EC%99%9C-Java%EC%97%90%EC%84%9C-BigDecimal%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%B4%EC%95%BC-%ED%95%A0%EA%B9%8C</link>
            <guid>https://velog.io/@mh_kim/%EC%99%9C-Java%EC%97%90%EC%84%9C-BigDecimal%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%B4%EC%95%BC-%ED%95%A0%EA%B9%8C</guid>
            <pubDate>Thu, 29 Aug 2024 07:44:36 GMT</pubDate>
            <description><![CDATA[<h3 id="1-float와-double">1. float와 double</h3>
<h4 id="float">float</h4>
<ul>
<li>비트 크기: 32비트</li>
<li>표현 범위: 약 ±3.4e−38 ~ ±3.4e38</li>
<li>유효 자릿수: 약 7자리</li>
<li>용도: 부동소수점 숫자를 표현할 때 사용되며, 메모리 사용이 적기 때문에 수치 계산에서 성능이 중요한 경우에 사용됨.<h4 id="double">double</h4>
</li>
<li>비트 크기: 64비트</li>
<li>표현 범위: 약 ±1.7e−308 ~ ±1.7e308</li>
<li>유효 자릿수: 약 15자리</li>
<li>용도: float보다 더 정밀한 부동소수점 숫자를 표현할 때 사용되며, 대부분의 경우에 기본적으로 사용됨.</li>
</ul>
<p>부동소수점 숫자(float, double)의 문제점: float와 double은 부동소수점 연산을 사용하기 때문에 정확한 소수 계산이 불가능할 수 있습니다. 이는 컴퓨터가 2진수 기반으로 계산을 수행하기 때문에 발생하는 문제로, 특정 소수점 이하의 값은 정확하게 표현할 수 없습니다.</p>
<p>예시:</p>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        double a = 1.1;
        double b = 2.2;
        double result = a + b;

        System.out.println(&quot;1.1 + 2.2 = &quot; + result);  // 예상: 3.3, 실제: 3.3000000000000003
    }
}</code></pre>
<p>위 예제에서 1.1과 2.2를 더하면 3.3이 나와야 하지만, 실제 출력값은 약간의 오차가 있는 3.3000000000000003이 나옵니다. 이는 double의 정확도 문제로 인한 것입니다.</p>
<h3 id="2-biginteger와-bigdecimal">2. BigInteger와 BigDecimal</h3>
<h4 id="biginteger">BigInteger</h4>
<ul>
<li>비트 크기: 무제한 (메모리가 허용하는 범위 내에서)</li>
<li>표현 범위: 정수의 범위를 무제한으로 표현할 수 있음.</li>
<li>유효 자릿수: 제한 없음</li>
<li>용도: 매우 큰 정수를 정확하게 계산해야 할 때 사용.<h4 id="bigdecimal">BigDecimal</h4>
</li>
<li>비트 크기: 무제한 (메모리가 허용하는 범위 내에서)</li>
<li>표현 범위: 무제한 소수 (정확한 소수점 연산이 필요할 때 사용)</li>
<li>유효 자릿수: 제한 없음</li>
<li>용도: 금융 계산 등 소수점 이하의 정확도가 중요한 계산에 사용.</li>
</ul>
<blockquote>
<p>BigDecimal을 사용해야 하는 이유: 
BigDecimal은 소수점을 포함한 숫자를 정확하게 표현하고 계산할 수 있는 클래스입니다. 이는 금융 계산이나 정밀한 과학 계산 등에서 매우 중요합니다. BigDecimal은 10진수 기반으로 계산을 수행하므로, 부동소수점 방식의 오차가 발생하지 않습니다.</p>
</blockquote>
<p>예시:</p>
<pre><code class="language-java">import java.math.BigDecimal;

public class Main {
    public static void main(String[] args) {
        BigDecimal a = new BigDecimal(&quot;1.1&quot;);
        BigDecimal b = new BigDecimal(&quot;2.2&quot;);
        BigDecimal result = a.add(b);

        System.out.println(&quot;1.1 + 2.2 = &quot; + result);  // 출력: 3.3
    }
}</code></pre>
<p>위 예제에서 BigDecimal을 사용하면 1.1 + 2.2의 결과가 정확히 3.3으로 출력됩니다. BigDecimal은 문자열로 초기화하여 생성하는 것이 권장되는데, 이는 생성 과정에서 부동소수점의 부정확성이 개입되지 않도록 하기 위함입니다.</p>
<h3 id="3-숫자-정확도가-떨어지는-경우의-예시">3. 숫자 정확도가 떨어지는 경우의 예시</h3>
<p>double과 같은 부동소수점 타입을 사용하여 금융 계산을 수행하면 작은 오차가 누적되어 큰 문제가 될 수 있습니다.</p>
<p>예시:</p>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        double price = 19.99;
        double quantity = 100;
        double total = price * quantity;

        System.out.println(&quot;Total: &quot; + total);  // 예상: 1999.00, 실제: 1998.9999999999998
    }
}</code></pre>
<p>위 예제에서 double을 사용하여 계산한 결과는 약간의 오차가 있는 1998.9999999999998이 됩니다. 금융 시스템에서 이러한 오차는 큰 문제가 될 수 있습니다.</p>
<p>BigDecimal 사용:</p>
<pre><code class="language-java">import java.math.BigDecimal;

public class Main {
    public static void main(String[] args) {
        BigDecimal price = new BigDecimal(&quot;19.99&quot;);
        BigDecimal quantity = new BigDecimal(&quot;100&quot;);
        BigDecimal total = price.multiply(quantity);

        System.out.println(&quot;Total: &quot; + total);  // 출력: 1999.00
    }
}</code></pre>
<p>위 코드에서 BigDecimal을 사용하면 정확히 1999.00이 출력됩니다. 따라서 소수점 이하의 정확도가 중요한 경우에는 반드시 BigDecimal을 사용하는 것이 좋습니다.</p>
<h3 id="4-결론">4. 결론</h3>
<p>부동소수점 타입인 float와 double은 빠른 계산이 가능하지만, 숫자의 정확도 문제가 발생할 수 있습니다. 특히, 금융 계산과 같이 정확한 소수점 연산이 중요한 경우에는 BigDecimal을 사용하여 이러한 문제를 방지하는 것이 좋습니다. BigDecimal은 10진수 기반으로 정확한 계산을 제공하며, 이러한 특성 덕분에 정확한 소수점 연산이 가능합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Java Collections Framework의 주요 종류와 특징 및 성능]]></title>
            <link>https://velog.io/@mh_kim/java-Java-Collections-Framework%EC%9D%98-%EC%A3%BC%EC%9A%94-%EC%A2%85%EB%A5%98%EC%99%80-%ED%8A%B9%EC%A7%95-%EB%B0%8F-%EC%84%B1%EB%8A%A5</link>
            <guid>https://velog.io/@mh_kim/java-Java-Collections-Framework%EC%9D%98-%EC%A3%BC%EC%9A%94-%EC%A2%85%EB%A5%98%EC%99%80-%ED%8A%B9%EC%A7%95-%EB%B0%8F-%EC%84%B1%EB%8A%A5</guid>
            <pubDate>Mon, 19 Aug 2024 08:33:49 GMT</pubDate>
            <description><![CDATA[<h3 id="1-list">1. List</h3>
<ul>
<li><strong>설명</strong>: 
순서가 있는 데이터의 모음으로, 중복된 요소를 허용합니다.</li>
<li><strong>주요 구현 클래스</strong>: 
ArrayList, LinkedList, Vector</li>
<li><strong>특징</strong>:<ul>
<li><strong>ArrayList</strong>: 동적 배열로, 인덱스를 통한 빠른 접근이 가능하지만, 삽입/삭제가 비효율적일 수 있습니다.</li>
<li><strong>LinkedList</strong>: 이중 연결 리스트로, 삽입/삭제가 빠르지만, 인덱스 접근이 느립니다.</li>
<li><strong>Vector</strong>: ArrayList와 유사하지만, 동기화된 버전입니다.(성능 이슈: 대안책으로 ConcurrentHashMap)</li>
<li><strong>Stack</strong>: List 구현체로 포함되어 있지만, Stack이 LIFO(Last In, First Out) 구조를 가지며 Vector를 기반으로 동작합니다.</li>
</ul>
</li>
<li><strong>장점</strong>:
데이터의 순서가 유지됨
중복된 데이터를 허용</li>
<li><strong>단점</strong>:
특정 상황에서 성능이 비효율적일 수 있음 (예: ArrayList의 삽입/삭제)</li>
</ul>
<h3 id="2-set">2. Set</h3>
<ul>
<li><strong>설명</strong>: 
중복되지 않는 요소의 모음으로, 순서가 없는 컬렉션입니다.</li>
<li>주요 구현 클래스: 
HashSet, LinkedHashSet, TreeSet</li>
<li><strong>특징</strong>:<ul>
<li>HashSet: 해시 테이블을 사용하여 빠른 검색과 삽입을 지원합니다.</li>
<li>LinkedHashSet: 입력된 순서를 유지하는 HashSet입니다.</li>
<li>TreeSet: 정렬된 상태로 데이터를 유지하는 이진 검색 트리 기반의 Set입니다.</li>
</ul>
</li>
<li><strong>장점</strong>:
중복 요소를 허용하지 않음
TreeSet을 사용하면 자동으로 정렬된 상태 유지</li>
<li><strong>단점</strong>:
HashSet은 순서를 보장하지 않음
TreeSet은 삽입/삭제/검색이 상대적으로 느림</li>
</ul>
<h3 id="3-queue">3. Queue</h3>
<ul>
<li><strong>설명</strong>: 
FIFO(First In, First Out) 원칙에 따라 동작하는 컬렉션입니다.</li>
<li><strong>주요 구현 클래스</strong>: 
LinkedList, PriorityQueue, ArrayDeque</li>
<li><strong>특징</strong>:<ul>
<li>LinkedList: 큐의 양쪽에서 삽입/삭제가 가능한 이중 연결 리스트 기반의 큐입니다.</li>
<li>PriorityQueue: 요소의 우선순위에 따라 처리되는 큐입니다.</li>
<li>ArrayDeque: 큐의 양쪽에서 삽입/삭제가 가능한 배열 기반의 덱입니다.</li>
</ul>
</li>
<li><strong>장점</strong>:
다양한 큐 구조를 지원 (예: 우선순위 큐)
큐의 양쪽에서 삽입/삭제가 가능한 구조 지원</li>
<li><strong>단점</strong>:
PriorityQueue는 동등한 우선순위의 요소가 있을 때 예측하기 어려움</li>
</ul>
<h3 id="4-map">4. Map</h3>
<ul>
<li><strong>설명</strong>: 
키와 값의 쌍으로 이루어진 데이터 구조입니다. 키는 중복될 수 없으며, 값은 중복될 수 있습니다.</li>
<li><strong>주요 구현 클래스</strong>: 
HashMap, LinkedHashMap, TreeMap, Hashtable</li>
<li><strong>특징</strong>:<ul>
<li>HashMap: 해시 테이블을 기반으로 하여 키-값 쌍을 빠르게 저장하고 검색할 수 있습니다.</li>
<li>LinkedHashMap: 입력된 순서를 유지하는 HashMap입니다.</li>
<li>TreeMap: 키를 정렬된 상태로 유지하는 이진 검색 트리 기반의 맵입니다.</li>
<li>Hashtable: HashMap과 유사하지만 동기화된 버전입니다.(성능 이슈: 대안책으로 ConcurrentHashMap)</li>
</ul>
</li>
<li><strong>장점</strong>:
키-값 쌍으로 데이터를 저장하여 빠른 검색 가능
TreeMap을 사용하면 키가 자동으로 정렬됨</li>
<li><strong>단점</strong>:
HashMap과 Hashtable은 순서를 보장하지 않음
TreeMap은 삽입/삭제/검색이 상대적으로 느림</li>
</ul>
<h3 id="5-시간-및-공간복잡도">5. 시간 및 공간복잡도</h3>
<ul>
<li><strong>접근 시간 (Access Time)</strong><ul>
<li>ArrayList: 인덱스를 통한 요소 접근은 O(1)의 시간 복잡도를 가지며 매우 빠릅니다. 그러나 리스트의 크기가 매우 커질 경우 메모리 관리 측면에서 성능 저하가 발생할 수 있습니다.</li>
<li>LinkedList: 인덱스 접근이 O(n)의 시간 복잡도를 가지므로, 리스트의 길이가 길어질수록 접근 시간이 선형적으로 증가합니다.</li>
</ul>
</li>
<li><strong>검색 시간 (Search Time)</strong><ul>
<li>HashSet/HashMap: 해시 테이블 기반으로, 일반적으로 O(1)의 검색 시간을 가집니다. 하지만 해시 충돌이 발생할 경우 성능이 저하될 수 있습니다.</li>
<li>TreeSet/TreeMap: 정렬된 트리 구조로 O(log n)의 검색 시간을 가지며, 대규모 데이터에서 일정한 성능을 유지할 수 있습니다.</li>
</ul>
</li>
<li><strong>삽입 및 삭제 시간 (Insertion/Deletion Time)</strong><ul>
<li>ArrayList: 요소 삽입/삭제 시, 특히 리스트 중간에서의 작업은 O(n)의 시간 복잡도를 가지며, 리스트의 크기가 클수록 더 많은 요소를 이동해야 하므로 성능이 저하됩니다.</li>
<li>LinkedList: 요소 삽입/삭제는 리스트의 양 끝에서 O(1)의 시간 복잡도를 가지지만, 중간에서의 삽입/삭제는 O(n) 시간이 걸릴 수 있습니다.</li>
<li>TreeSet/TreeMap: 삽입/삭제 시 트리를 재구성해야 하므로 O(log n)의 시간이 걸리며, 크기가 커질수록 성능이 영향을 받을 수 있습니다.</li>
</ul>
</li>
<li><strong>공간 복잡도 (Space Complexity)</strong><ul>
<li>모든 컬렉션 클래스는 O(n)의 공간 복잡도를 가지며, 저장되는 요소의 수에 비례하여 메모리를 사용합니다. 그러나 동적 배열 기반 컬렉션(ArrayList, Vector)은 추가적인 메모리를 할당하여 크기를 조정할 수 있기 때문에 잠재적인 메모리 오버헤드가 발생할 수 있습니다.</li>
</ul>
</li>
</ul>
<table>
<thead>
<tr>
<th align="center">Collection Type</th>
<th align="center">Time Complexity (Access)</th>
<th align="center">Time Complexity (Search)</th>
<th align="center">Time Complexity (Insertion)</th>
<th align="center">Time Complexity (Deletion)</th>
<th align="center">Space Complexity</th>
</tr>
</thead>
<tbody><tr>
<td align="center">ArrayList</td>
<td align="center">O(1)</td>
<td align="center">O(n)</td>
<td align="center">O(1)</td>
<td align="center">O(n)</td>
<td align="center">O(n)</td>
</tr>
<tr>
<td align="center">LinkedList</td>
<td align="center">O(n)</td>
<td align="center">O(n)</td>
<td align="center">O(1)</td>
<td align="center">O(1)</td>
<td align="center">O(n)</td>
</tr>
<tr>
<td align="center">Vector</td>
<td align="center">O(1)</td>
<td align="center">O(n)</td>
<td align="center">O(1)</td>
<td align="center">O(n)</td>
<td align="center">O(n)</td>
</tr>
<tr>
<td align="center">Stack</td>
<td align="center">O(1)</td>
<td align="center">O(n)</td>
<td align="center">O(1)</td>
<td align="center">O(1)</td>
<td align="center">O(n)</td>
</tr>
<tr>
<td align="center">HashSet</td>
<td align="center">N/A</td>
<td align="center">O(1)</td>
<td align="center">O(1)</td>
<td align="center">O(1)</td>
<td align="center">O(n)</td>
</tr>
<tr>
<td align="center">LinkedHashSet</td>
<td align="center">N/A</td>
<td align="center">O(1)</td>
<td align="center">O(1)</td>
<td align="center">O(1)</td>
<td align="center">O(n)</td>
</tr>
<tr>
<td align="center">TreeSet</td>
<td align="center">O(log n)</td>
<td align="center">O(log n)</td>
<td align="center">O(log n)</td>
<td align="center">O(log n)</td>
<td align="center">O(n)</td>
</tr>
<tr>
<td align="center">PriorityQueue</td>
<td align="center">O(log n)</td>
<td align="center">O(log n)</td>
<td align="center">O(log n)</td>
<td align="center">O(log n)</td>
<td align="center">O(n)</td>
</tr>
<tr>
<td align="center">HashMap</td>
<td align="center">N/A</td>
<td align="center">O(1)</td>
<td align="center">O(1)</td>
<td align="center">O(1)</td>
<td align="center">O(n)</td>
</tr>
<tr>
<td align="center">LinkedHashMap</td>
<td align="center">N/A</td>
<td align="center">O(1)</td>
<td align="center">O(1)</td>
<td align="center">O(1)</td>
<td align="center">O(n)</td>
</tr>
<tr>
<td align="center">TreeMap</td>
<td align="center">O(log n)</td>
<td align="center">O(log n)</td>
<td align="center">O(log n)</td>
<td align="center">O(log n)</td>
<td align="center">O(n)</td>
</tr>
</tbody></table>
<hr>
<p>Reference
<a href="https://docs.oracle.com/javase/8/docs/technotes/guides/collections/reference.html">https://docs.oracle.com/javase/8/docs/technotes/guides/collections/reference.html</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] 원시 타입, 참조 타입, 래퍼 클래스]]></title>
            <link>https://velog.io/@mh_kim/java-%EC%9B%90%EC%8B%9C-%ED%83%80%EC%9E%85-%EC%B0%B8%EC%A1%B0-%ED%83%80%EC%9E%85-%EB%9E%98%ED%8D%BC-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@mh_kim/java-%EC%9B%90%EC%8B%9C-%ED%83%80%EC%9E%85-%EC%B0%B8%EC%A1%B0-%ED%83%80%EC%9E%85-%EB%9E%98%ED%8D%BC-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Mon, 19 Aug 2024 08:09:14 GMT</pubDate>
            <description><![CDATA[<h3 id="1-원시-타입-primitive-types">1. 원시 타입 (Primitive Types)</h3>
<blockquote>
<p>예시: int, char, float, boolean, byte, short, long, double</p>
</blockquote>
<p>특징</p>
<ul>
<li>간단한 데이터 저장: 원시 타입은 기본적인 데이터 값을 직접 저장합니다.</li>
<li>고정된 크기: 각 원시 타입은 고정된 메모리 크기를 차지합니다. 예를 들어, int는 항상 4바이트를 차지합니다.</li>
<li>메모리 효율성: 원시 타입은 값 자체를 스택 메모리에 저장하기 때문에 메모리 사용이 효율적이고, 연산 속도가 빠릅니다.</li>
<li>값 전달: 원시 타입은 값에 의한 전달(pass by value)이 이루어집니다. 즉, 함수에 전달될 때 값의 복사본이 전달되며, 원래의 값에는 영향을 주지 않습니다.</li>
</ul>
<h3 id="2-참조-타입-reference-types">2. 참조 타입 (Reference Types)</h3>
<blockquote>
<p>예시: 클래스, 배열, 인터페이스, String (예: String, Integer, ArrayList)</p>
</blockquote>
<p>특징</p>
<ul>
<li>객체를 참조: 참조 타입은 객체의 메모리 주소를 참조하여 데이터를 관리합니다. 즉, 실제 데이터는 힙(heap) 메모리에 저장되고, 변수는 이 데이터를 가리키는 주소를 가지고 있습니다.</li>
<li>유연성: 참조 타입은 다양한 데이터 구조와 복잡한 객체를 저장할 수 있습니다. 예를 들어, 배열이나 클래스 객체는 모두 참조 타입에 속합니다.</li>
<li>값 전달: 참조 타입은 참조에 의한 전달(pass by reference)을 사용합니다. 즉, 함수에 객체의 참조 주소가 전달되며, 이를 통해 객체의 원래 데이터를 수정할 수 있습니다.</li>
<li>동적 할당: 참조 타입은 동적으로 메모리를 할당하며, 크기를 필요에 따라 조정할 수 있습니다.</li>
</ul>
<h3 id="3-wrapper-클래스-wrapper-classes">3. Wrapper 클래스 (Wrapper Classes)</h3>
<blockquote>
<p>예시: Integer, Character, Float, Boolean, Double, Byte, Short, Long</p>
</blockquote>
<p>특징</p>
<ul>
<li>기본 타입의 객체화: Wrapper 클래스는 기본 데이터 타입을 객체로 감싸는 클래스입니다. 이를 통해 기본 타입을 객체로 다룰 수 있습니다.</li>
<li>Java 컬렉션과의 호환성: 
Wrapper 클래스는 Java의 컬렉션 프레임워크와 같이 객체를 필요로 하는 곳에서 기본 타입을 사용할 수 있도록 해줍니다. 예를 들어, ArrayList<Integer>와 같이 객체 타입으로만 이루어진 컬렉션에 기본 타입을 넣을 수 있습니다.</li>
<li>유틸리티 메서드: Wrapper 클래스는 기본 데이터 타입이 제공하지 않는 다양한 메서드를 제공합니다. 예를 들어, Integer.parseInt(&quot;123&quot;)는 문자열을 정수로 변환하는 메서드입니다.</li>
<li>자동 박싱/언박싱: Java는 기본 타입과 Wrapper 클래스 간의 자동 변환(Autoboxing/Unboxing)을 지원합니다. 예를 들어, int 값을 Integer로 자동 변환하거나, Integer 객체를 int로 자동 변환할 수 있습니다.</li>
</ul>
<h3 id="주요-차이점-요약">주요 차이점 요약</h3>
<table>
<thead>
<tr>
<th align="center">특징</th>
<th align="center">원시 타입 (Primitive Types)</th>
<th align="center">참조 타입 (Reference Types)</th>
<th align="center">Wrapper 클래스 (Wrapper Classes)</th>
</tr>
</thead>
<tbody><tr>
<td align="center">저장 방식</td>
<td align="center">값 자체를 저장</td>
<td align="center">객체의 참조(메모리 주소)를 저장</td>
<td align="center">기본 타입을 객체로 감쌈</td>
</tr>
<tr>
<td align="center">메모리 사용</td>
<td align="center">고정된 크기, 메모리 효율적</td>
<td align="center">동적 메모리 할당, 더 많은 메모리 사용</td>
<td align="center">동적 메모리 할당, 추가적인 오버헤드</td>
</tr>
<tr>
<td align="center">값 전달 방식</td>
<td align="center">값에 의한 전달 (Pass by Value)</td>
<td align="center">참조에 의한 전달 (Pass by Reference)</td>
<td align="center">참조에 의한 전달 (Pass by Reference)</td>
</tr>
<tr>
<td align="center">타입의 본질</td>
<td align="center">기본 데이터 타입 (Primitive Type)</td>
<td align="center">객체, 클래스, 배열, 인터페이스 등</td>
<td align="center">기본 타입의 객체화(Reference Type)</td>
</tr>
<tr>
<td align="center">예시</td>
<td align="center">int, char, boolean</td>
<td align="center">String, Array, Class&quot;</td>
<td align="center">&quot;Integer, Character, Boolean</td>
</tr>
<tr>
<td align="center">유연성</td>
<td align="center">고정적, 제한적</td>
<td align="center">유연하고 확장 가능</td>
<td align="center">기본 타입과 컬렉션 등 객체 기반 사용에 유연</td>
</tr>
<tr>
<td align="center">사용 목적</td>
<td align="center">간단한 데이터 연산, 성능 중시</td>
<td align="center">복잡한 데이터 구조 및 객체 지향 프로그래밍</td>
<td align="center">기본 타입을 객체로 다루기, 컬렉션 사용</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] JPA에서 toString StackOverflowError 발생]]></title>
            <link>https://velog.io/@mh_kim/JPA%EC%97%90%EC%84%9C-toString-StackOverflowError-%EB%B0%9C%EC%83%9D</link>
            <guid>https://velog.io/@mh_kim/JPA%EC%97%90%EC%84%9C-toString-StackOverflowError-%EB%B0%9C%EC%83%9D</guid>
            <pubDate>Fri, 19 Jul 2024 19:55:31 GMT</pubDate>
            <description><![CDATA[<p>프로젝트 진행중 아래와 같은 오류가 발생했습니다.
<img src="https://velog.velcdn.com/images/mh_kim/post/2033c6b1-d05b-46a1-8ba1-1fc4aa2b795f/image.png" alt=""></p>
<h2 id="java-code">java code</h2>
<p>Member.class</p>
<pre><code>@Entity
@Getter @Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(of = {&quot;id&quot;, &quot;username&quot;, &quot;age&quot;})
@NamedQuery(
        name=&quot;Member.findByUsername&quot;,
        query=&quot;select m from Member m where m.username = :username&quot;)
@NamedEntityGraph(name = &quot;Member.all&quot;, attributeNodes =
@NamedAttributeNode(&quot;team&quot;))
public class Member extends BaseEntity {

    @Id
    @GeneratedValue
    @Column(name = &quot;member_id&quot;)
    private  Long id;
    private String username;
    private int age;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = &quot;team_id&quot;)
    private Team team;

        @Override
    public String toString() {
        return &quot;Member{&quot; +
                &quot;id=&quot; + id +
                &quot;, username=&#39;&quot; + username + &#39;\&#39;&#39; +
                &quot;, age=&quot; + age +
                &quot;, team=&quot; + team +
                &#39;}&#39;;
    }
</code></pre><p>Team.class</p>
<pre><code>@Entity
@Getter @Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@ToString(of = {&quot;id&quot;, &quot;name&quot;})
public class Team extends BaseEntity {

    @Id
    @GeneratedValue
    @Column(name = &quot;team_id&quot;)
    private Long id;
    private String name;

    @BatchSize(size = 13)
    @OneToMany(mappedBy = &quot;team&quot;)
    private List&lt;Member&gt; members = new ArrayList&lt;&gt;();

    public Team(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return &quot;Team{&quot; +
                &quot;id=&quot; + id +
                &quot;, name=&#39;&quot; + name + &#39;\&#39;&#39; +
                &quot;, members=&quot; + members +
                &#39;}&#39;;
    }
}</code></pre><p>다대일 양방향 관계로 설정을 하고, 각각의 Entity에서 자동 생성으로 toString()을 생성했습니다.
이런 경우, 순환 참조가 되며 무한 루프에 빠지게 됩니다.
 &quot;, members=&quot; + members +
 &quot;, team=&quot; + team +</p>
<h2 id="해결-방법">해결 방법</h2>
<p>toString을 자동 생성하더라도, 이후에 양방향 관계에 있는 경우 참조값이 객체인 경우 삭제합니다.</p>
<hr>
<p>Reference
<a href="https://velog.io/@bbbbooo/JPA-%EC%88%9C%ED%99%98-%EC%B0%B8%EC%A1%B0-%EC%8B%9C-StackOverFlow-java.lang.StackOverflowError">https://velog.io/@bbbbooo/JPA-%EC%88%9C%ED%99%98-%EC%B0%B8%EC%A1%B0-%EC%8B%9C-StackOverFlow-java.lang.StackOverflowError</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[탐색 알고리즘 (Search Algorithm)]]></title>
            <link>https://velog.io/@mh_kim/%ED%83%90%EC%83%89-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-Search-Algorithm</link>
            <guid>https://velog.io/@mh_kim/%ED%83%90%EC%83%89-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-Search-Algorithm</guid>
            <pubDate>Thu, 18 Jul 2024 16:39:47 GMT</pubDate>
            <description><![CDATA[<h3 id="탐색-알고리즘이란">탐색 알고리즘이란?</h3>
<p>탐색 알고리즘은 데이터 집합에서 특정 값이나 조건을 만족하는 데이터를 찾는 알고리즘입니다. 데이터의 형태와 탐색 목표에 따라 다양한 종류의 탐색 알고리즘이 존재하며, 각각의 알고리즘은 시간 복잡도, 공간 복잡도, 구현 난이도 등의 특징을 가집니다.</p>
<h3 id="탐색-알고리즘의-종류">탐색 알고리즘의 종류</h3>
<p><strong>1. 선형 탐색 (Linear Search)</strong></p>
<p>원리: 데이터를 처음부터 끝까지 순차적으로 비교하여 원하는 값을 찾습니다.
장점: 구현이 간단하고, 정렬되지 않은 데이터에도 적용 가능합니다.
단점: 데이터의 크기가 커질수록 탐색 시간이 오래 걸립니다. (시간 복잡도: O(n))
활용: 데이터의 크기가 작거나, 정렬되지 않은 데이터에서 특정 값을 찾을 때 사용됩니다.</p>
<p><strong>2. 이진 탐색 (Binary Search)</strong></p>
<p>원리: 정렬된 데이터를 반으로 나누어 탐색 범위를 줄여나가며 원하는 값을 찾습니다.
장점: 탐색 속도가 매우 빠릅니다. (시간 복잡도: O(log n))
단점: 데이터가 정렬되어 있어야만 사용 가능합니다.
활용: 정렬된 데이터에서 특정 값을 찾거나, 범위 내에 있는 값들을 찾을 때 사용됩니다.</p>
<p><strong>3. 깊이 우선 탐색 (Depth-First Search, DFS)</strong></p>
<p>원리: 그래프나 트리 구조에서 한 방향으로 깊게 탐색해 나가는 방식입니다.
장점: 구현이 비교적 간단하고, 스택을 이용하여 구현할 수 있습니다.
단점: 최단 경로를 찾는 데에는 적합하지 않습니다.
활용: 그래프 또는 트리의 모든 노드를 방문해야 하는 경우, 사이클 탐지, 위상 정렬 등에 사용됩니다.</p>
<p><strong>4. 너비 우선 탐색 (Breadth-First Search, BFS)</strong></p>
<p>원리: 그래프나 트리 구조에서 시작 노드로부터 가까운 노드부터 단계별로 탐색해 나가는 방식입니다.
장점: 최단 경로를 찾는 데 유용합니다.
단점: 큐를 이용하여 구현해야 하므로, 메모리 사용량이 많을 수 있습니다.
활용: 최단 경로 문제, 그래프의 연결 요소 찾기, 최소 신장 트리 (MST) 등에 사용됩니다.</p>
<p><strong>5. 해시 탐색 (Hash Search)</strong></p>
<p>원리: 해시 함수를 이용하여 데이터를 해시 테이블에 저장하고, 탐색 시 해시 함수를 다시 적용하여 빠르게 원하는 데이터를 찾습니다.
장점: 탐색 속도가 매우 빠릅니다. (평균 시간 복잡도: O(1))
단점: 해시 충돌 발생 시 추가적인 처리가 필요하고, 메모리 사용량이 많을 수 있습니다.
활용: 데이터베이스 인덱싱, 캐싱, 중복 데이터 제거 등에 사용됩니다.</p>
<h3 id="탐색-알고리즘-시간-및-공간-복잡도-비교">탐색 알고리즘 시간 및 공간 복잡도 비교</h3>
<table>
<thead>
<tr>
<th align="center">Algorithm</th>
<th align="center">시간 복잡도(Best)</th>
<th align="center">시간 복잡도(Average)</th>
<th align="center">시간 복잡도(Worst)</th>
<th align="center">공간 복잡도</th>
</tr>
</thead>
<tbody><tr>
<td align="center">선형 탐색</td>
<td align="center">O(1)</td>
<td align="center">O(n)</td>
<td align="center">O(n)</td>
<td align="center">O(1)</td>
</tr>
<tr>
<td align="center">이진 탐색</td>
<td align="center">O(1)</td>
<td align="center">O(log n)</td>
<td align="center">O(log n)</td>
<td align="center">O(1)</td>
</tr>
<tr>
<td align="center">깊이 우선 탐색 (DFS)</td>
<td align="center">O(1)</td>
<td align="center">O(V + E)</td>
<td align="center">O(V + E)</td>
<td align="center">O(V)</td>
</tr>
<tr>
<td align="center">너비 우선 탐색 (BFS)</td>
<td align="center">O(1)</td>
<td align="center">O(V + E)</td>
<td align="center">O(V + E)</td>
<td align="center">O(V)</td>
</tr>
<tr>
<td align="center">해시 탐색</td>
<td align="center">O(1)</td>
<td align="center">O(1)</td>
<td align="center">O(n)</td>
<td align="center">O(n)</td>
</tr>
</tbody></table>
<h3 id="탐색-알고리즘-선택-시-고려-사항">탐색 알고리즘 선택 시 고려 사항</h3>
<p>데이터의 크기: 데이터의 크기가 작으면 선형 탐색도 충분히 빠를 수 있지만, 데이터가 커질수록 이진 탐색이나 해시 탐색이 유리합니다.
데이터의 정렬 여부: 데이터가 정렬되어 있으면 이진 탐색을 사용할 수 있습니다.
탐색 빈도: 탐색을 자주 해야 하는 경우, 해시 탐색이 유리할 수 있습니다.
메모리 제약: 메모리 사용량이 제한적인 경우, 메모리를 적게 사용하는 알고리즘을 선택해야 합니다.</p>
<hr>
<p>Reference
<a href="https://velog.io/@gwichanlee/Algorithm%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-3">https://velog.io/@gwichanlee/Algorithm%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-3</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[정렬 알고리즘(Sorting Algorithm)]]></title>
            <link>https://velog.io/@mh_kim/%EC%A0%95%EB%A0%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98Sorting-Algorithm</link>
            <guid>https://velog.io/@mh_kim/%EC%A0%95%EB%A0%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98Sorting-Algorithm</guid>
            <pubDate>Thu, 18 Jul 2024 02:20:38 GMT</pubDate>
            <description><![CDATA[<p>정렬 알고리즘은 데이터를 특정한 순서대로 배열하는 알고리즘입니다. 다양한 종류의 정렬 알고리즘이 있으며, 각각의 알고리즘은 시간 복잡도, 공간 복잡도, 안정성 등의 특징을 가집니다. 자주 사용되는 정렬 알고리즘은 다음과 같습니다.</p>
<h3 id="정렬-알고리즘의-종류">정렬 알고리즘의 종류</h3>
<p><strong>1. 버블 정렬 (Bubble Sort)</strong></p>
<ul>
<li>원리: 인접한 두 요소를 비교하며 자리를 바꾸는 방식으로 정렬합니다. 가장 큰 요소가 마지막으로 이동하는 - 모습이 거품 같아서 버블 정렬이라고 불립니다.</li>
<li>장점: 구현이 간단합니다.</li>
<li>단점: 시간 복잡도가 O(n^2)으로 비효율적입니다.</li>
<li>활용: 다른 정렬 알고리즘에 비해 효율성이 떨어져 실제 코딩 테스트에서는 거의 사용되지 않습니다.</li>
</ul>
<p><strong>2. 선택 정렬 (Selection Sort)</strong></p>
<ul>
<li>원리: 가장 작은 요소를 찾아 첫 번째 위치에 놓고, 그다음으로 작은 요소를 찾아 두 번째 위치에 놓는 방식을 반복합니다.</li>
<li>장점: 구현이 간단합니다.</li>
<li>단점: 시간 복잡도가 O(n^2)으로 비효율적입니다.</li>
<li>활용: 다른 정렬 알고리즘에 비해 효율성이 떨어져 실제 코딩 테스트에서는 거의 사용되지 않습니다.</li>
</ul>
<p><strong>3. 삽입 정렬 (Insertion Sort)</strong></p>
<ul>
<li>원리: 두 번째 요소부터 시작하여, 앞쪽의 이미 정렬된 부분과 비교하여 자신의 위치를 찾아 삽입합니다.</li>
<li>장점: 구현이 간단하고, 이미 정렬된 데이터에 대해서는 빠릅니다.</li>
<li>단점: 시간 복잡도가 O(n^2)으로 비효율적입니다.</li>
<li>활용: 데이터가 거의 정렬되어 있거나, 데이터의 크기가 작을 때 사용하면 효율적입니다.</li>
</ul>
<p><strong>4. 퀵 정렬 (Quick Sort)</strong></p>
<ul>
<li>원리: 피벗을 기준으로 작은 값은 왼쪽, 큰 값은 오른쪽으로 분할하는 과정을 재귀적으로 반복합니다.</li>
<li>장점: 평균 시간 복잡도가 O(n log n)으로 빠릅니다.</li>
<li>단점: 최악의 경우 시간 복잡도가 O(n^2)이 될 수 있습니다.</li>
<li>활용: 대부분의 경우 빠른 성능을 보이므로, 코딩 테스트에서 가장 많이 사용되는 정렬 알고리즘 중 하나입니다.</li>
</ul>
<p><strong>5. 병합 정렬 (Merge Sort)</strong></p>
<ul>
<li>원리: 데이터를 계속해서 반으로 나눈 뒤, 정렬된 부분을 다시 합치는 방식으로 정렬합니다.</li>
<li>장점: 안정적인 정렬이며, 시간 복잡도가 O(n log n)으로 보장됩니다.</li>
<li>단점: 추가적인 메모리 공간이 필요합니다.</li>
<li>활용: 안정적인 정렬이 필요하거나, 연결 리스트를 정렬할 때 사용하면 효율적입니다.</li>
</ul>
<p><strong>6. 힙 정렬 (Heap Sort)</strong></p>
<ul>
<li>원리: 힙 자료구조를 이용하여 정렬합니다.</li>
<li>장점: 시간 복잡도가 O(n log n)으로 보장됩니다.</li>
<li>단점: 구현이 복잡하고, 추가적인 메모리 공간이 필요합니다.</li>
<li>활용: 우선순위 큐를 구현하거나, k번째로 작은 (큰) 값을 찾을 때 사용하면 효율적입니다.</li>
</ul>
<p><strong>7. 기수 정렬 (Radix Sort)</strong></p>
<ul>
<li>원리: 각 자릿수를 기준으로 정렬하는 방식입니다.</li>
<li>장점: 시간 복잡도가 O(kn)으로 빠릅니다. (k는 자릿수)</li>
<li>단점: 정수 또는 문자열 데이터에만 적용 가능합니다.</li>
<li>활용: 특정 조건(데이터가 숫자이고 자릿수가 제한적)일 때 매우 빠른 성능을 보입니다.</li>
</ul>
<p><strong>8. 계수 정렬 (Counting Sort)</strong></p>
<ul>
<li>원리: 데이터의 범위를 이용하여 정렬하는 방식입니다.</li>
<li>장점: 시간 복잡도가 O(n+k)로 매우 빠릅니다. (k는 데이터의 범위)</li>
<li>단점: 데이터의 범위가 작을 때만 효율적입니다.</li>
<li>활용: 데이터의 범위가 제한적이고, 중복된 값이 많을 때 사용하면 효율적입니다.</li>
</ul>
<h3 id="정렬-알고리즘-시간-및-공간-복잡도-비교">정렬 알고리즘 시간 및 공간 복잡도 비교</h3>
<table>
<thead>
<tr>
<th align="center">Algorithm</th>
<th align="center">시간 복잡도(Best)</th>
<th align="center">시간 복잡도(Average)</th>
<th align="center">시간 복잡도(Worst)</th>
<th align="center">공간 복잡도</th>
</tr>
</thead>
<tbody><tr>
<td align="center">버블 정렬</td>
<td align="center">O(n)</td>
<td align="center">O(n^2)</td>
<td align="center">O(n^2)</td>
<td align="center">O(1)</td>
</tr>
<tr>
<td align="center">선택 정렬</td>
<td align="center">O(n^2)</td>
<td align="center">O(n^2)</td>
<td align="center">O(n^2)</td>
<td align="center">O(1)</td>
</tr>
<tr>
<td align="center">삽입 정렬</td>
<td align="center">O(n)</td>
<td align="center">O(n^2)</td>
<td align="center">O(n^2)</td>
<td align="center">O(1)</td>
</tr>
<tr>
<td align="center">퀵 정렬</td>
<td align="center">O(n log n)</td>
<td align="center">O(n log n)</td>
<td align="center">O(n^2)</td>
<td align="center">O(log n)</td>
</tr>
<tr>
<td align="center">병합 정렬</td>
<td align="center">O(n log n)</td>
<td align="center">O(n log n)</td>
<td align="center">O(n log n)</td>
<td align="center">O(n)</td>
</tr>
<tr>
<td align="center">힙 정렬</td>
<td align="center">O(n log n)</td>
<td align="center">O(n log n)</td>
<td align="center">O(n log n)</td>
<td align="center">O(1)</td>
</tr>
<tr>
<td align="center">기수 정렬</td>
<td align="center">O(kn)</td>
<td align="center">O(kn)</td>
<td align="center">O(kn)</td>
<td align="center">O(n+k)</td>
</tr>
<tr>
<td align="center">계수 정렬</td>
<td align="center">O(n+k)</td>
<td align="center">O(n+k)</td>
<td align="center">O(n+k)</td>
<td align="center">O(n+k)</td>
</tr>
</tbody></table>
<h3 id="정렬-알고리즘-선택-시-고려-사항">정렬 알고리즘 선택 시 고려 사항</h3>
<p>데이터의 크기: 데이터의 크기가 작으면 삽입 정렬과 같은 간단한 알고리즘이 유리할 수 있습니다.
데이터의 특징: 데이터가 거의 정렬되어 있거나, 특정 범위 안에 있는 경우 특정 알고리즘이 더 효율적일 수 있습니다.
안정성: 정렬 후에도 동일한 값의 순서가 유지되어야 하는 경우 안정적인 정렬 알고리즘을 선택해야 합니다.
시간 복잡도: 일반적으로 퀵 정렬이나 병합 정렬과 같은 O(n log n) 알고리즘이 효율적입니다.
공간 복잡도: 추가적인 메모리 공간이 제한적인 경우, 공간 복잡도가 낮은 알고리즘을 선택해야 합니다.</p>
<hr>
<p>Reference</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[알고리즘의 개념과 종류]]></title>
            <link>https://velog.io/@mh_kim/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EC%9D%98-%EA%B0%9C%EB%85%90%EA%B3%BC-%EC%A2%85%EB%A5%98</link>
            <guid>https://velog.io/@mh_kim/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EC%9D%98-%EA%B0%9C%EB%85%90%EA%B3%BC-%EC%A2%85%EB%A5%98</guid>
            <pubDate>Tue, 16 Jul 2024 15:39:56 GMT</pubDate>
            <description><![CDATA[<h3 id="알고리즘이란">알고리즘이란?</h3>
<p>알고리즘은 특정 문제를 해결하기 위한 명확하고 논리적인 단계들의 집합입니다. 컴퓨터 과학에서는 컴퓨터가 특정 작업을 수행하도록 지시하는 명령어들의 집합을 의미하며, 일상생활에서도 요리 레시피, 가구 조립 설명서 등을 알고리즘의 예시로 볼 수 있습니다.</p>
<p>알고리즘은 다음과 같은 특징을 가집니다.</p>
<p>입력: 알고리즘이 처리해야 할 데이터
출력: 알고리즘의 실행 결과
명확성: 각 단계는 모호하지 않고 명확하게 정의되어야 함
유한성: 한정된 시간 안에 실행을 완료해야 함
효율성: 최소한의 시간과 자원을 사용하여 문제를 해결해야 함</p>
<h3 id="알고리즘의-기본적인-종류">알고리즘의 기본적인 종류</h3>
<p>알고리즘은 다양한 기준으로 분류할 수 있으며, 문제 해결 방식이나 적용 분야에 따라 여러 종류가 존재합니다.</p>
<p><strong>1. 문제 해결 방식에 따른 분류</strong></p>
<ul>
<li>완전 탐색 (Brute-Force): 가능한 모든 경우의 수를 탐색하여 최적의 해를 찾는 방법입니다. 단순하지만 경우의 수가 많아지면 비효율적일 수 있습니다.</li>
<li>탐욕 알고리즘 (Greedy Algorithm): 각 단계에서 가장 최선의 선택을 하는 방식으로 진행하며, 항상 최적의 해를 보장하지는 않습니다.</li>
<li>분할 정복 (Divide and Conquer): 문제를 작은 하위 문제로 나누어 해결하고, 결과를 결합하여 원래 문제의 답을 얻는 방식입니다.</li>
<li>동적 계획법 (Dynamic Programming): 하위 문제의 해를 저장하고 재활용하여 중복 계산을 피하고 효율성을 높이는 방식입니다.</li>
<li>백트래킹 (Backtracking): 모든 가능한 경우의 수를 탐색하되, 조건에 맞지 않으면 이전 단계로 돌아가 다른 경우를 시도하는 방식입니다.</li>
<li>가지치기 (Branch and Bound): 백트래킹과 유사하지만, 가능성이 없는 경우는 더 이상 탐색하지 않아 효율성을 높입니다.</li>
</ul>
<p><strong>2. 설계 패러다임에 따른 분류</strong></p>
<ul>
<li>재귀 알고리즘 (Recursive Algorithm): 자기 자신을 호출하여 문제를 해결하는 방식입니다.</li>
<li>반복 알고리즘 (Iterative Algorithm): 반복문을 사용하여 문제를 해결하는 방식입니다.</li>
<li>무작위 알고리즘 (Randomized Algorithm): 무작위 선택을 통해 문제를 해결하며, 항상 동일한 결과를 보장하지는 않습니다.</li>
<li>휴리스틱 알고리즘 (Heuristic Algorithm): 경험이나 직관에 기반하여 빠르게 근사적인 해를 찾는 방식입니다.</li>
</ul>
<p><strong>3. 적용 분야에 따른 분류</strong></p>
<ul>
<li>정렬 알고리즘 (Sorting Algorithm): 데이터를 특정 순서대로 나열합니다.</li>
<li>탐색 알고리즘 (Searching Algorithm): 데이터 집합에서 특정 값을 찾습니다.</li>
<li>그래프 알고리즘 (Graph Algorithm): 그래프 형태로 표현된 데이터의 관계를 분석하고 처리합니다.</li>
<li>문자열 알고리즘 (String Algorithm): 문자열 데이터를 처리하는 알고리즘입니다.</li>
<li>기하 알고리즘 (Geometric Algorithm): 기하학적인 문제를 해결하는 알고리즘입니다.</li>
</ul>
<p><strong>4. 시간 복잡도에 따른 분류</strong></p>
<ul>
<li>다항 시간 알고리즘 (Polynomial Time Algorithm): 실행 시간이 입력 크기의 다항식으로 표현되는 알고리즘입니다.</li>
<li>지수 시간 알고리즘 (Exponential Time Algorithm): 실행 시간이 입력 크기의 지수 함수로 표현되는 알고리즘입니다.</li>
<li>NP-완전 문제 (NP-Complete Problem): 다항 시간 안에 해를 찾는 알고리즘이 아직 발견되지 않은 문제입니다.</li>
</ul>
<p>이 외에도 다양한 기준으로 알고리즘을 분류할 수 있습니다. 알고리즘에 대한 이해를 높이기 위해서는 각 분류 기준과 해당 기준에 따른 알고리즘의 종류를 숙지하는 것이 중요합니다.</p>
<hr>
<p>Reference
<a href="https://coffeebaralog.tistory.com/11">https://coffeebaralog.tistory.com/11</a>
<a href="https://velog.io/@swch56/01-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%A2%85%EB%A5%98">https://velog.io/@swch56/01-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%A2%85%EB%A5%98</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[자료구조의 종류]]></title>
            <link>https://velog.io/@mh_kim/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%9D%98-%EC%A2%85%EB%A5%98</link>
            <guid>https://velog.io/@mh_kim/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%9D%98-%EC%A2%85%EB%A5%98</guid>
            <pubDate>Mon, 15 Jul 2024 15:34:53 GMT</pubDate>
            <description><![CDATA[<h3 id="자료구조란">자료구조란?</h3>
<p>자료구조는 데이터를 효율적으로 저장하고 관리하기 위한 구조입니다. 컴퓨터는 방대한 양의 데이터를 다루기 때문에 효율적인 자료구조를 사용하는 것이 중요합니다. 적절한 자료구조를 선택하면 데이터 검색, 삽입, 삭제 등의 작업 속도를 향상시키고 메모리 사용량을 줄일 수 있습니다.</p>
<p>자료구조는 프로그래밍의 기초이자 핵심입니다. 효율적인 자료구조를 사용하면 프로그램의 성능을 크게 향상시킬 수 있습니다. 예를 들어, 데이터 검색이 빈번한 프로그램에서 배열 대신 해시 테이블을 사용하면 검색 속도를 획기적으로 높일 수 있습니다. </p>
<p>또한, 자료구조에 대한 이해는 알고리즘 학습에도 도움이 됩니다.</p>
<h3 id="선형-자료구조-linear-data-structure">선형 자료구조 (Linear Data Structure)</h3>
<p><strong>1. 배열 (Array)</strong></p>
<ul>
<li>개념: 같은 종류의 데이터를 연속된 메모리 공간에 저장하는 자료구조입니다.</li>
<li>장점: 인덱스를 사용하여 빠르게 데이터에 접근할 수 있습니다.</li>
<li>단점: 크기가 고정되어 있어 삽입이나 삭제가 비효율적입니다.</li>
<li>활용: 데이터베이스, 이미지 처리 등</li>
</ul>
<p><strong>2. 연결 리스트 (Linked List)</strong></p>
<ul>
<li>개념: 각 데이터 요소가 다음 요소의 주소를 저장하는 방식으로 연결된 자료구조입니다.</li>
<li>장점: 삽입이나 삭제가 용이합니다.</li>
<li>단점: 특정 요소에 접근하려면 처음부터 순차적으로 탐색해야 합니다.</li>
<li>활용: 동적 메모리 할당, 스택, 큐 구현 등</li>
</ul>
<p><strong>3. 스택 (Stack)</strong></p>
<ul>
<li>개념: LIFO (Last In First Out) 방식으로 데이터를 관리하는 자료구조입니다.</li>
<li>장점: 함수 호출, 실행 취소 기능 구현에 유용합니다.</li>
<li>단점: 데이터 접근이 제한적입니다.</li>
<li>활용: 웹 브라우저 방문 기록, 실행 취소 기능 등</li>
</ul>
<p><strong>4. 큐 (Queue)</strong></p>
<ul>
<li>개념: FIFO (First In First Out) 방식으로 데이터를 관리하는 자료구조입니다.</li>
<li>장점: 대기열, 작업 스케줄링에 활용됩니다.</li>
<li>단점: 데이터 접근이 제한적입니다.</li>
<li>활용: 프린터 대기열, 운영체제 스케줄링 등</li>
</ul>
<h3 id="비선형-자료구조-non-linear-data-structure">비선형 자료구조 (Non-Linear Data Structure)</h3>
<p><strong>1. 트리 (Tree)</strong></p>
<ul>
<li>개념: 계층적인 관계를 표현하는 자료구조입니다.</li>
<li>장점: 데이터 검색, 정렬에 효율적입니다.</li>
<li>단점: 구현이 복잡할 수 있습니다.</li>
<li>활용: 파일 시스템, 검색 엔진 등</li>
</ul>
<p><strong>2. 그래프 (Graph)</strong></p>
<ul>
<li>개념: 객체 간의 관계를 표현하는 자료구조입니다.</li>
<li>장점: 다양한 관계 표현에 유용합니다.</li>
<li>단점: 구현이 복잡할 수 있습니다.</li>
<li>활용: 소셜 네트워크, 지도 등</li>
</ul>
<p><strong>3. 해시 테이블 (Hash Table)</strong></p>
<ul>
<li>개념: 키-값 쌍으로 데이터를 저장하는 자료구조입니다.</li>
<li>장점: 빠른 데이터 검색이 가능합니다.</li>
<li>단점: 해시 충돌 문제를 해결해야 합니다.</li>
<li>활용: 데이터베이스, 캐싱 시스템 등</li>
</ul>
<h3 id="기타-자료구조">기타 자료구조</h3>
<p><strong>1. 힙 (Heap)</strong></p>
<ul>
<li>개념: 완전 이진 트리 형태의 자료구조로, 부모 노드의 값이 자식 노드의 값보다 항상 크거나 작은 특징을 가집니다. (최대 힙, 최소 힙)</li>
<li>장점: 우선순위 큐 구현에 효율적입니다. 최대/최소값을 빠르게 찾을 수 있습니다.</li>
<li>단점: 정렬된 상태를 유지해야 하므로 삽입/삭제 연산에 시간이 소요됩니다.</li>
<li>활용: 우선순위 큐, 힙 정렬, Dijkstra 알고리즘 등</li>
</ul>
<p><strong>2. Trie (트라이)</strong></p>
<ul>
<li>개념: 문자열을 저장하고 효율적으로 검색하기 위한 트리 형태의 자료구조입니다.</li>
<li>장점: 문자열 검색, 자동 완성 기능 구현에 효과적입니다.</li>
<li>단점: 메모리 사용량이 많을 수 있습니다.</li>
<li>활용: 사전 검색, 자동 완성, IP 라우팅 등</li>
</ul>
<h3 id="자료구조-선택시-고려할-사항">자료구조 선택시 고려할 사항</h3>
<ul>
<li>데이터의 특성 (종류, 크기, 삽입/삭제 빈도 등)</li>
<li>사용 목적 (검색, 정렬, 삽입/삭제 등)</li>
<li>시간 복잡도 (각 작업에 대한 시간 복잡도)</li>
<li>공간 복잡도 (메모리 사용량)</li>
</ul>
<hr>
<p>Reference
<a href="https://bnzn2426.tistory.com/115">https://bnzn2426.tistory.com/115</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[github 꾸미기]]></title>
            <link>https://velog.io/@mh_kim/github-%EA%BE%B8%EB%AF%B8%EA%B8%B0</link>
            <guid>https://velog.io/@mh_kim/github-%EA%BE%B8%EB%AF%B8%EA%B8%B0</guid>
            <pubDate>Mon, 15 Jul 2024 02:30:58 GMT</pubDate>
            <description><![CDATA[<p>github의 메인페이지에서 보여지는 기본 화면을 꾸미기 위해 리서치를 하던 도중 좋은 사이트를 발견했습니다. 해당 사이트에서는 github url을 안내하며 공식 페이지의 리드미를 참고하면 된다고만 안내가 되어 있어 좀더 상세하게 적용 순서를 정리하였습니다.</p>
<h3 id="languages--github-stats">Languages &amp; Github Stats</h3>
<p>깃허브 통계 이미지와 프로젝트에 사용된 언어 통계 이미지를 제공합니다. 대체적인 사이트에서는 링크를 복사하여 리드미에 붙여넣기만 하면 자동으로 표시되는데에 비해 초반 셋팅이 좀더 필요합니다.
URL: <a href="https://github.com/rahul-jha98/github-stats-transparent">https://github.com/rahul-jha98/github-stats-transparent</a>
<img src="https://velog.velcdn.com/images/mh_kim/post/e377c751-dfa6-4b40-83c5-589427a23320/image.png" alt=""></p>
<h3 id="내-페이지-만들기">내 페이지 만들기</h3>
<p>내 깃헙 아이디와 동일한 리드미 페이지를 생성합니다.
깃헙 아이디가 judy라면, judy/judy가 되도록 레포지토리 name을 설정하고 리드미 파일을 추가하여 레포지토리를 생성합니다.
<img src="https://velog.velcdn.com/images/mh_kim/post/91562fa7-a3cf-446d-bfd9-c568c4e594bd/image.png" alt=""></p>
<h3 id="포크하여-이미지-생성하기">포크하여 이미지 생성하기</h3>
<ol>
<li>rahul-jha98/github-stats-transparent 레포지토리를 포크합니다.</li>
<li>포크된 레포지토리에 들어가서 Actions 페이지를 클릭합니다.</li>
<li>워크플로리스트에서 Generate Stats Images를 선택하고 오른쪽의 런 워크플로를 클릭합니다.
<img src="https://velog.velcdn.com/images/mh_kim/post/5788939e-3096-44e9-972c-221c61d5a3cd/image.png" alt=""></li>
<li>이미지가 성공적으로 생성되면, branch를 main에서 output으로 변경하고 폴더안으로 들어가면 2개의 이미지가 생성되어 있습니다. 이미지 위치에서 github url을 복사합니다.</li>
</ol>
<h3 id="내-페이지에-링크-추가">내 페이지에 링크 추가</h3>
<p>리드미 페이지를 열어 아래 링크를 추가하고 URL을 수정하여 적용하면 메인페이지에서 생성된 통계 이미지가 이쁘게 표시됩니다!</p>
<pre><code>![](https://github.com/.../output/generated/overview.svg#gh-dark-mode-only)
![](https://github.com/.../output/generated/overview.svg#gh-light-mode-only)
![](https://github.com/.../output/generated/languages.svg#gh-dark-mode-only)
![](https://github.com/.../output/generated/languages.svg#gh-light-mode-only)</code></pre><hr>
<p>Reference
<a href="https://hulrud.tistory.com/3">https://hulrud.tistory.com/3</a>
<a href="https://github.com/rahul-jha98/github-stats-transparent">https://github.com/rahul-jha98/github-stats-transparent</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Blockchain] 해외 프로젝트의 런치풀, 에어드랍 작업 순서]]></title>
            <link>https://velog.io/@mh_kim/%ED%95%B4%EC%99%B8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%9D%98-%EB%9F%B0%EC%B9%98%ED%92%80-%EC%97%90%EC%96%B4%EB%93%9C%EB%9E%8D-%EC%9E%91%EC%97%85-%EC%88%9C%EC%84%9C</link>
            <guid>https://velog.io/@mh_kim/%ED%95%B4%EC%99%B8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%9D%98-%EB%9F%B0%EC%B9%98%ED%92%80-%EC%97%90%EC%96%B4%EB%93%9C%EB%9E%8D-%EC%9E%91%EC%97%85-%EC%88%9C%EC%84%9C</guid>
            <pubDate>Thu, 27 Jun 2024 08:24:50 GMT</pubDate>
            <description><![CDATA[<h3 id="에어드랍이란">에어드랍이란?</h3>
<p>코인 에어드랍을 간단히 말하면 신규 코인을 런칭하는 해외 프로젝트의 이벤트에 참여하거나 해외 거래소의 런치패드나 런치풀에 참여하는 것을 말합니다.</p>
<h3 id="런치패드-런치풀이란">런치패드, 런치풀이란?</h3>
<p>런치패드 또는 런치풀은 IEO(거래소 공개)와 유사한 개념입니다. IEO는 거래소가 비상장 가상자산 프로젝트를 직접 선정해 해당 프로젝트의 가상자산을 투자자에게 판매하는 형식을 의미하며, 국내는 가상자산 개발자들이 직접 발행해 투자자를 모아 자금을 조달하는 ICO와 IEO 모두 법적으로 금지되어 있습니다. </p>
<h3 id="런치패드-순서">런치패드 순서</h3>
<p>국내에서 해외거래소의 런치패드에 참여하기 위해선, 일단 국내 거래소에서 코인을 구매해야 합니다. 금융위원회가 신용카드 거래 금지 대상에 가상자산을 추가하여 개인의 달러 송금이 제한되어 있어, 한국의 원화 거래소에서 구매해야 하는 구조이기 때문입니다.</p>
<p>예를 들어 바이빗(bybit)의 런치패드에 참여하기로 정했다면,</p>
<ol>
<li>국내 거래소에서 코인 구매</li>
<li>국내 거래소에서 바이빗(bybit)으로 코인 출금</li>
<li>바이빗(bybit) 런치패드에 참여하여 일정 기간 코인 락업(Lock-up)</li>
<li>정해진 기간 이후 에어드랍</li>
<li>에어드랍 받은 코인과 락업 해제된 코인을 국내 거래소로 송금하여 판매하여 현금화</li>
</ol>
<p>의 순서로 이루어집니다.</p>
<h3 id="체크리스트">체크리스트</h3>
<p>바이빗 런치패드에 스테이킹해야하는 코인의 종류(usdt or mnt)
코인 구매 및 출금을 진행할 국내 거래소(업비트, 빗썸)
국내 거래소에서 출금 지원되는 네트워크와 해외거래소 리스트, 최소 출금 수량 
바이빗에서 입금에 지원되는 네트워크와 해외거래소 리스트</p>
<h3 id="국내-거래소-코인-구매">국내 거래소 코인 구매</h3>
<p>국내 거래소에서 코인을 구매할 때에는 출금 수수료가 낮은 코인을 선택합니다. 출금 수수료는 각 코인마다 상이하며 각 거래소의 홈페이지에서 확인이 가능합니다.
업비트: <a href="https://upbit.com/service_center/guide">https://upbit.com/service_center/guide</a>
빗썸: <a href="https://m.bithumb.com/react/info/fee/inout">https://m.bithumb.com/react/info/fee/inout</a></p>
<p>보은통 usdt를 구매하여 송금하는 경우가 많은데 위 코인들이 유동성이 많아 매매가 쉽고 대체로 모든 거래소에서 거래가 가능하기 때문입니다.
또한 출금 수수료가 무료이기 때문에 런치패드에서 사용할 usdt 수량을 맞춰 구매가 가능합니다. </p>
<h3 id="런치패드-참여">런치패드 참여</h3>
<p>국내 거래소에서 usdt를 구매하여 바이빗의 내 usdt 지갑 주소로 송금한 후 런치패드에 참여하면 참여가 완료됩니다.
요즘은 예치 형식으로 하여 참여 금액에 따라 분배하는 방식이 많아 많이 넣을수록 많은 수량을 에어드랍 받을수도 있지만, 런치패드에 따라 방식이 다르므로 내용을 확인하고 수량을 결정합니다.
락업 기간이 끝나면 에어드랍이 들어온걸 확인하고 현금화를 하고 싶다면 에어드랍 받은 코인을 usdt로 변환하여 다시 국내 거래소로 보내 현금화를 할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Node.js + Express를 이용한 RESTful API 예제(9) - docker-compose 작성]]></title>
            <link>https://velog.io/@mh_kim/Node.js-Express%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-RESTful-API-%EC%98%88%EC%A0%9C9-docker-compose-%EC%9E%91%EC%84%B1</link>
            <guid>https://velog.io/@mh_kim/Node.js-Express%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-RESTful-API-%EC%98%88%EC%A0%9C9-docker-compose-%EC%9E%91%EC%84%B1</guid>
            <pubDate>Wed, 29 May 2024 14:34:06 GMT</pubDate>
            <description><![CDATA[<p>Docker 파일로 설정할 경우, 외부에서 프로젝트로 변수 전달이 안되기 때문에 docker-compose를 작성하여 외부에서 환경 설정값인 key-value를 설정하여 프로젝트에 반영되도록 하겠습니다.</p>
<h3 id="docker-composeyaml-작성">docker-compose.yaml 작성</h3>
<pre><code class="language-javascript">services:
  app:
    build:
      context: .
      dockerfile: ./Dockerfile
      target: prod
    environment:
      NODE_ENV: production
    ports:
      - 3004:3002
    restart: &quot;unless-stopped&quot;</code></pre>
<h3 id="실행">실행</h3>
<pre><code class="language-shell"> //prod
 docker-compose up -d</code></pre>
<p>스크립트의 타겟과 환경변수를 dev로 변경하면 dev로 실행이 가능합니다.
Docker를 사용하면 실제 프로젝트의 변수값을 대입하기가 어렵지만, docker-compose의 environment를 사용하면 프로젝트의 env값 변경이 가능하여 편리합니다. docker-compose는 한번에 여러 앱을 실행할때 한번에 처리하기 위해 사용하는 용도로도 충분히 훌륭하지만 environment값을 외부에서 주입이 가능하기에 app이 하나여도 사용하는 가치가 있다 생각되었습니다.</p>
<hr>
<p>Reference
<a href="https://docs.docker.com/compose/compose-file/build/">https://docs.docker.com/compose/compose-file/build/</a>
<a href="https://gyuuuu.github.io/devlog/pm2/">https://gyuuuu.github.io/devlog/pm2/</a>
<a href="https://medium.com/sjk5766/docker-compose%EB%A1%9C-node-express-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0-7c9ab4544172">https://medium.com/sjk5766/docker-compose%EB%A1%9C-node-express-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0-7c9ab4544172</a>
<a href="https://jojoldu.tistory.com/587">https://jojoldu.tistory.com/587</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Blockchain] nfxbus로 유투브 프리미엄 저렴하게 구독하기 - 암호화폐(USDT)로 결제하기]]></title>
            <link>https://velog.io/@mh_kim/nfxbus%EB%A1%9C-%EC%9C%A0%ED%88%AC%EB%B8%8C-%ED%94%84%EB%A6%AC%EB%AF%B8%EC%97%84-%EC%A0%80%EB%A0%B4%ED%95%98%EA%B2%8C-%EA%B5%AC%EB%8F%85%ED%95%98%EA%B8%B0-%EC%95%94%ED%98%B8%ED%99%94%ED%8F%90USDT%EB%A1%9C-%EA%B2%B0%EC%A0%9C%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@mh_kim/nfxbus%EB%A1%9C-%EC%9C%A0%ED%88%AC%EB%B8%8C-%ED%94%84%EB%A6%AC%EB%AF%B8%EC%97%84-%EC%A0%80%EB%A0%B4%ED%95%98%EA%B2%8C-%EA%B5%AC%EB%8F%85%ED%95%98%EA%B8%B0-%EC%95%94%ED%98%B8%ED%99%94%ED%8F%90USDT%EB%A1%9C-%EA%B2%B0%EC%A0%9C%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 27 May 2024 15:48:11 GMT</pubDate>
            <description><![CDATA[<p>최근 구독중인 서비스가 늘어나면서 지출액을 줄여보기 위해 OTT 공유사이트를 찾아보았습니다.
마침 구매 방식에 암호화폐를 선택 가능하여, 빗썸에서 암호화폐 USDT를 구매, nfxbus 유투브 프미리엄을 구매해보도록 하겠습니다. </p>
<blockquote>
<p><strong>nfxbus 할인 코드(10%): 9S2NKV</strong></p>
</blockquote>
<h3 id="ott-공유-사이트-종류">OTT 공유 사이트 종류</h3>
<p>국내 블로그에서 최근에 많이 언급된 사이트 3곳을 비교해 보았습니다.</p>
<ul>
<li><a href="https://ko.gamsgo.com/">겜스고(GamsGo)</a></li>
<li><a href="https://www.nfxbus.com/#/plat/home">nfxbus(nfxbus)</a></li>
<li><a href="https://goingbus.com/">고잉버스(goingbus)</a></li>
</ul>
<h3 id="사이트별-12개월-구독-비용24527-기준">사이트별 12개월 구독 비용(24.5.27 기준)</h3>
<p>모두 할인코드 적용가이며, 사이트별로 5~10% 사이에서 할인됩니다. 할인 코드는 최근 블로그들중 할인율이 높은 블로그의 할인 코드를 참고하였습니다.</p>
<table>
<thead>
<tr>
<th align="center">겜스고</th>
<th align="center">nfxbus</th>
<th align="center">고잉버스</th>
</tr>
</thead>
<tbody><tr>
<td align="center">$39.19</td>
<td align="center">$35.78</td>
<td align="center">$39.77</td>
</tr>
</tbody></table>
<p>nfxbus의 12개월 구독 비용이 제일 저렴하여 nfxbus로 선택했습니다.</p>
<h3 id="구독방법">구독방법</h3>
<ol>
<li><p>회원 가입 후, 메인 화면에서 유투브 프리미엄 구독 클릭합니다.
<img src="https://velog.velcdn.com/images/mh_kim/post/8fff8b9d-54f4-49ff-b3dc-f5fabb81e27f/image.png" alt=""></p>
</li>
<li><p>원하는 기간을 선택한 후, 할인 코드 입력, 지불 방법은 BTC/USDT/ETH/를 선택하고 구입을 클릭합니다.
<img src="https://velog.velcdn.com/images/mh_kim/post/976a73bd-1a74-4abf-83d6-4f4a04d2a9d2/image.png" alt=""></p>
</li>
<li><p>구입을 클릭 후 메모의 내용을 확인하고 다시 구입을 클릭합니다.</p>
<blockquote>
<p>메모：YouTube Premium을 구입한 경우 “구독” 페이지에서 YouTube 로그인 사서함을 제출하십시오.제출 후 직원은 이메일로 YouTube Premium 홈 그룹 초대 링크를 보냅니다.메일박스 정보를 확인하고 가입을 수락하려면 클릭하십시오.
상품명：Youtube Premium
가격：39.59
구입 시간：12 months + 4 month gift
선물：4 months</p>
</blockquote>
</li>
<li><p>구매 코인은 여러 종류 선택이 가능한데, 가장 저렴한 방법은 출금 수수료가 저렴한 코인을 사용하는 방법이므로, 빗썸에서 USDT(trc20)을 구매하여 전송하는 방식으로 진행합니다. 이 방법으로 진행하면 USDT 현재 시세가 구매 비용이 됩니다. (카드로 구매할 경우, 각종 수수료가 부과되어 설명한 방법보다 약 4,000원정도 비싸집니다.)</p>
</li>
</ol>
<ul>
<li>Select payment method -&gt; Pay with Crypto</li>
<li>Select a currency -&gt; USDT(TRC20)</li>
<li>Amount to Pay에서 보내야할 USDT 수량 확인(39.59)
<img src="https://velog.velcdn.com/images/mh_kim/post/258599a7-5528-4196-99f6-49ca66baaf97/image.png" alt=""></li>
</ul>
<ol start="5">
<li><p>빗썸에 로그인하여 USDT를 넉넉하게 40개 구매하여 nfxbus에서 발급받은 receiving address로 출금합니다. USDT 출금은 무료이며, 홈페이지에서 다른 코인의 출금수수료도 확인 가능합니다.
빗썸 출금 수수료: <a href="https://www.bithumb.com/react/info/fee/inout">https://www.bithumb.com/react/info/fee/inout</a></p>
</li>
<li><p>빗썸 출금 완료 및 nfxbus 입금 완료가 되면 nfxbus 화면에 완료 페이지가 표시됩니다.
<img src="https://velog.velcdn.com/images/mh_kim/post/bcbf2bde-9e89-4dc2-aac9-fc920ab9442a/image.png" alt=""></p>
</li>
<li><p>홈페이지 메뉴의 구독을 클릭하고, 유투브 프리미엄에 추가할 개인 G메일 주소를 입력합니다.
주소를 보내고 나면 약 20분 내외로 유투브 그룹 가입 메일을 받습니다. 저는 한국 시간으로 일요일 저녁 9시 34분에 구매하였고, G메일을 받는 시간이 9시 47분이었는데 처리 시간에 따라서는 실시간으로 메일을 받는 경우도 있는걸로 보이네요. 메일 링크로 그룹에 가입하면 바로 유투브를 광고없이 구독 가능합니다.
<img src="https://velog.velcdn.com/images/mh_kim/post/9da2bd90-be44-436d-9514-bf2e7b2dfff1/image.png" alt=""></p>
</li>
<li><p>만약 문제가 있는 경우에는 메뉴의 고객센터를 클릭하면 구매 내역을 확인 가능하고 구매한 구독의 처리 상태를 확인 가능합니다. 이 페이지에서 추가 문의도 가능합니다.
<img src="https://velog.velcdn.com/images/mh_kim/post/49a85a76-da66-4f80-bf66-3681fa74c2e8/image.png" alt=""></p>
</li>
</ol>
<p>거래소에서 매수, 매도를 하거나 다른 코인으로 스왑해본 경험은 있었는데, 실제 구매에 암호화폐를 사용해보니 신기했습니다. 해외에 사는 친구가 커피나 옷을 암호화폐로 구매했다는 이야기를 들었을때도 묘한 기분이 들었는데 직접 구매를 해보니 암호화폐가 실생활에 쓰일 날이 머지않았다는 생각이 드네요. 아직은 불안한 부분이 많지만 금방 코인이 현찰을 대체하게 되지 않을까라는 생각이 들었습니다.</p>
<hr>
<p>Reference
<a href="https://powerpointary.tistory.com/entry/nfxbus-%EB%84%B7%ED%94%8C%EB%A6%AD%EC%8A%A4">https://powerpointary.tistory.com/entry/nfxbus-%EB%84%B7%ED%94%8C%EB%A6%AD%EC%8A%A4</a>
<a href="https://www.nfxbus.com/#/plat/home">https://www.nfxbus.com/#/plat/home</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Node.js + Express를 이용한 RESTful API 예제(8) - Dockerfile 작성]]></title>
            <link>https://velog.io/@mh_kim/Node.js-Express%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-RESTful-API-%EC%98%88%EC%A0%9C8-Dockerfile-%EC%9E%91%EC%84%B1</link>
            <guid>https://velog.io/@mh_kim/Node.js-Express%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-RESTful-API-%EC%98%88%EC%A0%9C8-Dockerfile-%EC%9E%91%EC%84%B1</guid>
            <pubDate>Fri, 24 May 2024 14:52:06 GMT</pubDate>
            <description><![CDATA[<p>개인 로컬 환경의 영향을 받지않고 빠르고 간편하게 실행할 수 있도록 Dockerfile을 작성합니다.
Docker를 사용하면 애플리케이션을 인프라에서 분리하여 소프트웨어를 신속하게 제공할 수 있습니다. Docker를 사용하면 애플리케이션을 관리하는 것과 동일한 방식으로 인프라를 관리할 수 있습니다. 코드 전달, 테스트 및 배포를 위한 Docker의 방법론을 활용하면 코드 작성과 프로덕션 환경 실행 사이의 지연 시간을 크게 줄일 수 있습니다.
먼저 Docker 이미지를 생성하고, 생성된 이미지를 컨테이너로 빌드하고 실행합니다.</p>
<h3 id="컨테이너란">컨테이너란?</h3>
<p>컨테이너는 해당 호스트 시스템에서 실행되는 다른 모든 프로세스와 격리된 호스트 시스템에서 실행되는 샌드박스 프로세스입니다. 이러한 격리는 오랫동안 Linux에 있었던 기능인 커널 네임스페이스와 cgroup을 활용합니다. Docker는 이러한 기능을 접근하기 쉽고 사용하기 쉽게 만듭니다. 요약하자면, 컨테이너는 다음을 수행합니다.</p>
<ul>
<li>실행 가능한 이미지 인스턴스입니다. Docker API 또는 CLI를 사용하여 컨테이너를 생성, 시작, 중지, 이동 또는 삭제할 수 있습니다.</li>
<li>로컬 머신, 가상 머신에서 실행하거나 클라우드에 배포할 수 있습니다.</li>
<li>이식 가능하며 모든 OS에서 실행될 수 있습니다.</li>
<li>다른 컨테이너와 격리되어 자체 소프트웨어, 바이너리, 구성 등을 실행합니다.</li>
</ul>
<h3 id="이미지란">이미지란?</h3>
<p>실행 중인 컨테이너는 격리된 파일 시스템을 사용합니다. 이 격리된 파일 시스템은 이미지에 의해 제공되며 이미지에는 애플리케이션을 실행하는 데 필요한 모든 것(모든 종속성, 구성, 스크립트, 바이너리 등)이 포함되어야 합니다. 또한 이미지에는 환경 변수, 기본 명령과 같은 컨테이너에 대한 다른 구성도 포함되어 있습니다.</p>
<h3 id="dockerfile-생성">Dockerfile 생성</h3>
<p>프로젝트에 대한 Docker 관련 시작 파일을 생성합니다. </p>
<pre><code class="language-shell">docker init</code></pre>
<p>프로젝트 초기화를 실행하면, 4개의 기본 파일이 생성됩니다.</p>
<ul>
<li>.dockerignore</li>
<li>Dockerfile</li>
<li>compose.yaml</li>
<li>README.Docker.md</li>
</ul>
<p>프로젝트 내용에 맞게 수정합니다.</p>
<pre><code class="language-shell">ARG NODE_VERSION=20.12.2

################################################################################
# Use node image for base image for all stages.
FROM node:${NODE_VERSION}-alpine as base

# Set working directory for all build stages.
WORKDIR /app

# Expose the port that the application listens on.
EXPOSE 3001

################################################################################
# Create a stage for installing production dependecies.
FROM base as dev

COPY ./package.json ./

RUN npm install

COPY . /app/

CMD [&quot;npm&quot;, &quot;run&quot;, &quot;dev&quot;]</code></pre>
<h3 id="docker-실행">Docker 실행</h3>
<pre><code class="language-shell"> docker build . -t eth-dapp
 docker run -it -p 3001:3001 eht-dapp</code></pre>
<hr>
<p>Reference
<a href="https://docs.docker.com/guides/">https://docs.docker.com/guides/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Node.js + Express를 이용한 RESTful API 예제(7) - middleware 기능을 이용한 Interceptor 작성]]></title>
            <link>https://velog.io/@mh_kim/Node.js-Express%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-RESTful-API-%EC%98%88%EC%A0%9C7-middleware-%EA%B8%B0%EB%8A%A5%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-Interceptor-%EC%9E%91%EC%84%B1</link>
            <guid>https://velog.io/@mh_kim/Node.js-Express%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-RESTful-API-%EC%98%88%EC%A0%9C7-middleware-%EA%B8%B0%EB%8A%A5%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-Interceptor-%EC%9E%91%EC%84%B1</guid>
            <pubDate>Tue, 21 May 2024 15:45:11 GMT</pubDate>
            <description><![CDATA[<p>express의 middleware 기능을 이용하여 좀더 코드를 깔끔하게 response 형식을 공통화화고, index.ts에서 middleware 기능을 따로 분리하여 각각 기능별로 관리하도록 하겠습니다.</p>
<h3 id="response-interceptor하여-공통처리">response interceptor하여 공통처리</h3>
<p>response에서 responseCode 200으로 성공인 경우에는 공통처리를 하고 다음 미들웨어로 넘어가지 않고 종료하도록 처리합니다.</p>
<pre><code class="language-javascript">import { NextFunction, Request, Response } from &#39;express&#39;;

const responseFilter = (req: Request, res: Response, next: NextFunction) =&gt; {
  console.log(&#39;[ responseFilter ]=============&#39;);
  console.log(res.statusCode);
  if (res.statusCode == 200) {
    const result = res.locals.apiResponse;
    res.status(200).send({
      status: 200,
      success: true,
      data: result
    });
  } else {
    next();
  }
};

export default responseFilter;</code></pre>
<h3 id="commonlogts-작성">commonLog.ts 작성</h3>
<p>기존에 index.ts의 app.use안에 작성한 request 요청시마다 선 실행되었던 코드를 분리하여 따로 작성합니다.</p>
<pre><code class="language-javascript">import { NextFunction, Request, Response } from &#39;express&#39;;

const commonLog = (req: Request, res: Response, next: NextFunction) =&gt; {
  console.log(&#39;[ commonLog ]==================&#39;);
  console.log(&#39;requestURL: &#39; + req.url);
  console.log(&#39;requestMethod: &#39; + req.method);
  if (req.method !== &#39;GET&#39;) {
    console.log(&#39;requestBody: &#39; + JSON.stringify(req.body));
  }
  next();
};

export default commonLog;</code></pre>
<h3 id="commonerrorts-작성">commonError.ts 작성</h3>
<p>기존에 index.ts의 app.use안에 작성한 error handling 관련 소스를 분리하여 따로 작성합니다.</p>
<pre><code class="language-javascript">import { NextFunction, Request, Response } from &#39;express&#39;;

const commonError = (
  err: { message: string },
  req: Request,
  res: Response,
  next: NextFunction
) =&gt; {
  console.error(&#39;[ commonError ]================&#39;);
  console.error(`[errMessage]: ${err.message}`);
  res.status(500).send({
    status: 500,
    success: false,
    message: &#39;Server Error&#39;,
    error: err.message
  });
};

export default commonError;</code></pre>
<h3 id="분리된-내용을-indexts에-적용">분리된 내용을 index.ts에 적용</h3>
<p>middleware는 위치에 따라 적용 순서가 변경되므로 순서에 유의하여 아래와 같이 작성합니다.</p>
<pre><code class="language-javascript">import commonLog from &#39;./middleware/commonLog&#39;;
import responseFilter from &#39;./middleware/responseFilter&#39;;
import commonError from &#39;./middleware/commonError&#39;;

// middleware - log
app.use(commonLog);

// ETH api
const router = express.Router();
router.use(&#39;/eth&#39;, ethRouter);
app.use(&#39;/api&#39;, router);

// middleware - response format
app.use(responseFilter);

// error handling
app.use(commonError);</code></pre>
<hr>
<p>Reference
<a href="https://expressjs.com/en/guide/writing-middleware.html">https://expressjs.com/en/guide/writing-middleware.html</a>
<a href="https://www.geeksforgeeks.org/how-to-intercept-response-send-response-json-in-express-js/">https://www.geeksforgeeks.org/how-to-intercept-response-send-response-json-in-express-js/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Node.js + Express를 이용한 RESTful API 예제(6) - OpenAPI3 적용]]></title>
            <link>https://velog.io/@mh_kim/Node.js-Express%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-RESTful-API-%EC%98%88%EC%A0%9C6-OpenAPI3-%EC%A0%81%EC%9A%A9</link>
            <guid>https://velog.io/@mh_kim/Node.js-Express%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-RESTful-API-%EC%98%88%EC%A0%9C6-OpenAPI3-%EC%A0%81%EC%9A%A9</guid>
            <pubDate>Mon, 20 May 2024 16:27:52 GMT</pubDate>
            <description><![CDATA[<h3 id="openapi란">OpenAPI란?</h3>
<p>API 설계는 오류가 발생하기 쉬우며 API를 모델링할 때 실수를 찾아 수정하는 것은 매우 어렵고 시간이 많이 걸립니다. Swagger Editor는 OAS(OpenAPI 사양)를 사용하여 API를 설계하기 위해 구축된 최초의 편집기였으며 OAS를 사용하여 API를 구축하는 개발자의 요구 사항을 지속적으로 충족해 왔습니다. 편집기는 실시간으로 디자인을 검증하고 OAS 준수 여부를 확인하며 이동 중에도 시각적 피드백을 제공합니다.</p>
<h3 id="설치">설치</h3>
<p>패키지를 설치합니다.</p>
<pre><code class="language-shell">npm install swagger-cli swagger-ui-express yamljs
npm install -D @types/swagger-ui-express @types/yamljs</code></pre>
<p>기본 설정 파일을 위한 폴더와 설정 파일을 생성합니다.</p>
<ul>
<li>src/swagger 폴더를 생성<ul>
<li>openapi.yaml 작성</li>
</ul>
</li>
</ul>
<pre><code class="language-yaml">openapi: 3.0.0
info:
  version: 1.0.0
  title: ETH DAPP API docs
  description: ETH DAPP STARTER
  license:
    name: mh
servers:
  - url: http://localhost:{port}
    variables:
      port:
        default: &#39;3001&#39;

#Paths api 경로 지정, paths에 추가한 순서로 작성된다.
paths: {}</code></pre>
<h3 id="indexts에서-swaggerui-연동-소스-추가">index.ts에서 swaggerUI 연동 소스 추가</h3>
<pre><code class="language-javascript">//swagger 연결
import swaggerUi from &#39;swagger-ui-express&#39;;
import YAML from &#39;yamljs&#39;;
const path = require(&#39;path&#39;);
const swaggerSpec = YAML.load(path.join(__dirname, &#39;../build/swagger.yaml&#39;))
app.use(&#39;/api-docs&#39;, swaggerUi.serve, swaggerUi.setup(swaggerSpec));
</code></pre>
<h3 id="packagejson-파일에-스크립트-추가">package.json 파일에 스크립트 추가</h3>
<pre><code class="language-javascript">&quot;scripts&quot;: {
  // swagger.yaml로 파일 통합해주는 코드
  &quot;api-docs&quot;: &quot;swagger-cli bundle ./swagger/openapi.yaml --outfile build/swagger.yaml --type yaml&quot;,
  // swagger.yaml 파일 생성
  &quot;predev&quot;: &quot;npm run api-docs&quot;, 
}</code></pre>
<p>지금까지의 파일 설정이 모두 완료되면, <a href="http://localhost:8000/api-docs">http://localhost:8000/api-docs</a> 에서 swagger 화면을 볼 수 있습니다.</p>
<h3 id="api-명세-작성">API 명세 작성</h3>
<p>명세 작성은 하나로 합쳐서도 가능하지만, 메인과 서브로 나누어 메인에서는 공통 부분을 각 도메인별로 필요한 부분을 작성하는 것이 보고 이해하기에 좋습니다.</p>
<h4 id="openapiyaml">openapi.yaml</h4>
<pre><code class="language-javscript">openapi: 3.0.0
info:
  version: 1.0.0
  title: ETH DAPP API docs
  description: ETH DAPP STARTER
  license:
    name: test
servers:
  - url: http://localhost:{port}
    variables:
      port:
        default: &#39;3001&#39;

components:
  #Schemas : model 정보
  schemas:
    create:
      properties:
        mnemonic:
          type: string
          description: 니모닉키
        startnum:
          type: number
          description: path 시작 번호
        count:
          type: number
          description: 생성할 주소 갯수
    send:
      properties:
        to:
          type: string
          description: 보낼 주소
        value:
          type: string
          description: 보낼 수량
    Error:
      type: object
      properties:
        success:
          type: boolean
        message:
          type: string
  #Examples
  examples:
    createExample:
      value:
        {
          &quot;mnemonic&quot;: &quot; digital.....&quot;,
          &quot;startnum&quot;: 0,
          &quot;count&quot;: 3
        }
    sendExample:
      value:
        {
          &quot;to&quot;: &quot;0x9E28854441B...............&quot;,
          &quot;value&quot;: &quot;0.0002&quot;
        }

  #Responses 재사용되는 애들
  responses:
    successResponse:
      description: successful request with no data
      content:
        application/json:
          schema:
            type: object
            example: {&quot;status&quot;: 200, &quot;success&quot;: true, &quot;message&quot;: &quot;message&quot;}
    BadRequest:
      description: 잘못된 요청
      content:
        application/json:
          schema:
            $ref: &quot;#/components/schemas/Error&quot;
          example:
            success: false
            message: 잘못된 요청
    InternalServerError:
      description: 서버 에러
      content:
        application/json:
          schema:
            $ref: &quot;#/components/schemas/Error&quot;
          example:
            success: false
            message: 서버 내부 오류

#Paths api 경로 지정, paths에 추가한 순서로 작성된다.
paths:
  /api/eth/createMasterAddress:
    $ref: &#39;./eth.yaml#/~1createMasterAddress&#39;
  /api/eth/createChildAddress:
    $ref: &#39;./eth.yaml#/~1createChildAddress&#39;
  /api/eth/sendTransaction:
    $ref: &#39;./eth.yaml#/~1sendTransaction&#39;
  /api/eth/getBalance/{address}:
    $ref: &#39;./eth.yaml#/~1getBalance~1{address}&#39;
  /api/eth/getGasPrice:
    $ref: &#39;./eth.yaml#/~1getGasPrice&#39;
  /api/eth/getNonce/{address}:
    $ref: &#39;./eth.yaml#/~1getNonce~1{address}&#39;
  /api/eth/checksumAddress/{address}:
    $ref: &#39;./eth.yaml#/~1checksumAddress~1{address}&#39;
</code></pre>
<h4 id="ethyaml">eth.yaml</h4>
<pre><code class="language-javscript">/createChildAddress:
  post:
    tags:
      - eth
    summary: 마스터 키로 주소 생성
    consumes:
      - application/json
    requestBody:
      x-name: body
      required: true
      content:
        application/json:
          schema:
            $ref: &#39;./openapi.yaml#/components/schemas/create&#39;
          examples:
            createExample:
              $ref: &#39;./openapi.yaml#/components/examples/createExample&#39;
    responses:
      &#39;200&#39;:
        $ref: &#39;./openapi.yaml#/components/responses/successResponse&#39;
      &#39;400&#39;:
        $ref: &#39;./openapi.yaml#/components/responses/BadRequest&#39;
      &#39;500&#39;:
        $ref: &#39;./openapi.yaml#/components/responses/InternalServerError&#39;
/sendTransaction:
  post:
    tags:
[....위와 같은 형식으로 필요한 내용을 추가한다]</code></pre>
<h3 id="완성">완성</h3>
<p><img src="https://velog.velcdn.com/images/mh_kim/post/3a91b046-84b3-49b1-bb04-63e981fb3336/image.png" alt=""></p>
<hr>
<p>Reference
<a href="https://velog.io/@server30sopt/Node.js-Swagger-openapi-3.0.0-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0-3evmesru">https://velog.io/@server30sopt/Node.js-Swagger-openapi-3.0.0-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0-3evmesru</a>
<a href="https://swagger.io/docs/specification/api-host-and-base-path/">https://swagger.io/docs/specification/api-host-and-base-path/</a>
<a href="https://bump.sh/blog/express-api-openapi">https://bump.sh/blog/express-api-openapi</a></p>
]]></description>
        </item>
    </channel>
</rss>