정렬이란 특정 조건에 맞추어 주어진 데이터를 순서대로 나열하는 것을 의미한다. 우리에게 가장 익숙한 정렬이라면 아마 랜덤하게 주어진 숫자를 오름차순 혹은 내림차순으로 정리하는 정렬일 것이다. 정렬 알고리즘에는 정말 다양한 종류가 존재한다. 삽입정렬, 선택정렬, 퀵정렬, 계수정렬, 병합정렬, 힙정렬 등등.
일반적으로 각 프로그래밍 언어에서 표준 라이브러리에서 사용되는 정렬알고리즘은 퀵정렬이나 병합정렬이라고 한다. 퀵정렬은 최악의 경우, 그 시간복잡도가 O(N** 2)이 되지만, 표준 라이브러리에서는 그 경우를 알아서 제어해서, 최악의 경우에도 O(NlogN)의 시간복잡도를 보장한다고 한다. 그렇기 때문에 문제 상에서 직접 정렬 알고리즘을 짜도록 유도하는 것이 아니라면 각 프로그래밍 언어에서 제공하는 정렬 메소드 등을 사용하는 것이 효율적이다.
파이썬에는 두 가지의 정렬 메소드가 존재한다. 하나는 sort()이고 하나는 sorted()인데 두 가지 메소드에는 공통점과 차이점이 모두 존재한다.
1. 공통점
a=[2,4,6,4,8,5,2]
a.sort(key=lambda x:-x)
print(a)
>> [8, 6, 5, 4, 4, 2, 2]
코드 해설: 여기서 key=lambda x:-x를 통해 a가 내림차순으로 정렬된 것을 확인할 수 있다 . 내림차순으로 정렬된 이유는 a의 각 데이터들에 대해 해당 값에 마이너스를 씌웠을 때를 기준으로 정렬했기 때문이다.2. 차이점
오늘은 정렬 알고리즘을 복습했다. 책을 먼저 읽고, 이코테 강의도 봤다. 그리고선 유형별 기출문제를 풀기 시작했는데 이 문제가 첫 번째 문제였다. 사실 이전에도 여러번 본 적 있는 문제였다. 다만 그때마다 정렬 조건이 너무 까다로워 보여서 번번히 넘겨버렸었다. 하지만 이젠 더 이상 넘길 수가 없어서 문제를 꼼꼼히 읽고 풀기 시작했다.
정말 막막했다. 도대체 어떻게 순차적으로 각 조건에 맞춰서 정렬을 해야 하는지 감이 잡히지 않았다. 특히 앞 점수가 동일할 경우라는 조건이 제일... 제일 싫었다. 그래도 풀어야겠다는 생각에 다음과 같은 코드를 작성했었다.
def sorting(a,b,start,index,scores):
while index<len(students):
if students[index][a]==students[index-1][a]:
scores.append(students[index])
else:
if b==2:
scores.sort(key=lambda score:score[b])
elif b==3:
scores.sort(reverse=True, key=lambda score:score[b])
students[start:start+len(scores)]=scores
scores.clear()
scores=[students[index]]
start=index
index+=1
if b==2:
scores.sort(key=lambda score:score[b])
elif b==3:
scores.sort(reverse=True, key=lambda score:score[b])
students[start:start+len(scores)]=scores
n=int(input())
students=[]
for i in range(n):
name,kor,eng,math=input().split()
students.append((name,int(kor),int(eng),int(math)))
students.sort(reverse=True, key=lambda score:score[1])
sorting(1,2,0,1,[students[0]])
sorting(2,3,0,1,[students[0]])
-해당코드는 틀린코드입니다-
다시 봐도 참 복잡하다... 이 코드로 수학 점수까지 정렬하는 것은 성공했으나 도저히 국어, 영어, 수학 점수가 같을 때 이름을 정렬하는 것은 해결할수가 없었다. 그렇게 약 1시간 이상을 헤매었을까... 도저히 이러다간 저녁을 못 먹겠다 싶어서 해설을 펼쳤는데... 웬걸 너무 간단해서 허탈할 정도였다.
이코테 책 내 국영수 해설에 따르면, 파이썬에서는 튜플을 원소로 하는 리스트가 있을 때, 그 리스트를 정렬하면 기본적으로 각 튜플을 구성하는 원소의 순서에 맞게 정렬된다는 특징이 있다는 것이다. 예까지 인용하자면 아래와 같다.
예를 들어 튜플이 3개의 원소로 구성된다면, 모든 원소가 첫 번째 원소의 순서에 맞게 정렬되고, 첫 번째 원소의 값이 같은 경우 두 번째 원소의 순서에 맞게 정렬되고, 거기에 두 번째 원소의 값까지 같은 경우 세 번째 원소의 순서에 맞게 정렬된다.
-이코테 책 인용-
즉 다시 말해, 이를 이용하면 첫 번째 원소의 값이 같은지 다른지를 비교할 필요가 없다는 것이다. 정말이지 너무 반가운 설명이었다. 이를 이용하고, 앞서 설명했던 것처럼 sort()함수에 key를 통해 특정 조건을 적용하여 정렬할 수 있다는 점을 이용하면 이 문제를 간단하게 풀 수 있는 셈이다. 이를 코드로 풀명 다음과 같다.
#백준 10825번 국영수 핵심코드
#학생들의 이름과 점수들을 튜플로 묶어서 students라는 리스트에 삽입했다고 가정하자.
students.sort(key=lambda x:(-x[1],x[2],-x[3],x[0]))
처음으로 공부한 걸 제대로 복기해보는 것 같다. 쓰다보디 괜히 욕심도 생격서 길게 쓰게 되었는데, 나름대로 만족스럽다. 정렬 알고리즘은 기본 중에 기본이라고 한다. 코딩테스트에는 정렬 알고리즘을 작성하는 문제보다는 활용하는 문제가 더 많이 나온다고 하지만(왜냐하면 다른 알고리즘에 필요한 경우가 많아서) 기술면접 등에서 잘 출제되는 문제라고 하니, 잘 새겨두어야겠다!