<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>프로그래머가 되고 싶은 감자</title>
    <link>https://2lucesicutstellae.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Fri, 12 Jun 2026 00:06:20 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>김셀리</managingEditor>
    <item>
      <title>[알고리즘] 병합 정렬, 퀵 정렬 (with 재귀 함수)</title>
      <link>https://2lucesicutstellae.tistory.com/33</link>
      <description>&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 재귀함수란&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 분할 정복이란&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 병합 정렬&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;병합 정렬이란&lt;/li&gt;
&lt;li&gt;시간복잡도와 공간복잡도&lt;/li&gt;
&lt;li&gt;구현&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 퀵 정렬&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;퀵 정렬이란&lt;/li&gt;
&lt;li&gt;시간복잡도와 공간복잡도&lt;/li&gt;
&lt;li&gt;구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 재귀 함수 Recursive Function&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;함수 내부에서 자기 자신을 다시 호출&lt;/span&gt;하여 작업을 수행하는 프로그래밍 기법 &lt;span style=&quot;color: #9d9d9d;&quot;&gt;(예: 팩토리얼(Factorial))&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;구성요소
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;기본 사례(Base Case) : 재귀호출을 멈추고 값을 반환하는 &lt;span style=&quot;color: #006dd7;&quot;&gt;종료 조건&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;-&amp;gt; 종료 조건이 없으면 무한 루프에 빠지거나 스택 오버플로우가 발생할 수 있음&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;재귀 사례(Recursive Case) : 함수가 자기 자신을 호출하는 조건 및 연산&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;장점 : 코드 간결. 가독성 굳. 복잡한 알고리즘을 단순한 논리로 표현&lt;/li&gt;
&lt;li&gt;단점 :
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;함수 호출될 때마다 호출 정보가 메모리 스택에 쌓임&lt;/li&gt;
&lt;li&gt;종료 조건이 잘못되거나 데이터가 너무 크면 스택 오버플로우 에러가 발생할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;일반함수와 재귀함수 차이점&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.7519%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 45.3101%; text-align: center;&quot;&gt;일반 함수&lt;/td&gt;
&lt;td style=&quot;width: 41.9379%; text-align: center;&quot;&gt;재귀 함수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.7519%; text-align: center;&quot;&gt;메모리&lt;/td&gt;
&lt;td style=&quot;width: 45.3101%;&quot;&gt;변수 재사용. 추가 메모리 할당 없음&lt;/td&gt;
&lt;td style=&quot;width: 41.9379%;&quot;&gt;호출마다 메모리 새로 할당&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.7519%; text-align: center;&quot;&gt;속도&lt;/td&gt;
&lt;td style=&quot;width: 45.3101%;&quot;&gt;상대적으로 빠름&lt;/td&gt;
&lt;td style=&quot;width: 41.9379%;&quot;&gt;함수 호출 오버헤드로 상대적으로 느림&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.7519%; text-align: center;&quot;&gt;위험성&lt;/td&gt;
&lt;td style=&quot;width: 45.3101%;&quot;&gt;무한 루프 시 CPU 점유율이 올라갈 수 있으나 메모리 에러는 드묾&lt;/td&gt;
&lt;td style=&quot;width: 41.9379%;&quot;&gt;종료 조건이 없으면 스택 오버플로우(메모리 부족)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 분할 정복 Divide and Conquer&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;분할(Divide)&lt;/b&gt; : 해결하기 힘든 거대한 문제를 유사한 형태의 여러 하위 문제로 쪼개고&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;정복(Conquer)&lt;/b&gt; : 각각을 재귀적으로 해결한 뒤&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;결합(Combine) &lt;/b&gt;: 그 결과를 합쳐&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;최종 해답을 얻어내는 알고리즘 설계 기법&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;분할 정복을 활용한 알고리즘 : 병합 정렬(합병 정렬), 퀵 정렬, 이진 탐색, 거듭제곱 연산&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;장점 : 복잡하고 거대한 문제를 효율적으로 해결 가능&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;단점 : 재귀 함수 사용으로 스택 오버플로우가 발생할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 병합 정렬 Merge Sort&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2188&quot; data-origin-height=&quot;1371&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OK2sY/dJMcabxI7zK/0muxBJyMU0kzdId571w9o0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OK2sY/dJMcabxI7zK/0muxBJyMU0kzdId571w9o0/img.png&quot; data-alt=&quot;병합 정렬&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OK2sY/dJMcabxI7zK/0muxBJyMU0kzdId571w9o0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOK2sY%2FdJMcabxI7zK%2F0muxBJyMU0kzdId571w9o0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;570&quot; height=&quot;357&quot; data-origin-width=&quot;2188&quot; data-origin-height=&quot;1371&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;병합 정렬&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 병합 정렬이란&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 큰 문제를 &lt;span style=&quot;color: #006dd7;&quot;&gt;두 개의 작은 문제로 분할&lt;/span&gt;한 뒤 각자 계산하고 &lt;span style=&quot;color: #006dd7;&quot;&gt;나중에 합치는&lt;/span&gt; 방법&lt;/li&gt;
&lt;li&gt;동작 방식
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;배열의 길이는 최소 1보다 커야 한다. &lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(= &lt;span style=&quot;text-align: start;&quot;&gt;배열 길이가 1 이하이면 이미 정렬된 것으로 본다.)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;분할(Divide)&lt;/b&gt; : 정렬되지 않은 배열을 절반으로 잘라 비슷한 크기의 두 파티션으로 나눈다. (원소가 2개가 남을 때까지 분할)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;정복(Conquer)&lt;/b&gt; : 분할이 완료되면 나눈 각 파티션을 재귀적으로 호출해 정렬한다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;결합(Combine)&lt;/b&gt; : 정렬이 완료되면 나누었던 두 파티션을 하나의 정렬된 배열로 병합한다. (이 때 정렬된 배열이 임시 배열에 저장된다)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;복사(Copy)&lt;/b&gt; : 임시 배열에 저장된 결과를 원래 배열에 복사한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;장점 :
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;연결리스트를 사용할 경우, 링크 인덱스만 변경하면 되므로 이동 연산이 줄어듦 (추가 메모리가 필요하지 않음)&lt;/li&gt;
&lt;li&gt;퀵 정렬과 비교했을 때 데이터 분포에 영향을 받지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단점 :&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;배열을 사용할 경우, 추가적인 메모리(임시 배열)이 필요&lt;/li&gt;
&lt;li&gt;이동 연산이 많아, 레코드 개수가 클 경우에는 비효율적&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 시간복잡도와 공간복잡도&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시간복잡도 : O(n log n)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;배열의 개수가 1개가 될 때까지 분할 하므로 n번의 합병&lt;/li&gt;
&lt;li&gt;각 합병 단계마다 원소 개수 만큼의 비교와 이동이 이루어짐&lt;/li&gt;
&lt;li&gt;배열을 반씩 분할해가며 정렬&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;공간복잡도 : O(n)&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;데이터 개수가 n일 때, 정렬과정에서 추가적 메모리(임시 배열) 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 구현&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;크게 분할 및 정복을 수행하는 함수(merge_sort)와 결합(merge)을 수행하는 함수로 나눈다&lt;/li&gt;
&lt;li&gt;merge_sort를 먼저 만든다&lt;/li&gt;
&lt;li&gt;배열의 길이가 1이 될 때까지 재귀함수를 호출한다&lt;/li&gt;
&lt;li&gt;비슷한 크기로 나누기 위해 mid 변수를 생성한다&lt;/li&gt;
&lt;li&gt;mid를 기준으로 배열을 left, right로 나눠 임시 저장한다&lt;/li&gt;
&lt;li&gt;left와 right를 계속 분할한다&lt;/li&gt;
&lt;li&gt;merge 함수를 사용해 최종 정렬을 해준다&lt;/li&gt;
&lt;li&gt;배열의 길이가 1이라면 배열 그대로 반환한다&lt;/li&gt;
&lt;li&gt;merge를 만든다&lt;/li&gt;
&lt;li&gt;마지막으로 최종 정렬된 결과를 담을 리스트 변수(result)를 하나 생성한다&lt;/li&gt;
&lt;li&gt;left, right의 각 배열의 현재 위치를 가리키는 인덱스를 생성한다&lt;/li&gt;
&lt;li&gt;left 배열의 인덱스가 배열 길이보다 작고, right 배열의 인덱스도 배열 길이보다 작은 동안 반복한다&lt;/li&gt;
&lt;li&gt;left, right 배열의 값을 비교하고 더 작은&amp;nbsp; 값을 result에 넣고 인덱스에 1을 더한다 (다음 데이터로)&lt;/li&gt;
&lt;li&gt;result에 나머지 배열을 모두 담고 반환한다&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1781164085569&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 합병 정렬
# 1. 분할 및 정복 함수
def merge_sort(arr):
    if len(arr) &amp;gt; 1:
        mid = len(arr) // 2

        left = arr[:mid]
        right = arr[mid:]

        return merge(merge_sort(left), merge_sort(right))
    return arr

# 2. 결합 함수
def merge(left, right):
    result = []     # 최종 정렬된 결과를 담을 리스트
    i, j = 0, 0     # 각 배열의 현재 위치를 가리키는 인덱스

    while i &amp;lt; len(left) and j &amp;lt; len(right):
        if left[i] &amp;lt; right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1

    result = result + left[i:]      # if문으로 만들어도 좋음
    result = result + right[j:]

    return result

# 합병 정렬 수행
print(merge_sort([3, 1, 4, 1, 5]))  # [1, 1, 3, 4, 5]
print(merge_sort([5, 4, 3, 2, 1]))  # [1, 2, 3, 4, 5]
print(merge_sort([1]))              # [1]&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 퀵 정렬 Quick Sort&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1364&quot; data-origin-height=&quot;1960&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blaFUZ/dJMcadoJtEh/gakWTmMb9lDkLQ29v855P1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blaFUZ/dJMcadoJtEh/gakWTmMb9lDkLQ29v855P1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blaFUZ/dJMcadoJtEh/gakWTmMb9lDkLQ29v855P1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblaFUZ%2FdJMcadoJtEh%2FgakWTmMb9lDkLQ29v855P1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;426&quot; height=&quot;612&quot; data-origin-width=&quot;1364&quot; data-origin-height=&quot;1960&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 퀵 정렬이란&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;불안정 정렬에 속하며, 다른 원소와의 비교만으로 매우 빠르게 정렬을 수행하는 알고리즘&lt;/li&gt;
&lt;li&gt;동작방식
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;피벗을 지정한다.&lt;br /&gt;(첫 번째 원소, 마지막 원소, 중간값, 무작위, 듀얼 피벗)&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;분할(Divide)&lt;/b&gt; : 배열을 피벗 기준으로 비균등하게 2개의 부분 배열로 분할한다.&lt;br /&gt;-&amp;gt; 피벗을 중심으로 왼쪽: 피벗보다 작은 요소들 / 오른쪽: 피벗보다 큰 요소들&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;정복(Conquer)&lt;/b&gt; : 부분 배열을 정렬한다. 부분 배열의 크기가 충분히 작지 않으면 순환 호출을 이용하여 다시 분할 정복 방법을 적용한다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;결합(Combine)&lt;/b&gt; : 정렬된 부분 배열들을 하나의 배열로 합병한다.&lt;/li&gt;
&lt;li&gt;배열 크기가 0이나 1이 될 때까지 반복한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;장점 : 배열 내에서 교환하는 방식(제자리 정렬)으로 추가적인 메모리 공간을 필요로 하지 않음&lt;/li&gt;
&lt;li&gt;단점 : 정렬된 배열에 대해서는 불균형 분할로 인해 더 오랜 시간이 소요됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 시간복잡도와 공간복잡도&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시간복잡도 : 평균 O(n log n)&amp;nbsp; &amp;nbsp; /&amp;nbsp; &amp;nbsp; 최악 &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;O(n&amp;sup2;)&lt;/span&gt; &amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;배열의 개수가 1이 될 때까지 분할하므로 log(n)번 분할&lt;br /&gt;또한 분할할 때마다 피벗 기준으로 정렬되기 때문에, n번의 비교 연산이 이루어짐 -&amp;gt; 평균 O(n log n)&lt;/li&gt;
&lt;li&gt;이미 정렬된 배열일 경우 분할이 n번만큼 이루어짐 -&amp;gt;&amp;nbsp; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;최악&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;O(n&amp;sup2;)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;공간복잡도 : O(n)&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;데이터 개수가 n일 때, 주어진 배열 내에서 교환이 이루어짐&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 구현&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;병합 정렬과 마찬가지로 배열의 길이가 1이 될 때까지 반복한다&lt;/li&gt;
&lt;li&gt;배열의 첫 요소를 피벗으로 선택하고 저장할 변수(p)를 생성한다&lt;/li&gt;
&lt;li&gt;리스트 컴프리헨션을 사용하여 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;left 배열에는&lt;span&gt; p보다 작은 수들을, middle에는 p와 같은 수들을, right 배열에는 p보다 큰 수들을 담는다&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;이를 반복한다&lt;/li&gt;
&lt;li&gt;left, middle, right를 병합하여 리턴한다&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1781164113787&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# 퀵 정렬
def quick_sort(arr):
    if len(arr) &amp;gt; 1:
        p = arr[0]      # 배열의 첫 요소를 피벗으로 선택

        left = [x for x in arr if x &amp;lt; p]
        middle = [x for x in arr if x == p]
        right = [x for x in arr if x &amp;gt; p]

        return quick_sort(left) + middle + quick_sort(right)
    return arr

print(quick_sort([3, 1, 4, 1, 5]))  # [1, 1, 3, 4, 5]&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 정렬 알고리즘들은 코드를 읽어보기만 했지 직접 구현해보는 것은 처음이었다. 이번 과제도 시간이 꽤 소요되었지만 그만큼 분명 얻어가는 것은 있다. 재귀 함수는 당연히 종료 조건이 있어야 한다. 알고리즘 수업에서 종료 조건을 채우는 문제를 틀렸던 기억 덕분에 잘 기억하고 있었다. 분할 정복이라는 개념도 알고 있었지만 한 번 더 정리하여 어떤 알고리즘에 쓰이는지 확실하게 알게 되었다.&amp;nbsp;&lt;/p&gt;</description>
      <category>KDT/과제</category>
      <category>mergesort</category>
      <category>quicksort</category>
      <category>reculsivefunction</category>
      <category>병합정렬</category>
      <category>재귀함수</category>
      <category>퀵정렬</category>
      <author>김셀리</author>
      <guid isPermaLink="true">https://2lucesicutstellae.tistory.com/33</guid>
      <comments>https://2lucesicutstellae.tistory.com/33#entry33comment</comments>
      <pubDate>Thu, 11 Jun 2026 23:28:47 +0900</pubDate>
    </item>
    <item>
      <title>[알고리즘] 버블 정렬, 선택 정렬, 삽입 정렬</title>
      <link>https://2lucesicutstellae.tistory.com/32</link>
      <description>&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 정렬 알고리즘이란&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 버블 정렬&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정의&lt;/li&gt;
&lt;li&gt;오름차순/내림차순 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 선택 정렬&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정의&lt;/li&gt;
&lt;li&gt;오름차순/내림차순 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 삽입 정렬&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정의&lt;/li&gt;
&lt;li&gt;오름차순/내림차순 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5.r&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;andom 데이터를 생성하여 성능 비교&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 정렬 알고리즘&amp;nbsp; Sorting Algorithm&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;졍렬 : 데이터를 &lt;span style=&quot;color: #006dd7;&quot;&gt;어떤 기준(오름차순, 내림차순 등)에 따라 순서대로&lt;/span&gt; 나열&lt;/li&gt;
&lt;li&gt;정렬 알고리즘으로 데이터를 정렬하면 이진 탐색이 가능&lt;/li&gt;
&lt;li&gt;종류
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비교 기반 정렬 : 데이터를 서로 비교하여 정렬하는 정렬 &lt;span style=&quot;color: #9d9d9d;&quot;&gt;ex.버블, 선택, 삽입, 병합, 퀵, 힙&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;비비교 기반 정렬 : 데이터 간의 직접적인 비교없이 정렬 &lt;span style=&quot;color: #9d9d9d;&quot;&gt;ex. 계수, 기수&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. &lt;/b&gt;&lt;b&gt;버블 정렬 Bubble Sort&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 버블 정렬이란&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2646&quot; data-origin-height=&quot;1772&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lWo6z/dJMcafUtlgP/O6HOsrkiyyKGmDx6D9KkAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lWo6z/dJMcafUtlgP/O6HOsrkiyyKGmDx6D9KkAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lWo6z/dJMcafUtlgP/O6HOsrkiyyKGmDx6D9KkAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlWo6z%2FdJMcafUtlgP%2FO6HOsrkiyyKGmDx6D9KkAK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;558&quot; height=&quot;374&quot; data-origin-width=&quot;2646&quot; data-origin-height=&quot;1772&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;인접한 두 원소를 비교&lt;/span&gt;하여 자리 교환&lt;/li&gt;
&lt;li&gt;장점 : 구현이 매우 간단&lt;/li&gt;
&lt;li&gt;단점 : 하나의 요소가 왼쪽에서 가장 오른쪽으로 이동하기 위해 배열의 모든 요소들과 교환되어야 함&lt;/li&gt;
&lt;li&gt;시간복잡도 : O(n&amp;sup2;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;2. 오름차순 구현&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;매개변수로 배열을 받아온다&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;바깥 루프는 (배열길이) - 1 만큼 돌면 된다&lt;br /&gt;- 마지막 남은 요소는 자동으로 위치가 정해지기 때문이다 &lt;br /&gt;- 한 번 돌 때마다 가장 큰 수가 맨 뒤로 확정된다&lt;br /&gt;- 확정된 숫자 제외한만큼 안쪽 루프 수행하면 된다&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;안쪽 루프는 j번째와 j+1번째를 비교하는데, j+1이 범위를 넘으면 안되므로 (배열길이) - i - 1 이 된다&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;j번째와 j+1번째의 데이터를 비교하여 왼쪽 데이터가 더 크면 자리를 swap&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;정렬된 배열을 반환한다&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1781077538547&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 버블 정렬 - 오름차순
def bubble_sort_asc(arr):
    for i in range(len(arr) - 1):
        for j in range(len(arr) - i - 1):
            if arr[j] &amp;gt; arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]
    return arr

arr = [3, 6, 9, 2, 8, 6, 11, 10]
print(bubble_sort_asc(arr))		# [2, 3, 6, 6, 8, 9, 10, 11]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;3. 내림차순 구현 &lt;/b&gt;: &lt;/span&gt;오름차순에서 조건문만 변경해주면 쉽게 구현 가능&lt;/p&gt;
&lt;pre id=&quot;code_1781077548641&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 버블 정렬 - 내림차순
def bubble_sort_desc(arr):
    for i in range(len(arr) - 1):
        for j in range(len(arr) - i - 1):
            if arr[j] &amp;lt; arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]
    return arr

