리스트
- 순서대로 저장하는 시퀀스이자 변경 가능한 목록
- 입력 순서가 유지되며, 내부적으로 동적 배열로 구현
- 매우 다양한 기능 제공
- 리스트를 사용하면 스택과 큐의 사용 유무를 고민하지 않아도 됨
- 스택과 큐에서 사용 가능한 모든 연산 제공
O(1)에 실행 가능한 연산들
- 리스트 마지막 요소를 .append( )로 추가,
- 리스트의 마지막 요소를 pop( )으로 추출,
- 원하는 인덱스 조회하는 연산
( * 요소를 삭제하거나 큐의 연산이기도 한 첫 번째 요소를 추출하는 pop(1)은 O(n)에 해당 )
- 리스트에 큐의 연산을 사용할 때는 주의가 필요함
- 데크(Deque)와 같은 자료형으로 성능을 높일 수 있음
리스트의 주요 연산 시간 복잡도
연산 | 시간복잡도 | 설명 |
len(a) | O(1) | 전체 요소의 개수 리턴 |
a[ i ] | O(1) | 인덱스 i의 요소를 가져옴 |
a[ i : j ] | O(k) | 인덱스 i부터 j-1까지 슬라이스의 길이만큼인 k개의 요소를 가져옴 (이 경우 객체 k개에 대한 조회가 필요함) |
elem in a | O(n) | elem 요소가 존재하는지 확인, 처음부터 순차 탐색하므로 n만큼 시간 소요 |
a.count(elem) | O(n) | elem 요소의 개수를 리턴 |
a.index(elem) | O(n) | elem 요소의 인덱스를 리턴 |
a.append(elem) | O(1) | 리스트 마지막에 elem 요소 추가 |
a.pop( ) | O(1) | 리스트 마지막 요소를 추출, 스택의 연산 |
a.pop(0) | O(n) | 리스트 첫번째 요소를 추출, 큐의 연산 이 경우 전체 복사가 필요하므로 O(n) 큐의 연산을 주로 사용한다면 리스트보다는 O(1)에 가능한 데크(deque)권장 |
del a[ i ] | O(n) | i에 따라 다름, 최악의 경우 O(n)임 |
a.sort( ) | O(n log n) | 정렬한다. 팀소트를 사용, 최선의 경우 O(n)에도 실행될 수 있음 |
min(a), max(a) | O(n) | 최솟값 / 최댓값을 계산하기 위해서는 전체를 선형 탐색해야 함 |
a.reverse( ) | O(n) | 뒤집음. 리스트는 입력 순서가 유지되므로 뒤집게 되면 입력 순서가 반대로 됨 |
- 리스트의 경우 탐색 시 값의 존재 유무를 확인하려면 정렬된 경우, 이진 탐색이 효율적
- 대체로 정렬된 상태가 아니기 때문에, 리스트의 경우 모든 엘리먼트를 순차적으로 조회하는 형태로 구현
- 최악의 경우 항상 O(n)이 소요됨
리스트 활용 방법
- 리스트 선언
a = list()
a = []
- 리스트 초깃값 지정과 append( )를 이용한 추가
- 파이썬은 자료형 타입을 신경쓰지 않고 자유롭게 삽입이 가능함
a = [1, 2, 3]
a.append(4)
>>> [1, 2, 3, 4]
# 숫자 이외의 다양한 자료형 삽입
a.append('안녕')
a.append(True)
- 특정 위치의 인덱스를 지정해 요소 추가
// 3번째 인덱스에 5를 삽입
a.insert(3, 5)
>>> [1, 2, 3, 5, 4]
- 슬라이싱
- 특정 범위 내의 값 가져오기
- 슬라이싱은 문자열에 유용하게 활용되는 기능
a = [1, 2, 3, 4, 5]
# 인덱스1에서 인덱스3 이전까지의 값 가져오기
a[1:3]
>> [2, 3]
# 처음부터 값을 가져옴
a[:3]
>> [1, 2, 3]
#(종료 인덱스 생략도 가능)
a[4:]
>> [5]
# 인덱스 1, 2, 3의 값
a[1:4]
# 인덱스 1, 3의 값
# 세 번째 파라미터, 단계를 지정할 수 있음
# 아래 예시는 2칸씩 건너뛰게 됨
# 1에서 시작해 1에서 두 칸 건너뛴 3까지의 값을 가졍ㅁ
a[1:4:2]
IndexError 발생시 try 구문으로 에러에 대한 예외처리
try:
print(a[9])
except IndexError:
print("존재하지 않는 인덱스")
- 리스트 요소 삭제
- 인덱스로 삭제
- 값으로 삭제
# del 키워드 사용
a = [1, 2, 3, 4, 5]
del a[0]
>> [2, 3, 4, 5]
# remove( ) 함수 사용
a.remove(5)
>> [2, 3, 4]
# pop( ) 함수 사용
a.pop(1)
>> [2, 4]
리스트 특징
- 연속된 공간에 요소를 배치하는 배열의 장점과 다양한 타입을 연결해 배치하는 연결 리스트의 장점을 모두 취한 듯한 형태
- 파이썬의 모든 자료형은 원시 타입이 아닌 객체로 되어 있음
- 정수, 문자, 불리언 등 제각기 다양한 타입을 동시에 단일 리스트에서 관리하는게 가능함
- 각 자료형의 크기는 저마다 서로 다르기 때문에 연속된 메모리 공간에 할당하는 것은 불가능
- 각각의 객체에 대한 참조로 구현
- 때문에 인덱스를 조회하는 데에도 모든 포인터의 위치를 찾아가서 타입 코드를 확인하고 값을 일일이 살펴봐야 하는 추가적인 작업 필요 - 속도면에서 불리함
- 리스트와 객체에 대한 참조로 인해 속도를 희생하게 됨
딕셔너리
- 키/값 구조로 이뤄진 딕셔너리
- 입력 순서가 유지, 내부적으로 해쉬 테이블로 구현
- 인덱스를 숫자로만 지정할 수 있는 리스트와 달리
- 딕셔너리는 문자를 포함해 다양한 타입을 키로 사용할 수 있음
- 파이썬의 딕셔너리는 해시할 수 있다면 숫자, 문자, 집합까지 불변 객체를 모두 키로 사용 가능
- 이 과정을 해싱, 해시 테이블을 이용해 자료를 저장함
- 해시 테이블은 다양한 타입을 키로 지원하면서도 입력과 조회 모두 O(1)에 가능함
- 해시 테이블은 최악의 경우 O(n)이 될 수 있으나 대부분의 경우 훨씬 더 빨리 실행됨
- 분할 상환 분석에 따른 시간 복잡도는 O(1)
연산 | 시간 복잡도 | 설명 |
len(a) | O(1) | 요소의 개수를 리턴 |
a[key] | O(1) | 키를 조회하여 값을 리턴 |
a[key] = value | O(1) | 키/값을 삽입 |
key in a | O(1) | 딕셔너리에 키가 존재하는 지 확인 |
- 딕셔너리는 대부분의 연산이 O(1)에 처리 가능한 자료형
- * 딕셔너리의 입력 순서가 유지될 것이라고 가정하고 문제를 푸는 것을 권장 X
딕셔너리 활용 방법
- 딕셔너리 선언
a = dict()
a = {}
- 딕셔너리 key1, key2 초깃값 지정과 새로운 key3 별도 선언 후 값 지정
a = {'key1' : 'value1', 'key2' : 'value2'}
a['key3'] = 'value3'
>> {'key1' : 'value1', 'key2' : 'value2', 'key3' : 'value3'}
딕셔너리의 키 지정 후 값 조회 (존재하지 않는 키 조회시 에러 발생)
a['key1']
>> 'value1'
# 반복문을 이용한 조회
for k, v in a.items():
print(k, v)
딕셔너리에 KeyError 에러가 발생하면 try 구문으로 예외 처리할 수 있음
try:
print(a['key4])
except KeyError:
print('존재하지 않는 키')
# 키가 존재하는지 미리 확인하는 코드
if 'key4' in a:
print('존재하는 키')
else:
print('존재하지 않는 키')
딕셔너리의 키 삭제
del a['key1']
>> {'key2' : 'value2', 'key3' : 'value3'}
딕셔너리 모듈
특수한 형태의 컨테이너 자료형 defaultdict, Counter, OrderedDict
defaultdict 객체
- 존재하지 않는 키를 조회할 경우, 에러 메세지 출력 대신
- 디폴트 값을 기준으로 해당 키에 대한 딕셔너리 아이템을 생성해줌
- 실제로는 collections.defaultdict 클래스를 가짐
# A와 B에 5와 4를 할당, 딕셔너리에 2개의 아이템 존재
a = collections.defaultdict(int)
>> a['A'] = 5
>> a['B'] = 4
# 존재하지 않는 C
>> a['C'] += 1
>>>defaultdict(<class 'int'>, {'A' : 5, 'B' : 4, 'C' : 1})
- 존재하지 않은 값 C에 1을 더하는 코드가 들어왔을 때,
- 원래라면 KeyError가 발생해야되는데 defaultdict 객체는 에러 없이 바로 +1 연산 수행
- 이 경우는 디폴트가 0을 기준으로 자동으로 생성한 후 여기에 1을 더해
- 최종적으로 1이 만들어짐 - {'A' : 5, 'B' : 4, 'C' : 1}
Counter 객체
- 아이템에 대한 개수를 계산해 딕셔너리로 리턴
- 키에는 아이템 값, 값에는 해당 아이템의 개수가 들어간 딕셔너리
a = [1, 5, 5, 5, 6, 6]
b = collections.Counter(a)
Counter({5:3, 6:2, 1:1})
가장 빈도수가 높은 요소 추출
# 가장 빈도가 높으 2개의 요소 추출
b.most)common(2)
>> [(5, 3), (6, 2)]
OderedDict 객체
- 해시 테이블을 이용한 자료형은 입력 순서가 유지되지 않음 (파이썬 3.6 이하는 이에 해당)
- 입력 순서가 유지되는 OrderedDict 객체 제공
- 코딩 테스트가 하위 버전을 사용한다면 이에 주의해야 함 (입력 순서대로 결과를 추출해 풀이를 제출해야 하는 경우)
collections.OrderedDict({'banana' : 3, 'apple' : 4})
OrderedDict([('banana', 3), ('apple', 4)])
'Kakao Cloud School > Study : Python Algorithm interview' 카테고리의 다른 글
[파이썬 알고리즘 인터뷰] 2부 4장 빅오, 자료형 (0) | 2022.06.28 |
---|---|
[파이썬 알고리즘 인터뷰] 2부 3장 파이썬 (0) | 2022.06.28 |