<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>hyun_woo.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Thu, 14 Aug 2025 02:10:31 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>hyun_woo.log</title>
            <url>https://velog.velcdn.com/images/hyun_woo/profile/87c39477-be4e-4705-bd08-14bc414cbd66/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. hyun_woo.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hyun_woo" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[CS]멀티스레드 vs 멀티프로세스]]></title>
            <link>https://velog.io/@hyun_woo/CS%EB%A9%80%ED%8B%B0%EC%8A%A4%EB%A0%88%EB%93%9C-vs-%EB%A9%80%ED%8B%B0%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4</link>
            <guid>https://velog.io/@hyun_woo/CS%EB%A9%80%ED%8B%B0%EC%8A%A4%EB%A0%88%EB%93%9C-vs-%EB%A9%80%ED%8B%B0%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4</guid>
            <pubDate>Thu, 14 Aug 2025 02:10:31 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[[네트워크] VPN]]></title>
            <link>https://velog.io/@hyun_woo/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-VPN</link>
            <guid>https://velog.io/@hyun_woo/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-VPN</guid>
            <pubDate>Fri, 08 Aug 2025 13:11:46 GMT</pubDate>
            <description><![CDATA[<h1 id="vpn이란">VPN이란?</h1>
<p><strong>가상 사설망(VPN: Virtual Private Network)</strong>은 사용자가 사설망에 연결된 것처럼 인터넷에 액세스할 수 있도록 하는 인터넷 보안 서비스</p>
<p>정의상 VPN 연결은 다음과 같다.</p>
<blockquote>
<ul>
<li>연결 프로세스에 실제 케이블이 없기 때문에 &#39;Virtual&#39;</li>
</ul>
</blockquote>
<ul>
<li>이 연결을 통해 다른 사용자가 내 데이터 또는 검색 활동을 볼 수 없기 때문에 &#39;Private&#39;</li>
<li>컴퓨터와 VPN 서버 등 여러 디바이스가 함께 작동하여 설정된 링크를 유지하므로 &#39;Network&#39;</li>
</ul>
<h2 id="vpn-등장-배경">VPN 등장 배경</h2>
<h3 id="사설망이란">사설망이란?</h3>
<p>인터넷이 성장함에 따라 IPv4 Address의 폭발적인 수요가 일어났고 IPv4의 주소는 점점 부족해지기 시작하였다. 그리하여 탄생한 것이 바로 사설망(Private Network)이다.
IPv4 대역 중 일부를 Private IP로 지정하여 근거리 통신망 LAN에서 사용하도록 하여 IPv4 주소를 절약하였다.
사설망의 장점은 IPv4 주소 절약뿐만 아니라 보안적인 측면에서도 존재한다.
사설 IP를 이용해 별도의 네트워크를 구성함으로써 외부 인터넷과 내부의 네트워크를 분리하고 외부 인터넷의 접근으로부터 내부 네트워크를 보호할 수 있다. 그렇기에 필요한 경우에만 NAT(Network Address Translation)을 이용해 공인 인터넷 통신을 수행한다.
그런데, 여기저기 다양한 장소에 사설망이 구축되기 시작하면서 멀리 떨어져 있는 다른 사설망과의 연결의 필요성이 크게 증가하기 시작하였다.    </p>
<h3 id="전용-회선의-등장">전용 회선의 등장</h3>
<p>기업의 경우, 회사 네트워크를 구축하면서 멀리 떨어져있는 지사 네트워크를 연결하기 위해 전용회선을 사용한다. 즉, 본사 사설망과 지사 사설망을 연결하는 것이다. 공인 인터넷이 아닌 인터넷 서비스 공급자(ISP)의 망 일부를 독점하여 사용하기 때문에 내부 트래픽이 아니면 접근할 수 없어 데이터의 안전이 보장된다는 것이 전용 회선의 큰 장점이다.
<img src="https://velog.velcdn.com/images/hyun_woo/post/7899b950-770c-4ddc-8de0-42597b25e676/image.png" width=400>
하지만 전용 회선은 큰 단점도 존재한다. 망 일부를 독점하여 사용하는 만큼 값이 매우 비싸다.
따라서 사람들은 비싼 전용 회선을 사용하지 않고도 사설망끼리 연결할 방법을 찾기 시작하였다.</p>
<p>이를 위하여 다음 두가지의 조건이 충족 되어야 한다.</p>
<blockquote>
<ul>
<li>비싼 전용 회선이 아닌 공인망을 사용하여 사설망과 사설망을 연결할 수 있어야 한다.</li>
</ul>
</blockquote>
<ul>
<li>데이터가 안전하게 암호화되어야 한다.</li>
</ul>
<p>이 두가지를 해결한 것이 바로 VPN(Virtual Private Network)이다.</p>
<h2 id="vpn">VPN</h2>
<p>VPN은 공인 인터넷을 사이에 둔 사설망과 사설망이 공인 IP로의 NAT와 같은 제약 없이 사설 IP를 이용해 통신(Routing)할 수 있도록 지원하며 데이터의 암호화를 제공한다.
<img src="https://velog.velcdn.com/images/hyun_woo/post/7b322a60-4524-4768-8da4-90b86d902738/image.png" width=400></p>
<p>VPN은 공인 인터넷에서 IP packet을 캡슐화함과 동시에 데이터를 암호화를 수행한다.
이 기술을 보통 터널링(Tunnerling)이라 한다.</p>
<p>터널링(Tunneling)은 간단히 말해서 원래 직접 갈 수 없는 데이터를, 다른 데이터(다른 프로토콜) 안에 넣어서 안전하게 목적지까지 보내는 기술이다. 원래 인터넷은 사설 IP를 직접 라우팅하지 않는다.(라우터 규칙)</p>
<h1 id="vpn-보안">VPN 보안</h1>
<h2 id="ip-숨기기">IP 숨기기</h2>
<p>VPN을 켜면, 내 PC ↔ VPN 서버 사이에 암호화된 터널이 만들어진다.</p>
<p>인터넷으로 나가는 모든 요청은 내 PC에서 바로 목적지로 가는 게 아니라:</p>
<ol>
<li>먼저 VPN 서버로 감</li>
<li>VPN 서버가 대신 목적지에 접속</li>
</ol>
<p>목적지 웹사이트/서비스 입장에서는 “VPN 서버의 IP”가 보이고, 내 진짜 IP는 감춰진다.</p>
<blockquote>
<p>따라서 VPN을 이용하면 광고·트래킹·정부 검열 대상에서도 내 위치·IP를 추적하기 어려움.</p>
</blockquote>
<h2 id="데이터-암호화">데이터 암호화</h2>
<p>내 PC ↔ VPN 서버 구간이 암호화(AES, ChaCha20 등) 되어 있으므로:</p>
<ul>
<li>공용 와이파이에서 스니핑(패킷 도청) 불가</li>
<li>ISP나 중간 라우터도 내가 어떤 사이트에 접속하는지, 어떤 데이터를 주고받는지 알 수 없음.</li>
</ul>
<p>다만, VPN 서버 ↔ 목적지 사이트 구간은 암호화 안 될 수도 있음(HTTPS 안 쓰면 노출 가능).</p>
<h2 id="한계">한계</h2>
<ul>
<li>VPN 서버 운영자는 내 접속 기록을 남길 수 있음</li>
<li>속도 저하</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Docker] Docker 기본 개념]]></title>
            <link>https://velog.io/@hyun_woo/Docker-%EB%8F%84%EC%BB%A4%EB%9E%80</link>
            <guid>https://velog.io/@hyun_woo/Docker-%EB%8F%84%EC%BB%A4%EB%9E%80</guid>
            <pubDate>Fri, 08 Aug 2025 05:45:43 GMT</pubDate>
            <description><![CDATA[<h2 id="docker란">Docker란?</h2>
<pre><code>Docker란 Go언어로 작성된 리눅스 컨테이너 기반으로하는 오픈소스 가상화 플랫폼이다.
개발자는 Docker를 통하여 애플리케이션을 신속하게 구축, 테스트, 배포할수 있게 된다.</code></pre><h3 id="가상화를-사용하는-이유는">가상화를 사용하는 이유는?</h3>
<pre><code>가상화는 하나의 물리적 자원을 논리적으로 여러 개처럼 나누어 사용하는 기술이다.
쉽게 말해, 하나의 컴퓨터에서 여러 컴퓨터가 있는 것처럼 운영하는 방식이다.</code></pre><p>가상화가 처음 등장했던 1960~70년대 상황을 살펴보면, 무어의 법칙에 의해 하드웨어의 성능은 빠르게 증가하는 가운데, 그 당시 소프트웨어의 발전 속도는 하드웨어의 발전 속도를 따라가지 못했다.
<img src="https://velog.velcdn.com/images/hyun_woo/post/cbb97f7d-cef8-4a80-867d-17183159a08f/image.png" alt="">
위의 타임라인을 보면 소프트웨어는 1990년대 이후 급격히 발전한 것을 볼 수 있고, 소프트웨어가 요구하는 서버 사양에 비해 소프트웨어를 실행 중인 서버의 성능이 훨씬 좋다 보니, 서버의 성능을 10% 수준밖에 활용하지 못하는 엄청난 비효율이 발생했다.</p>
<p>이러한 비효율을 해결하기 위하여 고안된 것이 바로 <strong>가상화</strong>개념이다.
한 대의 서버를 마치 여러 대의 서버처럼 사용할 수 있다면? 즉, 한 대의 서버 위에 동시에 여러 개의 OS를 설치하고 여러 애플리케이션을 실행시킬 수 있다면, 자원 비효율 문제를 해결할 수 있었고 실제로 가상화 적용 이후 5<del>15%에 그치던 자원 사용률은 60</del>80% 수준까지 향상되었다고 한다.</p>
<p>대표적인 가상화 플랫폼으로는 VMware, virtualbox 등이 있다.</p>
<h4 id="가상화의-종류">가상화의 종류</h4>
<p>크게 두가지를 볼 수 있다.</p>
<pre><code>- 하드웨어가상화(VM) : 물리적 하드웨어 위에 하이퍼바이저(Hypervisor)를 올려 여러 OS 실행
- OS수준 가상화(컨테이너) : 하나의 OS 커널을 공유하며, 프로세스/파일 시스템을 격리</code></pre><p><img src="https://velog.velcdn.com/images/hyun_woo/post/062e9091-5e69-47de-b573-c184c90d11be/image.png" alt=""></p>
<p>커널이란 하드웨어를 제어하기 위한 명령어이다.
여기서 주목할건 <strong>&quot;OS마다 명령어를 해석하는 규칙이 다름&quot;</strong>
ex) 인사 = hello, Hello, HELLO
ex) 덧셈 = add(맥), ADD(레드햇), Add(윈도우)</p>
<p>나라마다 언어가 다르듯 어떠한 연산을 하려 할 때 위에 예시들처럼 같은 의미이지만 말하는 바가 다르기 때문에 처리할 명령을 이해할 수 없다.</p>
<p>그러면, 어떻게 이러한 명령어들을 이해해서 각각 OS를 구동하게 할 수 있을까?
OS의 커널을 수정해야한다 (= OS의 소스를 까서 수정을 해야한다는 뜻 = Guest OS를 수정해야한다는 뜻)</p>
<p><strong>하이퍼바이저</strong></p>
<pre><code>하이퍼바이저가 각 OS마다 말하는 명령을 하드웨어가 이해할 수 있게 하나의 명령어로 번역해준다.</code></pre><h3 id="컨테이너란">컨테이너란?</h3>
<pre><code>운영 체제 커널을 공유하며, 경량 프로세스 격리를 제공</code></pre><p>컨테이너는 해운업계 솔루션이였다.
화물을 어떻게 하면 효율적으로 옮길까 라고 생각해봤을 때, 표준화된 컨테이너 박스를 만들고 무엇을 넣어도 표준화된 운송선만 있다면  똑같이 세워서 효율적으로 운송할 수 있는 것이 &#39;컨테이너&#39;다. </p>
<pre><code>이러한 컨셉을 IT에 적용한것이 바로 &#39;컨테이너&#39;</code></pre><p>소프트웨어 코드, 애플리케이션 코드가 작동하기 위해 필요한 컴포넌트와 함께 표준화된 방식으로 패키징해서 컨테이너 엔진만 있으면 돌아갈 수 있도록 하는 구조를 &#39;컨테이너&#39;라고 정의한다.</p>
<h3 id="vm-vs-container">VM vs Container</h3>
<p>가장 큰 차이점은 <strong>Guest OS의 유무</strong>이다.
VM에서는 Guest Os가 설치되어 독립되는 실행환경인 반면
컨테이너에서는 Host OS의 커널을 공유하게 된다.</p>
<p>컨테이너에서는 Host Os위에 어플리케이션의 실행 패키지인 이미지를 배포만 하면 되는데
VM은 하나의 어플리케이션을 실행하기 위해 VM을 띄우고 자원을 할당하고 Guest OS를 부팅한 뒤에야 비로서 애플리케이션을 실행하게 되는 것이다.</p>
<h3 id="결론">결론</h3>
<p>Docker는 컨테이너 엔진이다. 즉, 컨테이너를 생성하고 실행하고 관리하는 소프트웨어 중 하나이다.</p>
<p>다음 글에서는 도커의 기초적인 사용법과 개념들을 알아보겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[암호학] 키 관리와 분배]]></title>
            <link>https://velog.io/@hyun_woo/%EC%95%94%ED%98%B8%ED%95%99-%ED%82%A4-%EA%B4%80%EB%A6%AC%EC%99%80-%EB%B6%84%EB%B0%B0</link>
            <guid>https://velog.io/@hyun_woo/%EC%95%94%ED%98%B8%ED%95%99-%ED%82%A4-%EA%B4%80%EB%A6%AC%EC%99%80-%EB%B6%84%EB%B0%B0</guid>
            <pubDate>Fri, 08 Aug 2025 04:38:01 GMT</pubDate>
            <description><![CDATA[<h2 id="대칭키-암호를-이용한-대칭키-분배">대칭키 암호를 이용한 대칭키 분배</h2>
<h3 id="대칭키-암호란">대칭키 암호란?</h3>
<p>대칭키 암호란 동일한 키로 암호화와 복호화를 수행하는 암호 알고리즘이다.
대표적인 알고리즘: AES, DES
특징으로는 비대칭키 암호보다 속도가 빠르다.
<img src="https://velog.velcdn.com/images/hyun_woo/post/8704df65-348a-4cb6-9b29-6a6a8bc6b63b/image.png" width=500></p>
<p>동일한 키로 암호화와 복호화를 수행하니 암호화 하는 사람과 복호화 하는 사람은 동일한 키를 분배 받아야한다. 이를 어떻게 할지가 본 문서의 핵심이다.</p>
<p>두 참가자가 키를 분배 받는 방식을 생각해보면 대략 4개로 나눌 수 있다.</p>
<ol>
<li>A가 키를 선택하여 B에게 직접 전달</li>
<li>제 3자가 키를 선택하여 A와 B에게 직접 전달</li>
<li>A와 B가 이전에 사용한 적 있는 키를 이용하여 암호화하여 상대에게 전달</li>
<li>A와 B가 제 3자인 C와 암호화된 링크가 있다면, C가 암호화 된 링크 상에서 A와 B에게 키를 전달</li>
</ol>
<h3 id="직접-전달-방식의-한계">직접 전달 방식의 한계</h3>
<p>여기서 1번 2번 방식은 한계가 있다.
이유는 분산 시스템이나 IP레벨에서 이루어지는 통신에서는 매우 많은 장치가 다른 매우 많은 장치들과 통신을 해야되기 때문이다. 하나의 장치가 각각 다른 장치들 모두의 키를 다르게 소유하고 있어야하기 때문에 <strong>각 장치는 매우 많은 키가 필요하다.</strong>
<img src ="https://velog.velcdn.com/images/hyun_woo/post/61cf9337-2e80-483c-bbe8-27f0c3d78ca7/image.png" width=500></p>
<h3 id="이전-키로-암호화하여-전달-방식의-한계">이전 키로 암호화하여 전달 방식의 한계</h3>
<p>3번 방식도 마찬가지로 한계가 있다.
마찬가지로 매우 방대한 양의 키가 필요하며, 공격자가 만약 이전 키를 얻으면 이후의 키들은 모두 복호화가 가능하기 때문이다. <strong>도미노 처럼</strong></p>
<h3 id="암호화된-링크를-통한-전달">암호화된 링크를 통한 전달</h3>
<p>따라서 이러한 1,2,3번 방식의 문제를 해결하기 위하여 가장 좋은 방법은 &#39;키 분배 센터&#39;를 이용하는 방법이다.
<img src="https://velog.velcdn.com/images/hyun_woo/post/dceca032-fd32-4076-9b02-007fc1eb9019/image.png" alt=""></p>
<p>이 방식에서는 &#39;필요한 키의 개수 ==  사용자 수&#39;이다. 이유는 각 사용자는 KDC(Key Distribution Scenario)와 둘만의 유일한 마스터키를 교환하기만 하면 그 이후는 세션 키를 사용함으로써 통신이 필요할 때만 키를 생성하기 때문이다. 이러한 KDC구조는 계층적으로 존재할 수도 있다. 이제 이러한 방식이 어떤식으로 동작하는지 알아보자.</p>
<h4 id="kdc방식의-키-분배-시나리오">KDC방식의 키 분배 시나리오</h4>
<p><img src="https://velog.velcdn.com/images/hyun_woo/post/cc76f8d6-359f-47eb-a987-d0a4558c775f/image.png" alt=""></p>
<p>먼저 알아야 될 것은 &#39;세션키&#39;의 개념이다. 세션키는 하나의 통신 세션에서 사용하는 키이며, 통신이 끝나면 폐기된다. 이렇게 폐기함으로써 공격자가 키를 해독할 시간을 주지 않는 것이다. 여기서는 이러한 세션키(즉 대칭키 역할을 수행한다.)를 KDC 방식에서 어떻게 분배하는지 서술한다.</p>
<ol>
<li>A가 KDC에게 자신의 식별자, B의 식별자, 임시비표 N1을 전송함으로 세션 키를 요청한다.<ul>
<li>여기서 임시비표는 난수 혹은 타임스탬프 등의 값이며 이번 통신과 다른 통신과 혼돈하지 않기 위하여 사용한다.</li>
</ul>
</li>
<li>KDC는 사전에 A와 공유된 A의 마스터키로 암호화하여 세션키와 (1)에서 수신한 내용을 A에게 송신한다. 추가로 A는 B에게 KDC를 대신해서 전달해줄 B를 위한 내용도 같이 수신한다.</li>
<li>KDC와 A만 아는 A의 비밀키로 암호화되어 (1)의 내용들을 전달 받았기에 A만 세션 키를 복호화할 수 있으며, 상대방이 KDC라는 것을 확인할 수 있다. 이제 A가 세션키를 저장한 후에 B에게 KDC에게 받은 내용을 대신 전달한다. 내용은 B의 비밀키로 암호화된 세션키와 A의 식별자로 구성되어있다.</li>
<li>B는 마찬가지로 세션키를 소유하게 되며, 해당 내용이 KDC로부터 전송된것이라는 것을 알 수 있다. 또한 A의 식별자가 있기 때문에 통신 상대방이 A라는 것도 알 수 있다. 하지만 상대방이 A인 것을 확인하기 위하여 임시비표 N2를 생성하여 A에게 세션키로 암호화하여 전송한다. 세션키를 가진 사람은 A와 B뿐이기 때문이다.</li>
<li>A는 복호화하여 N2를 함수화하여 다시 B에게 전달하여 자신이 A라는 것을 인증하게 된다.</li>
</ol>
<h3 id="세션-키-수명-주기">세션 키 수명 주기</h3>
<p>현대에 대부분의 통신은 세션키를 통하여 암호화하여 안전한 통신을 한다.
세션키는 공격자에게 복호화할 시간을 주지 않기 때문에 빈번하게 갱신될 수록 안전하다.
하지만 계속 세션키를 생성하고 분뱋는 과정에서 오버헤드가 발생하기 마련이고, 대칭키 암호의 가장 큰 장점 중에 하나인 속도가 빠르다는 점을 상쇄시킨다. 
따라서 <strong>안전</strong>과 <strong>효율</strong> 사이 <strong>적절한 균형</strong>을 맞출 필요가 있다.</p>
<p><strong>연결형 프로토콜</strong>에서는 보통 새로운 연결마다 세션 키를 사용한다. 이 때 만약 오래 연결되어 있는 통신이라면 특정 주기마다 세션 키를 갱신해야할 필요가 있다.
<strong>비연결형 프로토콜</strong>에서는 명시적인 연결 시작과 종료가 없다. 따라서 일정 시간이나 일정 수의 교환마다 세션 키를 갱신해야할 필요가 있다.</p>
<h3 id="자동화된-키-분배">자동화된 키 분배</h3>
<p>연결형 프로토콜을 사용할 때 SSM(Session Key Module)을 통하여 호스트나 터미널의 개입 없이 시스템에서 자동적으로 키 교환이 수행되도록 설계할 수 있다.
<img src = "blob:https://velog.io/cca5cf0c-c9b2-4e35-8f4e-3736948b9a79" width =700></p>
<h3 id="비중앙집중형-키-제어">비중앙집중형 키 제어</h3>
<p>앞서 KDC없이 직접 전달 방식은 매우 많은 키를 필요로 한다는 한계가 있었다. 하지만 이러한 한계에도 불구하고 작은 규모의 환경이나 보안이 매우 중요한 환경에서는 사용된다.</p>
<p>이유는 다음과 같다.</p>
<ul>
<li>중앙집중형 방식은 중앙 기관이 공격 당하면 키가 노출된다.</li>
<li>따라서 KDC는 신뢰할 수 있게 설계되어야한다.</li>
</ul>
<p>이러한 요구사항들이 필요 없고, 서버 해킹에 대하여도 안전한 비중앙집중형 키 분배 방식은 효율은 비록 낮을지언정 강력한 보안을 제공하기 때문에 WhatsApp, 텔레그램 비밀대화 등에서 사용된다. 이를 종단 간 암호화라고 한다.</p>
<h4 id="시나리오">시나리오</h4>
<p><img src="https://velog.velcdn.com/images/hyun_woo/post/026b7c4c-7906-426d-8492-c8ce09d61b13/image.png" alt=""></p>
<p>A와 B는 사전에 둘만의 마스터키를 소유하고 있다고 가정한다.
통신을 위한 세션 키를 얻기 위하여 다음과 같은 절차를 수행한다.</p>
<ol>
<li>A가 B에게 세션 키를 요청하기 위하여 자신의 식별자와 임시비표 N1을 생성하여 송신한다.</li>
<li>B는 A에게 둘만의 마스터키로 암호화하여 세션키와 A이 식별자, B의 식별자, 함수화된 N1, 새로운 N2를 생성하여 전달한다.</li>
<li>A는 마스터키로 복호화하여 상대방이 B인것을 알게 되며, 세션키를 저장한다. 추가로 N2를 함수화하여 세션키로 B에게 전송하며 자신이 A인것을 인증하게 된다.</li>
</ol>
<p>이로써 A와 B는 안전하게 통신할 준비가 되었다.</p>
<p>다음 글에서는 비대칭키 암호를 이용한 대칭키 분배에 대하여 다뤄보겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[GIT] 원하는 파일만 push하는 방법(.gitignore)]]></title>
            <link>https://velog.io/@hyun_woo/GIT-%EC%9B%90%ED%95%98%EB%8A%94-%ED%8C%8C%EC%9D%BC%EB%A7%8C-push%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95.gitignore</link>
            <guid>https://velog.io/@hyun_woo/GIT-%EC%9B%90%ED%95%98%EB%8A%94-%ED%8C%8C%EC%9D%BC%EB%A7%8C-push%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95.gitignore</guid>
            <pubDate>Wed, 18 Jun 2025 12:51:31 GMT</pubDate>
            <description><![CDATA[<p>github에 업로드를 할 때 특정 파일을 제외하고 업로드 하고 싶으면 다음과 같이 하면 된다.
참고로 git bash를 이용하여 하는 방법이다.</p>
<h2 id="1-해당-프로젝트-폴더에서-git-bash를-실행">1. 해당 프로젝트 폴더에서 Git Bash를 실행</h2>
<h2 id="2-gitignore파일-생성">2. .gitignore파일 생성</h2>
<pre><code class="language-bash">touch .gitignore</code></pre>
<h2 id="3-에디터로-파일-열기">3. 에디터로 파일 열기</h2>
<ul>
<li>VScode로 열기<pre><code class="language-bash">code .gitignore</code></pre>
<h2 id="4-에디터로-수정">4. 에디터로 수정</h2>
</li>
<li>파일 내용을 수정한다.
```bash<h1 id="모든-파일-무시">모든 파일 무시</h1>
</li>
<li><h1 id="c-파일만-추적">.c 파일만 추적</h1>
!*.c</li>
</ul>
<h1 id="원하면-readme도-추가">원하면 README도 추가</h1>
<p>!README.md
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘]그래프]]></title>
            <link>https://velog.io/@hyun_woo/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EA%B7%B8%EB%9E%98%ED%94%84</link>
            <guid>https://velog.io/@hyun_woo/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EA%B7%B8%EB%9E%98%ED%94%84</guid>
            <pubDate>Fri, 14 Feb 2025 04:55:14 GMT</pubDate>
            <description><![CDATA[<h1 id="그래프">그래프</h1>
<ul>
<li>객체 사이이 연결 관계를 표현할 수 있는 자료 구조</li>
<li>정점(vertex)와 간선(edge)들의 유한 집합</li>
<li>G = {V, E}</li>
</ul>
<h2 id="그래프의-종류">그래프의 종류</h2>
<ul>
<li><p>무방향 그래프 (undirected graph)</p>
</li>
<li><p>방향 그래프 (directed graph)</p>
</li>
<li><p>가중치 그래프(weighted graph) </p>
</li>
<li><p>부분 그래프(subgraph): 어떤 그래프의 정점과 간선의 일부로 이루어진 그래프</p>
</li>
<li><p>차수(degree): 그 정점에 인접한 정점의 수</p>
</li>
<li><p>연결 그래프(connected graph): 무방향 그래프에 있는 모든 정점 쌍에 대하여 항상 경로가 존재하는것.</p>
</li>
<li><p>완전 그래프(complete graph): 모든 정점들이 서로 연결되어 있는 그래프</p>
</li>
</ul>
<h2 id="그래프의-표현-방법">그래프의 표현 방법</h2>
<ul>
<li>인접 행렬(adjacency matrix): 2차원 배열을 사용</li>
<li>인접 리스트(adjacency list): 연결 리스트를 사용</li>
</ul>
<h1 id="그래프의-탐색">그래프의 탐색</h1>
<p>하나의 정점으로부터 시작하여 차례대로 모든 정점들을 한 번씩 방문하는 것</p>
<h2 id="탐색의-방법">탐색의 방법</h2>
<ul>
<li>DFS(depth first search): 깊이 우선 탐색</li>
<li>BFS(breath first search): 너비 우선 탐색</li>
</ul>
<h1 id="최소-비용-신장-트리">최소 비용 신장 트리</h1>
<p>신장 트리(spanning tree)</p>
<ul>
<li>그래프 내의 모든 정점을 포함하는 트리</li>
<li>모든 정점이 연결 되어 있어야 하고 사이클을 포함하면 안 됨</li>
<li>따라서 n개의 정점을 정확히 n-1개의 간선으로 연결</li>
<li>하나의 그래프에는 많은 신장 트리가 존재 가능</li>
<li>DFS, BFS 도중 사용된 간선만 모으면 만들 수 있음</li>
</ul>
<p>최소 비용 신장 트리(MST)</p>
<ul>
<li>네트워크에 있는 모든 정점들을 가장 적은 수의 간선과 비용으로 연결</li>
</ul>
<h2 id="mst-알고리즘">MST 알고리즘</h2>
<h3 id="kruskal의-mst-알고리즘">Kruskal의 MST 알고리즘</h3>
<ul>
<li>탐욕적인 방법(greedy method)</li>
<li>매 순간 가장 좋다고 생각되는 것을 선택</li>
<li>kruskal의 알고리즘은 지역적인 해답 뿐만 아니라 전역적인 해답도 최적의 해</li>
</ul>
<ol>
<li>간선들을 가중치의 오름차순으로 정렬</li>
<li>사이클 형성 검사 - union-find연산</li>
<li>간선의 개수가 정점의 개수 -1개이면 종료</li>
</ol>
<h4 id="시간-복잡도-분석">시간 복잡도 분석</h4>
<p>union-find 알고리즘을 이용하면 간선들을 정렬하는 시간에 좌우된다.</p>
<h3 id="prim의-mst-알고리즘">Prim의 MST 알고리즘</h3>
<ul>
<li>시작 정점에서부터 출발하여 신장 트리 집합을 단계적으로 확장</li>
<li>포함된 신장 트리 집합에 인접한 정점들 중에서 최소비용으로 연결된 정점을 선택</li>
<li>마찬가지로 간선의 개수가 정점의 개수 - 1개이면 종료</li>
</ul>
<h4 id="시간-복잡도-분석-1">시간 복잡도 분석</h4>
<ul>
<li>주 반복문이 정점의 수 n만큼 반복, 내부 반복문이 n번 반복</li>
<li>따라서 O(n^2)</li>
</ul>
<h3 id="kruskal-vs-prim">Kruskal vs Prim</h3>
<p>희소 그래프의 경우에는 Kruskal
밀집 그래프의 경우에는 Prim</p>
<h1 id="최단-경로">최단 경로</h1>
<p>최단 경로(shortest path): 네트워크에서 정점 i와 정점 j를 연결하는 경로 중 가중치 합이 최소가 되는 경로</p>
<ul>
<li>가중치 인접 행렬 사용</li>
</ul>
<h2 id="dijkstra의-최단-경로-알고리즘">Dijkstra의 최단 경로 알고리즘</h2>
<p>하나의 시작 정점으로부터 모든 다른 정점까지의 최단 경로를 찾는 알고리즘</p>
<h2 id="floyd의-최단-경로-알고리즘">Floyd의 최단 경로 알고리즘</h2>
<p>그래프에 존재하는 모든 정점 사이의 최단 경로</p>
<h2 id="복잡도-분석">복잡도 분석</h2>
<ul>
<li>Dijkstra: O(n^2)</li>
<li>Floyd: O(n^3)</li>
</ul>
<p>하지만 모든 정점 쌍의 최단 경로 구할 때 Dijkstra도 O(n^3)이 된다.
Floyd의 알고리즘은 매우 간결한 반복 구문을 사용하므로 Dijkstra의 알고리즘에 비해 상당히 빨리 모든 정점 간의 최단 경로를 찾을 수 있다.</p>
<h2 id="위상-정렬">위상 정렬</h2>
<ul>
<li>방향 그래프를 정렬</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 우선순위 큐(Heap)]]></title>
            <link>https://velog.io/@hyun_woo/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84-%ED%81%90Heap</link>
            <guid>https://velog.io/@hyun_woo/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84-%ED%81%90Heap</guid>
            <pubDate>Tue, 11 Feb 2025 06:51:41 GMT</pubDate>
            <description><![CDATA[<h2 id="우선순위-큐">우선순위 큐</h2>
<p>우선순위 큐는 우선 순위의 개념을 큐에 도입한 자료구조이다.</p>
<p><strong>응용되는 사례는 다음과 같다.</strong></p>
<ul>
<li>시뮬레이션 시스템</li>
<li>네트워크 트래픽 제어</li>
<li>운영 체제에서의 작업 스케쥴링</li>
<li>수치 해석적인 계산</li>
</ul>
<p>우선순위 큐는 여러 방법으로 구현이 가능한데, 가장 효율적인 구조는 heap이다.</p>
<h2 id="heap">Heap</h2>
<ul>
<li>완전 이진 트리의 일종으로 우선순위 큐를 위하여 특별히 만들어진 자료 구조</li>
<li>여러 개의 값들 중에서 가장 큰 값이나 가장 작은 값을 빠르게 찾아내도록 만들어진 자료 구조</li>
</ul>
<p>특징으로는 느슨한 정렬 상태를 유지한다.
추가로 중복된 값을 허용한다.</p>
<h3 id="heap의-종류">Heap의 종류</h3>
<ul>
<li><p>최대 히프(max heap)</p>
<blockquote>
<p> 부모노드 &gt;= 자식노드</p>
</blockquote>
</li>
<li><p>최소 히프(min heap)</p>
<blockquote>
<p>부모노드 &lt;= 자식노드</p>
</blockquote>
</li>
</ul>
<h3 id="heap의-구현">Heap의 구현</h3>
<p>히프는 완전 이진 트리이기 때문에 각각의 노드의 차례대로 번호를 붙일 수 있다. 따라서 히프를 저장하는 표준적인 자료구조는 <strong>배열</strong>이다.</p>
<ul>
<li>왼쪽 자식의 인덱스 = (부모의 인덱스) * 2</li>
<li>오른쪽 자식의 인덱스 = (부모의 인덱스) * 2 + 1</li>
<li>부모의 인덱스 = (자식의 인덱스) / 2</li>
</ul>
<h3 id="heap의-복잡도-분석">Heap의 복잡도 분석</h3>
<p>삽입, 삭제의 시간 복잡도 : O(log n)</p>
<h2 id="heap-정렬">Heap 정렬</h2>
<ul>
<li>히프의 특성을 이용하여 삽입 삭제만으로 정렬 가능</li>
</ul>
<h3 id="heap-정렬의-복잡도">Heap 정렬의 복잡도</h3>
<ul>
<li>O(n log n)</li>
</ul>
<p>히프 정렬은 전체 자료를 정렬하는 것이 아니라 가장 큰 값 몇 개만 정렬 할 때 가장 유용하다.</p>
<h2 id="허프만-코드">허프만 코드</h2>
<p>최소 히프를 이용하여 구현</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘]트리(Tree)]]></title>
            <link>https://velog.io/@hyun_woo/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%ED%8A%B8%EB%A6%ACTree</link>
            <guid>https://velog.io/@hyun_woo/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%ED%8A%B8%EB%A6%ACTree</guid>
            <pubDate>Mon, 10 Feb 2025 07:56:02 GMT</pubDate>
            <description><![CDATA[<h2 id="트리">트리</h2>
<ul>
<li>비선형 자료구조</li>
<li>계층적인 자료를 표현하는데 적합한 자료구조
ex) 컴퓨터 디렉토리 구조, 인공지능 문제(결정트리)</li>
</ul>
<p><strong>트리는 한 개 이상의 노드로 이루어진 유한 집합이다.</strong></p>
<h2 id="이진-트리">이진 트리</h2>
<ul>
<li>모든 노드가 2개의 서브 트리를 가지고 있는 트리 </li>
</ul>
<pre><code>-서브 트리는 공집합일 수 있음
-서브트리간에 순서가 존재함
-n개의 노드를 가진 이진 트리는 n-1개의 간선을 가짐
-높이 h일때 노드 개수 : 최소 h , 최대 2^h-1</code></pre><h3 id="이진-트리-분류">이진 트리 분류</h3>
<h4 id="포화이진트리full-binary-tree">포화이진트리(full binary tree)</h4>
<pre><code>-트리의 각 레벨에 노드가 꽉 차있는 이진트리
-전체 노드 개수는 정확히 2^h-1
-번호 매기는 방법 : 레벨 단위로 왼쪽에서 오른쪽으로</code></pre><h4 id="완전-이진-트리complete-binary-tree">완전 이진 트리(complete binary tree)</h4>
<pre><code>-높이가 k일때 레벨 1부터 k-1까지는 노드가 모두 채워져 있고 
 마지막 레벨에서는 왼쪽부터 오른쪽으로 순서대로 채워져 있는 이진트리
-따라서 포화이진트리는 항상 완전이진트리
-노드번호는 포화 이진 트리와 동일</code></pre><h4 id="스레드-이진-트리threaded-binary-tree">스레드 이진 트리(threaded binary tree)</h4>
<pre><code>이진 트리의 NULL 링크를 활용하여 순환 호출 없이도 트리의 노드들을 순회 할 수 있음
</code></pre><h3 id="이진-트리-표현-방법">이진 트리 표현 방법</h3>
<ul>
<li>배열</li>
<li>포인터</li>
</ul>
<h4 id="배열을-이용한-이진-트리">배열을 이용한 이진 트리</h4>
<pre><code>노드 i의 부모 노드 인덱스 = i / 2
노드 i의 왼쪽 자식 노드 인덱스 = 2i
노드 i의 오른쪽 자식 노드 인덱스 = 2i + 1</code></pre><h4 id="링크-표현법">링크 표현법</h4>
<pre><code>왼쪽 포인터
오른쪽 포인터
데이터</code></pre><p><strong>순회 방법</strong></p>
<p>VLR : preorder traversal(전위순회)
LVR : inorder traversal(중위순회)
LRV : postorder traversal(후위순회)</p>
<h2 id="이진-탐색-트리bst">이진 탐색 트리(BST)</h2>
<p>이진 탐색 트리 : 이진 탐색 트리의 성질을 만족하는 이진트리</p>
<pre><code>- 모든 원소의 키는 유일한 키를 가진다.
- 왼쪽 서브 트리 키들은 루트 키보다 작다.
- 오른쪽 서브 트리의 키들은 루트의 키보다 크다.
- 왼쪽과 오른쪽 서브 트리도 이진 탐색 트리이다.</code></pre><h3 id="삭제-연산">삭제 연산</h3>
<p>삭제 연산 시에는 세 가지 경우를 고려해야 한다.</p>
<ol>
<li>삭제하려는 노드가 단말 노드일 경우</li>
<li>삭제하려는 노드가 하나의 왼쪽이나 오른쪽 서브 트리중 하나만 가지고 있는 경우</li>
<li>삭제하려는 노드가 두개의 서브 트리 모두 가지고 있는 경우</li>
</ol>
<h3 id="이진-탐색-트리의-분석">이진 탐색 트리의 분석</h3>
<ul>
<li>레벨 당 두배로 노드의 개수가 늘기 때문에 이진탐색 트리의 높이는 log N</li>
<li>이진 탐색 트리에서의 탐색, 삽입, 삭제 연산의 시간복잡도는 O(트리의 높이)</li>
<li>따라서 이진 탐색 트리의 평균적인 경우의 시간 복잡도는 O(log h)</li>
<li>단 최악의 경우(경사 트리) : O(N)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘]연결 리스트]]></title>
            <link>https://velog.io/@hyun_woo/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@hyun_woo/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Thu, 06 Feb 2025 07:27:28 GMT</pubDate>
            <description><![CDATA[<h2 id="리스트">리스트</h2>
<p>배열을 이용하여 리스트를 구현하면 순차적인 메모리 공간이 할당 되므로
리스트의 순차적 표현(sequential representation)이라고 한다.</p>
<blockquote>
<ul>
<li><strong>장점</strong>  : 빠름</li>
</ul>
</blockquote>
<ul>
<li><strong>단점</strong> : 크기가 고정됨</li>
</ul>
<h2 id="연결리스트">연결리스트</h2>
<p>연결 리스트는 포인터를 사용하여 데이터를 연결한다.
(동적으로 공간 확보)</p>
<blockquote>
<p><strong>장점</strong></p>
</blockquote>
<ul>
<li>크기 제한이 없다.</li>
<li>중간에서도 쉽게 삽입 삭제가 가능하다.</li>
</ul>
<blockquote>
<p><strong>단점</strong></p>
</blockquote>
<ul>
<li>구현이 복잡하다.</li>
<li>임의의 항목을 추출할 때 배열보다 오래걸림</li>
<li>포인터도 저장하여야 하므로 메모리 공간 많이 차지</li>
</ul>
<p>하나의 프로그램에서 여러 연결리스트들은 첫번째 데이터로 구별</p>
<p>즉 첫번째 데이터만 알 수 있다면 연결 리스트의 나머지 데이터도 알 수 있다.</p>
<h3 id="자기참조-구조체">자기참조 구조체</h3>
<p>자기참조 구조체란 자기 자신의 구조체를 가르키는 포인터를 포함하는 구조체를 의미한다.</p>
<h3 id="원형-연결-리스트">원형 연결 리스트</h3>
<p><strong>중요 개념</strong></p>
<ul>
<li>원형 연결리스트에서 head는 마지막 노드</li>
</ul>
<blockquote>
<p><strong>장점</strong></p>
</blockquote>
<ul>
<li>하나의 노드에서 다른 모든 노드로 접근이 가능</li>
<li>노드의 삽입과 삭제가 단순 연결 리스트보다 용이</li>
<li>리스트의 끝에 노드를 삽입하는 연산이 효율적</li>
</ul>
<blockquote>
<p> <strong>응용</strong></p>
</blockquote>
<ul>
<li>원형 연결리스트는 컴퓨터의 여러 응용프로그램을 하나의 CPU를 이용하여 실행할 때 필요하다.</li>
<li>멀티 플레이어 게임</li>
</ul>
<h3 id="이중-연결-리스트">이중 연결 리스트</h3>
<p>이중 연결 리스트는 단순 연결 리스트에서는 선행 노드를 찾기 어렵다는 문제를
양방향으로 자유롭게 움직일 수 있게 보안하여 만들어진 자료구조이다.</p>
<blockquote>
<p><strong>장점</strong></p>
</blockquote>
<ul>
<li>양방향으로 검색이 가능함(유용함)</li>
</ul>
<blockquote>
<p><strong>단점</strong></p>
</blockquote>
<ul>
<li>공간을 많이 차지하고 코드가 복잡함</li>
</ul>
<ul>
<li>실제 응용 프로그램에서는 이중 연결 리스트와 원형 연결 리스트를 혼합하여 많이 사용함</li>
</ul>
<h3 id="연결-리스트로-구현한-스택">연결 리스트로 구현한 스택</h3>
<ul>
<li>크기가 제한되지 않는다는 큰 장점이 있다</li>
<li>하지만 배열 보다는 삽입 삭제 등 연산에 시간이 더 걸린다.</li>
</ul>
<h3 id="연결-리스트로-구현한-큐">연결 리스트로 구현한 큐</h3>
<ul>
<li>마찬가지로 크기가 제한 되지 않는다.</li>
<li>하지만 코드가 복잡해지며 링크 필드 때문에 메모리 공간을 더 많이 차지한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 큐(Queue)]]></title>
            <link>https://velog.io/@hyun_woo/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%ED%81%90Queue</link>
            <guid>https://velog.io/@hyun_woo/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%ED%81%90Queue</guid>
            <pubDate>Wed, 05 Feb 2025 05:51:41 GMT</pubDate>
            <description><![CDATA[<h2 id="큐">큐</h2>
<p>큐는 FIFO: First-In First-Out (선입선출) 구조이다.</p>
<h3 id="큐의-응용">큐의 응용</h3>
<p>큐는 현실세계의 실제상황을 시뮬레이션 하는 상황에서 많이 응용된다.</p>
<h3 id="선형-큐linear-queue">선형 큐(Linear Queue)</h3>
<p>1차원 배열을 이용하여 구현한 큐</p>
<ul>
<li>선형큐는 삽입과 삭제를 반복하다보면 rear이 맨 마지막 인덱스를 가리키고  앞에는 비어있을 수 있지만 이를 꽉 찼다고 인식함. </li>
<li>배열에 앞부분이 비어 있더라도 사용하지 못한다.<ul>
<li>요소들을 이동시키면 되지만 상당히 비효율</li>
</ul>
</li>
</ul>
<h3 id="원형-큐calcular-queue">원형 큐(Calcular Queue)</h3>
<p>배열이 원형으로 처음과 끝이 연결되어 있다는 개념
(실제로 원형으로 변화하는 것은 아니고 선형 큐와 마찬가지로 1차원 배열)</p>
<ul>
<li>선형 큐의 문제점을 보안</li>
<li>선형 큐에서 간단하게 변경 가능</li>
</ul>
<h3 id="덱deque">덱(deque)</h3>
<p>덱(deque): double-ended queue</p>
<blockquote>
<p> front와 rear에서 삽입 삭제가 가능한 큐</p>
</blockquote>
<ul>
<li>스택과 큐의 연산들을 모두 가지고 있음</li>
<li>add_front, delete_front = push, pop</li>
<li>add rear, delete_front = enqueue, dequeue</li>
<li>원형 큐에서 확장하면 손쉽게 구현</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 스택]]></title>
            <link>https://velog.io/@hyun_woo/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%8A%A4%ED%83%9D</link>
            <guid>https://velog.io/@hyun_woo/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%8A%A4%ED%83%9D</guid>
            <pubDate>Wed, 05 Feb 2025 01:15:06 GMT</pubDate>
            <description><![CDATA[<p>스택은 LIFO: Last-In First-Out (후입선출) 이다.</p>
<p>즉 스택은 자료의 출력순서가 입력순서의 역순으로 이루어져야 할 경우에 적합한 자료구조이다.</p>
<p>스택의 대표적인 예로는 다음이 있다.</p>
<ul>
<li>운영체제가 사용하는 시스템 스택</li>
<li>텍스트 에디터 되돌리기 기능</li>
<li>스마트폰 되돌리기 기능</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[{exit(0), exit(1), return} difference]]></title>
            <link>https://velog.io/@hyun_woo/exit0-exit1-return-difference</link>
            <guid>https://velog.io/@hyun_woo/exit0-exit1-return-difference</guid>
            <pubDate>Tue, 04 Feb 2025 07:23:30 GMT</pubDate>
            <description><![CDATA[<pre><code>exit(0) = 정상종료
exit(1) = 비정상종료
따라서 C언어에서 main 함수 안에 있는 return과 exit(0)는 같다.</code></pre><p>return과 exit(1) 둘 다 프로그램을 종료 시킬 수 있지만</p>
<blockquote>
<p>프로그램을 즉시 종료해야할 때 는 exit(1) 을 사용하는 것이 바람직하다.
ex) 치명적인 오류가 발생하여 더 이상 실행할 필요가 없을 경우 전체 프로그램을 종료</p>
</blockquote>
<p><strong>하지만 메모리 누수나 흐름 제어 문제를 유발할 수 있으므로 신중히 사용해야 한다.</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Git] branch]]></title>
            <link>https://velog.io/@hyun_woo/Git-branch</link>
            <guid>https://velog.io/@hyun_woo/Git-branch</guid>
            <pubDate>Mon, 03 Feb 2025 05:54:34 GMT</pubDate>
            <description><![CDATA[<h3 id="branch">branch</h3>
<p>새로운 기능을 개발하거나 버그를 수정할 때 별도의 브랜치를 만들어 독립적으로 작업할 수 있다.</p>
<p>✅ 브랜치를 사용하면 여러 명이 동시에 다른 작업을 진행하면서도, 안정적인 코드를 유지할 수 있음</p>
<ul>
<li>브랜치 목록 확인</li>
</ul>
<pre><code class="language-bash">git branch</code></pre>
<ul>
<li><p>새로운 브랜치 생성</p>
<pre><code class="language-bash">git branch 브랜치이름</code></pre>
</li>
<li><p>브랜치 삭제</p>
<pre><code class="language-bash">git branch -d 브랜치이름</code></pre>
</li>
<li><p>브랜치 전환</p>
<pre><code class="language-bash">git checkout 브랜치이름</code></pre>
</li>
</ul>
<h3 id="merge">merge</h3>
<pre><code class="language-bash">git merge 브랜치이름</code></pre>
<p>두 브랜치가 공통으로 갖고 있는 commit을 base라고 한다.</p>
<h4 id="fast-foword-merge">fast-foword merge</h4>
<ul>
<li><p>Fast-Forward Merge는 병합하려는 브랜치가 다른 브랜치의 직선상에 있는 경우 발생</p>
</li>
<li><p>즉, 병합 대상 브랜치가 다른 브랜치의 최신 커밋을 포함한 직선적 역사일 때</p>
</li>
<li><p>새로운 병합 커밋을 만들지 않고, 브랜치 포인터만 이동하여 병합을 완료</p>
</li>
</ul>
<h4 id="3-way-merge">3-way merge</h4>
<ul>
<li><p>3-Way Merge는 두 브랜치가 서로 다른 커밋을 포함하고 있을 때 발생</p>
</li>
<li><p>즉, 두 브랜치가 공통 조상 커밋 이후에 각각 다른 변경이 이루어진 경우</p>
</li>
<li><p>이때 Git은 세 개의 커밋(공통 조상, 첫 번째 브랜치의 최신 커밋, 두 번째 브랜치의 최신 커밋)을 비교하여 병합을 수행</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[GIT] 원격 저장소]]></title>
            <link>https://velog.io/@hyun_woo/GIT-%EC%9B%90%EA%B2%A9-%EC%A0%80%EC%9E%A5%EC%86%8C</link>
            <guid>https://velog.io/@hyun_woo/GIT-%EC%9B%90%EA%B2%A9-%EC%A0%80%EC%9E%A5%EC%86%8C</guid>
            <pubDate>Mon, 03 Feb 2025 04:14:57 GMT</pubDate>
            <description><![CDATA[<p>github와 사용하기 위해서는 로컬 저장소와 원격 저장소를 연동하는 작업이 필요하다.</p>
<h3 id="원격-저장소-등록하기">원격 저장소 등록하기</h3>
<pre><code class="language-bash">git remote add 원격저장소이름 원격저장소주소</code></pre>
<p>참 고 : origin
원격 저장소의 이름을 orgin으로 지정하면 된다. master와 마찬가지로 git 공식 명칭은 아니지만 원격 저장소의 이름으로 사용되는 이름이다.</p>
<h3 id="git-push">git push</h3>
<ul>
<li><p>처음 push할 경우</p>
<pre><code class="language-bash">git push -u origin master</code></pre>
<pre><code class="language-bash">git push --set-upstream origin master</code></pre>
</li>
<li><p>이후에</p>
<pre><code class="language-bash">git push</code></pre>
</li>
</ul>
<h3 id="git-pull">git pull</h3>
<ul>
<li>원격 저장소의 최신 변경 사항을 로컬 저장소로 가져와서 병합(Merge) 하는 명령어<pre><code class="language-bash">git pull</code></pre>
</li>
</ul>
<h3 id="git-clone">git clone</h3>
<ul>
<li>원격 저장소를 복제하여 로컬 저장소를 생성(처음 원격 저장소를 받을 때 사용)</li>
</ul>
<pre><code class="language-bash">git clone &lt;원격 저장소 주소&gt;</code></pre>
<h3 id="ignore">.ignore</h3>
<ul>
<li>push를 할 때 여러가지 이유로 add에 포함시키고 싶지 않은 파일을 정의할 수 있음</li>
</ul>
<ol>
<li>git init을 한 폴더에 .gitignore 파일을 생성</li>
<li>양식에 맞게 제외할 파일들을 나열하면 된다.</li>
</ol>
<p>제외할 파일 혹은 폴더의 이름을 적어도 되고 특정 확장자를 전부 제외할 수도 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[GIT] 기본 명령어 (2)]]></title>
            <link>https://velog.io/@hyun_woo/GIT-%EA%B8%B0%EB%B3%B8-%EB%AA%85%EB%A0%B9%EC%96%B4-2</link>
            <guid>https://velog.io/@hyun_woo/GIT-%EA%B8%B0%EB%B3%B8-%EB%AA%85%EB%A0%B9%EC%96%B4-2</guid>
            <pubDate>Mon, 03 Feb 2025 02:50:19 GMT</pubDate>
            <description><![CDATA[<h3 id="git-diff">git diff</h3>
<ul>
<li>git diff - show change<pre><code class="language-bash">git diff</code></pre>
</li>
</ul>
<h3 id="git-checkout">git checkout</h3>
<ul>
<li>브랜치 전환<pre><code class="language-bash">git checkout 브랜치이름</code></pre>
</li>
<li>특정 커밋 상태로 이동<pre><code class="language-bash">git checkout 커밋해시</code></pre>
<h3 id="git-reset">git reset</h3>
</li>
<li>Stagint Area에 올라간 파일을 Unstaging (git add 명령 취소)<pre><code class="language-bash">git reset 파일이름</code></pre>
</li>
<li>reset 옵션</li>
<li>soft : 커밋 취소, Staging 상태 유지</li>
<li>mixed : 커밋 취소, Staging 취소, local은 변경 상태로 유지</li>
<li>hard : 커밋취소, Staging 취소, local 변경 상태 취소</li>
</ul>
<h3 id="git-revert">git revert</h3>
<pre><code class="language-bash">git revert 커밋해시</code></pre>
<ul>
<li>지정한 커밋의 변경 사항을 취소하는 새로운 커밋을 생성</li>
<li>기존 커밋 히스토리는 유지됨</li>
<li>협업 중에 과거 커밋을 되돌릴 때 안전한 방법</li>
</ul>
<h3 id="git-tag">git tag</h3>
<p>git에서 관리하는 tag는 다음 두 가지가 있다.</p>
<ul>
<li>Lightweight tag : tag 이름만 기록</li>
<li>Annotated tag : tag 이름 외에 설명(메시지), 서명, 작성자 정보, 날짜 등의 정보 포함</li>
</ul>
<p>Lightweight tag는 특정 commit을 참조하는 포인터와 같은 기능만 가진다. 반면 Annotated tag는 참조 외에 다양한 내용을 포함하므로 git 내부 데이터베이스에 정보가 저장된다.</p>
<p>태그 목록 확인</p>
<pre><code class="language-bash">git tag</code></pre>
<p>Lightweight 태그 생성</p>
<pre><code class="language-bash">git tag 태그이름 커밋해시</code></pre>
<p>Annotated tag</p>
<pre><code class="language-bash">git tag -a [tag명] [commit hash]</code></pre>
<h4 id="원격-저장소에도-태그-push">원격 저장소에도 태그 push</h4>
<pre><code class="language-bash">git push --tags</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[GIT] 기본 명령어]]></title>
            <link>https://velog.io/@hyun_woo/GIT-%EA%B8%B0%EB%B3%B8-%EB%AA%85%EB%A0%B9%EC%96%B4</link>
            <guid>https://velog.io/@hyun_woo/GIT-%EA%B8%B0%EB%B3%B8-%EB%AA%85%EB%A0%B9%EC%96%B4</guid>
            <pubDate>Mon, 03 Feb 2025 02:18:35 GMT</pubDate>
            <description><![CDATA[<h3 id="git-add">git add</h3>
<ul>
<li>특정 파일만 add<pre><code class="language-bash">git add 파일명</code></pre>
</li>
<li>한번에 add<pre><code class="language-bash">git add .</code></pre>
</li>
</ul>
<h3 id="git-status">git status</h3>
<ul>
<li>git에 의해 관리되는 파일들의 상태를 확인하는 명령어<pre><code class="language-bash">git status</code></pre>
</li>
</ul>
<h3 id="git-commit">git commit</h3>
<ul>
<li><p>에디터로 진입하여 commit 메세지를 입력</p>
<pre><code class="language-bash">git commit</code></pre>
</li>
<li><p>에디터 없이 commit 메세지를 입력</p>
<pre><code class="language-bash">git commit -m &quot;메세지 내용&quot;</code></pre>
</li>
</ul>
<h3 id="한번에-add와-commit">한번에 add와 commit</h3>
<ul>
<li>새로 추가된 파일이 없을 때 한정하여 사용<pre><code class="language-bash">git commit -am &quot;메세지 내용&quot;</code></pre>
</li>
</ul>
<h3 id="git-log">git log</h3>
<ul>
<li>commit 히스토리를 조회하는 기능<pre><code class="language-bash">git log</code></pre>
</li>
<li>한줄로 보기<pre><code class="language-bash">git log --onelint</code></pre>
</li>
<li>그래프 형태로 브랜치 파악<pre><code class="language-bash">git log --graph</code></pre>
</li>
<li>모든 브랜치 파악<pre><code class="language-bash">git log --all --graph --decorate --oneline</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[GIT] 시작하기]]></title>
            <link>https://velog.io/@hyun_woo/Git</link>
            <guid>https://velog.io/@hyun_woo/Git</guid>
            <pubDate>Fri, 24 Jan 2025 01:59:24 GMT</pubDate>
            <description><![CDATA[<h3 id="git-시작하기">git 시작하기</h3>
<ul>
<li>git init<pre><code class="language-bash">git init</code></pre>
</li>
</ul>
<ol>
<li>git init은 새로운 git 저장소를 생성하고 초기화하는 명령어이다.</li>
<li>git init 명령어를 실행하면 폴더에 .git이라는 숨긴 레포지토리를 생성한다.</li>
</ol>
<ul>
<li>git config<pre><code class="language-bash">git config user.name &quot;User1&quot;
git config user.email &quot;User1@gmail.com&quot;</code></pre>
git config는 유저설정하는 명령어이다.</li>
</ul>
<h3 id="git의-동작개념">git의 동작개념</h3>
<p>git은 3가지의 작업 영역을 갖고 있다.</p>
<ul>
<li>Working Directory : 작업하고 있는 파일들이 위치하는 영역</li>
<li>Staging Area : commit 하기 전 commit 할 파일들이 위치하는 영역</li>
<li>Repository : 이력이 기록된 파일들이 위치하는 영역
<img src="https://velog.velcdn.com/images/hyun_woo/post/64945fe0-c2e1-4998-9c5a-809c3681b2a9/image.jpg" alt=""></li>
</ul>
<p>여기서 staging Area는 별도의 폴더 공간이 있는 것은 아니라 index 파일로 관리 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 순환]]></title>
            <link>https://velog.io/@hyun_woo/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9E%AC%EA%B7%80%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@hyun_woo/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9E%AC%EA%B7%80%ED%95%A8%EC%88%98</guid>
            <pubDate>Sat, 18 Jan 2025 11:11:46 GMT</pubDate>
            <description><![CDATA[<h1 id="순환">순환</h1>
<h2 id="순환이란">순환이란?</h2>
<p><strong>순환</strong>이란 어떤 알고리즘이나 함수가 자기 자신을 호출하여 문제를 해결하는 프로그래밍 기법이다.</p>
<p>순환은 본질적으로 순환적인 문제나 그러한 자료구조를 다루는 프로그램에 적합하다. </p>
<ul>
<li><p>장점
순환은 어떤 문제에서는 반복에 비해 알고리즘을 훨씬 명확하고 간결하게 나타낼 수 있다.</p>
</li>
<li><p>단점</p>
</li>
<li><p>일반적으로 순환은 함수 호출을 하게 되므로 반복에 비해 수행속도 면에서는 떨어진다.
(물론 순환이 반복보다 빠른 예제도 존재하긴 한다.)</p>
</li>
<li><p>순환 호출시에는 호출이 일어날 때마다 호출하는 함수의 상태를 기억되어야 하므로 여분의 기억장소가 필요하다.</p>
</li>
</ul>
<p>순환 시에는 반드시 순환 호출을 멈추는 문장이 필요하다. 만약 멈추는 문장이 없다면 무한히 순환 호출을 하게 되어 결국 오류를 발생시키기 때문이다.</p>
<h2 id="순환-호출의-내부">순환 호출의 내부</h2>
<ul>
<li><p>하나의 함수가 자기 자신을 다시 호출하는 것은 다른 함수를 호출하는 것과 동일</p>
</li>
<li><p>복귀주소가 시스템 스택에 할당되고, 호출되는 함수를 위한 매개변수(parameter)와 지역 변수를 스택으로부터 할당 받음</p>
</li>
<li><p>호출된 함수의 코드의 시작 위치로 점프(만약, 호출된 함수가 자기 자신이라면 자기 자신의 시작 주소로 점프)</p>
</li>
<li><p>호출된 함수가 끝나게 되면 시스템 스택에 복귀 주소를 호출하여 호출한 함수로 되돌아가게 됨</p>
</li>
</ul>
<h2 id="순환의-원리">순환의 원리</h2>
<p>분할 정복(divide and conquer): 주어진 문제를 더 작은 동일한 문제들로 분해하여 해결하는 방법</p>
<h1 id="순환-예제">순환 예제</h1>
<h2 id="팩토리얼-계산">팩토리얼 계산</h2>
<pre><code class="language-c">int factorial(int n)
{
    if (n &lt;= 1) return(1);
    else return (n * factorial(n - 1));
}</code></pre>
<h2 id="거듭제곱값-계산">거듭제곱값 계산</h2>
<p>지수법칙을 이용하여 효율적으로 작성하였다.
<img src="https://velog.velcdn.com/images/hyun_woo/post/eab3c80f-8c62-4463-ada2-3bb2822919e4/image.png" alt="">
위의 지수의 덧셈 성질을 이용하여 </p>
<blockquote>
</blockquote>
<p>2^8 = 2^4 + 2^4
2^9 = 2^4 + 2^4 + 2^1</p>
<blockquote>
<p>a^n = a^(n / 2) + a^(n / 2)</p>
</blockquote>
<pre><code class="language-c">double power(double x, int n)
{
    if(n == 0) return 1;
    else if((n % 2) == 0) return power(x * x, n / 2);
    else return x * power(x * x, (n - 1) / 2);
}</code></pre>
<p>거듭제곱값을 계산하는 프로그램은 반복적인 방법보다 순환적인 방법으로 구현하는 것이 효과적이다. 입력 값이 알고리즘의 반복마다 반씩 줄기 때문에 시간복잡도는 O(log n)이다.</p>
<h2 id="피보나치-수열의-계산">피보나치 수열의 계산</h2>
<pre><code class="language-c">int fib(int n)
{
    if(n == 0) return 0;
    if(n == 1) return 1;
    return (fib(n - 1) + fib(n - 2));
}</code></pre>
<p>피보나치 수열은 정의 자체가 순환적으로 되어있다. 따라서 구현 시에 순환 호출을 사용하는 것이 자연스러운 방법이다. 위 코드는 매우 단순하고 이해하기 쉽지만 매우 비효율적이다.
이유는 중간에 이미 계산되었던 값을 기억하지 않고 다시 계산하기 때문이다.
시간 복잡도도 O(2^n)으로 실질적으로 피보나치 수열은 순환적인 방법으로 계산하는 것이 불가능하다. 따라서 반복적인 방법으로 계산해야 한다.</p>
<h2 id="하노이탑-문제">하노이탑 문제</h2>
<pre><code class="language-c">void hanoi(int n, char from, char tmp, char to)
{
    if(n == 1)
    {
        printf(&quot;원판 1을 %c에서 %c로 옮긴다.\n&quot;, from, to);
    }
    else
    {
        hanoi(n - 1, from, to, tmp);
        printf(&quot;원판 %d를 %c에서 %c로 옮긴다.\n&quot;, n, from, to);
        hanoi(n - 1, tmp, from, to);
    }
}

int main()
{
    hanoi(4, &#39;A&#39;, &#39;B&#39;, &#39;C&#39;);

    return 0;
}</code></pre>
<h1 id="반복적인-형태로-바꾸기-어려운-순환">반복적인 형태로 바꾸기 어려운 순환</h1>
<p>대부분의 순환적인 형태의 코드는 반복적인 형태로도 변환이 가능하다.</p>
<ul>
<li><p>꼬리 순환(tail recursion)은 쉽게 반복적인 형태로 변환이 가능하다.</p>
</li>
<li><p>머리 순환(head recursion)이나 여러 군데에서 순환호출을 하는 경우 반복적인 형태로 바꾸는 것이 쉽지 않다.</p>
</li>
</ul>
<p>만약 알고리즘을 꼬리 순환과 머리 순환 양쪽으로 모두 표현이 가능하다면 꼬리 순환으로 작성하여야 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 알고리즘의 복잡도 분석 방법]]></title>
            <link>https://velog.io/@hyun_woo/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EC%9D%98-%EB%B3%B5%EC%9E%A1%EB%8F%84-%EB%B6%84%EC%84%9D-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@hyun_woo/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EC%9D%98-%EB%B3%B5%EC%9E%A1%EB%8F%84-%EB%B6%84%EC%84%9D-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sat, 18 Jan 2025 07:19:52 GMT</pubDate>
            <description><![CDATA[<h1 id="알고리즘-복잡도-분석">알고리즘 복잡도 분석</h1>
<p>알고리즘 복잡 분석은 코드를 직접 구현하지 않고도 모든 입력을 고려하는 방법이다. 실행 하드웨어나 소프트웨어 환경과는 관계 없이 알고리즘의 효율성을 평가할 수 있다.</p>
<h2 id="시간-복잡도-함수">시간 복잡도 함수</h2>
<p>알고리즘의 수행 시간 분석을 <strong>시간 복잡도(time complexity)</strong> 라고 한다.</p>
<p>연산의 수를 입력의 개수 n의 함수로 나타낸 것을 시간복잡도 함수라고 하고 <strong>T(n)</strong> 이라고 표기한다.</p>
<p>시간 복잡도 함수에서는 차수가 가장 큰 항만을 고려하면 충분하다.</p>
<blockquote>
<p>T(n) = n^2 + n + 1</p>
</blockquote>
<p>여기서  n = 1000  일 때 T(n) 의 값은 1,001,001이고 이중에서 첫 번째 항이 전체의 약 99.9%를 차지한다.</p>
<p>따라서 입력 자료의 개수가 큰 경우에는 차수가 가장 큰 항이 전체의 값을 주도함을 알 수 있다.</p>
<p>따라서 시간 복잡도 함수에서 중요한 것은 n이 증가하였을 때에, 연산의 총횟수가 n에 비례하여 증가하는지, 아니면 n^2의 비례하여 증가하는지, 아니면 다른 증가추세를 가지는지가 더 중요하다.</p>
<h2 id="빅오-표기법">빅오 표기법</h2>
<p>시간 복잡도 함수에서 <strong>불필요한 정보를 제거</strong>하여 알고리즘 분석을 쉽게 할 목적으로 시간 복잡도를 표시하는 방법을 <strong>빅오 표기법</strong>이라고 한다.</p>
<p>빅오 표기법은 n의 값에 따른 함수의 상한값을 나타내는 방법이다.</p>
<p>다음은 빅오 표기법에 의한 알고리즘의 수행시간을 비교한 것이다.</p>
<blockquote>
<p>O(1) &lt; O(log n) &lt; O(n) &lt; O( n * log n) &lt; O(n^2)  &lt; O(2^n) &lt; O(n!)</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/hyun_woo/post/a71b13ff-5cf4-4654-af1a-07883bfa71db/image.jpg" alt=""></p>
<p>여기서 알고리즘이 지수형이나 팩토링얼형의 시간복잡도를 가진다면 사실상 사용할 수 없는 알고리즘이다. 
그 이유는 입력의 개수가 30을 넘으면 현재의 가장 강력한 super computer를 동작시켜도 우주가 탄생되어 지금까지 흘러온 시간보다 더 많은 수행 시간을 요구 하기 때문이다.</p>
<h2 id="그-외-시간복잡도-표기법">그 외 시간복잡도 표기법</h2>
<p>Big-Ω(빅 오메가) 표기법 : 알고리즘 최상의 실행 시간을 표기한다.
Big-θ(빅 세타) 표기법  : 알고리즘 평균 실행 시간을 표기한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 프로그램의 수행 시간 측정 방법]]></title>
            <link>https://velog.io/@hyun_woo/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8%EC%9D%98-%EC%88%98%ED%96%89-%EC%8B%9C%EA%B0%84-%EC%B8%A1%EC%A0%95-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@hyun_woo/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8%EC%9D%98-%EC%88%98%ED%96%89-%EC%8B%9C%EA%B0%84-%EC%B8%A1%EC%A0%95-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sat, 18 Jan 2025 06:39:46 GMT</pubDate>
            <description><![CDATA[<h1 id="clock-함수를-사용한-수행시간-측정">clock() 함수를 사용한 수행시간 측정</h1>
<p>알고리즘의 성능을 분석하고자 할 때 동일한 조건의 컴퓨터에서의 동일한 조건에서 수행시간을 측정하는 방법을 알아보자.</p>
<p>실제 사용할 수 있는 경우는 제한적이지만 대단히 정확하고 확실한 방법이다.</p>
<pre><code class="language-c">#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;time.h&gt;

int main()
{
    clock_t start, stop;
    float duration;
    start = clock(); //측정 시작

    // 측정하고자 하는 프로그램

    stop = clock(); // 측정 종료
    duration = (float)(stop - start) / CLOCK_PER_SEC;
    printf(&quot;수행시간 : %f\n&quot;, duration);

    return 0;
}</code></pre>
<p>clock() 함수는 호출 프로세스에 의하여 사용된 CPU 시간을 계산한다.
또 한 호출 되었을 때의 시스템 시각을 CLOCK_PER_SEC 단위로 반환한다.</p>
<p>이 방법을 사용하여 알고리즘을 비교하려면 반드시 똑같은 하드웨어를 사용하여 알고리즘들의 수행시간을 측정하여야 한다.</p>
<p>그 외에도 프로그래밍 언어, 동일한 데이터 사용 등 고려해야 할 사항이 있다.</p>
]]></description>
        </item>
    </channel>
</rss>