arr = [3, 6, 9, 2, 8, 6, 11, 10]
print(bubble_sort_desc(arr))		# [11, 10, 9, 8, 6, 6, 3, 2]&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 선택 정렬 Selection Sort&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 선택 정렬이란&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1786&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2T4tC/dJMcaicChAV/kPtQFMSdsr7HN8KZrRYKz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2T4tC/dJMcaicChAV/kPtQFMSdsr7HN8KZrRYKz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2T4tC/dJMcaicChAV/kPtQFMSdsr7HN8KZrRYKz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2T4tC%2FdJMcaicChAV%2FkPtQFMSdsr7HN8KZrRYKz0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;347&quot; height=&quot;484&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1786&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;처리되지 않은 데이터 중,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;가장 작은 데이터(또는 가장 큰 데이터)&lt;/span&gt;를 선택해 맨 앞에 있는 데이터와 바꾸는 것 반복&lt;/li&gt;
&lt;li&gt;장점 : 알고리즘이 단순하고 구현이 쉬움&lt;/li&gt;
&lt;li&gt;단점 : 배열이 길어질수록 시간이 지수적으로 증가하여 비효율&lt;/li&gt;
&lt;li&gt;시간복잡도 : O(n&amp;sup2;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;2. 오름차순 구현&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;매개변수로 배열을 받아온다&lt;/li&gt;
&lt;li&gt;바깥 루프는 (배열길이) - 1 만큼 돈다&lt;br /&gt;- 마지막 남은 요소는 자동으로 위치가 정해지기 때문이다&lt;/li&gt;
&lt;li&gt;바깥 루프 내부에서 최솟값의 인덱스를 담을 변수(min)를 i로 초기화한다&lt;/li&gt;
&lt;li&gt;안쪽 루프는 이미 정렬된 i 까지의 요소를 제외하고 i+1부터 배열의 끝까지 돈다&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;span&gt;안쪽 루프를 돌면서 arr[j]가 arr[min]보다 작으면(오름차순) &lt;/span&gt;&lt;/span&gt;&lt;span&gt; min을 j로 갱신한다&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;min 인덱스 갱신 후 안쪽 루프 밖에서 min 인덱스에 해당하는 요소와 현재 요소의 자리를 swap&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;정렬된 배열을 반환한다&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1781078531564&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 선택 정렬 - 오름차순
def selection_sort_asc(arr):
    for i in range(len(arr) - 1):
        min = i
        for j in range(i + 1, len(arr)):
            if arr[min] &amp;gt; arr[j]:
                min = j
        arr[min], arr[i] = arr[i], arr[min]
    return arr

arr = [3, 6, 9, 2, 8, 6, 11, 10]
print(selection_sort_asc(arr))      # [2, 3, 6, 6, 8, 9, 10, 11]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;3. 내림차순 구현&amp;nbsp;&lt;/b&gt;: 오름차순에서 조건문만 변경해주면 쉽게 구현 가능 &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1781079046981&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 선택 정렬 - 내림차순
def selection_sort_desc(arr):
    for i in range(len(arr) - 1):
        min = i
        for j in range(i + 1, len(arr)):
            if arr[min] &amp;lt; arr[j]:
                min = j
        arr[min], arr[i] = arr[i], arr[min]
    return arr

arr = [3, 6, 9, 2, 8, 6, 11, 10]
print(selection_sort_desc(arr))      # [11, 10, 9, 8, 6, 6, 3, 2]&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 삽입 정렬 Insertion Sort&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 삽입 정렬이란&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2818&quot; data-origin-height=&quot;3736&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/G0nCQ/dJMcaf1aUhT/YWLmCoogSbQs4uJJH8a6u1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/G0nCQ/dJMcaf1aUhT/YWLmCoogSbQs4uJJH8a6u1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/G0nCQ/dJMcaf1aUhT/YWLmCoogSbQs4uJJH8a6u1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FG0nCQ%2FdJMcaf1aUhT%2FYWLmCoogSbQs4uJJH8a6u1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;657&quot; height=&quot;871&quot; data-origin-width=&quot;2818&quot; data-origin-height=&quot;3736&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 데이터를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;적절한 위치에&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;삽입&lt;/li&gt;
&lt;li&gt;특정 데이터가 적절 위치에 들어가기 이전에 그 앞까지의 데이터는 이미 정렬되어 있다고 가정&lt;/li&gt;
&lt;li&gt;장점 : 실행 시간 측면에서 효율적&lt;/li&gt;
&lt;li&gt;단점 : 선택 정렬에 비해 구현 난이도가 높음&lt;/li&gt;
&lt;li&gt;시간복잡도 : O(n&amp;sup2;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;2. 오름차순 구현&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;매개변수로 배열을 받아온다&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;외부 루프는 배열의 두번째 요소부터 마지막 요소까지 돈다&lt;br /&gt;- 두 번째 요소부터 바로 왼쪽 요소와 비교하며 자리를 바꿀 것이기 때문이다&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;내부 루프는 현재 인덱스부터 맨 처음 인덱스까지 돈다&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;현재 인덱스의 데이터와 바로 왼쪽 인덱스의 데이터를 비교하여 조건에 맞으면 swap&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;정렬된 배열을 반환한다&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1781079207942&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 삽입 정렬 - 오름차순
def insertion_sort_asc(arr):
    for i in range(1, len(arr)):
        for j in range(i, 0, -1):
            if arr[j] &amp;lt; arr[j-1]:
                arr[j-1], arr[j] = arr[j], arr[j-1]
    return arr
        
arr = [3, 6, 9, 2, 8, 6, 11, 10]
print(insertion_sort_asc(arr))      # [2, 3, 6, 6, 8, 9, 10, 11]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;3. 내림차순 구현 &lt;/b&gt;: 오름차순에서 조건문만 변경해주면 쉽게 구현 가능 &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1781079221472&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 삽입 정렬 - 내림차순def insertion_sort_desc(arr):
    for i in range(1, len(arr)):
        for j in range(i, 0, -1):
            if arr[j] &amp;gt; arr[j-1]:
                arr[j-1], arr[j] = arr[j], arr[j-1]
    return arr

arr = [3, 6, 9, 2, 8, 6, 11, 10]
print(insertion_sort_desc(arr))     # [11, 10, 9, 8, 6, 6, 3, 2]&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. random 데이터를 생성하여 성능 비교&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;랜덤값과 시간측정에 필요한 모듈 import&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;버블, 선택, 삽입 정렬의 오름차순 구현한 코드들을 가져온다&lt;/li&gt;
&lt;li&gt;random 배열 생성한다&lt;br /&gt;- &lt;u&gt;시드&lt;/u&gt;를 사용하여 같은 랜덤 배열로 사용할 수 있도록 한다&lt;br /&gt;- 정렬 함수마다 다른 배열을 정렬하여 비교하게 되면 정확한 성능 비교가 되지 않을 수 있기 때문이다&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;time 모듈로 시작과 끝을 담을 변수를 생성한다&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;의미있는 결과를 위해 범위와 개수를 크게 지정하여 랜덤 배열을 생성&lt;br /&gt;- range(0, 10000) : 0부터 9999까지 숫자 범위&lt;br /&gt;- 5000 : 그중에서 5000개를 뽑기&lt;br /&gt;- sample : 중복없이 랜덤으로 뽑기&lt;/li&gt;
&lt;li&gt;각 정렬 함수들을 실행하여 시간 측정한 결과를 출력한다&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;결과 :
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;버블 정렬과 삽입 정렬은 비슷한 성능이고, 선택 정렬이 조금 더 빠른 것을 확인 할 수 있다&lt;/li&gt;
&lt;li&gt;세 정렬 모두 시간복잡도가 O(n&amp;sup2;)이지만 선택 정렬은 swap 횟수가 적기 때문이다&lt;/li&gt;
&lt;li&gt;swap하는 코드의 위치를 보면&lt;br /&gt;선택 정렬은 바깥 루프 안에서 swap되고&lt;br /&gt;버블과 삽입 정렬은 안쪽 루프 안에서 swap되는 것을 확인할 수 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781081043388&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import random
import time

# 버블 정렬
def bubble_sort_asc(arr):
    for i in range(len(arr) - 1):
        for j in range(len(arr) - i - 1):
            if arr[j] &amp;gt; arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]
    return arr

# 선택 정렬
def selection_sort_asc(arr):
    for i in range(len(arr) - 1):
        min = i
        for j in range(i + 1, len(arr)):
            if arr[min] &amp;gt; arr[j]:
                min = j
        arr[min], arr[i] = arr[i], arr[min]
    return arr

# 삽입 정렬
def insertion_sort_asc(arr):
    for i in range(1, len(arr)):
        for j in range(i, 0, -1):
            if arr[j] &amp;lt; arr[j-1]:
                arr[j-1], arr[j] = arr[j], arr[j-1]
    return arr

random.seed(10)
start = time.time()
arr1= random.sample(range(0, 10000), 5000)
bubble_sort_asc(arr1)
end = time.time()
print(f&quot;버블 정렬 : {(end-start) * 10}&quot;)

random.seed(10)
start = time.time()
arr2= random.sample(range(0, 10000), 5000)
selection_sort_asc(arr2)
end = time.time()
print(f&quot;선택 정렬 : {(end-start) * 10}&quot;)

random.seed(10)
start = time.time()
arr3= random.sample(range(0, 10000), 5000)
insertion_sort_asc(arr3)
end = time.time()
print(f&quot;삽입 정렬 : {(end-start) * 10}&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[과제 후기]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 조건문을 작성하는 과정에서 오름차순인지 내림차순인지에 따라 값을 비교하는 부분의 부등호를 정하는 것에서 헷갈렸다. 내가 어떤 기준에 의해 정렬할 것인지 (오름/내림) 생각하면서 작성할 필요가 있다. 필요없는 변수를 사용했다가 내부에서 필요가 없어 지운 변수도 있었다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 시간복잡도가 같더라도 성능의 차이가 발생할 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 파이썬 개념 강의에서 배운 random과 seed를 사용해볼 수 있었고, 시간을 측정하는 time 모듈도 사용해볼 수 있었다.&lt;/p&gt;</description>
      <category>KDT/과제</category>
      <category>버블 정렬</category>
      <category>삽입 정렬</category>
      <category>선택 정렬</category>
      <category>알고리즘</category>
      <author>김셀리</author>
      <guid isPermaLink="true">https://2lucesicutstellae.tistory.com/32</guid>
      <comments>https://2lucesicutstellae.tistory.com/32#entry32comment</comments>
      <pubDate>Wed, 10 Jun 2026 22:00:29 +0900</pubDate>
    </item>
    <item>
      <title>[15일차] 웹 개념, HTML, CSS</title>
      <link>https://2lucesicutstellae.tistory.com/31</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 웹 Web&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터넷을 통해 정보를 보고, 읽고, 상호작용할 수 있게 해주는 서비스&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt; HTML&lt;/span&gt;로 만들어진 문서(웹 페이지)를 브라우저(크롬, 사파리 등)가 읽어서 화면에 보여주는 방식으로 작동&lt;/li&gt;
&lt;li&gt;웹은 인터넷 위에서 돌아가는 서비스 중 하나로, 우리가 주소창에 URL을 입력하면 HTTP 같은 프로토콜을 통해 서버에 요청하고, 그 결과를 받아와서 보여주는 구조&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 웹의 작동 방식&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;사용자가 웹 브라우저에 주소(URL) 입력 &lt;span style=&quot;color: #9d9d9d;&quot;&gt;(https://www.example/com)&lt;/span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;DNS 서버가 주소를 IP 주소로 변경&lt;/li&gt;
&lt;li&gt;브라우저가 서버에 요청 전송 (HTTP 요청)
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-end=&quot;636&quot; data-start=&quot;577&quot;&gt;이제 브라우저는 해당 IP 주소를 가진 서버에게 &quot;웹 페이지 보여줘!&quot; 라는 메시지를 전송&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-end=&quot;676&quot; data-start=&quot;637&quot;&gt;이 메시지는 HTTP 요청(Request) 이라고 함&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-end=&quot;694&quot; data-start=&quot;677&quot;&gt;요청은 웹서버에 도착&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-end=&quot;694&quot; data-start=&quot;677&quot;&gt;HTTP의 Port번호 : 80&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;서버가 요청을 받고, 웹 페이지 파일을 응답 (HTTP 응답)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버는 요청을 받으면, 내부에 저장된 HTML, CSS, JavaScript 등의 파일을 찾아서 브라우저에게 전송&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d; text-align: left;&quot;&gt;(HTML: 구조 / CSS: 디자인 / JS: 동작 이 세 가지를 함께 전송)&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-end=&quot;862&quot; data-start=&quot;827&quot;&gt;이걸 HTTP 응답(Response) 이라고 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;브라우저가 파일을 해석해서 화면에 띄움
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-end=&quot;1038&quot; data-start=&quot;966&quot;&gt;브라우저는 서버로부터 받은 HTML, CSS, JS 파일을 읽고 해석해서 웹페이지처럼 화면에 그려줌&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-end=&quot;1087&quot; data-start=&quot;1039&quot;&gt;사용자는 웹사이트를 눈으로 보고, 클릭하고, 입력할 수 있는 상태가 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. DNS (Domain Name System)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;우리가 웹사이트 주소를 입력할 때 사용하는 도메인 이름&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(예: www.example.com)&lt;/span&gt;을&lt;br /&gt;컴퓨터가 이해할 수 있는 IP 주소&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(예: 93.184.216.34)&lt;/span&gt;로 바꿔주는 시스템&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Client와 Server (C/S)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버(Server)와 클라이언트(Client)는 인터넷에서 정보를 주고받는 관계를 설명하는 기본 개념&lt;/li&gt;
&lt;li&gt;클라이언트 : &lt;span style=&quot;color: #006dd7;&quot;&gt;정보를 요청&lt;/span&gt;하는 쪽 &lt;span style=&quot;color: #9d9d9d;&quot;&gt;(ex. 우리가 사용하는 웹 브라우저, 스마트폰 앱)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;서버 : 요청을 받아 &lt;span style=&quot;color: #006dd7;&quot;&gt;정보나 서비스를 제공&lt;/span&gt;하는 쪽 &lt;span style=&quot;color: #9d9d9d;&quot;&gt;(ex. 웹사이트의 본체나 데이터가 저장된 컴퓨터&lt;/span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt; (s/w or h/w)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 최초의 웹 사이트&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1991년, 스위스에 있는 CERN(유럽 입자 물리 연구소)에서 &lt;br /&gt;팀 버너스리(Tim Berners-Lee)라는 과학자에 의해 만들어 짐&lt;/li&gt;
&lt;li&gt;개설&amp;nbsp;시기:&amp;nbsp;1991년&amp;nbsp;8월&amp;nbsp;6일&amp;nbsp;주소(URL):&amp;nbsp;&lt;a href=&quot;http://info.cern.ch/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;http://info.cern.ch/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 웹 서비스&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터넷을 통해 클라이언트(사용자)와 서버 간에 데이터를 주고받으며 기능이나 정보를 제공하는 소프트웨어 시스템&lt;/li&gt;
&lt;li&gt;사용자는 웹 브라우저나 애플리케이션을 통해 웹 서버에 요청을 보내고,&lt;br /&gt;서버는 요청에 맞는 데이터를 처리하여 결과를 응답&lt;/li&gt;
&lt;li&gt;웹 서비스는 HTML 페이지 제공, 파일 업로드, API 서비스 등 다양한 형태로 제공되며, HTTP 프로토콜을 기반으로 작동&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 파이썬의 웹 서비스란? &lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파이썬에서 웹 서비스를 개발한다는 것 &lt;br /&gt;= 파이썬 코드로 사용자의 요청&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(예: 게시글 보기, 로그인 시도 등)&lt;/span&gt;을 처리하는 웹 애플리케이션을 만들고, 이를 웹을 통해 사용할 수 있도록 서버를 실행하는 것을 의미&lt;/li&gt;
&lt;li&gt;파이썬으로 웹 서비스를 만들 때 가장 많이 사용하는 도구 = 웹 프레임워크
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Flask (플라스크)&lt;/b&gt; &amp;ndash; 가볍고 배우기 쉬운 웹 프레임워크
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;고전, 기능이 거의 없음 -&amp;gt; 실제 서비스에서는 사용하지 않음&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot; data-start=&quot;503&quot; data-end=&quot;537&quot;&gt;추천 : 초보자. 공부용 혹은 소규모 프로젝트 (설치도 간단하고, 코드를 빠르게 작성 가능)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; letter-spacing: 0px;&quot;&gt;&lt;b&gt;Django (장고)&lt;/b&gt; &amp;ndash; 대형 서비스도 가능한 풀스택 프레임워크&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; letter-spacing: 0px;&quot;&gt;사용자 인증, 데이터베이스 연동, 관리자 페이지 등 다양한 기능이 기본 내장&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; letter-spacing: 0px;&quot;&gt;특히 파이썬으로 웹 사이트를 만드는데 최적화&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; letter-spacing: 0px;&quot;&gt;추천 : 더 구조적이고 큰 프로젝트에 적합 &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;FastAPI&lt;/b&gt; &amp;ndash; 빠르고 현대적인 비동기 웹 프레임워크&lt;span style=&quot;color: #000000; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비동기 지원 (async/await 사용): 고성능 서버를 쉽게 작성할 수 있어, 많은 요청을 빠르게 처리&lt;/li&gt;
&lt;li&gt;자동 API 문서 생성: 개발자가 API 문서를 따로 만들 필요 없이 /docs에 접속하면 Swagger UI로 자동 생성된 문서를 확인 가능&lt;/li&gt;
&lt;li&gt;타입 힌트를 통한 유효성 검사: Python의 타입 힌트를 이용해 입력값을 자동으로 검증해주고, 오류 메시지를 깔끔하게 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. html이란&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. html 기본 형태 출력하기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;emmet 단축키: !&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781054692171&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&amp;gt;
    &amp;lt;title&amp;gt;html&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;!--
        HTML 주석문
        작성일 : 2026-06-10
        작성자 : 김사과
    --&amp;gt;
    HTML이란?!!!!!
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;열리는 태그와 닫히는태그가 쌍으로 존재&lt;/li&gt;
&lt;li&gt;태그 : html, head, body 등&lt;/li&gt;
&lt;li&gt;속성 : 태그 뒤에 설정된 내용들&lt;/li&gt;
&lt;li&gt;lang = &quot;en&quot; : 시각장애인들이 인터넷을 사용할 때 소리로 인터넷을 사용하는데, 그 때 출력되는 언어의 종류&lt;/li&gt;
&lt;li&gt;head : 문서의 정보를 담는 부분
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;meta : 메타 정보를 설정하는 태그&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;charset : 컴퓨터가 문자를 이해할 수 있도록 사람의 언어나 기호를 고유한 숫자(바이트)로 매핑해 놓은 규격
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UTF-8 : 전 세계 거의 모든 언어를 지원하며 웹 표준으로 가장 널리 사용&lt;/li&gt;
&lt;li&gt;ASCII :&lt;span&gt;&amp;nbsp;&lt;/span&gt;영문과 숫자 위주의 가장 기본적인 7비트 문자셋&lt;/li&gt;
&lt;li&gt;EUC-KR :&lt;span&gt;&amp;nbsp;&lt;/span&gt;과거 한국어 웹 문서나 시스템에서 주로 사용되던 한글 완성형 문자셋&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;name, content, initial-scale : 모바일 반응형으로 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;nbsp;title : 브라우저 제목표시줄에 들어가는 이름&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;body : 눈에 보이는 정보를 담는 부분. 실제 화면을 구성하는 부분&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 가상 서버 사용하기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아직 백엔드를 배우지 않았기 때문에 가상으로 서버 환경에서 실습하기 위해 가상 서버를 사용해보자&lt;/li&gt;
&lt;li&gt;vscode Extensions에서&lt;span style=&quot;color: #006dd7;&quot;&gt;&amp;nbsp;Live Server&lt;/span&gt;를 설치&lt;/li&gt;
&lt;li&gt;단축키 사용 : &lt;span style=&quot;color: #006dd7;&quot;&gt;Alt 키 + l + o&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;코드 수정 후 저장하면 바로 반영됨&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 주석문&lt;/b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;emmet 단축키 : &lt;span style=&quot;color: #006dd7;&quot;&gt;ctrl + /&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;주석문 색 바꾸기 :&amp;nbsp;file - preference - settings - launch 검색 - edit in settings.json 파일에 아래 코드 삽입&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781056543817&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;editor.tokenColorCustomizations&quot;: {
	&quot;comments&quot;: &quot;#FFA7AF&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 텍스트&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;vscode Extensions에서 &lt;span style=&quot;color: #006dd7; text-align: start;&quot;&gt;auto rename tag &lt;span style=&quot;color: #333333;&quot;&gt;설치&lt;/span&gt;&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;:&lt;/span&gt; 열리는 태그 수정 시 자동으로 닫히는 태그 수정&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 34.1861%;&quot;&gt;&lt;span&gt;content : 태그가 들어있는 글자 영역&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;border : content를 감싸는 영역&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;padding : content와 border 사이의 영역&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;margin : border 바깥 영역&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 65.8139%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;189&quot; data-origin-height=&quot;151&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYAXml/dJMcajvLuvF/WCXaM9kVK6mZ4civuq2b30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYAXml/dJMcajvLuvF/WCXaM9kVK6mZ4civuq2b30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYAXml/dJMcajvLuvF/WCXaM9kVK6mZ4civuq2b30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYAXml%2FdJMcajvLuvF%2FWCXaM9kVK6mZ4civuq2b30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;158&quot; height=&quot;126&quot; data-origin-width=&quot;189&quot; data-origin-height=&quot;151&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. html 태그 종류&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;color: #333333; text-align: start; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.6977%;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;블록 태그&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 79.3023%;&quot;&gt;한 줄 전체를 차지하며 줄바꿈이 자동으로 발생&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;ex. h태그, p태그&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.6977%;&quot;&gt;&lt;span&gt;인라인 태그&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 79.3023%;&quot;&gt;내용만큼만&amp;nbsp;공간을&amp;nbsp;차지하며&amp;nbsp;줄바꿈이&amp;nbsp;발생하지&amp;nbsp;않음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 제목 태그&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1781060048160&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;h1&amp;gt;안녕하세요. Heading&amp;lt;/h1&amp;gt;
&amp;lt;h2&amp;gt;안녕하세요. Heading&amp;lt;/h2&amp;gt;
&amp;lt;h3&amp;gt;안녕하세요. Heading&amp;lt;/h3&amp;gt;
&amp;lt;h4&amp;gt;안녕하세요. Heading&amp;lt;/h4&amp;gt;
&amp;lt;h5&amp;gt;안녕하세요. Heading&amp;lt;/h5&amp;gt;
&amp;lt;h6&amp;gt;안녕하세요. Heading&amp;lt;/h6&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 문단 태그&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.1628%;&quot;&gt;&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;&lt;/td&gt;
&lt;td style=&quot;width: 78.8372%;&quot;&gt;- 문단을 만드는 태그&lt;br /&gt;- 블록 태그&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 서식 태그&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;strong과 em : html5에서 나온 접근성 태그 (리더기에서 더 쎈 발음을 내주는 용도)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781071276801&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    &amp;lt;p&amp;gt;&amp;lt;b&amp;gt;굵게&amp;lt;/b&amp;gt;표현하기&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;굵게&amp;lt;/strong&amp;gt;표현하기&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;&amp;lt;i&amp;gt;이탤릭체&amp;lt;/i&amp;gt; 표현하기&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;&amp;lt;em&amp;gt;이탤릭체&amp;lt;/em&amp;gt; 표현하기&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;&amp;lt;ins&amp;gt;밑줄&amp;lt;/ins&amp;gt; 표현하기&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;&amp;lt;del&amp;gt;삭제&amp;lt;/del&amp;gt; 표현하기&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;x&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt; + y&amp;lt;sup&amp;gt;3&amp;lt;/sup&amp;gt; = z&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;H&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;O&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 리스트&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;emmet 단축키 : ul&amp;gt;li*3 (ul의 자식태그로 li태그 3개)&lt;br /&gt;dl&amp;gt;dt{내용}+dd*3 (dl의 자식 태그로 dt와 dd 3개. dt의 내용을 {}로 담음. dt와 dd는 형제태그)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781068177148&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- 순서가 없는 태그 emmet : ul&amp;gt;li*3 --&amp;gt;
&amp;lt;ul&amp;gt;
    &amp;lt;li&amp;gt;김사과&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;오렌지&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;바나나&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;!-- 순서가 있는 태그 --&amp;gt;
&amp;lt;ol&amp;gt;
    &amp;lt;li&amp;gt;김사과&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;오렌지&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;반하나&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;!-- 설명 목록 태그 dl&amp;gt;dt+dd*3  dl&amp;gt;dt{류정원}+dd*3--&amp;gt;
 &amp;lt;dl&amp;gt;
    &amp;lt;dt&amp;gt;류정원 선생님&amp;lt;/dt&amp;gt;
    &amp;lt;dd&amp;gt;김사과&amp;lt;/dd&amp;gt;
    &amp;lt;dd&amp;gt;오렌지&amp;lt;/dd&amp;gt;
    &amp;lt;dd&amp;gt;반하나&amp;lt;/dd&amp;gt;
 &amp;lt;/dl&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. 이미지&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 절대 경로와 상대 경로&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실습 중에는 가상 서버를 돌려 이미지를 찾아오기 때문에 실제 C드라이브가 어디있는지 모름&lt;/li&gt;
&lt;li&gt;상대 경로를 사용하거나 절대 경로는 웹에 있는 경로 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781068295004&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- 절대 경로 --&amp;gt;
&amp;lt;img src=&quot;C:\sj\4_HTML_CSS\spring1.png&quot; alt=&quot;봄&quot;&amp;gt;
&amp;lt;img src=&quot;https://tcpschool.com/img/logo.png&quot; alt=&quot;tcp스쿨 로고&quot;&amp;gt;
&amp;lt;!-- 상대 경로 --&amp;gt;
&amp;lt;img src=&quot;spring1.png&quot; alt=&quot;봄&quot;&amp;gt;
&amp;lt;img src=&quot;images/spring2.png&quot; alt=&quot;봄&quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 웹에서 사용하는 사용 가능한 이미지 포멧&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.1628%;&quot;&gt;png&lt;/td&gt;
&lt;td style=&quot;width: 78.8372%;&quot;&gt;투명도 표현&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.1628%;&quot;&gt;jpeg/jpg&lt;/td&gt;
&lt;td style=&quot;width: 78.8372%;&quot;&gt;압축률이 좋아 파일 크기가 작음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.1628%;&quot;&gt;gif&lt;/td&gt;
&lt;td style=&quot;width: 78.8372%;&quot;&gt;여러 이미지를 합쳐 움직이는 사진을 만들 수 있음. 해상도 낮음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.1628%;&quot;&gt;webp&lt;/td&gt;
&lt;td style=&quot;width: 78.8372%;&quot;&gt;png, jpeg/jpg, gif 기능 모두 가지고 있음&lt;br /&gt;최초 브라우저와 현재 브라우저의 버전 차이 때문에 지원하지 않는 브라우저가 많음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.1628%;&quot;&gt;svg&lt;/td&gt;
&lt;td style=&quot;width: 78.8372%;&quot;&gt;벡터로 저장. 디지털로 되어 있어서 코드로 이미지 사용 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;6. 하이퍼링크&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1781071330786&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- 절대 경로 --&amp;gt;
&amp;lt;a href=&quot;https://www.naver.com&quot;&amp;gt;네이버&amp;lt;/a&amp;gt;
&amp;lt;a href=&quot;https://tcpschool.com&quot;&amp;gt;&amp;lt;img src=&quot;https://tcpschool.com/img/logo.png&quot; alt=&quot;tcp스쿨 로고&quot;&amp;gt;&amp;lt;/a&amp;gt;
&amp;lt;!-- 상대 경로 --&amp;gt;
&amp;lt;a href=&quot;./4_이미지.html&quot;&amp;gt;이미지 페이지&amp;lt;/a&amp;gt;
&amp;lt;a href=&quot;./pages/subpage.html&quot;&amp;gt;서브 페이지&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;7. CSS (Cascading Style Sheets)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML과 함께 사용되며 웹 페이지의 스타일로 레이아웃을 정의하는 스타일시트 언어&lt;/li&gt;
&lt;li&gt;스타일 적용 방법
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;인라인 스타일 : HTML 태그 안에 직접 style 속성으로 css 작성&lt;/li&gt;
&lt;li&gt;내부 스타일 : &amp;lt;style&amp;gt;태그를 &amp;lt;head&amp;gt; 안에 작성하여 css 작성&lt;/li&gt;
&lt;li&gt;외부 스타일 : css 코드를 별도의 .css 파일에 작성하고, HTML 문서에서 link 태그로 연결&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;css 원칙 : 더 나중에 있는 것이 우선 순위 (인라인 스타일이 가장 높은 우선순위)&lt;/li&gt;
&lt;li&gt;외부 스타일 시트를 대부분 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781071575430&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- 내부 스타일, 외부 스타일(link) --&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;style&amp;gt;
        body { background-color: deepskyblue; }
        h1 { color: white; text-align: center;  }
    &amp;lt;/style&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;./css/test.css&quot;&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;!-- 인라인 스타일 --&amp;gt;
&amp;lt;p style=&quot;color: gold&quot;&amp;gt;안녕하세요 CSS입니다&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;8. 다양한 선택자&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 태그 선택자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 클래스 선택자(.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 아이디 선택자(#) : 같은 이름을 가진 id가 존재하면 안됨 (에러가 발생하지 않지만 안됨)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 그룹 선택자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 클래스 선택자 여러 개 적용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 의사 클래스 선택자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. 속성 선택자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;8. 자식 선택자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9. 자손 선택자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10. 형제 선택자&lt;/p&gt;
&lt;pre id=&quot;code_1781073325433&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- head --&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;다양한 선택자&amp;lt;/title&amp;gt;
    &amp;lt;style&amp;gt;
        /* 1. 태그 선택자 */
        h1 { color: deepskyblue; text-align: center; }
        /* 2. 클래스 선택자(.) : 여러 요소에 적용 가능*/
        .intro { font-weight: bold; color: deeppink; }
        /* 3. 아이디 선택자(#) */
        #favorite-list { 
            background-color: ivory;
            padding: 10px;
         }
        /* 4. 그룹 선택자 */
        p, li { font-size: 20px; }  /* pc기본 글꼴 사이즈는 16px */
        /* 5. 클래스 선택자 : 중복으로 적용 가능*/
        .bluecolor { color: blue; }
        .highlight { font-style: italic; }
        /* 6. 의사 클래스 선택자 */
        a:hover { color: yellowgreen; text-decoration: none;}
        /* 7. 속성 선택자 */
        h1[title=&quot;제목&quot;] { background-color: ivory; }
        /* 8. 자식 선택자 */
        ul#favorite-list &amp;gt; li { list-style-type: square; }
        /* 9. 자손 선택자(자식 포함) */
        ul#favorite-list p { 
            color: violet;
            font-weight: bold;
         }
         /* 10. 형제 선택자 */
        p.intro + p { background-color: aqua; }
    &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1781076562651&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- body --&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;h1 title=&quot;제목&quot;&amp;gt;선택자&amp;lt;/h1&amp;gt;

    &amp;lt;p class=&quot;intro&quot;&amp;gt;이 문단은 첫번째 문단입니다.&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;이 문단은 두번째 문단입니다.&amp;lt;/p&amp;gt;

    &amp;lt;ul id=&quot;favorite-list&quot;&amp;gt;
        &amp;lt;li class=&quot;bluecolor&quot;&amp;gt;김사과&amp;lt;/li&amp;gt;
        &amp;lt;li class=&quot;bluecolor highlight&quot;&amp;gt;반하나&amp;lt;/li&amp;gt;
        &amp;lt;li class=&quot;bluecolor&quot;&amp;gt;오렌지&amp;lt;/li&amp;gt;
        &amp;lt;li class=&quot;bluecolor&quot;&amp;gt;&amp;lt;p&amp;gt;이메론&amp;lt;/p&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;p&amp;gt;출석부&amp;lt;/p&amp;gt;
    &amp;lt;/ul&amp;gt;

    &amp;lt;a href=&quot;https://www.naver.com&quot;&amp;gt;외부 링크&amp;lt;/a&amp;gt;
    &amp;lt;a href=&quot;#top&quot;&amp;gt;내부 링크&amp;lt;/a&amp;gt;
    &amp;lt;a href=&quot;./5_하이퍼링크.html&quot; class=&quot;intro&quot;&amp;gt;하이퍼링크&amp;lt;/a&amp;gt;
&amp;lt;/body&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 프레임워크와 언어는 좋고 안좋고가 아니고 프로젝트에 얼마나 적합한지, 퍼포먼스를 얼마나 낼 수 있는지 판단하는 것이 중요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 브라우저는 에러를 내지 않고 자기 방식대로 출력 (오타가 나도 브라우저가 판단해서 출력)&lt;br /&gt;&amp;nbsp; &amp;nbsp; -&amp;gt; 정확하게 작성하기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 컴퓨터와 핸드폰의 해상도가 다르기 때문에 최적화되도록 브라우저가 모바일에서 해상도를 확 낮춰서 보여줌&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* emmet 사이트 : &lt;a href=&quot;https://emmet.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://emmet.io/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.w3schools.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;* https://www.w3schools.com/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 복붙 단축키 : shift + alt + 화살표위아래키&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* html 태그는 트리구조라 emmet 단축키 (ul&amp;gt;li*3, dl&amp;gt;dt+dd*3) 사용 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* css에서 선택자를 모르면 크롤링을 할 수가 없음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>KDT/4. 웹</category>
      <category>CSS</category>
      <category>dns</category>
      <category>HTML</category>
      <category>Server와 Client</category>
      <category>웹</category>
      <author>김셀리</author>
      <guid isPermaLink="true">https://2lucesicutstellae.tistory.com/31</guid>
      <comments>https://2lucesicutstellae.tistory.com/31#entry31comment</comments>
      <pubDate>Wed, 10 Jun 2026 16:33:16 +0900</pubDate>
    </item>
    <item>
      <title>[14일차-3] MySQL을 활용한 단어장 (작성중)</title>
      <link>https://2lucesicutstellae.tistory.com/30</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1781015386777&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 사용할 MySQLdb 모듈 선택
import MySQLdb&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1781015422369&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Word:
    def __init__(self, eng, kor, lev=1):
        self.eng = eng
        self.kor = kor
        self.lev = lev

    def __repr__(self):     # 매직메서드
        return f&quot;Word(eng={self.eng}', kor='{self.kor}', lev={self.lev})&quot;
    
    @property               # 제너레이터
    def eng(self):
        return self.__eng

    @eng.setter
    def eng(self,eng):
        if not eng:         # eng가 존재하지 않으면 에러
            raise ValueError('영어 단어는 비워둘 수 없습니다')
        self.__eng = eng
    
    @property
    def kor(self):
        return self.__kor
    
    @kor.setter
    def kor(self, kor):
        if not kor:
            raise ValueError('뜻을 비워둘 수 없습니다')
        self.__kor = kor

    @property
    def lev(self):
        return self.__lev
    
    @lev.setter
    def lev(self, lev):
        lev = int(lev)
        if lev &amp;lt; 1:
            raise ValueError('레벨은 1 이상이어야 합니다')
        self.__lev = lev&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1781015430424&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# db 관리하는 클래스
# Data Access Object : db에 연결시켜주는 객체
class WordsDAO:
    def __init__(self):
        self.db = None

    def connect(self):
        self.db = MySQLdb.connect(host='localhost', user='apple', password='1111', db='ai', charset='utf8')

    def disconnect(self):
        if self.db:
            self.db.close()

    def insert(self, word):     # word 객ㅊ
        self.connect()
        cur = self.db.cursor()
        sql = &quot;insert into voca (eng, kor, lev) values (%s, %s, %s)&quot;
        data = (word.eng, word.kor, word.lev)
        cur.execute(sql, data)
        self.db.commit()
        cur.close()
        self.disconnect()

    def select_all(self):
        self.connect()
        cur = self.db.cursor(MySQLdb.cursors.DictCursor)
        sql = &quot;select eng, kor, lev from voca order by eng asc&quot;
        cur.execute(sql)
        rows = cur.fetchall()
        cur.close()
        self.disconnect()
        return rows
    
    def search_all(self, eng):
        self.connect()
        cur = self.db.cursor(MySQLdb.cursors.DictCursor)
        # sql = &quot;select eng, kor, lev from voca where eng like '%%s%'&quot; -&amp;gt; 이상하도다. concat으로 연결 %%두개는 %하나로 실행
        sql = &quot;select eng, kor, lev from voca where eng like concat('%%', %s, '%%')&quot;
        cur.execute(sql, (eng,))        
        rows = cur.fetchall()
        cur.close()
        self.disconnect()
        return rows
    
    def search(self, eng):
        self.connect()
        cur = self.db.cursor(MySQLdb.cursors.DictCursor)
        sql = &quot;select eng, kor, lev from voca where eng=%s&quot;
        cur.execute(sql, (eng,))
        row = cur.fetchone()
        cur.close()
        self.disconnect()
        return row
    
    def update(self, word):
        self.connect()
        cur = self.db.cursor()
        sql = &quot;update voca set kor=%s, lev=%s where eng=%s&quot;
        data = (word.kor, word.lev, word.eng)
        result = cur.execute(sql, data)
        self.db.commit()
        cur.close()
        self.disconnect()
        return result
    
    def delete(self, eng):
        self.connect()
        cur = self.db.cursor()
        sql = &quot;delete from voca where eng=%s&quot;
        result = cur.execute(sql, (eng,))
        self.db.commit()
        cur.close()
        self.disconnect()
        return result&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1781015441756&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 실질적으로 작동하는 알고리즘
class WordsService:
    def __init__(self):
        self.dao = WordsDAO()

    def insert_word(self):
        eng = input(&quot;단어를 입력하세요: &quot;)
        kor = input(&quot;뜻을 입력하세요: &quot;)
        lev = input(&quot;레벨을 입력하세요: &quot;)

        word = Word(eng, kor, lev)
        self.dao.insert(word)
        print(&quot;단어가 등록되었습니다&quot;)

    def print_all(self):
        words = self.dao.select_all()
        if not words:
            print(&quot;등록된 단어가 없습니다&quot;)
            return
        for word in words:
            print(f&quot;{word['eng']} 뜻:{word['kor']}, 레벨:{word['lev']}&quot;)

    def search_words(self):
        eng = input(&quot;검색할 단어를 입력하세요: &quot;)
        words = self.dao.search_all(eng)
        if not words:
            print(&quot;찾는 단어가 없습니다&quot;)
            return
        for word in words:
            print(f&quot;{word['eng']} 뜻:{word['kor']}, 레벨:{word['lev']}&quot;)

    def edit_word(self):
        eng = input(&quot;수정할 단어를 입력하세요: &quot;)
        word = self.dao.search(eng)
        if not word:
            print(&quot;수정할 단어가 없습니다&quot;)
            return
        kor = input(&quot;새로운 뜻을 입력하세요: &quot;)
        lev = input(&quot;새로운 레벨을 입력하세요: &quot;)
        word = Word(eng, kor, lev)
        result = self.dao.update(word)
        if result &amp;gt; 0:
            print(&quot;수정되었습니다&quot;)
        else:
            print(&quot;수정에 실패했습니다&quot;)

    def delete_word(self):
        eng = input(&quot;삭제할 단어를 입력하세요: &quot;)
        word = self.dao.search(eng)
        if not word:
            print(&quot;삭제할 단어가 없습니다&quot;)
            return
        result = self.dao.delete(eng)
        if result &amp;gt; 0:
            print(&quot;삭제되었습니다&quot;)
        else:
            print('삭제에 실패했습니다')&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1781015448517&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Menu:
    def __init__(self):
        self.service = WordsService()

    def run(self):
        while True:
            try:
                print()
                print(&quot;===== 단어장 프로그램 =====&quot;)
                print(&quot;1. 등록하기&quot;)
                print(&quot;2. 출력하기&quot;)
                print(&quot;3. 검색하기&quot;)
                print(&quot;4. 수정하기&quot;)
                print(&quot;5. 삭제하기&quot;)
                print(&quot;6. 종료하기&quot;)
                menu = int(input(&quot;메뉴를 선택하세요&quot;))

                if menu ==  1:
                    print(&quot;단어를 등록합니다&quot;)
                    self.service.insert_word()

                elif menu == 2:
                    print(&quot;단어를 출력합니다&quot;)
                    self.service.print_all()
                    
                elif menu == 3:
                    print(&quot;단어를 검색합니다&quot;)
                    self.service.search_words()

                elif menu == 4:
                    print(&quot;단어를 수정합니다&quot;)
                    self.service.edit_word()

                elif menu == 5:
                    print(&quot;단어를 삭제합니다&quot;)
                    self.service.delete_word()

                elif menu == 6:
                    print(&quot;프로그램을 종료합니다&quot;)
                    break
                
                else:
                    print(&quot;메뉴는 1부터 6까지 입력해주세요&quot;)
            except Exception as e:
                print(&quot;오류: &quot;, e)
                print(&quot;다시 입력하세요&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1781015477346&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;menu = Menu()
menu.run()&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# class Word&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# class WordsDAO&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# class WordsService&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# class Menu&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# 1. 등록하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Menu에서 self.service.insert_word() 만들기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. WordsService에서 insert_word()만들고 안에서 insert()&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. WordsDAO에 insert() 만들기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. WordService에서 마저 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;#&amp;nbsp;2.&amp;nbsp;출력하기&lt;/b&gt; &lt;br /&gt;1.&amp;nbsp;Menu에서&amp;nbsp;self.service.print_all()&amp;nbsp;만들기 &lt;br /&gt;2.&amp;nbsp;WordsService에서&amp;nbsp;print_all()만들고&amp;nbsp;안에서&amp;nbsp;select_all() &lt;br /&gt;3.&amp;nbsp;WordsDAO에&amp;nbsp;select_all()&amp;nbsp;만들기 &lt;br /&gt;4.&amp;nbsp;WordsService에서&amp;nbsp;마저&amp;nbsp;작성 &lt;br /&gt;&lt;br /&gt;&lt;b&gt;#&amp;nbsp;3.&amp;nbsp;검색하기&lt;/b&gt; &lt;br /&gt;1.&amp;nbsp;Menu에서&amp;nbsp;self.service.search_words()&amp;nbsp;만들기 &lt;br /&gt;2.&amp;nbsp;WordsService에서&amp;nbsp;search_words()만들고&amp;nbsp;안에서&amp;nbsp;self.dao.search_all(eng) &lt;br /&gt;3.&amp;nbsp;WordsDAO에&amp;nbsp;search_all(eng)&amp;nbsp;만들기 &lt;br /&gt;4.&amp;nbsp;WordsService에서&amp;nbsp;마저&amp;nbsp;작성 &lt;br /&gt;&lt;br /&gt;&lt;b&gt;# 4. 수정하기&lt;/b&gt;&lt;br /&gt;1.&amp;nbsp;Menu에서&amp;nbsp;self.service.edit_word()&amp;nbsp;만들기 &lt;br /&gt;2.&amp;nbsp;WordsService에서&amp;nbsp;edit_word()만들고&amp;nbsp;안에서&amp;nbsp;self.dao.search(eng) &lt;br /&gt;3.&amp;nbsp;WordsDAO에&amp;nbsp;search(eng)&amp;nbsp;만들기 &lt;br /&gt;4.&amp;nbsp;WordsService에서&amp;nbsp;마저&amp;nbsp;작성하다가&amp;nbsp;self.dao.update(word)&amp;nbsp;만들기 &lt;br /&gt;5.&amp;nbsp;WordsDAO에&amp;nbsp;update(word)&amp;nbsp;만들기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# 5. 삭제하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Menu에서 self.service.delete_word()&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. WordsService에서 delete_word()만들고 안에서 self.dao.search(eng)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. WordsDAO에 있는 search(eng) 재사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. WordsService에 마저 작성하다가 self.dao.delete(eng) 만들기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. WordsDAO에 delete(eng)만들기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. WordsService에 마저 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 모든 코드를 한번에 작성하려고 하지 말 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 우선 코드 흐름을 파악하는 것에 집중&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 번호로 정리해 둔 내용을 보며 작성하는 흐름에 익숙해져보자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 객체지향적인 코드를 작성해보았는데, 앞으로도 이런 코드를 사용할거라고 생각하니 걱정이 된다. 복습을 꼼꼼히 해야할 필요가 있다.&lt;/p&gt;</description>
      <category>KDT/3. Python과 MySQL 연동</category>
      <author>김셀리</author>
      <guid isPermaLink="true">https://2lucesicutstellae.tistory.com/30</guid>
      <comments>https://2lucesicutstellae.tistory.com/30#entry30comment</comments>
      <pubDate>Tue, 9 Jun 2026 23:41:58 +0900</pubDate>
    </item>
    <item>
      <title>[14일차-2] MySQL 연동</title>
      <link>https://2lucesicutstellae.tistory.com/29</link>
      <description>&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;# MySQL 연동&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-size: 1.44em;&quot;&gt;(DB 연결하기)&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. mysqlclient 설치&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파이썬에서 MySQL 데이터베이스와 상호작용하기 위해 사용하는 공식 라이브러리&lt;/li&gt;
&lt;li&gt;PyMySQL, mysqlclient 를 가장 많이 사용&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(SQLAlchemy를 실무에서는 가장 많이 사용)&lt;/span&gt;&lt;br /&gt;-&amp;gt; 사용법이 비슷하나 mysqlclient가 속도상으로도 유리하기 때문에 권장&lt;/li&gt;
&lt;li&gt;venv에서 아래 명령어 입력하여 설치&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781015315449&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;python -m pip install mysqlclient&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ipynb 파일에서 import 되는지 확인 (설치명과 모듈명이 다름 주의)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781015315450&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;import MySQLdb&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. MySQL 접속&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;MySQLdb.connect(host='IP주소(or도메인주소)', user='사용자명', password='비밀번호', db='데이터베이스명')&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre id=&quot;code_1781015315450&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# db 연결
# 객체를 받을 변수(db) 선언해서 받아오기
db = MySQLdb.connect(host='localhost', user='root', password='1234', db='ai')
db		

# &amp;lt;_mysql.connection open to 'localhost' at 000002375B69B430&amp;gt;
# db를 조회해보면 connection 객체임을 알 수 있다&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. cursor 생성&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 데이터베이스 connection에 대해 독립적으로 SQL문을 실행할 수 있는 작업 환경을 제공하는 객체&lt;/li&gt;
&lt;li&gt;하나의 connection에 동시에 한 개의 cursor만 생성 가능&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(변수 여러 개를 사용한다고 cursor가 여러 개인 것이 아님. 같은 경로를 사용)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;cursor를 통해 SQL문을 실행하면 실행 결과를 튜플 단위로 반환&lt;/li&gt;
&lt;li&gt;execute안에 sql문을 변수에 넣어서 사용 가능&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;ex) cur.execute(sql, date)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;1개 값을 튜플로 넣을 때 튜플 형식 지키기&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;ex) cur.execute(sql, (userid,))&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781015315451&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# 커서 객체 생성
cur = db.cursor()

# SQL문 실행
cur.execute(&quot;select * from member&quot;) 	# 7

# 7개의 행이 반환된 것을 확인 가능
# SQL문에 세미콜론 안써도 됨&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. SQL문의 결과 반환 - 튜플 형태&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;cursor는 기본적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;tuple&lt;/span&gt;형 결과를 반환&lt;/li&gt;
&lt;li&gt;결과 반환 방법 2가지
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;fetchall() : 한 번에 모든&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;tuple을 가&lt;/span&gt;져옴. 검색 결과가 매우 많다면 메모리 오버헤드 발생할 수 있음&lt;/li&gt;
&lt;li&gt;fetchone() : 한 번에 하나의&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;tuple을&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;가져옴. 다시 fetchone() 메서드를 호출하면 다음 데이터를 가져옴&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;마지막 데이터까지 도달하면 데이터가 나오지 않음&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(이미 데이터 한 바퀴를 다 돌아서)&lt;/span&gt;&lt;br /&gt;-&amp;gt; 그럴 땐&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;다시 execute&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;해주면 됨&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(fetchall() 또는 fetchone()으로 마지막 데이터를 가져온 오는 경우)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781015315451&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt; data = cur.fetchall()
 data&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1781015315451&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;cur.execute(&quot;select userid, name, gender from member&quot;)

# 실행할 때마다 다음 데이터로 넘어감
row = cur.fetchone()
row&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1781015315451&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# SQL문을 변수에 넣어 사용해도 결과는 같음
sql = &quot;select userid, name, gender, hp from member&quot;
cur.execute(sql)

row = cur.fetchone()
row&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;반복문으로 데이터를 가져올 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781015315452&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;sql = &quot;select userid, name, gender, hp from member&quot;
cur.execute(sql)

while True:
	row = cur.fetchone()	# 데이터를 하나씩 가져오는데
    if row:			# 데이터가 있으면 출력
    	print(row)
    else:			# 데이터가 없으면 반복문 빠져나가기
    	break&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. SQL문의 결과 반환 - 딕셔너리 형태&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커서 생성 시 괄호 안에 MySQLdb.cursors.DictCursor 추가&lt;/li&gt;
&lt;li&gt;튜플로 반환하면 인덱스가 아닌&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;컬럼명으로 접근&lt;/span&gt;이 가능하여 편리&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;cursor(MySQLdb.cursors.DictCursor)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre id=&quot;code_1781015315452&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;sql = &quot;select userid, name, gender, hp from member&quot;
cur = db.cursor(MySQLdb.cursors.DictCursor)
cur.execute(sql)

result = cur.fetchall()
result&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1781015315452&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# 결과
({'userid': 'apple', 'name': '김사과', 'gender': '여자', 'hp': '010-1111-1111'},
 {'userid': 'banana', 'name': '반하나', 'gender': '여자', 'hp': '010-2222-2222'},
 {'userid': 'orange', 'name': '오렌지', 'gender': '남자', 'hp': '010-3333-3333'},
 {'userid': 'melon', 'name': '이메론', 'gender': '남자', 'hp': '010-4444-4444'},
 {'userid': 'cherry', 'name': '채리', 'gender': '여자', 'hp': '010-5555-5555'},
 {'userid': 'berry', 'name': '배애리', 'gender': '여자', 'hp': '010-6666-6666'},
 {'userid': 'avocado', 'name': '안가도', 'gender': '남자', 'hp': '010-7777-7777'},
 {'userid': 'mango', 'name': '마앙고', 'gender': '남자', 'hp': '010-8888-8888'},
 {'userid': 'pear', 'name': '배철수', 'gender': '남자', 'hp': '010-9999-9999'},
 {'userid': 'peach', 'name': '복숭아', 'gender': '남자', 'hp': '010-0000-0000'})&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 코드를 사용하여 데이터를 파악하기 쉽게 출력해보자&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781015315455&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;sql = &quot;select userid, name, gender, hp from member&quot;
cur = db.cursor(MySQLdb.cursors.DictCursor)
cur.execute(sql)        

while True:
    row = cur.fetchone()
    if row:     # 데이터가 있다면
        print(f&quot;아이디:{row['userid']}, 이름:{row['name']}, 성별:{row['gender']}, 전화번호:{row['hp']}&quot;)
    else:
        break&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1781015315456&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# 결과
아이디:apple, 이름:김사과, 성별:여자, 전화번호:010-1111-1111
아이디:banana, 이름:반하나, 성별:여자, 전화번호:010-2222-2222
아이디:orange, 이름:오렌지, 성별:남자, 전화번호:010-3333-3333
아이디:melon, 이름:이메론, 성별:남자, 전화번호:010-4444-4444
아이디:cherry, 이름:채리, 성별:여자, 전화번호:010-5555-5555
아이디:berry, 이름:배애리, 성별:여자, 전화번호:010-6666-6666
아이디:avocado, 이름:안가도, 성별:남자, 전화번호:010-7777-7777
아이디:mango, 이름:마앙고, 성별:남자, 전화번호:010-8888-8888
아이디:pear, 이름:배철수, 성별:남자, 전화번호:010-9999-9999
아이디:peach, 이름:복숭아, 성별:남자, 전화번호:010-0000-0000&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. cursor와 connection 닫기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DB 사용이 끝난 후 연결을 끊지 않으면 계속 사용하는 줄 알고 -&amp;gt; 메모리를 차지하게 되어 -&amp;gt; 속도가 느려질 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781015315457&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# cursor 연결 끊기
cur.close()

# db 연결 끊기
db.close()&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. DB 데이터 삽입하기&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 데이터 삽입&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;MySQL 연결&lt;/li&gt;
&lt;li&gt;커서 생성&lt;/li&gt;
&lt;li&gt;insert문 작성해서 변수에 저장&lt;/li&gt;
&lt;li&gt;insert문에 들어갈 데이터를 튜플 형태로 변수에 저장&lt;/li&gt;
&lt;li&gt;커서로 sql문 실행&lt;/li&gt;
&lt;li&gt;db에 반영&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1781015315458&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;db = MySQLdb.connect(host='localhost', user='root', password='1234', db='ai')
cur = db.cursor()

sql = &quot;insert into member (userid, userpw, name, hp, email, gender, ssn1, ssn2) values (%s, %s, %s, %s, %s, %s, %s, %s)&quot;
data = ('mango', '8888', '마앙고', '010-8888-8888', 'mango@mango.com', '남자', '000000', '0000000')
cur.execute(sql, data)
db.commit()&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 데이터 삽입&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;insert문에 들어갈 여러 건의 데이터를 튜플로 만들고 튜플들을 리스트로 묶어서&amp;nbsp;저장&lt;/li&gt;
&lt;li&gt;executemany()로 리스트 안의 튜플을 순서대로 %s에 매핑하여 여러 건 한번에 insert&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1781015315458&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;sql = &quot;insert into member (userid, userpw, name, hp, email, gender, ssn1, ssn2) values (%s, %s, %s, %s, %s, %s, %s, %s)&quot;
# 튜플 여러 개를 리스트로 묶어 사용
data = [('pear', '9999', '배철수', '010-9999-9999', 'pear@pear.com', '남자', '000000', '0000000'),
        ('peach', '0000', '복숭아', '010-0000-0000', 'peach@peach.com', '남자', '000000', '0000000')]
# 여러 데이터 넣을 때 사용
cur.executemany(sql, data)
db.commit()&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 예제&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 회원가입 프로그램&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;MySQL 연결 및 커서 생성&lt;/li&gt;
&lt;li&gt;while문 안에 try-except문으로 잘못된 입력 처리&lt;/li&gt;
&lt;li&gt;while문으로 userid부터 gender까지 12개의 컬럼에 대해 input 작성&lt;/li&gt;
&lt;li&gt;sql문 작성해서 변수에 저장&lt;/li&gt;
&lt;li&gt;input한 12개의 변수를 튜플로 묶어 저장&lt;/li&gt;
&lt;li&gt;커서로 sql문 실행&lt;/li&gt;
&lt;li&gt;db에 반영&lt;/li&gt;
&lt;li&gt;'가입되었습니다' 문구 출력&lt;/li&gt;
&lt;li&gt;추가로 가입하는지 여부 확인 후,아니오 선택 시 프로그램 종료,&amp;nbsp;네 선택 시 while문 반복&lt;/li&gt;
&lt;li&gt;커서 및 db 연결 제거&lt;/li&gt;
&lt;/ol&gt;
&lt;div style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot; data-text-less=&quot;닫기&quot; data-text-more=&quot;더보기&quot; data-ke-type=&quot;moreLess&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;a style=&quot;color: #0070d1;&quot;&gt;더보기&lt;/a&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1781015315459&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# db와 cursor 생성
db = MySQLdb.connect(host='localhost', user='root', password='1234', db='ai')
cur = db.cursor()

while True:
    try:
        userid = input('아이디를 입력하세요: ')
        userpw = input('비밀번호를 입력하세요: ')
        name = input('이름을 입력하세요: ')
        hp = input('전화번호를 입력하세요: ')
        email = input('이메일을 입력하세요: ')
        ssn1 = input('주민등록번호 앞자리를 입력하세요: ')
        ssn2 = input('주민등록번호 뒷자리를 입력하세요: ')
        zipcode = input('우편번호를 입력하세요: ')
        address1 = input('주소를 입력하세요: ')
        address2 = input('상세주소를 입력하세요: ')
        address3 = input('참고사항을 입력하세요: ')
        gender = input('성별을 입력하세요(남자 또는 여자): ')
        sql = &quot;insert into member (userid, userpw, name, hp, email, gender, ssn1, ssn2, zipcode, address1, address2, address3) values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)&quot;
        data = (userid, userpw, name, hp, email, gender, ssn1, ssn2, zipcode, address1, address2, address3)
        cur.execute(sql, data)
        db.commit()     # db에 반영
        print('가입되었습니다!')
        yn = input('추가로 가입하시겠습니까? (y/n): ')
        if yn.lower() == 'n':
            print('프로그램을 종료합니다')
            break
    except Exception as e:
        print('다시 입력하세요')

cur.close()
db.close()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 로그인 프로그램&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;MySQL 연결 및 커서 생성&lt;/li&gt;
&lt;li&gt;userid, userpw를 input 받기&lt;/li&gt;
&lt;li&gt;sql문 작성해서 변수에 저장&lt;/li&gt;
&lt;li&gt;input한 2개 변수를 튜플로 묶어 저장&lt;/li&gt;
&lt;li&gt;커서로 sql문 실행&lt;/li&gt;
&lt;li&gt;5번의 결과에 따라 로그인 되었는지, 아닌지 조건문 작성&lt;/li&gt;
&lt;li&gt;커서 및 db 연결 제거&lt;/li&gt;
&lt;/ol&gt;
&lt;div style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot; data-text-less=&quot;닫기&quot; data-text-more=&quot;더보기&quot; data-ke-type=&quot;moreLess&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;a style=&quot;color: #0070d1;&quot;&gt;더보기&lt;/a&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1781015315461&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;db = MySQLdb.connect(host='localhost', user='root', password='1234', db='ai')
cur = db.cursor()

userid = input('아이디를 입력하세요: ')
userpw = input('비밀번호를 입력하세요: ')

sql = 'select idx from member where userid=%s and userpw=%s'
data = (userid, userpw)
result = cur.execute(sql, data)

if result &amp;gt; 0:
    print('로그인 되었습니다')
else:
    print('아이디 또는 비밀번호를 확인하세요')

cur.close()
db.close()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 회원정보 수정 프로그램&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;MySQL 연결 및 커서 생성&lt;/li&gt;
&lt;li&gt;while문 안에 try-except문으로 잘못된 입력 처리&lt;/li&gt;
&lt;li&gt;while문으로 비밀번호를 제외한 모든 정보에 대해 input 작성&lt;br /&gt;(userid를 입력받아 아이디에 해당하는 name~gender 컬럼을 수정)&lt;/li&gt;
&lt;li&gt;sql문 작성 후 변수에 저장&lt;/li&gt;
&lt;li&gt;sql문에 매핑되도록 튜플로 저장&lt;/li&gt;
&lt;li&gt;커서로 sql문 실행&lt;/li&gt;
&lt;li&gt;db에 반영&lt;/li&gt;
&lt;li&gt;6번의 결과에 따라 변경되었는지, 아닌지 조건문 작성&lt;/li&gt;
&lt;li&gt;변경할 내용이 더 있는지 여부 확인 후, 아니오 선택 시 프로그램 종료, 네 선택 시 while문 반복&lt;/li&gt;
&lt;li&gt;커서 및 db 연결 제거&lt;/li&gt;
&lt;/ol&gt;
&lt;div style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot; data-text-less=&quot;닫기&quot; data-text-more=&quot;더보기&quot; data-ke-type=&quot;moreLess&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;a style=&quot;color: #0070d1;&quot;&gt;더보기&lt;/a&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1781015315462&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;db = MySQLdb.connect(host='localhost', user='root', password='1234', db='ai')
cur = db.cursor()

while True:
    try:
        userid = input('변경할 아이디를 입력하세요: ')
        name = input('이름을 입력하세요: ')
        hp = input('전화번호를 입력하세요: ')
        email = input('이메일을 입력하세요: ')
        ssn1 = input('주민등록번호 앞자리를 입력하세요: ')
        ssn2 = input('주민등록번호 뒷자리를 입력하세요: ')
        zipcode = input('우편번호를 입력하세요: ')
        address1 = input('주소를 입력하세요: ')
        address2 = input('상세주소를 입력하세요: ')
        address3 = input('참고사항을 입력하세요: ')
        gender = input('성별을 입력하세요(남자 또는 여자): ')

        sql = 'update member set name=%s, hp=%s, email=%s, ssn1=%s, ssn2=%s, zipcode=%s, address1=%s, address2=%s, address3=%s, gender=%s where userid=%s'
        data = (name, hp, email, ssn1, ssn2, zipcode, address1, address2, address3, gender, userid)
        result = cur.execute(sql, data)
        db.commit()

        # 몇개가 update 되었는지 반환되기 때문에 그걸로 0보다 크면 변경되었다, 아니면 에러
        if result &amp;gt; 0:
            print('변경되었습니다')
        else:
            print('에러!')

        yn = input('변경할 내용이 더 있으십니까?(y/n): ')
        if yn.lower() == 'n':
            print('프로그램을 종료합니다')
            break

    except Exception as e:
        print('다시 입력하세요')

cur.close()
db.close()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 회원 탈퇴 프로그램&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;MySQL 연결 및 커서 생성&lt;/li&gt;
&lt;li&gt;탈퇴할 아이디를 입력 받음&lt;/li&gt;
&lt;li&gt;sql문 작성 후 변수에 저장&lt;/li&gt;
&lt;li&gt;커서로 sql문 실행&lt;/li&gt;
&lt;li&gt;db에 반영&lt;/li&gt;
&lt;li&gt;5번의 결과에 따라 탈퇴되었는지, 아닌지 조건문 작성&lt;/li&gt;
&lt;li&gt;커서 및 db 연결 제거&lt;/li&gt;
&lt;/ol&gt;
&lt;div style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot; data-text-less=&quot;닫기&quot; data-text-more=&quot;더보기&quot; data-ke-type=&quot;moreLess&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;&lt;a style=&quot;color: #0070d1;&quot;&gt;더보기&lt;/a&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1781015315463&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;db = MySQLdb.connect(host='localhost', user='root', password='1234', db='ai')
cur = db.cursor()

userid = input(&quot;탈퇴할 아이디를 입력하세요: &quot;)

sql= 'delete from member where userid=%s'
result = cur.execute(sql, (userid,))        # 1개 값을 튜플로 넣을 때 쉼표
db.commit()

if result &amp;gt; 0:
    print('탈퇴되었습니다')
else:
    print('에러!')

cur.close()
db.close()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;* cur.execute() 시 세미콜론 안써도 되는 이유 :&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서는 한 문장이 끝났다는 의미로 세미콜론이 필요했지만, 파이썬에서는 한 문장씩 사용하기 때문에 없어도 된다&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;* DB만 끊지 않고 cursor와 db를 모두 끊는 이유 :&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 커서와 DB연결(connection)은 서로 다른 리소스이기 때문&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- cursor : 쿼리를 실행하고 결과를 가져오는 객체 (메모리 점유)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- db(connection) : 데이터베이스와 실제 네트워크 연결&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- db를 닫으면 커서도 같이 닫히지만 경우에 따라 경고나 에러가 발생할 수 있음&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 따라서 커서를 먼저 닫고 db를 끊기&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;* commit() : DML(insert, update, delete)은 반드시 커밋해야 DB에 반영&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;* select, update, delete는 execute하면 몇 개를 조회, 수정, 삭제 했는지 개수를 반환&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;* sql문 작성해서 변수에 저장 시, f-string으로도 가능하지만 보안상 좋지 않음&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;(&lt;u&gt;SQL Injection&lt;/u&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;공격을 받을 수 있으니 사용을 권장하지 않음)&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 입력 폼에 악성 SQL 구문을 주입하여 DB 조작하는 공격&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 사용자 개인 정보 탈취, 관리자 권한 우회, DB 삭제 및 변조&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;ex. sql = f&quot;select idx from member where userid={userid} and userpw={userpw}&quot;&lt;/span&gt;&lt;/p&gt;</description>
      <category>KDT/3. Python과 MySQL 연동</category>
      <author>김셀리</author>
      <guid isPermaLink="true">https://2lucesicutstellae.tistory.com/29</guid>
      <comments>https://2lucesicutstellae.tistory.com/29#entry29comment</comments>
      <pubDate>Tue, 9 Jun 2026 23:28:53 +0900</pubDate>
    </item>
    <item>
      <title>[14일차-1] 뷰</title>
      <link>https://2lucesicutstellae.tistory.com/28</link>
      <description>&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;#뷰 View&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;select 문을 저장해둔&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;가상의 테이블&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(자주 사용하는 select 문 결과를 편하게 사용하기 위함)&lt;/li&gt;
&lt;li&gt;뷰를 사용하는 이유
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;u&gt;복잡한 SQL 단순화&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;재사용 (자주 쓰는 조회 저장)&lt;/li&gt;
&lt;li&gt;가독성 (SQL을 보기 쉽게 구성)&lt;/li&gt;
&lt;li&gt;&lt;u&gt;보안 (특정 컬럼만 공개)&lt;/u&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;데이터를 직접 저장하지 않음 (원본 테이블의 select 결과를 보여주는 가상 테이블. 실제 테이블 x)&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;ex. member 테이블 데이터를 변경하면 -&amp;gt; view의 결과도 같이 변경&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;1. 뷰 생성&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 20px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 20px;&quot;&gt;create view 뷰이름&amp;nbsp; as select문&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre id=&quot;code_1781015252568&quot; class=&quot;pgsql&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;-- member 테이블에서 포인트가 100 이상인 userid, name, point를
-- vip_member로 view 생성
create view vip_member as
select userid, name, point from member where point &amp;gt;= 100;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 뷰 사용&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1781015252569&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;-- vip_member 뷰 사용
select * from vip_member;
select * from vip_member where point &amp;gt;= 150;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1781015252569&quot; class=&quot;routeros&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;-- 회원주소 뷰(member_address) 조회
-- userid, name, address1 + address2 + addres3 as address
create view member_address as 
select userid, name, concat(address1, ' ', address2, ' ', address3) as address from member;

-- 생성한 뷰 확인
select * from member_address;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 뷰 수정&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;뷰를 수정하기 위해서는 create on replace로 덮어 씌워야 한다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781015252570&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;-- vip_member 뷰에 email을 포함해서 조회
create on replace view vip_member as
select userid, name, point, email from member where point &amp;gt;= 100;

-- 수정한 뷰 확인
select * from vip_member;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 뷰 구조 확인&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;show create view 뷰이름;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre id=&quot;code_1781015252571&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;-- vip_member 뷰의 구조 확인
show create view vip_member;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 뷰 목록 확인&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생성되어 있는 뷰 목록을 확인할 수 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1781015252572&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;SHOW FULL TABLES WHERE Table_type = 'VIEW';&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. join을 사용한 뷰 생성&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1781015252572&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;-- member 테이블의 idx와 orders 테이블의 member_idx가 같은 것으로 두 테이블을 조인해서
-- userid, name, product_name, price, order_date를 조회하는 뷰 생성 (member_order)
create view member_order as
select m.userid, m.name, o.product_name, o.price, o.order_date from member as m
join orders as o on m.idx = o.member_idx;

-- 생성한 뷰 확인
select * from member_order;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>KDT/2. MySQL</category>
      <author>김셀리</author>
      <guid isPermaLink="true">https://2lucesicutstellae.tistory.com/28</guid>
      <comments>https://2lucesicutstellae.tistory.com/28#entry28comment</comments>
      <pubDate>Tue, 9 Jun 2026 23:28:08 +0900</pubDate>
    </item>
    <item>
      <title>[13일차] 서브 쿼리, 사용자계정(작성중)</title>
      <link>https://2lucesicutstellae.tistory.com/25</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 서브쿼리 Sub Query&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SQL문 안에 들어가는 또 다른 SELECT문&lt;/li&gt;
&lt;li&gt;예시&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780878157791&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 김사과보다 포인트가 많은 회원을 검색
select point from member where name = '김사과';
select * from member where point &amp;gt; 150;

-- 서브쿼리를 사용하여 한 번에 작성
select * from member where point &amp;gt; (select point from member where name = '김사과');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 단일 행 서브쿼리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;결과가 하나의 값만 나오는 서브쿼리&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780878380853&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 포인트가 가장 높은 회원 검색
select * from member where point = (select max(point) from member);

-- 서브쿼리만 실행해보면 max(point)가 250인 것 확인 가능
select max(point) from member;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 다중 행 서브쿼리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;결과가 여러 개 나오는 서브쿼리&lt;/li&gt;
&lt;li&gt;in, any, all을 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780879154676&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 포인트가 200 이상인 userid 목록에 포함된 회원 검색
select * from member where userid in (select userid from member where point &amp;gt;= 150);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. from 절 서브쿼리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서브쿼리 결과를 임시 '테이블'처럼 사용하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780879595004&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 포인트가 150 이상인 회원의 이름과 포인트를 조회
select name, point from (select name, point from member where point &amp;gt;= 150) as high_point_member;

-- from 절 서브쿼리를 조회하면 테이블 형태로 나올 것
select name, point from member where point &amp;gt;= 150;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. select 절 서브쿼리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;조회 결과에 서브쿼리 결과를 함께 보여주는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780879708516&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 각 회원의 포인트와 전체 평균 포인트를 함께 검색
select name, (select avg(point) from member) as avg_point from member;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. exists 서브쿼리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;존재 여부를 확인할 때 사용&lt;/li&gt;
&lt;li&gt;아래 orders 예제를 모두 푼 후 다시 보자&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780884316829&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 주문 내역이 있는 회원을 검색
select * from member m where exists (select 1 from orders o o.member_idx = m.idx);

-- select 1 : 하나라도 존재하는지 확인&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# 예제를 풀어보자&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;orders 테이블 생성 후 데이터 삽입&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780879774359&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- orders 테이블 생성
create table orders (
    order_id int auto_increment primary key,
    member_idx int not null,
    product_name varchar(100) not null,
    price int not null,
    order_date datetime default now(),
    foreign key (member_idx) references member(idx)
);

-- 데이터 삽입
insert into orders(member_idx, product_name, price)
values
(1, '키보드', 50000),
(1, '마우스', 30000),
(2, '모니터', 250000),
(2, '노트북 거치대', 40000),
(3, 'USB', 15000),
(4, '노트북', 1200000),
(4, '헤드셋', 90000);

-- 잘 만들어졌는지 확인
select * from orders;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예제를 풀어보자&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780879801247&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 1. 주문한 적이 있는 회원들만 조회
select * from member where idx in (select member_idx from orders);

-- 2. 주문한 적이 없는 회원들만 조회
select * from member where idx not in (select member_idx from orders);

-- 3. 가장 비싼 상품을 주문한 회원 조회
select * from member where idx = (select member_idx from orders where price = (select max(price) from orders));

-- 4. 가장 비싼 상품을 주문한 회원의 이름과 상품명, 가격을 조회
select m.name, o.product_name, o.price from member as m left join orders as o on m.idx = o.member_idx
where o.price = (select max(price) from orders);

-- 4번 처음 풀 때, 아래처럼 만들었는데 결과는 같음
select m.name, o.product_name, o.price
	from member as m left join orders as o on m.idx = o.member_idx
    where idx = (
		select member_idx from orders where price = (select max(price) from orders)
        )
	order by o.price desc limit 1;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. 서브쿼리로 스키마와 테이블 복사&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;orders 스키마를 복사해와서 orders_copy 스키마 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780927222187&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- orders 테이블 형태만 복사
create table orders_copy (
    order_id int auto_increment primary key,
    member_idx int not null,
    product_name varchar(100) not null,
    price int not null,
    order_date datetime default now(),
    foreign key (member_idx) references member(idx)
);

-- 형태만 복사했으니 데이터는 없는 상태
select * from orders_copy;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서브쿼리를 사용하여 orders 테이블의 데이터를 orders_copy로 복사 (테이블 형태가 똑같아야 가능)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780927387901&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 서브쿼리로 데이터 복사
insert into orders_copy (select * from orders);

-- 잘 복사되었는지 확인
select * from orders_copy;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. UNION&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 개의 select 결과를 하나로 합쳐주는 기능&lt;/li&gt;
&lt;li&gt;조회 결과를 위 아래로 이어 붙이는 기능&lt;/li&gt;
&lt;li&gt;중복 데이터 제거&lt;/li&gt;
&lt;li&gt;union all : 중복 데이터 제거하지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서울 회원과 부산 회원 합치기&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780927590407&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select name, address1 from member where address1 like '서울%'	-- 서울 회원
union
select name, address1 from member where address1 like '부산%';	-- 부산 회원&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로운 voca_new 테이블 생성 후, 데이터 삽입하고 잘 들어갔는지 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780927623243&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- voca_new 테이블 생성
create table voca_new (
	eng varchar(50) primary key,
    kor varchar(50) not null,
    lev int default 1,
    regdate datetime default now()
);

-- 데이터 삽입
insert into voca_new values('pineapple', '파인애플', 2, now());
insert into voca_new values('papaya', '파파야', 2, now());
insert into voca_new values('blueberry', '블루베리', 1, now());

-- 잘 들어갔는지 확인
select * from voca_new;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;voca의 eng, kor, lev와 voca_new의 eng, kor, lev를 조회&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780927778076&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select eng, kor, lev from voca
union
select eng, kor, lev from voca_new;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;겹치는 데이터 사과 추가 후 다시 union 해보자&lt;br /&gt;-&amp;gt; 중복되는 데이터는 보이지 않는 것이 확인 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780927815816&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;insert into voca_new values('apple', '사과', 1, now());

select eng, kor, lev from voca union select eng, kor, lev from voca_new;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그렇다면 voca와 voca_new의 eng, kor, lev, regdate를 모두 조회&lt;br /&gt;-&amp;gt; regdate는 다르기 때문에 중복 데이터가 아니라 사과가 2개가 조회됨&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780927916434&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select eng, kor, lev, regdate from voca union select eng, kor, lev, regdate from voca_new;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;중복데이터를 제거하지 않고 조회&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780928000882&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select eng, kor, lev from voca union all select eng, kor, lev from voca_new;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;3. 사용자 계정&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스에 접속할 수 있는 로그인 계정&lt;/li&gt;
&lt;li&gt;root 계정은 모든 권한을 가진 계정이기 때문에 실제 사용 시 위험할 수 있음&lt;/li&gt;
&lt;li&gt;프로젝트 별로 계정을 따로 만들고 필요한 권한만 부여하는 것이 일반적&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 계정 생성&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;create&amp;nbsp;user&amp;nbsp;'계정명'@'접속위치'&amp;nbsp;identified&amp;nbsp;by&amp;nbsp;'비밀번호';&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;localhost : 같은 컴퓨터(내 컴퓨팅)에서만 접속&lt;/li&gt;
&lt;li&gt;'apple'@'%' : 어디서든 접속 가능&lt;/li&gt;
&lt;li&gt;'apple'@'192.168.0.%' : 192.168.0.으로 시작하는 내부망에서만 접속 가능&lt;/li&gt;
&lt;li&gt;'apple'@' 192.168.0.10' : 특정 ip에서만 접속 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780963953601&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- apple이라는 계정을 만들고 비밀번호는 1111, localhost로 접속하도록 계정 만들기
create user 'apple'@'localhost' identified by '1111';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 권한 부여 및 확인&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 17px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20.3488%;&quot;&gt;권한 부여&lt;/td&gt;
&lt;td style=&quot;width: 79.6512%; height: 17px;&quot;&gt;grant 권한종류 on 데이터베이스명.테이블명 to '계정명'@'접속위치';&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.3488%;&quot;&gt;권한 확인&lt;/td&gt;
&lt;td style=&quot;width: 79.6512%;&quot;&gt;show grants for '계정명'@'접속위치';&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;all : 모든 일반 권한. select, insert, update, delete, create, drop, alter, index&lt;/li&gt;
&lt;li&gt;ai.* : ai 데이터베이스 안의 모든 테이블&lt;/li&gt;
&lt;li&gt;*.* : 모든 데이터베이스 안의 모든 테이블&lt;/li&gt;
&lt;li&gt;ai.member : ai 데이터베이스 안의 member 테이블&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;apple, banana, orange 계정 생성 후 아래와 같이 권한 부여&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;apple : 모든 권한&lt;/li&gt;
&lt;li&gt;banana : select 권한만&amp;nbsp;&lt;/li&gt;
&lt;li&gt;orange : select, insert, update, delete 권한&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780967560697&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- apple 계정에 모든 권한 부여
grant all on ai.* to 'apple'@'localhost';

-- 권한 확인
show grants for 'apple'@'localhost';&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1780985270201&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- banana 계정 생성 후 select 권한만 부여
create user 'banana'@'localhost' identifited by '2222';
grant select on ai.* to 'banana'@'localhost';

-- orange 계정 생성 후 select, insert, update, delete 권한 부여
create user 'orange'@'localhost' identified by '3333';
grant select, insert, update, delete on ai.* to 'orange'@'localhost';&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;apple, banana, orange 계정으로 로그인해보고 파일 만들어보기&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780985577517&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 김사과.sql
use ai;
show databases;
show tables;

select * from member;

-- root 계정이 아닌 다른 계정에서는 create user 불가능
-- create user 'banana'@'localhost' identified by '2223';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. &lt;b&gt;권한 회수하기&lt;/b&gt; &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. &lt;b&gt;사용자 비밀번호 변경하기&lt;/b&gt; &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# ip 주소란&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;4. MySQL 함수&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 문자열 함수&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 수학 함수&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 날짜 함수&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 조건 함수&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. 형변환 함수&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. 집계 함수&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>KDT/2. MySQL</category>
      <category>mysql함수</category>
      <category>union</category>
      <category>사용자계정</category>
      <category>서브쿼리</category>
      <author>김셀리</author>
      <guid isPermaLink="true">https://2lucesicutstellae.tistory.com/25</guid>
      <comments>https://2lucesicutstellae.tistory.com/25#entry25comment</comments>
      <pubDate>Mon, 8 Jun 2026 22:44:54 +0900</pubDate>
    </item>
    <item>
      <title>[13일차 과제] 자료구조(힙)</title>
      <link>https://2lucesicutstellae.tistory.com/24</link>
      <description>&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 힙이란?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 힙의 동작 과정&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;삽입&lt;/li&gt;
&lt;li&gt;삭제&lt;/li&gt;
&lt;li&gt;Heapify&lt;/li&gt;
&lt;li&gt;루트 제거 과정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 시간 복잡도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 힙 구현&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;insert()&lt;/li&gt;
&lt;li&gt;delete()&lt;/li&gt;
&lt;li&gt;print_heap()&lt;/li&gt;
&lt;li&gt;최대 힙/ 최소 힙 둘 다 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 힙(Heap)이란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 힙의 개념 및 특징&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정한 순서에 따라 정렬된 요소들을 저장하는 &lt;span style=&quot;color: #006dd7;&quot;&gt;트리 기반&lt;/span&gt;의 자료구조&lt;/li&gt;
&lt;li&gt;여러 개의 값들 중 최댓값이나 최솟값을 빠르게 찾기 위해 만들어진 자료구조&lt;/li&gt;
&lt;li&gt;힙 트리에서는 중복된 값을 허용 (이진 탐색 트리에서는 중복값 허용 x)&lt;/li&gt;
&lt;li&gt;우선 순위가 가장 높은 데이터(최댓값)가 루트에 위치&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;완전 이진 트리&lt;/span&gt;로 구현:&lt;br /&gt;마지막 레벨을 제외한 모든 레벨이 완전히 채워져 있고, 마지막 레벨은 왼쪽부터 채워져 있는 형태&lt;/li&gt;
&lt;li&gt;부모-자식 노드 관계 : &lt;br /&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;최대 힙에서는 부모 노드가 항상 자식노드보다 크거나 같은 값&lt;/li&gt;
&lt;li&gt;최소 힙에서는 부모 노드가 항상 자식 노드보다 작거나 같은 값&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;배열 기반으로 구현하는 이유
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;완전 이진 트리의 특성을 활용해 부모-자식 노드 간의 이동을 간단히 해결하기 위함&lt;/li&gt;
&lt;li&gt;트리를 탐색할 필요 없이 인덱스 연산만으로 접근이 가능
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;(왼쪽 자식 인덱스) = (부모 인덱스) x 2&amp;nbsp;&lt;/li&gt;
&lt;li&gt;(오른쪽 자식 인덱스) = (부모 인덱스) x 2 + 1&lt;/li&gt;
&lt;li&gt;(부모 인덱스) = (자식 인덱스) / 2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;일반 이진 트리와의 차이점&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 54px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10.814%; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 42.2092%; height: 20px; text-align: center;&quot;&gt;일반 이진 트리&lt;/td&gt;
&lt;td style=&quot;width: 46.9768%; height: 20px; text-align: center;&quot;&gt;힙 (완전 이진 트리)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 10.814%;&quot;&gt;정의&lt;/td&gt;
&lt;td style=&quot;width: 42.2092%; height: 17px;&quot;&gt;자식 노드를 최대 2개까지만 가지는 트리&lt;/td&gt;
&lt;td style=&quot;width: 46.9768%; height: 17px;&quot;&gt;마지막 레벨을 제외한 모든 레벨이 완전히 채워져 있고, 마지막 레벨은 왼쪽부터 채워져 있는 형태&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 10.814%;&quot;&gt;노드 규칙&lt;/td&gt;
&lt;td style=&quot;width: 42.2092%; height: 17px;&quot;&gt;부모-자식 노드 간의 특별한 규칙이 없음&lt;/td&gt;
&lt;td style=&quot;width: 46.9768%; height: 17px;&quot;&gt;부모 노드는 항상 자식 노드보다 크거나 같음 (최대 힙)&lt;br /&gt;또는 작거나 같음 (최소 힙)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 10.814%;&quot;&gt;주요 목적&lt;/td&gt;
&lt;td style=&quot;width: 42.2092%;&quot;&gt;데이터의 계층적 표현 및 탐색&lt;/td&gt;
&lt;td style=&quot;width: 46.9768%;&quot;&gt;우선순위 큐 구현, 최댓값/최솟값 탐색&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 10.814%;&quot;&gt;구현 방식&lt;/td&gt;
&lt;td style=&quot;width: 42.2092%;&quot;&gt;주로 포인터를 이용해 노드 연결하여 구현&lt;/td&gt;
&lt;td style=&quot;width: 46.9768%;&quot;&gt;중간에 빈 공간이 없어, 메모리 낭비가 없는 배열로 구현&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 힙 종류&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;709&quot; data-origin-height=&quot;284&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsLLsd/dJMcajvKcgp/MZ4UGkzYX7pEkYn3oVyap0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsLLsd/dJMcajvKcgp/MZ4UGkzYX7pEkYn3oVyap0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsLLsd/dJMcajvKcgp/MZ4UGkzYX7pEkYn3oVyap0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsLLsd%2FdJMcajvKcgp%2FMZ4UGkzYX7pEkYn3oVyap0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;512&quot; height=&quot;205&quot; data-origin-width=&quot;709&quot; data-origin-height=&quot;284&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최대 힙(Max Heap)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;최대 트리 : 각 노드의 키 값이 자식 노드가 있다면 그 자식의 키 값보다 크거나 같은 트리&lt;/li&gt;
&lt;li&gt;최대 힙 : 최대 트리이면서 완전 이진 트리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;최소 힙(Min Heap)
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;최소 트리 : 각 노드의 키 값이 자식노드가 있다며녀 그 자식의 키 값보다 작거나 같은 트리&lt;/li&gt;
&lt;li&gt;최소 힙 : 최소 트리이면서 완전 이진 트리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;그 외 : 이진 힙, 피보나치 힙, 이항 힙, Min-Max 힙&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 힙의 동작과정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 삽입(Insert)&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;트리의 가장 마지막 자리에 새로운 원소를 삽입&lt;/li&gt;
&lt;li&gt;새로 삽입한 노드와 부모 노드 값 비교 (Heapify Up)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최대 힙 : 부모 노드보다 값이 크면 위치를 교환&lt;/li&gt;
&lt;li&gt;최소 힙 : 부모 노드보다 값이 작으면 위치를 교환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;부모 노드와 비교하여 올바른 위치를 찾을 때까지 반복&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 삭제(Delete)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;힙의 삭제는 루트 노드에서만 삭제가 이루어짐
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최대 힙일 경우, 최댓값을 삭제&lt;/li&gt;
&lt;li&gt;최소 힙일 경우, 최솟값을 삭제&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;루트 노드를 삭제&lt;/li&gt;
&lt;li&gt;트리의 가장 마지막 노드를 루트 노드로 옮김&lt;/li&gt;
&lt;li&gt;루트 노드와 자식 노드 값을 비교 (Heapify Down)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최대 힙 : 두 자식 중 큰 값과 비교하여 자식이 더 크면 위치를 교환&lt;/li&gt;
&lt;li&gt;최소 힙 : 두 자식 중 작은 값과 비교하여 자식이 더 작으면 위치를 교환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;자식 노드와 비교하여 올바른 위치를 찾을 때까지 이 과정을 반복&lt;/li&gt;
&lt;/ol&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 37px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 20px;&quot;&gt;최대 힙 삽입&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 20px;&quot;&gt;최대 힙 삭제&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1582&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brAVCN/dJMcafz72r9/Hc9vZ9NmPPLOc8XvDueJK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brAVCN/dJMcafz72r9/Hc9vZ9NmPPLOc8XvDueJK1/img.png&quot; data-alt=&quot;최대 힙 삽입&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brAVCN/dJMcafz72r9/Hc9vZ9NmPPLOc8XvDueJK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrAVCN%2FdJMcafz72r9%2FHc9vZ9NmPPLOc8XvDueJK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;389&quot; height=&quot;481&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1582&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;최대 힙 삽입&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1582&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhH3Mh/dJMcaaewWXP/A3KDgak37beCBcsACvhkXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhH3Mh/dJMcaaewWXP/A3KDgak37beCBcsACvhkXK/img.png&quot; data-alt=&quot;최대 힙 삭제&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhH3Mh/dJMcaaewWXP/A3KDgak37beCBcsACvhkXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhH3Mh%2FdJMcaaewWXP%2FA3KDgak37beCBcsACvhkXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;379&quot; height=&quot;468&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1582&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;최대 힙 삭제&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Heapify&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터나 배열을 힙 구조로 재배열하는 과정&lt;/li&gt;
&lt;li&gt;일반 배열 상태에서 힙 성질(부모-자식 노드간 관계)을 만족하도록, 노드 위치를 아래로 내리며 질서를 잡는 과정&lt;/li&gt;
&lt;li&gt;삽입 / 삭제 후 힙 조건을 만족하도록 하는 과정에서 사용되는 연산
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;삽입 후 -&amp;gt; Heapify Up (상향식)&lt;/li&gt;
&lt;li&gt;삭제 후 -&amp;gt; Heapify Down (하향식)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 루트 제거 과정&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;힙에서 루트 노드의 값을 반환하고 제거하는 연산
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최대 힙 : 최댓값 반환 및 제거&lt;/li&gt;
&lt;li&gt;최소 힙 : 최솟값 반환 및 제거&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;삭제와 동일한 과정이지만, &lt;span style=&quot;color: #006dd7;&quot;&gt;반환 값&lt;/span&gt;을 활용하는 것에 초점&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;삭제 : 노드 제거를 위함, 반환 값 없음&lt;/li&gt;
&lt;li&gt;루트 제거 : 값을 꺼내서 활용하기 위함, 루트 값 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;루트 노드의 값을 저장 (반환하기 위해서)&lt;/li&gt;
&lt;li&gt;트리의 가장 마지막 노드를 루트 자리로 이동&lt;/li&gt;
&lt;li&gt;마지막 노드였던 자리 제거&lt;/li&gt;
&lt;li&gt;루트와 자식 노드 비교 (Heapify Down)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최대 힙 : 두 자식 중 큰 값과 비교하여 자식이 더 크면 위치를 교환&lt;/li&gt;
&lt;li&gt;최소 힙 : 두 자식 중 작은 값과 비교하여 자식이 더 작으면 위치를 교환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;올바른 위치를 찾을 때까지 반복&lt;/li&gt;
&lt;li&gt;저장해둔 루트 값을 반환&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 시간 복잡도&lt;/b&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 88px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.0775%; text-align: center; height: 20px;&quot;&gt;연산&lt;/td&gt;
&lt;td style=&quot;width: 11.2403%; text-align: center; height: 20px;&quot;&gt;시간 복잡도&lt;/td&gt;
&lt;td style=&quot;width: 73.6821%; text-align: center; height: 20px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 15.0775%; height: 17px;&quot;&gt;최대/최소 조회&lt;/td&gt;
&lt;td style=&quot;width: 11.2403%; height: 17px;&quot;&gt;O(1)&lt;/td&gt;
&lt;td style=&quot;width: 73.6821%; height: 17px;&quot;&gt;루트 노드 참조만 하면 됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 15.0775%; height: 17px;&quot;&gt;삽입&lt;/td&gt;
&lt;td style=&quot;width: 11.2403%; height: 17px;&quot;&gt;O(log n)&lt;/td&gt;
&lt;td style=&quot;width: 73.6821%; height: 17px;&quot;&gt;원소를 맨 끝에 추가 후, 부모 노드와 비교하여 위로 올라감 (상향식)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 15.0775%; height: 17px;&quot;&gt;삭제&lt;/td&gt;
&lt;td style=&quot;width: 11.2403%; height: 17px;&quot;&gt;O(log n)&lt;/td&gt;
&lt;td style=&quot;width: 73.6821%; height: 17px;&quot;&gt;루트 노드를 삭제하고, 맨 마지막 노드를 루트로 올린 뒤, 자식 노드와 비교하며 내려감 (하향식)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 15.0775%; height: 17px;&quot;&gt;Heapify&lt;/td&gt;
&lt;td style=&quot;width: 11.2403%; height: 17px;&quot;&gt;O(n)&lt;/td&gt;
&lt;td style=&quot;width: 73.6821%; height: 17px;&quot;&gt;n개의 데이터를 가진 배열을 힙으로 한 번에 구성&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 힙 구현&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# class MaxHeap 최대 힙 구현&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;init 생성자 :
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;힙은 초기에 데이터를 담을 배열만 있으면 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;insert() :&lt;br /&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;삽입할 요소를 매개변수로 받아옴&lt;/li&gt;
&lt;li&gt;배열에 값 삽입&lt;/li&gt;
&lt;li&gt;방금 삽입한(=마지막) 원소의 인덱스 cur = (배열길이) - 1&lt;/li&gt;
&lt;li&gt;삽입한 위치(cur)부터 heapify_up 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;heapify_up() :
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;인덱스가 0이면 루트이므로 return (끝)&lt;/li&gt;
&lt;li&gt;현재 노드의 부모 인덱스 구하기&lt;br /&gt;(힙 배열의 인덱스가 0부터 시작하기 때문에 cur // 2는 안됨)&lt;/li&gt;
&lt;li&gt;현재 노드 요소가 부모 노드 요소보다 크면 두 요소의 자리를 바꿈&lt;/li&gt;
&lt;li&gt;삽입했던 요소가 parent 위치에 있다. 완벽히 heap 될 때까지 heapify_up 재귀호출&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;delete() :
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;배열이 비어 있으면 return (끝)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;heapify_down() :
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;왼쪽, 오른쪽 자식 노드 인덱스&lt;/li&gt;
&lt;li&gt;현재 왼쪽, 오른쪽 중 가장 큰 값의 인덱스를 담을 변수 (초기값 = cur)&lt;/li&gt;
&lt;li&gt;자식이 배열 범위 안에 있을 때, 왼쪽(오른쪽) 자식이 더 크면 big 갱신&lt;/li&gt;
&lt;li&gt;cur이 가장 크면 힙 조건 만족하므로 종료&lt;/li&gt;
&lt;li&gt;두 요소의 자리를 바꾸고 완벽히 heap 될 때까지 heapify_down 재귀호출&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;get_max() :&amp;nbsp;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;delete와 다르게 요소 삭제 없이 루트 값(=최댓값)만 반환&lt;/li&gt;
&lt;li&gt;배열이 비어있으면 None 리턴&lt;br /&gt;아니면 루트 노드 리턴&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;print_heap() :
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;배열 전체 출력&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780907576353&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1. MaxHeap 구현
class MaxHeap:
    def __init__(self):     
        self.h_arr = []     # 힙은 초기에 데이터를 담을 배열만 있으면 됨

    # 삽입
    def insert(self, value):            # 삽입할 요소 매개변수로 받아옴
        self.h_arr.append(value)        # 배열에 값 삽입
        cur = len(self.h_arr) - 1      # 방금 삽입한(=마지막) 원소의 인덱스 cur = (배열길이) - 1
        self.heapify_up(cur)           # 삽입한 위치(cur)부터 heapify_up 수행

    def heapify_up(self, cur):
        if cur == 0:                    # 인덱스가 0이면 루트이므로 return (끝)
            return
        parent = (cur - 1) // 2         # 현재 노드의 부모 인덱스 구하기. 힙 배열의 인덱스가 0부터 시작 하기 때문에 cur // 2는 안됨
        if self.h_arr[cur] &amp;gt; self.h_arr[parent]:    # 현재 노드 요소가 부모 노드 요소보다 크면
            self.h_arr[cur], self.h_arr[parent] = self.h_arr[parent], self.h_arr[cur]   # 두 요소의 자리를 바꿈 (튜플로 처리하는 swap)
            # i = self.h_arr[cur]
            # self.h_arr[cur] = self.h_arr[parent]
            # self.h_arr[parent] = i
            self.heapify_up(parent)         # 삽입했던 요소가 parent 위치에 있다. 완벽히 heap이 될 때까지 heapify_up 재귀호출

    # 삭제
    def delete(self):
        if len(self.h_arr) == 0:     # 배열이 비어 있으면 return (끝)
            return 
        self.h_arr[0] = self.h_arr[-1]     # 마지막 노드를 루트 노드로 이동 (-1 = len(self.h_arr) - 1)
        self.h_arr.pop()                   # 마지막 노드 제거
        self.heapify_down(0)               # 루트에 대해 heapify_down 수행

    def heapify_down(self, cur):
        left = 2 * cur + 1      # 왼쪽 자식 노드 인덱스
        right = 2 * cur + 2     # 오른쪽 자식 노드 인덱스
        big = cur               # 현재 왼쪽, 오른쪽 중 가장 큰 값의 인덱스 (초기값 = cur)

        # 자식이 배열 범위 안에 있을 때만 비교
        if left &amp;lt; len(self.h_arr) and self.h_arr[left] &amp;gt; self.h_arr[big]:       # 왼쪽 자식이 더 크면 big 갱신
            big = left
        if right &amp;lt; len(self.h_arr) and self.h_arr[right] &amp;gt; self.h_arr[big]:     # 오른쪽 자식이 더 크면 big 갱신
            big = right

        if big == cur:      # cur이 가장 크면 힙 조건 만족 -&amp;gt; 종료
            return

        self.h_arr[big], self.h_arr[cur] = self.h_arr[cur], self.h_arr[big]     # 두 요소의 자리를 바꿈
        self.heapify_down(big)      # 완벽히 heap이 될 때까지 heapify_down 수행

    # 최댓값 조회 (삭제 없이 루트 값만 반환)
    def get_max(self):
        if len(self.h_arr) == 0:        # 배열이 비어있으면 delete와 달리 값을 반환해야하므로
            return None                 # None 리턴
        return self.h_arr[0]            # 루트 노드 = 최댓값

    # heap 데이터 출력
    def print_heap(self):
        print(self.h_arr)       # 배열 전체를 프린트&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1780907599828&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 2. 최대 힙 생성
h = MaxHeap()

# 3. 삽입 및 조회
h.insert(5)
h.insert(10)
h.insert(3)
h.insert(15)
h.print_heap()  # [15, 10, 3, 5]

# 4. 삭제 및 조회
h.delete()
h.print_heap()  # [10, 5, 3]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# 최소 힙 구현&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최대 힙을 활용해 최소 힙 구현&lt;/li&gt;
&lt;li&gt;&amp;gt;를 &amp;lt;로, big을 small로&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780924313403&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# MinHeap 구현
class MinHeap:
    def __init__(self):     
        self.h_arr = []     # 힙은 초기에 데이터를 담을 배열만 있으면 됨

    # 삽입
    def insert(self, value):            # 삽입할 요소 매개변수로 받아옴
        self.h_arr.append(value)        # 배열에 값 삽입
        cur = len(self.h_arr) - 1      # 방금 삽입한(=마지막) 원소의 인덱스 cur = (배열길이) - 1
        self.heapify_up(cur)           # 삽입한 위치(cur)부터 heapify_up 수행

    def heapify_up(self, cur):
        if cur == 0:                    # 인덱스가 0이면 루트이므로 return (끝)
            return
        parent = (cur - 1) // 2         # 현재 노드의 부모 인덱스 구하기. 힙 배열의 인덱스가 0부터 시작 하기 때문에 cur // 2는 안됨
        if self.h_arr[cur] &amp;lt; self.h_arr[parent]:    # 현재 노드 요소가 부모 노드 요소보다 작으면
            self.h_arr[cur], self.h_arr[parent] = self.h_arr[parent], self.h_arr[cur]   # 두 요소의 자리를 바꿈 (튜플로 처리하는 swap)
            # i = self.h_arr[cur]
            # self.h_arr[cur] = self.h_arr[parent]
            # self.h_arr[parent] = i
            self.heapify_up(parent)         # 삽입했던 요소가 parent 위치에 있다. 완벽히 heap이 될 때까지 heapify_up 재귀호출

    # 삭제
    def delete(self):
        if len(self.h_arr) == 0:     # 배열이 비어 있으면 return (끝)
            return 
        self.h_arr[0] = self.h_arr[-1]     # 마지막 노드를 루트 노드로 이동 (-1 = len(self.h_arr) - 1)
        self.h_arr.pop()                   # 마지막 노드 제거
        self.heapify_down(0)               # 루트에 대해 heapify_down 수행

    def heapify_down(self, cur):
        left = 2 * cur + 1      # 왼쪽 자식 노드 인덱스
        right = 2 * cur + 2     # 오른쪽 자식 노드 인덱스
        small = cur               # 현재 왼쪽, 오른쪽 중 가장 작은 값의 인덱스 (초기값 = cur)

        # 자식이 배열 범위 안에 있을 때만 비교
        if left &amp;lt; len(self.h_arr) and self.h_arr[left] &amp;lt; self.h_arr[small]:       # 왼쪽 자식이 더 크면 small 갱신
            small = left
        if right &amp;lt; len(self.h_arr) and self.h_arr[right] &amp;lt; self.h_arr[small]:     # 오른쪽 자식이 더 크면 small 갱신
            small = right

        if small == cur:      # cur이 가장 작으면 힙 조건 만족 -&amp;gt; 종료
            return

        self.h_arr[small], self.h_arr[cur] = self.h_arr[cur], self.h_arr[small]     # 두 요소의 자리를 바꿈
        self.heapify_down(small)      # 완벽히 heap이 될 때까지 heapify_down 수행

    # 최솟값 조회 (삭제 없이 루트 값만 반환)
    def get_min(self):
        if len(self.h_arr) == 0:        # 배열이 비어있으면 delete와 달리 값을 반환해야하므로
            return None                 # None 리턴
        return self.h_arr[0]            # 루트 노드 = 최솟값

    # heap 데이터 출력
    def print_heap(self):
        print(self.h_arr)       # 배열 전체를 프린트&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 힙을 구현할 때는 init 함수에 배열만 있으면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 다른 언어와 달리 파이썬에서는 두 변수의 위치를 바꿀 때 튜플을 사용해 바꿔줄 수 있어 편리하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 부모와 자식의 인덱스를 넣는 과정에서 틀리지 않도록 주의하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 힙을 구현한 코드를 C언어로 본 적은 있어도 직접 구현한 적은 처음이라 해시테이블과 마찬가지로 시간이 오래 걸렸지만 뿌듯하다.&lt;/p&gt;</description>
      <category>KDT/과제</category>
      <category>Heap</category>
      <category>heapify</category>
      <category>Maxheap</category>
      <category>MinHeap</category>
      <category>완전 이진 트리</category>
      <category>최대힙</category>
      <category>최소힙</category>
      <category>힙</category>
      <author>김셀리</author>
      <guid isPermaLink="true">https://2lucesicutstellae.tistory.com/24</guid>
      <comments>https://2lucesicutstellae.tistory.com/24#entry24comment</comments>
      <pubDate>Mon, 8 Jun 2026 22:38:53 +0900</pubDate>
    </item>
    <item>
      <title>[12일차] SQL문 연산자, 정규화</title>
      <link>https://2lucesicutstellae.tistory.com/23</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;11일차 &lt;b&gt;4. SQL 명령어 사용&lt;/b&gt;의&amp;nbsp;&lt;b&gt;DML&lt;/b&gt;에 이어서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. DML (이어서)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;11일차에 만들었던 member 테이블이 잘 있나 확인하고&lt;/li&gt;
&lt;li&gt;테이블에 gender 컬럼을 추가하자&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.3023%;&quot;&gt;컬럼명&lt;/td&gt;
&lt;td style=&quot;width: 80.6977%;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;설명&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.3023%;&quot;&gt;gender&lt;/td&gt;
&lt;td style=&quot;width: 80.6977%;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;varchar(10), not null&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컬럼들이 잘 생성되었는지 select문으로 확인해보자&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780836251673&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- member 테이블 확인
desc member;

-- gender 컬럼 추가
alter table member add gender varchar(10) not null;

-- member 테이블 데이터 확인 -&amp;gt; 컬럼만 조회됨 (데이터가 없으니까)
select * from member;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;회원 가입 : member 테이블에 회원 정보를 삽입해보자&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780835867209&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;insert into member (userid, userpw, name, hp, email, ssn1, ssn2, zipcode, address1, address2, address3, gender) values ('apple', '1111', '김사과', '010-1111-1111', 'apple@apple.com', '001011', '4011111', '12345', '서울 서초구', '양재동', '111-11', '여자');
insert into member (userid, userpw, name, hp, email, ssn1, ssn2, zipcode, address1, address2, address3, gender) values ('banana', '2222', '반하나', '010-2222-2222', 'banana@banana.com', '001011', '4011111', '12345', '서울 서초구', '양재동', '111-11', '여자');
insert into member (userid, userpw, name, hp, email, ssn1, ssn2, zipcode, address1, address2, address3, gender) values ('orange', '3333', '오렌지', '010-3333-3333', 'orange@orange.com', '001011', '4011111', '12345', '서울 서초구', '양재동', '111-11', '남자');
insert into member (userid, userpw, name, hp, email, ssn1, ssn2, zipcode, address1, address2, address3, gender) values ('melon', '4444', '이메론', '010-4444-4444', 'melon@melon.com', '001011', '4011111', '12345', '서울 서초구', '양재동', '111-11', '남자');
insert into member (userid, userpw, name, hp, email, ssn1, ssn2, zipcode, address1, address2, address3, gender) values ('cherry', '5555', '채리', '010-5555-5555', 'cherry@cherry.com', '001011', '4011111', '12345', '서울 서초구', '양재동', '111-11', '여자');&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;member 테이블의 point 컬럼을 수정해보자&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780836074881&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- idx가 5인 데이터에 대해 point를 0으로 수정
update member set point = 0 where idx = 5;

-- 모든 데이터에 대해 point를 50점 추가
update member set point = point + 50;

-- idx가 2인 데이터에 대해 point를 100점 추가
update member set point = point + 100 where idx = 2;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;select문으로 데이터를 조회해보자&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780836284141&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select 100;
select 100 + 50;
select 100 + 50 as 덧셈;
select 100 + 50 as '덧셈 연산';	-- 띄어쓰기는 '로 묶기
select '';		-- 빈 문자열(빈 문자가 들어가 있는 것)
select null;	-- 데이터가 없음
select 100 + '';
select 100 + null;	-- null과의 연산은 무조건 결과가 null&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. SQL의 연산자&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 산술 연산자&amp;nbsp;&lt;/b&gt;: + - * / mod(나머지) div(몫)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 비교 연산자&amp;nbsp;&lt;/b&gt;: =&amp;nbsp; &amp;nbsp;&amp;lt;&amp;nbsp; &amp;nbsp;&amp;gt;&amp;nbsp; &amp;nbsp;&amp;lt;=&amp;nbsp; &amp;nbsp;&amp;gt;=&amp;nbsp; &amp;nbsp;&amp;lt;&amp;gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 대입 연산자&amp;nbsp;&lt;/b&gt;: =&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. 논리 연산자&lt;/b&gt; : and or not xor&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. is 연산자&lt;/b&gt; : 양쪽의 피연산자가 모두 같으면 true(데이터가 출력), 아니면 false(데이터가 출력되지 않음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6. between A and B&amp;nbsp;&lt;/b&gt;: A보다는 크거나 같고, B보다는 작거나 같으면 true, 아니면 false&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7. in 연산자&lt;/b&gt; : 매개변수로 전달된 리스트에 값이 존재하면 true, 아니면 false&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8. like 연산자&lt;/b&gt; : 패턴으로 문자열을 검색하여 값이 존재하면 true, 아니면 false&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. SELECT문과 연산자 연습하기&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비교 연산자&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780836678871&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 포인트가 150이상인 멤버의 아이디, 이름, 포인트를 검색
select userid, name, point from member where point &amp;gt;= 150;
-- 포인트가 150이상이고, 200이하인 멤버의 아이디, 이름, 포인트, 성별을 검색
select userid, name, point, gender from member where point &amp;gt;= 150 and point &amp;lt;= 200;
select userid, name, point, gender from member where point between 150 and 200;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;두 가지 조건(and)을 사용한 로그인 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780836723099&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 로그인
select userid from member where userid = 'apple' and userpw = '1111';	-- 성공
select userid from member where userid = 'apple' and userpw = '1112';	-- 실패&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;논리 연산자(or)와 in 연산자&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780836748585&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 이름이 김사과, 반하나, 오렌지인 사람의 모든 정보를 검색
select * from member where name = '김사과' or name = '반하나' or name = '오렌지';
select * from member where name in ('김사과', '반하나', '오렌지');&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;member 테이블에 데이터 하나 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780836806803&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;insert into member (userid, userpw, name, hp, email, ssn1, ssn2, zipcode, address1, address2, address3, gender, regdate) values ('berry', '6666', '배애리', '010-6666-6666', 'berry@berry.com', '001011', '4011111', '12345', '서울 서초구', '양재동', '111-11', '여자', null);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;is 연산자와 is not 연산자&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780836852691&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- regdate가 null인 멤버를 검색
-- select * from member where regdate = null;	-- 불가능
select * from member where regdate is null;
select * from member where regdate is not null;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;like 연산자&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780836870087&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 아이디가 a로 시작하는 멤버의 정보를 검색
select * from member where userid like 'a%';
-- 아이디가 a로 끝나는 멤버의 정보를 검색
select * from member where userid like '%a';
-- 아이디가 a를 포함하는 멤버의 정보를 검색
select * from member where userid like '%a%';
-- 이메일이 '.com'으로 끝나는 멤버의 정보를 검색
select * from member where email like '%.com';
-- 이름이 3자인 멤버를 검색
select * from member where name like '___';
-- 이름 첫 글자가 '김'씨이며 3자인 멤버를 검색
select * from member where name like '김__';&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. order by (정렬)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오름차순(asc)가 기본값&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780836944197&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select * from member order by idx;	-- 오름차순 asc 생략
select * from member order by idx desc;	-- 내림차순
-- 멤버를 포인트 순으로 정렬
select * from member order by point desc;
-- 멤버를 포인트 순으로 정렬. 단 포인트가 같으면 가입 최신순으로 정렬
select * from member order by point desc, regdate desc;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. limit&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일부 row(레코드)를 검색&lt;/li&gt;
&lt;li&gt;limit 검색할 로우의 개수, limit 시작로우(인덱스) 가져울 로우의 개수&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780837056314&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select * from member limit 2;
select * from member limit 2, 3;
-- 멤버에서 포인트순으로 내림차순 정렬하고 포인트가 같다면 가입순으로 내림차순 한 뒤 top 3를 검색
select * from member order by point desc, regdate desc limit 3;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;6. group by&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780837096567&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select 그룹을 맺을 컬럼 또는 집계함수 from 테이블 group by 그룹을 맺을 컬럼
select 그룹을 맺을 컬럼 또는 집계함수 from 테이블 group by 그룹을 맺을 컬럼 having 그룹에 대한 조건&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그룹을 지어 조회해보자&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780837208276&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 성별로 그룹을 지어 성별을 조회
select gender from member group by gender;

-- 성별로 그룹을 지어 성별과 idx 수를 조회
select gender, count(idx) as 인원수 from member group by gender;

-- 성별로 그룹을 지어 성별이 여자인 데이터의 성별과 idx 수를 조회
select gender, count(idx) as 인원수 from member group by gender having gender = '여자';
select gender, count(idx) as 인원수 from member where gender = '여자' group by gender;

-- 성별로 그룹을 맺고 인원수가 3명 이상인 성별을 검색
select gender, count(idx) as 인원수 from member group by gender having count(idx) &amp;gt;= 3;
select gender, count(idx) as 인원수 from member group by gender having 인원수 &amp;gt;= 3;
select gender from member group by gender having count(idx) &amp;gt;= 3;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복잡한 sql을 구현해보자&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780837231429&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/*
	멤버 중 포인트가 50 이상인 멤버 중에서 성별로 그룹을 나눈 뒤,
	각 그룹의 포인트 평균을 구하고 평균의 포인트가 100 이상인 성별을 출력
    (단 성별이 남자, 여자 모두 출력된다면 포인트가 높은 성별을 우선으로 출력)
*/
select gender, avg(point) as 평균포인트 from member where point &amp;gt;= 50 group by gender having avg(point) &amp;gt;= 100 order by avg(point) desc;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;7. 정규화 Normalization&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스 테이블을 효율적으로 구조화하는 작업&lt;/li&gt;
&lt;li&gt;중복 데이터를 줄이고, 데이터가 꼬이지 않게 테이블을 나누는 과정&lt;/li&gt;
&lt;li&gt;데이터 무결성 유지, 유지보수 편리성 증가&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# 정규화 단계&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;제1정규형(1NF) : 하나의 칸에는 하나의 값만 들어가야 함&amp;nbsp;&lt;br /&gt;예) MySQL, Python을 한 칸에 넣을 수 없음&lt;/li&gt;
&lt;li&gt;제2정규형(2NF) : 1NF 만족, 기본키 전체에 완전 종속&lt;/li&gt;
&lt;li&gt;제3정규형(3NF) : 2NF 만족, 이행적 종속 제거&lt;br /&gt;* 이행적 종속 :&lt;br /&gt;&amp;nbsp; &amp;nbsp; 학번 -&amp;gt; 학과 번호&lt;br /&gt;&amp;nbsp; &amp;nbsp; 학과 번호 -&amp;gt; 학과명&lt;br /&gt;&amp;nbsp; &amp;nbsp; 학번 -&amp;gt; 학과명 : 간접 연결을 이행적 종속이라고 함&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;# 아래 테이블을 만들려고 하는데, 정규화해서 만들어보자 &lt;/b&gt;(필요한 데이터는 추가해서 만들어보자)&lt;/p&gt;
&lt;pre id=&quot;code_1780837564939&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;create table student_course (
    student_id INT,
    student_name VARCHAR(50),
    course_name VARCHAR(50),
    professor_name VARCHAR(50),
    professor_phone VARCHAR(20)
);&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1780837603772&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 학생 student
create table student (
	student_id int primary key,
    student_name varchar(20)
);
-- 교수 professor
create table professor (
	professor_id int primary key,
	professor_name varchar(20),
    professor_phone varchar(20)
);
-- 과목 course
create table course (
	course_id int primary key,
    course_name varchar(50),
    professor_id int,
    foreign key (professor_id) references professor(professor_id)
);
-- drop table enroll;
-- 수강 enroll
create table enroll (
	student_id int,	
    course_id int,
	foreign key(student_id) references student(student_id),
    foreign key(course_id) references course(course_id),
    primary key(student_id, course_id)
);&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;8. join&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;종류
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;inner join : 양쪽 테이블에 모두 있는 데이터에 대해 join&lt;/li&gt;
&lt;li&gt;left join : left에 있는 데이터에 대해서만 join (빈 곳은 NaN으로 채움)&lt;/li&gt;
&lt;li&gt;right join : right에 있는 데이터에 대해서만 join (빈 곳은 NaN으로 채움)&lt;/li&gt;
&lt;li&gt;cross join : 모든 경우에 대해 join&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;새로운 테이블 profile을 만들자&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780837692565&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;create table profile(
	idx int not null,
    height double,
    weight double,
    mbti varchar(10),
    foreign key(idx) references member(idx)
);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;profile 테이블에 데이터를 채우자&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780837719168&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;insert into profile values (1, 160, 50, 'ISTJ');
insert into profile values (3, 170, 70, 'ESTP');
insert into profile values (4, 175, 80, 'ENFJ');
insert into profile values (6, 175, 80, 'ENFJ');
-- insert into profile values (7, 175, 80, 'ENFJ'); 외래키 제약조건 위배&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;member 테이블과 profile 테이블을 join 해보자&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780837926983&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- inner join
select member.idx, userid, name, gender, mbti from member inner join profile 
on member.idx = profile.idx;
select m.idx, m.userid, m.name, m.gender, p.mbti from member as m 
inner join profile as p on m.idx = p.idx;

-- left join
select m.idx, m.userid, m.name, m.gender, p.mbti from member as m 
left join profile as p on m.idx = p.idx;

-- right join
select m.idx, m.userid, m.name, m.gender, p.mbti from member as m 
right join profile as p on m.idx = p.idx;

-- cross join
select userid, name, gender, mbti from member
cross join profile;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>KDT/2. MySQL</category>
      <category>group by</category>
      <category>Join</category>
      <category>LIMIT</category>
      <category>MySQL</category>
      <category>order by</category>
      <category>select</category>
      <category>정규화</category>
      <author>김셀리</author>
      <guid isPermaLink="true">https://2lucesicutstellae.tistory.com/23</guid>
      <comments>https://2lucesicutstellae.tistory.com/23#entry23comment</comments>
      <pubDate>Sun, 7 Jun 2026 21:33:00 +0900</pubDate>
    </item>
    <item>
      <title>[12일차 과제] 시간복잡도, 공간복잡도</title>
      <link>https://2lucesicutstellae.tistory.com/22</link>
      <description>&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 복잡도&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시간복잡도&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;공간복잡도&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;빅오표기법&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;3. 5가지&amp;nbsp;복잡도에&amp;nbsp;대한&amp;nbsp;간단한&amp;nbsp;예제&amp;nbsp;코드&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot;&gt;4. 반복문 개수에 따른 시간 복잡도&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 리스트에서 자주 사용하는 함수들의 시간복잡도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 공간복잡도가 증가하는 상황 예제 코드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;7. 비효율적인 코드와 효율적인 코드 비교&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 복잡도&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;알고리즘의 &lt;span style=&quot;color: #006dd7;&quot;&gt;성능&lt;/span&gt;을 나타내는 &lt;span style=&quot;color: #006dd7;&quot;&gt;척도&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;동일한 기능을 수행하는 알고리즘이 있다면 일반적으로 &lt;span style=&quot;color: #006dd7;&quot;&gt;복잡도가 낮을수록 좋은&lt;/span&gt; 알고리즘&lt;/li&gt;
&lt;li&gt;종류 : 시간복잡도와 공간복잡도&lt;/li&gt;
&lt;li&gt;효율적인 알고리즘을 사용한다는 가정 하에, 시간복잡도와 공간복잡도는 Trade-off 성립&lt;br /&gt;-&amp;gt; 메모리를 조금 더 많이 사용하면 반복되는 연산을 생략하거나 더 많은 정보를 관리하면서 복잡도를 줄일 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 시간복잡도(Time Complexity)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정한 크기의 입력에 대해 알고리즘이 &lt;span style=&quot;color: #006dd7;&quot;&gt;얼마나 오래&lt;/span&gt; 걸리는지 의미&lt;/li&gt;
&lt;li&gt;알고리즘을 위해 필요한 &lt;span style=&quot;color: #006dd7;&quot;&gt;연산의 횟수&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;빅오표기법을 사용함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 공간복잡도(Space Complexity)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정한 크기의 입력에 대해 알고리즘이 &lt;span style=&quot;color: #006dd7;&quot;&gt;얼마나 많은 메모리&lt;/span&gt;를 차지하는지 의미&lt;/li&gt;
&lt;li&gt;알고리즘을 위해 필요한 &lt;span style=&quot;color: #006dd7;&quot;&gt;메모리의 양&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;빅오표기법을 사용함&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;공간 복잡도를 따질 때는 &quot;추가로&quot; 사용하는 메모리만 계산&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;구성요소&lt;/span&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;고정 공간(Fixed Space)&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;입력 크기(n)과 관계없이 항상 일정하게 사용하는 메모리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;변수, 상수, 코드 자체 등&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;가변 공간(variable Space&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;입력 크기(n)에 따라서 변하는 메모리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;동적 할당, 재귀 호출 스택 등&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780729167800&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 매개변수 arr 자체는 제외
# 코드 내부에서 추가로 쓰는 메모리만 계산
def get_max(arr):
	m = arr[0]		# 변수 1개 추가 -&amp;gt; O(1)
    for x in arr:
    	if x &amp;gt; m:
        	m = x
    return m&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 빅오표기법(BIG-O Notation)&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 빠르게 증가하는 항만 고려하는 표기법으로, 함수의 상한만 표시&lt;span&gt;&amp;nbsp;&lt;/span&gt;(아무리 나빠도 이정도)&lt;/li&gt;
&lt;li&gt;빅오표기법의 규칙
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;상수항 무시 : 실행 시간에 영향을 주지 않는 상수는 버림&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;ex. O(3n) -&amp;gt; O(n)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;영향력 없는 항 무시 : 가장 증가 속도가 빠른 (차수가 가장 높은) 항만 남김&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;ex. O(n&amp;sup2; + n) -&amp;gt; O(n&amp;sup2;)&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 108px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 99.9999%; height: 20px;&quot; colspan=&quot;3&quot;&gt;점근적 복잡도 표기법 종류&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;표기법&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;기호&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;의미&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;빅오&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;O(n)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;최악의 경우 (상한)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;빅오메가&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&amp;Omega;(n)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;최선의 경우 (하한)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;빅세타&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&amp;Theta;(n)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;평균적인 경우 (상한 + 하한)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;리틀오&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;o(n)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;빅오보다 엄격한 상한&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rkTyN/dJMcafti6lB/n7DEmq1knQy0deI365pbC0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rkTyN/dJMcafti6lB/n7DEmq1knQy0deI365pbC0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rkTyN/dJMcafti6lB/n7DEmq1knQy0deI365pbC0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrkTyN%2FdJMcafti6lB%2Fn7DEmq1knQy0deI365pbC0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;439&quot; height=&quot;247&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 200px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 101.453%; height: 20px;&quot; colspan=&quot;4&quot;&gt;복잡도 종류 (빠른 순)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 11.1047%; text-align: center; height: 20px;&quot;&gt;표기법&lt;/td&gt;
&lt;td style=&quot;width: 10.8721%; text-align: center; height: 20px;&quot;&gt;이름&lt;/td&gt;
&lt;td style=&quot;width: 53.0814%; text-align: center; height: 20px;&quot;&gt;설명&lt;/td&gt;
&lt;td style=&quot;width: 26.3953%; text-align: center; height: 20px;&quot;&gt;예시 알고리즘&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 11.1047%; height: 20px;&quot;&gt;O(1)&lt;/td&gt;
&lt;td style=&quot;width: 10.8721%; height: 20px;&quot;&gt;상수&lt;/td&gt;
&lt;td style=&quot;width: 53.0814%; height: 20px;&quot;&gt;입력 크기(n)와 상관 없이 항상 일정한 시간이 걸림&lt;/td&gt;
&lt;td style=&quot;width: 26.3953%; height: 20px;&quot;&gt;배열 인덱스 접근&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 11.1047%; height: 20px;&quot;&gt;O(log n)&lt;/td&gt;
&lt;td style=&quot;width: 10.8721%; height: 20px;&quot;&gt;로그&lt;/td&gt;
&lt;td style=&quot;width: 53.0814%; height: 20px;&quot;&gt;입력 크기가 커질 때마다 처리 시간이 로그 비율로 줄어듦&lt;/td&gt;
&lt;td style=&quot;width: 26.3953%; height: 20px;&quot;&gt;이진 탐색&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 11.1047%; height: 20px;&quot;&gt;O(n)&lt;/td&gt;
&lt;td style=&quot;width: 10.8721%; height: 20px;&quot;&gt;선형&lt;/td&gt;
&lt;td style=&quot;width: 53.0814%; height: 20px;&quot;&gt;입력 크기에 비례하여 처리 시간 증가&lt;/td&gt;
&lt;td style=&quot;width: 26.3953%; height: 20px;&quot;&gt;선형 탐색(리스트 전체 탐색)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 11.1047%; height: 20px;&quot;&gt;O(n log n)&lt;/td&gt;
&lt;td style=&quot;width: 10.8721%; height: 20px;&quot;&gt;선형 로그&lt;/td&gt;
&lt;td style=&quot;width: 53.0814%; height: 20px;&quot;&gt;입력 크기를 반으로 쪼개 각각 O(log n)의 시간이 걸리는 작업 반복&lt;/td&gt;
&lt;td style=&quot;width: 26.3953%; height: 20px;&quot;&gt;병합 정렬(정렬알고리즘 중 가장 최선), 퀵 정렬&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 11.1047%; height: 20px;&quot;&gt;O(n&amp;sup2;)&lt;/td&gt;
&lt;td style=&quot;width: 10.8721%; height: 20px;&quot;&gt;이차&lt;/td&gt;
&lt;td style=&quot;width: 53.0814%; height: 20px;&quot;&gt;입력 크기의 제곱에 비례하여 처리 시간 증가&lt;br /&gt;데이터가 많아지면 성능이 급격히 저하&lt;/td&gt;
&lt;td style=&quot;width: 26.3953%; height: 20px;&quot;&gt;버블 정렬, 삽입 정렬&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 11.1047%; height: 20px;&quot;&gt;O(n&amp;sup3;)&lt;/td&gt;
&lt;td style=&quot;width: 10.8721%; height: 20px;&quot;&gt;삼차&lt;/td&gt;
&lt;td style=&quot;width: 53.0814%; height: 20px;&quot;&gt;입력 크기의 세제곱에 비례하여 처리 시간 증가&lt;br /&gt;데이터가 많아지면 성능이 급격히 저하&lt;/td&gt;
&lt;td style=&quot;width: 26.3953%; height: 20px;&quot;&gt;행렬 곱셈&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 11.1047%; height: 20px;&quot;&gt;O(2ⁿ)&lt;/td&gt;
&lt;td style=&quot;width: 10.8721%; height: 20px;&quot;&gt;지수&lt;/td&gt;
&lt;td style=&quot;width: 53.0814%; height: 20px;&quot;&gt;입력 크기에 따라 시간이 기하급수적으로 증가&lt;br /&gt;실무에서는 사용하기 매우 어려움&lt;/td&gt;
&lt;td style=&quot;width: 26.3953%; height: 20px;&quot;&gt;피보나치 재귀&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 11.1047%; height: 20px;&quot;&gt;O(n!)&lt;/td&gt;
&lt;td style=&quot;width: 10.8721%; height: 20px;&quot;&gt;팩토리얼&lt;/td&gt;
&lt;td style=&quot;width: 53.0814%; height: 20px;&quot;&gt;모든 경우의 수를 다 따짐&lt;/td&gt;
&lt;td style=&quot;width: 26.3953%; height: 20px;&quot;&gt;순열 완전 탐색&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 5가지 복잡도에 대한 간단한 예제 코드&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. O(n)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1780643558082&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 배열의 첫 번째 요소에 접근
# 입력 데이터 수가 달라도 항상 1번만 실행
def get_first(arr):
	return arr[0]
    
data1 = [10, 20, 30, 40, 50]
data2 = [11, 20, 30, 40, 50, 60, 70, 80, 90, 100]
print(get_first(data1))
print(get_first(data2))

# 10
# 11&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. O(log n)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력한 숫자가 2배 늘어도 연산 횟수가 1회 증가된 것을 확인할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780643748748&quot; class=&quot;python&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# 숫자를 절반씩 나누다가 1이 되면 종료
# n이 2배 늘어도 반복 횟수는 1번 증가
def cnt_halv(num):
    cnt = 0             # 연산 횟수 저장할 변수

    while num &amp;gt; 1:
        num //= 2       # 절반씩 줄어듦
        cnt += 1
    return cnt

print(f&quot;연산 횟수 : {cnt_halv(37)}&quot;)
print(f&quot;연산 횟수 : {cnt_halv(512)}&quot;)
print(f&quot;연산 횟수 : {cnt_halv(1024)}&quot;)

# 연산 횟수 : 5
# 연산 횟수 : 9
# 연산 횟수 : 10&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;3. O(n)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력 크기(리스트 크기)가 2배 되었을 때 연산 횟수 2배 증가된 것을 확인할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780645101490&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 리스트 전체를 순회하여 최댓값을 가져오는 경우
def get_max(arr):
    m = arr[0]       # max값을 저장할 변수(첫 번째 요소로 초기화)
                     # m = 0으로 초기화하면 음수만 있는 리스트에서 에러 발생 
    cnt = 0          # 연산 횟수 저장할 변수

    for li in arr:
        if li &amp;gt; m: 
            m = li
        cnt += 1
    return cnt, m


li1 = [3, 5, 1, 4, 100, 2, 9]
li2 = [3, 5, 1, 4, 101, 2, 9, 30, 50, 10, 40, 99, 20, 90]

cnt1, max1 = get_max(li1)       # 튜플 언패킹 (리턴값 2개를 받아올 변수 2개 사용)
cnt2, max2 = get_max(li2)
print(f&quot;최댓값 : {max1}, 연산 횟수 : {cnt1}&quot;)       # 최댓값 : 100, 연산 횟수 : 7
print(f&quot;최댓값 : {max2}, 연산 횟수 : {cnt2}&quot;)       # 최댓값 : 101, 연산 횟수 : 14&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4. O(n log n)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1780647302186&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 숫자를 절반씩 나누는 것을 입력한 데이터 수만큼 실행
def cnt_halv_all(arr):
    cnt = 0             # 연산 횟수 저장할 변수

    for i in arr:
        n = i           # arr 리스트의 요소 1개를 가져와서
        while n &amp;gt; 1:    # 1보다 클 때
            n //= 2     # 2로 나눈다
            cnt += 1
    return cnt

arr = [37, 512, 1024]
print(f&quot;연산 횟수 : {cnt_halv_all(arr)}&quot;)    # 연산 횟수 : 24&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5. O(n&amp;sup2;)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1780648015978&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 이중 반복문
# 모든 두 수의 합을 출력 &amp;rarr; n &amp;times; n = n&amp;sup2;번 실행

def print_all_hap(arr):
    cnt = 0         # 연산 횟수 저장할 변수

    for i in arr:       # 외부 반복문 n번
        for j in arr:   # 내부 반복문 n번       -&amp;gt; 총 n&amp;sup2;번
            print(f&quot;{i} + {j} = {i + j}&quot;, end = &quot;   &quot;)      # 각 경우를 모두 출력
            cnt += 1        # 이중 반복문을 도는 동안 연산 횟수 증가
        print()             # 외부 반복문 끝날 때마다 줄바꿈 (보기 좋게 출력하기 위함)
    
    return cnt
            
arr1 = [1, 2, 3]
arr2 = [1, 2, 3, 4, 5, 6]
print(f&quot;연산 횟수 : {print_all_hap(arr1)}&quot;)     # 연산 횟수 : 9
print(f&quot;연산 횟수 : {print_all_hap(arr2)}&quot;)     # 연산 횟수 : 36&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 반복문 개수에 따른 시간복잡도&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 단일 반복문 (1개)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시간 복잡도 : O(n)&lt;/li&gt;
&lt;li&gt;내부에서 입력 크기 n만큼 순회&lt;/li&gt;
&lt;li&gt;데이터가 늘어나는 만큼 연산 횟수도 정비례하여 증가&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;ex. 배열의 모든 요소 한 번 탐색&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 중첩 반복문 (2개)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시간 복잡도 : O(n&amp;sup2;)&lt;/li&gt;
&lt;li&gt;바깥쪽 반복문이 n번 돌 때마다 안쪽 반복문이 n번씩 실행되므로 총 n x n번의 연산 수행&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;ex. 이중 for문을 사용해 별(*) 찍기&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. k중 반복문 (k개)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시간 복잡도 : O(nᵏ)&lt;/li&gt;
&lt;li&gt;반복문의 깊이가 깊어질수록 (= k가 커질수록) 성능이 급격하게 저하&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;ex. 삼중 for문을 사용해 모든 경우의 수를 완전 탐색&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. 리스트에서 자주 사용하는 함수들의 시간복잡도&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리스트는 데이터구조(배열, 연결 리스트)와 사용 언어(파이선, 자바 등)에 따라 시간복잡도가 다르다&lt;/li&gt;
&lt;li&gt;9일차 과제에서 진행한 &lt;span style=&quot;color: #006dd7;&quot;&gt;단순 연결 리스트&lt;/span&gt;의 시간복잡도를 알아보자&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 253px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 99.9999%; text-align: left; height: 21px;&quot; colspan=&quot;3&quot;&gt;단순 연결리스트의 시간복잡도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 23.9147%; text-align: center; height: 21px;&quot;&gt;연산&lt;/td&gt;
&lt;td style=&quot;width: 16.3565%; text-align: center; height: 21px;&quot;&gt;시간복잡도&lt;/td&gt;
&lt;td style=&quot;width: 59.7287%; text-align: center; height: 21px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 85px;&quot;&gt;
&lt;td style=&quot;width: 23.9147%; height: 85px;&quot;&gt;맨 뒤 삽입 append&lt;/td&gt;
&lt;td style=&quot;width: 16.3565%; height: 85px;&quot;&gt;O(n) &lt;span style=&quot;color: #9d9d9d;&quot;&gt;tail 미사용 시 &lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 59.7287%; height: 85px;&quot;&gt;- 맨 앞 삽입이면 O(1)&lt;br /&gt;- 맨 뒤 삽입이면 O(n) : n개의 노드를 모두 순회 후 삭제 가능&lt;br /&gt;- tail 을 사용하게 되면 O(1)로 줄일 수 있으나, tail 관리를 위한 메모리를 사용하게 됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 42px;&quot;&gt;
&lt;td style=&quot;width: 23.9147%; height: 42px;&quot;&gt;임의 위치 삽입 insert&lt;/td&gt;
&lt;td style=&quot;width: 16.3565%; height: 42px;&quot;&gt;O(n)&lt;/td&gt;
&lt;td style=&quot;width: 59.7287%; height: 42px;&quot;&gt;- 맨 앞 삽입이면 O(1)&lt;br /&gt;- 그 외 삽입이면 O(n) : 해당 위치까지 순회하므로&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 42px;&quot;&gt;
&lt;td style=&quot;width: 23.9147%; height: 42px;&quot;&gt;인덱스(위치) 기준 삭제 pop&lt;/td&gt;
&lt;td style=&quot;width: 16.3565%; height: 42px;&quot;&gt;O(n)&lt;/td&gt;
&lt;td style=&quot;width: 59.7287%; height: 42px;&quot;&gt;- 맨 앞 삭제면 : O(1)&lt;br /&gt;- 그 외 삭제면 : O(n)&lt;br /&gt;&amp;nbsp; -&amp;gt; 단순 연결 리스트는 역방향 참조가 없기 때문에 맨 앞부터 해당 위치까지 순회 필요&lt;br /&gt;- 9일차 과제에서 구현한 단순 연결 리스트에는 pop을 구현하지 않았음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 23.9147%; height: 21px;&quot;&gt;값 기준 삭제 remove&lt;/td&gt;
&lt;td style=&quot;width: 16.3565%; height: 21px;&quot;&gt;O(n)&lt;/td&gt;
&lt;td style=&quot;width: 59.7287%; height: 21px;&quot;&gt;- 맨 앞 삭제면 : O(1)&lt;br /&gt;- 그 외 삭제면 : O(n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 23.9147%; height: 21px;&quot;&gt;정렬 sort&lt;/td&gt;
&lt;td style=&quot;width: 16.3565%; height: 21px;&quot;&gt;O(n&amp;sup2;)&lt;/td&gt;
&lt;td style=&quot;width: 59.7287%; height: 21px;&quot;&gt;- 일반적으로 버블 정렬/삽입 정렬 사용 : O(n&amp;sup2;)&lt;br /&gt;- 인덱스 접근이 불가해서 -&amp;gt; 퀵/병합 정렬 구현이 복잡함 : O(n log n)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;6. 공간복잡도가 증가하는 상황 예제 코드&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;O(1) O(n) O(n&amp;sup2;)&lt;/li&gt;
&lt;li&gt;실제 개발에서는 O(1), O(n)을 가장 많이 사용&lt;/li&gt;
&lt;li&gt;O(n&amp;sup2;), O(2ⁿ)은 피하는게 좋음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780731424122&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# O(1) : x는 1개짜리 공간 재사용
for x in arr:
	print(x)
    
# O(n) : result에 계속 추가로 쌓이기 때문에 n개의 요소가 동시에 메모리에 존재하게 된다
result = []
for x in arr:
	result.append(x)

# O(n&amp;sup2;) : matrix 리스트에 n개짜리 행이 n번 쌓임
def make_matrix(n):
	matrix = []
    for i in range(n):
    	row = [0] * n			# n개짜리 행이
        maxtrix.append(row)		# n번 쌓임
    return matrix&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;7. 비효율적인 코드와 효율적인 코드 비교&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리스트에서 최댓값 찾는 &lt;u&gt;비효율적&lt;/u&gt; 코드 : O(n&amp;sup2;)&lt;/li&gt;
&lt;li&gt;모든 요소를 서로 비교하므로 n x n번 순회&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780732121185&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def find max_bad(arr):
	for i in range(len(arr)):
    	is_max = True
        for j in range(len(arr)):
        	if arr[j] &amp;gt; arr[i]:
            	is_max = False
                break
         if is_max:
         	return arr[i]&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리스트에서 최댓값 찾는 &lt;u&gt;효율적&lt;/u&gt; 코드 : O(n)&lt;/li&gt;
&lt;li&gt;리스트를 한 번만 순회&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1780732265107&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def find_max_good(arr):
	max_val = arr[0]		# 첫 번째 값을 우선 max_val에 넣음
    for x in arr:			# arr을 돌면서 
    	if x &amp;gt; max_val:		# 각 요소를 비교
        	max_val = x		# 더 크면 max_val 최댓값 업데이트
    return max_val&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 복잡도 표기법은 위에 조사한 내용보다 더 많이 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 자료구조 과제 시 배열, 스택, 큐, 연결리스트 관련 포스터에 각각의 시간복잡도 확인 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 공간복잡도의 코드에서 for문의 변수 x는 반복문이 끝나면 메모리에서 해제되기 때문에 공간복잡도로 계산하지 않은지 궁금해서 알아보았다. 결론은 x가 동시에 하나만 존재하기 때문이다. for문 10번 반복해도 x라는 변수 1개짜리 공간만 재사용하기 때문에 여러 개의 x가 메모리에 존재하는 것이 아니기 때문에 O(1) 상수 공간으로 본다.&amp;nbsp;&lt;/p&gt;</description>
      <category>KDT/과제</category>
      <category>공간복잡도</category>
      <category>빅오표기법</category>
      <category>시간복잡도</category>
      <author>김셀리</author>
      <guid isPermaLink="true">https://2lucesicutstellae.tistory.com/22</guid>
      <comments>https://2lucesicutstellae.tistory.com/22#entry22comment</comments>
      <pubDate>Sun, 7 Jun 2026 21:29:19 +0900</pubDate>
    </item>
  </channel>
</rss>