데이터를 정렬하기 위해 임의의 두 숫자 배열을 가져와서 작은 수를 선택하여 1개의 배열을 만드는 함수를 만들어두었습니다. 이번에는 이 함수를 이용하여 실제 데이터를 정렬하고자 합니다.
정렬함수를 만들기에 앞서, 다음과 같이 모듈 제일 첫줄에 사용자 정의 변수를 선언해둡니다.
Y() As Double
End Type
typeArray라는 변수는 그 안에 크기가 지정되지 않은 Double형 배열입니다. 이렇게 해두면 숫자나 문자열같은 한 개의 데이터가 아니라, 한 개의 변수 안에 배열을 통째로 넣어두겠다는 말입니다.
이제 본격적으로 정렬 함수를 만들어보겠습니다. 또한, 중간 중간에 코멘트를 달아서 설명을 드리겠습니다.
--------------------------------------------------
Function GetSorted(iData() As Double, Optional iGetOrder As Boolean = False, Optional iIncrease As Boolean = True, Optional iDelDuplicate As Boolean = False) As Double()
Dim i As Long, j As Long, n As Long
tN = UBound(iData) - LBound(iData) + 1
If iGetOrder Then
tC = 2
ReDim tD1(1 To tN)
For i = tSN To tFN
n = i + 1 - tSN: ReDim tD1(n).Y(1 To 1, 1 To 2)
Next
Else
tC = 1
ReDim tD1(1 To tN)
For i = tSN To tFN
n = i + 1 - tSN: ReDim tD1(n).Y(1 To 1, 1 To 1): tD1(n).Y(1, 1) = iData(i)
Next
End If
'iGetOrder는 입력받은 숫자 배열의 순서(Order)를 찾아낼 것인지, 아니면 크기순으로 새로 정렬된 데이터 배열을 구할 것인지를 지정합니다. 기본값은 배열을 크기순으로 재정렬하는 것이므로 False로 두었습니다.
If tN = 1 Then tD2 = tD1
While UBound(tD1) > 1
tOdd = (UBound(tD1) Mod 2 = 1)
tN = Int(UBound(tD1) / 2): If tOdd Then tN = tN + 1
ReDim tD2(1 To tN)
For i = 2 To UBound(tD1) Step 2: tD2(i / 2).Y = SortStep(tD1(i - 1).Y, tD1(i).Y): Next
If tOdd Then tD2(tN).Y = tD1(UBound(tD1)).Y
tD1 = tD2
Wend
'만약 입력받은 데이터의 크기가 1이라면 정렬할 필요가 없습니다.
ReDim tD1(1).Y(tSN To tFN, 1 To tC)
If iIncrease Then
For i = tSN To tFN
n = i - tSN + 1
For j = 1 To tC
tD1(1).Y(i, j) = tD2(1).Y(n, j)
Next
Next
Else
For i = tSN To tFN
n = tFN - i + 1
For j = 1 To tC
tD1(1).Y(i, j) = tD2(1).Y(n, j)
Next
Next
End If
If iDelDuplicate Then
n = tSN: ReDim Preserve tV(tSN To n): tV(n) = tD1(1).Y(1, tC)
For i = tSN + 1 To tFN
If Not (tD1(1).Y(i - 1, 1) = tD1(1).Y(i, 1)) Then
n = n + 1: ReDim Preserve tV(tSN To n): tV(n) = tD1(1).Y(i, tC)
End If
Next
Else
ReDim Preserve tV(tSN To tFN)
For i = tSN To tFN
tV(i) = tD1(1).Y(i, tC)
Next
End If
GetSorted = tV
Erase tD1, tD2, tV
End Function
--------------------------------------------------
아래의 함수 GetSorted2는 통상의 교재에서 소개하는 정렬 알고리즘입니다. 2개의 데이터를 비교해서 작은 데이터를 앞으로 옮기는 것을 반복하는 방법입니다. 특별한 기능을 넣지 않은 이유도 있지만, 앞에서와 동일한 기능을 갖도록 하더라도 코드는 상대적으로 간결합니다.
tData = iData
tSN = LBound(tData): tFN = UBound(tData)
For i = tSN To tFN
For j = i + 1 To tFN
If tData(i) > tData(j) Then tVal = tData(i): tData(i) = tData(j): tData(j) = tVal
Next
Next
GetSorted2 = tData
Erase tData
End Function
위에서 코딩해둔 2개의 정렬함수의 속도차이를 비교해보실 수 있도록 아래와 같은 코드를 넣고 실행해보시기 바랍니다.
위의 함수는 현재 워크시트의 1열에 원하는 갯수만큼 난수를 발생시켜 입력합니다.
Sub Test1()
Dim tData() As Double, tSorted(), n As Long
n = 50000
tData = RandArray(n)
MsgBox "정렬 시작", vbInformation, "확인"
tData = GetSorted(tData, False, True, False)
ReDim tSorted(1 To n, 1 To 1)
For i = 1 To n
tSorted(i, 1) = tData(i)
Next
ActiveSheet.Range(Cells(1, 3), Cells(n, 3)).Value = tSorted
End Sub
Sub Test2()
Dim tData() As Double, tSorted(), n As Long
n = 50000
tData = RandArray(n)
MsgBox "정렬 시작", vbInformation, "확인"
tData = GetSorted2(tData)
ReDim tSorted(1 To n, 1 To 1)
For i = 1 To n
tSorted(i, 1) = tData(i)
Next
ActiveSheet.Range(Cells(1, 4), Cells(n, 4)).Value = tSorted
End Sub
Test1과 Test2는 각각 5만개의 난수 데이터를 생성하고, 서로 다른 정렬함수로 정렬하는 프로시저입니다. 만약, 오래된 사무용 PC에서 작업하신다면, 2만개 정도로 줄여도 됩니다. 혹은 PC 성능이 너무 좋아서 두 프로시저의 속도차이를 못느끼신다면, 10만개 혹은 100만개의 데이터를 생성하도록 해서 비교해보시면 되겠습니다.
위의 두 프로시저 비교를 마치고 나면, 엑셀에 내장된 정렬 기능과 Test1의 속도를 비교해보시면 좋을 것 같습니다. 아마, 속도차이를 크게 느끼지 못하실 것입니다. 대부분의 상용 소프트웨어나 파이썬 등에서 사용하는 정렬 알고리즘과 큰 차이가 나지는 않을 것입니다.
이상 데이터 정렬 알고리즘을 하나 소개해드렸습니다.
댓글 없음:
댓글 쓰기
의견이나 질문이 있으신 분은 언제든지 댓글을 달아주세요~