del(lst[2])
print(lst)
* 국가에서 지원하는 K-digital training 인공지능 코스를 수강하게 되었다.
여러 기관에서 이 코스를 진행하는 것으로 알고 있고, 상세한 커리큘럼과 난이도는 조금씩 다르다고 한다.
내가 수강하는 기관은 매일 매일 공부한 내용을 정리하여 포스팅할 것을 권장한다.
그날 공부한 내용을 정리하고 잘 몰랐다가 알게 된 것들에 대한 기록을 남기려고 한다.
*감상
: 솔직히 7~9강의 연결리스트는 너무 어려웠다.
파이썬 클래스에 대해서 배운 적이 있기는 하지만, (작년 11월에 파이썬 입문 수업 때)
지난, 1~3월에 들었던 빅데이터 분석 수업에서는 거의 활용하지 않았었기 때문에 가물가물하다.
솔직히 여기서 너무 헤매서 커리큘럼에서 하루 동안 제시한 진도를 모두 마무리하지 못했다.
<번외> 문자열 내에서 변수 출력하는 여러 방법 중 %
%s 문자열(string)
%d 정수(integer)(앞에 0붙일 수 있음 %03d 는 d 까지 합쳐서 총 3자리가 되도록 앞에 0을 붙이라는 뜻)
%f 실수(float) (실수는 소수점자리 지정가능 %.2f 는 소수점 둘 째자리까지 표시)
a = "Jane"
print("Hello! I'm %s." % (a))
결과 > Hello! I'm Jane.
num = 11
print("The room number is %03d." %(num))
결과 > The room number is 011.
ts1 = time.time()
stack = [k for k in range(1000000)]
ts2 = time.time()
elapsed = ts2-ts1
print("elapsed time = %.2fs." % (elapsed))
결과 > elapsed time = 0.09s.
본 강의는 프로그래머스 : 어서와! 자료구조와 알고리즘은 처음이지? 와 동일한 것 같다.
커리큘럼이 동일하다.
1. 자료구조와 알고리즘
- 웬만한 것들을 Python에서 이미 제공하는 데이터 타입으로 다 해결할 수 있는데 왜 자료구조를 알아야 하는건지
- 효과적으로 해결하고자 하는 문제가 무엇이냐에 따라서 적합하게 이용하려는 자료구조가 달라짐
- 기본적으로 제공되는 데이터 타입만으로는 해결할 수 없는 문제가 있다
- 알고리즘이란?
- 사전적 정의
- 어떤 문제를 해결하기 위한 절차, 방법, 명령어 들의 집합
- 프로그래밍
- 주어진 문제의 해결을 위한 자료구조와 연산 방법에 대한 선택
- 사전적 정의
- 해결하고자 하는 문제에 따라 (응용 종류와 범위에 따라) 최적의 해법은 서로 다르다 -> 선택을 위해 자료구조를 이해해야 함
2. 선형 배열 (linear array)
- 배열 array : 데이터를 순서대로 늘어놓은 형태
- 리스트 list : 파이썬의 데이터형
- 파이썬 리스트에서 사용할 수 있는 연산
- 리스트 길이와 실행시간 관계없는 연산 (상수 시간, O(1)) : .append() (끝에 원소 하나 붙이기), .pop() (끝에 원소 하나 빼기)
- 리스트 길이와 실행시간 비례하는 연산 (선형 시간, O(n)) : .insert() (원소 삽입), del() (원소 삭제)
- 그외 : .index() (원소 탐색)
lst = [5,60,20,14, 98,88]
lst.insert(2, 25)
print(lst)
결과 > [5, 60, 25, 20, 14, 98, 88]
del(lst[2])
print(lst)
결과 > [5, 60, 20, 14, 98, 88]
*.pop() 과 del()의 차이점
lst = [5,60,20,14, 98,88]
print(lst.pop(2))
print(lst)
결과> 20
[5, 60, 14, 98, 88]
lst.pop(2) del(lst[2])와는 달리 빼는 값을 반환한다.
lst = [5,60,20,14, 98,88]
del(lst[2])
print(del(lst[2]))
print(lst)
결과 > print(del(lst[2]))
^
SyntaxError: invalid syntax
3. 정렬과 탐색 (sort and search)
1) 정렬
- 복수의 원소로 주어진 데이터를 정해진 기준에 따라 새로 늘어놓는 작업
- Python의 리스트는 내장된 정렬기능이 있다
- 파이썬 내장 함수 : sorted()
- 정렬된 새로운 리스트를 return
- 리스트 메서드 : sort()
- 해당 리스트를 정렬해서 리스트 자체가 바뀜
- 정렬의 순서를 반대로 하고 싶을 때: reverse=True
- 파이썬 내장 함수 : sorted()
- string 정렬
- 알파벳순 정렬
- 대문자가 소문자보다 우선
- 문자열 길이 순서로 정렬하고 싶다면? 람다 활용해서 key 지정해서 정렬
2) 탐색
- 복수의 원소로 주어진 데이터에서 특정 원소를 찾아내는 작업
- 선형탐색 linear search, 순차탐색 sequential search
- 순차적으로 모든 요소를 탐색
- O(n)
- 이진탐색 binary search
- 배열이 이미 정렬되어 있을 때만
- 한번 비교가 일어날 때마다 리스트의 길이를 반씩 줄임(divide & conquer)
- O(log n)
- 이진탐색이 빠르지만, 정렬에 대한 복잡도를 생각해봐야 한다
def linear_search(L, x):
i = 0
while(i < len(L) and L[i] != x):
i += 1
if(i < len(L)):
return i
else:
return -1
def binary_search(L, x):
min = 0
max = len(L) - 1
idx = -1
while min <= max:
middle = (min + max) //2
if L[middle] == x:
idx =middle
break
elif L[middle] < x:
min = middle + 1
else:
max = middle - 1
answer = idx
return answer
4. ~5. 재귀 알고리즘
- 같은 알고리즘을 반복적으로 적용해서 풀어내는 방법
- 재귀함수(recursive function) : 하나의 함수에서 자기 자신을 다시 호출해서 작업하는 것
- 종결 조건 (수학에서는 점화식)이 필요
ex>
1. binary tree
2. 자연수의 합 구하기
3. n!
예제> 피보나치 순열을 1)재귀적 방법으로 2)반복적 방법으로 프로그래밍하기
- 재귀 버전recursive version 은 항상 counterpart 인 반복 버전iterative version이 있음 -> 무엇이 더 효율적일까? 복잡도가 더 낮은가? 고려해봐야 한다 ex> 재귀 함수 내에서 함수를 2번 이상 부르는데, n값이 매우 커지면 어떻게 되겠는가?
6. 알고리즘의 복잡도
1) 시간 복잡도 time complexity : 문제의 크기와 해결하는데 걸리는 시간 사이의 관계
2) 공간 복잡도 space complexity : 문제의 크기와 해결하는데 걸리는 메모리 공간 사이의 관계
알고리즘의 복잡도란 1), 2)로 컴퓨터의 자원을 얼마나 잡아먹느냐 라는 개념
시간 복잡도는 더 구체적으로
1) 평균 시간 복잡도 average time complexity : 임의의 입력 패턴을 가정했을 때 소요되는 시간 평균
2) 최악 시간 복잡도 worst-case time complexity: 가장 긴 시간을 소요하게 만드는 입력에서 소요되는 시간
특히 2)가 중요함
- Big O notation : 함수의 증가 양상을 대강 파악 가능
- O(n) 복잡도를 가지는 알고리즘 = 원소의 개수가 n개면 이에 비례해 소요 시간 증가
- O(logn) : 입력 크기의 로그에 비례하는 소요 시간 증가
1) 선형 시간 알고리즘 - O(n)
ex> linear search : n개의 무작위로 나열된 수에서 최댓값을 찾기
- Average case: O(n)
- Worst case : O(n)
- 모든 수를 다 탐색 하기 때문에 같음
2) 로그 시간 알고리즘 - O(logn)
ex> binary search : n개의 정렬된 수에서 특정값 찾기
- O(logn)의 복잡도를 가지고 문제를 풀 수 있으면 효율적
3) 이차 시간 알고리즘 - O(n^2)
ex> insertion search : 삽입 정렬(정렬할 요소를 정렬된 요소 중 어느곳에 넣어서 정렬된 상태를 유지)
- Best case: O(n) : 이미 정렬이 된 상태
- Worst case: O(n^2) : 역순으로 늘어서 있을 때
* 보다 낮은 복잡도를 가지는 정렬 알고리즘
- merge sort 병합정렬 - O(nlogn)
- 입력 패턴에 따라 정렬 속도 차이가 있지만 정렬 문제에 대해 O(nlogn)보다 낮은 복잡도를 갖는 알고리즘은 존재할 수 없음
- 정렬할 데이터를 반씩 나누어 각각을 정렬시킴 : O(logn)
- 정렬된 데이터를 두 묶음씩 한데 합친다 : O(n)
- 전체적으로 O(nlogn)이 된다
- 입력 패턴에 따라 정렬 속도 차이가 있지만 정렬 문제에 대해 O(nlogn)보다 낮은 복잡도를 갖는 알고리즘은 존재할 수 없음
* 복잡한 문제 ex> knapsack problem : 모든 경우의 수를 구해서 해결하면 O(n^2)
7~9. 연결 리스트 Linked Lists
- 추상적 자료 구조
1) 데이터 : 정수, 문자열....
2) 연산 a set of operations : 삽입, 삭제, 정렬, 탐색...
linear array 와 linked list 의 차이
- 선형 배열 : 번호가 붙여진 칸에 원소를 채워넣은 것
- 연결 리스트: 원소들을 줄줄이 엮어서 관리
- 연결 리스트의 장점
- 삭제, 삽입 등 처리를 선형 배열보다 빠르게 가능
- 연결 리스트의 단점
- 메모리 소요가 더 큼 : 링크 또한 저장해야 하므로
- n번째 원소를 찾는데 오래 걸림 : 선형 배열은 붙여진 번호를 이용할 수 있어 쉬운 반면, 연결 리스트는 앞에서 부터 하나씩 링크를 따라가면서 찾아야 함
- 연결 리스트의 기본 자료 구조
- Node :Data, Link(next)
- 맨 앞 노드는 head, 맨 뒤 노드는 tail
- node의 갯수
- 연결 리스트에 가할 수 있는 연산 정의
- 특정 원소 참조
- 리스트 순회 (traversal)
- 길이 얻어내기
- 원소의 삽입(insertion)/ 삭제(deletion)
- 두 리스트 합치기(concatenation)
- 더미노드 dummy node: 데이터 원소를 담고 있지 않은 자리만 차지하는 노드
- 더미노드가 있는 연결 리스트로 위의 6개 연산 구현하기
10. 양방향 연결 리스트(Doubly Linked Lists)
- 링크가 앞뒤로 다 연결되어있는 리스트
- 더미 노드도 head와 tail에 다 있음
- 메모리를 더 많이 잡아먹고, 리스트의 모습은 복잡해 지지만 연산 코드는 깔끔해짐 (예외 처리해야할 경우가 줄어듦)
- 위치 참조, 삽입, 삭제 등에서 binary search 활용 가능 (head에서 순방향, tail에서 역방향으로)
11. 스택(Stacks)
1) 스택이란?
- 자료를 보관할 수 있는 선형구조
- 단, 넣을 때에는 한 쪽 끝에서 밀어 넣어야 하고(push 연산), 꺼낼 때에는 넣었던 쪽에서 뽑아 꺼내야 하는 제약이 있다.(pop연산)
- 꺼낼 때 마지막에 넣었던 것부터 넣은 순서의 역순으로 꺼내지는 자료 구조
- 마지막에 넣은 것이 가장 먼저 꺼내어지는 성질 때문에 스택을 다른 말로는 후입선출(LIFO, Last In First Out) 자료구조
2) 스택의 동작
- 초기상태: 비어있는 스택(empty stack) S = stack()
- 데이터 원소 A를 스택에 추가 S.push(A)
- 데이터 원소 B를 스택에 추가 S.push(B)
- 데이터 원소 꺼내기 맨 위의 B가 r1에 담김 r1 = S.pop()
- 데이터 원소 한번 더 꺼내기 A가 r2에 담김 r2 = S.pop()
3) 스택에서 발생할 수 있는 오류
- 비어있는 스택에서 데이터 원소를 꺼내려 할 때 : 스택 언더플로우(stack underflow)
- 꽉 찬 스택에 데이터 원소를 넣으려 할 때: 스택 오버플로우(stack overflow)
4) 스택의 추상적 자료구조 구현
- 배열 array : 파이썬의 리스트와 메서드 이용
- 연결리스트 linked list : 양방향 연결 리스트 이용
- 연산의 정의
- size() : 현재 스택에 들어있는 데이터 원소의 수를 구함
- isEmpty() : 현재 스택이 비어있는지를 판단
- push(x) : 데이터 원소 x를 스택에 추가
- pop() : 스택의 맨 위에 저장된 데이터 원소를 제거 또한, 반환)
- peek() : 스택의 맨 위에 저장된 데이터 원소를 반환 (제거하지 않음)
- 라이브러리도 있다 (from pythonds.basic.stack import Stack)
5) 연습문제 = 수식의 괄호 유효성 검사
- 올바른 수식
(A+B)
{(A+B)*C}
[(A+B)*(C+D)]
- 올바르지 않은 수식
(A+B
{A+(B*C})
[(A+B)*(C+D)}
--> 정리하면
- 수식을 왼쪽부터 한 글자씩 읽어서 여는괄호를 만나면 스택에 푸시(마지막으로 여는 괄호를 기록)
- 닫는 괄호를 만나면 팝 -->이 때 비어있으면 x(열리지 않은 괄호를 닫았으므로), 팝했을 때 쌍을 이루는지 검사
- 끝까지 검사한 후, 스택이 비어 있어야 올바른 수식(아니면 연 괄호를 닫지 않은 것임)
'Programming > Python' 카테고리의 다른 글
[AI class day 3] 파이썬 코딩테스트 문제 풀이 TIL (0) | 2021.04.22 |
---|---|
자료 구조와 알고리즘 공부 기초부터 공부하기 (0) | 2021.04.22 |
[AI class day 2] 파이썬 자료구조와 알고리즘 TIL (0) | 2021.04.21 |
Q. 파이썬 ModuleNotFoundError: No module named 'requests' 오류 (1) | 2020.12.16 |
파이썬 기초 - PyQt 사용 연습 (0) | 2020.12.16 |