Страница: 1 | 2 | 3 | 4 | 5 |
|
Вопрос: Удаление дубликатов из массива
|
Добавлено: 11.11.05 15:04
|
|
Номер ответа: 19 Автор ответа: HOOLIGAN
Вопросов: 0 Ответов: 1066
|
Профиль | | #19
|
Добавлено: 13.11.05 08:07
|
GSerg
Да заметил я, что массив типа вариант. Потому и запостил.
Зачем нужно приводить (извиняюсь за термин) отстойную реализацию алгоритма, сделаную криво да косо, в качестве подтверждения мысли о недопустимости рекурсии - я не понял.
Так же непонятно, почему был приведен кусок кода, в котором сортируется вариант, в то время как человеку нужно сортировать строки?
Может вы невнимательно прочитали вопрос?
Ответить
|
Номер ответа: 21 Автор ответа: HOOLIGAN
Вопросов: 0 Ответов: 1066
|
Профиль | | #21
|
Добавлено: 13.11.05 08:42
|
Если сделать грамотно, то отличается только процедура сравнения двух элементов массива. Весь остальной код один и тот же для любого типа данных, будь то integer, string или double
Ответить
|
Номер ответа: 22 Автор ответа: GSerg
Вопросов: 0 Ответов: 1876
|
Профиль | | #22
|
Добавлено: 13.11.05 14:55
|
Зачем нужно приводить (извиняюсь за термин) отстойную реализацию алгоритма, сделаную криво да косо
В чём кривизна, очень хочу узнать.
Так же непонятно, почему был приведен кусок кода, в котором сортируется вариант, в то время как человеку нужно сортировать строки?
Видеть проблему там, где её нет, просто потому, что неохота принять иную точку зрения - человеческое свойство, мне непонятное.
Ok, не вопрос.
Переделываем пример на строки.
Form1
Option Explicit
Private Declare Function GetTickCount Lib "kernel32" () As Long
Private Type TimeExp
Bubble As Long
Exchange As Long
Heap As Long
Insertion As Long
Quick As Long
QuickNonRec As Long
Shelll As Long
End Type
Private Sub Form_Load()
Dim a As New Sorting, i As Long, MyArr(-800 To 4000) As String, Reserve(-800 To 4000) As String
Dim StartTime As Long
Dim TotalRanks As TimeExp
For i = LBound(MyArr) To UBound(MyArr)
MyArr(i) = CStr(Rnd * 800)
Reserve(i) = MyArr(i)
Next
Randomize Timer
StartTime = GetTickCount
a.QuickSort MyArr, LBound(MyArr), UBound(MyArr)
TotalRanks.Quick = GetTickCount - StartTime
'SaveArr App.Path + "\Quick.txt", MyArr()
RestoreArr Reserve(), MyArr()
StartTime = GetTickCount
a.QuickSortNonRecursive MyArr ', LBound(MyArr), UBound(MyArr)
TotalRanks.QuickNonRec = GetTickCount - StartTime
'SaveArr App.Path + "\Quick.txt", MyArr()
RestoreArr Reserve(), MyArr()
MsgBox "Ага! Вот результаты:" & vbNewLine & vbNewLine & "Пузырёк " & TotalRanks.Bubble & vbNewLine & _
"Обмен " & TotalRanks.Exchange & vbNewLine & _
"Куча " & TotalRanks.Heap & vbNewLine & _
"Вставка " & TotalRanks.Insertion & vbNewLine & _
"Быстрая " & TotalRanks.Quick & vbNewLine & _
"Быстрая нерекурсивная " & TotalRanks.QuickNonRec & vbNewLine & _
"Shell " & TotalRanks.Shelll & vbNewLine
End Sub
Private Sub RestoreArr(From() As String, Where() As String)
Dim i As Long
For i = LBound(From) To UBound(From)
Where(i) = From(i)
Next
End Sub
Sorting.cls
Option Explicit
Private Type QuickStack
Low As Long
High As Long
End Type
Private Sub SwapString(a As String, b As String)
Dim tmp As String
tmp = a: a = b: b = tmp
End Sub
Private Function RandInt(Lower As Long, Upper As Long) As Long
RandInt = Int(Rnd * (Upper - Lower + 1)) + Lower
End Function
Public Sub QuickSort(SortArray() As String, Low As Long, High As Long)
Dim RandIndex As Long, Partition As String
Dim i As Long, j As Long
If Low < High Then
If Abs(High - Low) = 1 Then 'Abs заюзан опять-таки из-за возможности отриц. индексов
' Если у нас два элемента в куске, то правильно их расставляем
' и прекращаем рекурсию:
If SortArray(Low) > SortArray(High) Then Swap SortArray(Low), SortArray(High)
Else 'Нет, больше двух элементов в куске!
' Выбираем случайный элемент, двигаем его в конец:
RandIndex = RandInt(Low, High)
SwapString SortArray(High), SortArray(RandIndex)
Partition = SortArray(High)
Do
' Идём с обоих сторон по направлению к "центральному":
i = Low: j = High
Do While (i < j) And (SortArray(i) <= Partition)
i = i + 1
Loop
Do While (j > i) And (SortArray(j) >= Partition)
j = j - 1
Loop
' Если мы не достигли "центрального", это значит, что два
' элемента любой стороне в неправильном порядке, меняем их:
If i < j Then SwapString SortArray(i), SortArray(j)
Loop While i < j
' Двигаем центральный обратно на его место в массиве:
SwapString SortArray(i), SortArray(High)
' Рекурсивно вызываемся (передаём сначала меньший кусок, чтобы занять
' меньше стекового пространства):
If (i - Low) < (High - i) Then
QuickSort SortArray, Low, i - 1
QuickSort SortArray, i + 1, High
Else
QuickSort SortArray, i + 1, High
QuickSort SortArray, Low, i - 1
End If
End If
End If
End Sub
Public Sub QuickSortNonRecursive(SortArray() As String)
Dim i As Long, j As Long, lb As Long, ub As Long
Dim stack() As QuickStack, stackpos As Long, ppos As Long, pivot As String
ReDim stack(1 To 1024)
stackpos = 1
stack(1).Low = LBound(SortArray)
stack(1).High = UBound(SortArray)
Do
'Взять границы lb и ub текущего массива из стека.
lb = stack(stackpos).Low
ub = stack(stackpos).High
stackpos = stackpos - 1
Do
'Шаг 1. Разделение по элементу pivot
ppos = (lb + ub) \ 2
i = lb: j = ub: pivot = SortArray(ppos)
Do
Do While SortArray(i) < pivot: i = i + 1: Loop
Do While pivot < SortArray(j): j = j - 1: Loop
If i <= j Then
SwapString SortArray(i), SortArray(j)
i = i + 1
j = j - 1
End If
Loop While i <= j
'Сейчас указатель i указывает на начало правого подмассива,
'j - на конец левого lb ? j ? i ? ub.
'Возможен случай, когда указатель i или j выходит за границу массива
'Шаги 2, 3. Отправляем большую часть в стек и двигаем lb,ub
If i < ppos Then 'правая часть больше
If i < ub Then
stackpos = stackpos + 1
stack(stackpos).Low = i
stack(stackpos).High = ub
End If
ub = j 'следующая итерация разделения будет работать с левой частью
Else
If j > lb Then
stackpos = stackpos + 1
stack(stackpos).Low = lb
stack(stackpos).High = j
End If
lb = i
End If
Loop While lb < ub
Loop While stackpos
End Sub
Теперь какие замечания?
Может вы невнимательно прочитали вопрос?
Мы внимательно читали вопрос.
Дискуссия ушла немного в сторону от сабжевого вопроса несколько постов назад.
Ответить
|
Номер ответа: 23 Автор ответа: GSerg
Вопросов: 0 Ответов: 1876
|
Профиль | | #23
|
Добавлено: 13.11.05 15:07
|
В процедуре QuickSort строку
If SortArray(Low) > SortArray(High) Then Swap SortArray(Low), SortArray(High)
заменить на
If SortArray(Low) > SortArray(High) Then SwapString SortArray(Low), SortArray(High)
Забыл одну.
Впрочем, на картину это не влият ваапще.
Ответить
|
Номер ответа: 24 Автор ответа: HOOLIGAN
Вопросов: 0 Ответов: 1066
|
Профиль | | #24
|
Добавлено: 13.11.05 15:32
|
Ну раз дискуссия ушла в сторону, то:
Первый вопрос - вариант - вроде решен.
Второй вопрос:
Partition As String
Partition = SortArray(High)
Do While (i < j) And (SortArray(i) <= Partition)
Зачем создавать постоянно копию строки, и сравнивать с копией? На выделение памяти под строку и на копирование уходит ведь достаточно много времени? Почему не избавиться от Partition, и не сравнивать напрямую SortArray(i) с SortArray(High) ?
Третий вопрос:
RandIndex = RandInt(Low, High)
Почему нерекурсивному варианту отказано хотя бы в ppos = (lb + ub) \ 2 ?
Не говоря уже о том, чтобы выбрать по принципу: средний из первого, последнего и стоящего в середине. Такой принцип позволяет сократить количество проходов ~ на 17%. Достаточно заметная величина.
Ответить
|
Номер ответа: 26 Автор ответа: HOOLIGAN
Вопросов: 0 Ответов: 1066
|
Профиль | | #26
|
Добавлено: 13.11.05 19:43
|
В сравнении с чем разница в 50 раз? Сравнение варианта "мог бы" с вариантом "на самом деле"? Тогда чем характеризуется вариант "мог бы"? Отказом от рекурсии, или может отказом от VB? Откуда такая цифра - 50, с какого потолка взята?
Можно ли это уточнить?
Ответить
|
Номер ответа: 28 Автор ответа: HOOLIGAN
Вопросов: 0 Ответов: 1066
|
Профиль | | #28
|
Добавлено: 13.11.05 22:32
|
Запускал
В отличие от оппонента не только кривую реализацию Strings.cls
Этот класс я дополнил двумя процедурами: quick_sort и partition, которые реализуют нормальный QuickSort.
Результаты:
Быстрая a-la GSerg 563 мс
Быстрая нерекурсивная 16 мс
Нормальная quick_sort 0~15 мс
Код с изменениями:
Option Explicit
Private Declare Function GetTickCount Lib "kernel32" () As Long
Private Type TimeExp
Bubble As Long
Exchange As Long
Heap As Long
Insertion As Long
Quick As Long
QuickNonRec As Long
Shelll As Long
End Type
Private Sub Form_Load()
Dim a As New Sorting, i As Long, MyArr(-800 To 4000) As String, Reserve(-800 To 4000) As String
Dim StartTime As Long
Dim TotalRanks As TimeExp
For i = LBound(MyArr) To UBound(MyArr)
MyArr(i) = CStr(Rnd * 800)
Reserve(i) = MyArr(i)
Next
Randomize Timer
StartTime = GetTickCount
a.QuickSort MyArr, LBound(MyArr), UBound(MyArr)
TotalRanks.Quick = GetTickCount - StartTime
For i = -800 To 4000
list1.AddItem MyArr(i)
Next i
RestoreArr Reserve(), MyArr()
StartTime = GetTickCount
a.QuickSortNonRecursive MyArr ', LBound(MyArr), UBound(MyArr)
TotalRanks.QuickNonRec = GetTickCount - StartTime
For i = -800 To 4000
list2.AddItem MyArr(i)
Next i
'---------------------------------------------------------------
Dim arr(4800) As String
For i = 0 To 4800
arr(i) = Reserve(i - 800)
Next i
'-------------- сортировка ------------------------------------
StartTime = GetTickCount
a.quick_sort arr, 0, 4800
TotalRanks.Shelll = GetTickCount - StartTime
'--------------- проверка -------------------------------------
For i = 0 To 4800
list3.AddItem arr(i)
Next i
MsgBox "Ага! Вот результаты:" & vbNewLine & vbNewLine & "Быстрая a-la GSerg " & TotalRanks.Quick & vbNewLine & _
"Быстрая нерекурсивная " & TotalRanks.QuickNonRec & vbNewLine & _
"Нормальная quick_sort " & TotalRanks.Shelll & vbNewLine
End Sub
Private Sub RestoreArr(From() As String, Where() As String)
Dim i As Long
For i = LBound(From) To UBound(From)
Where(i) = From(i)
Next
End Sub
Sorting.cls
Option Explicit
Private Type QuickStack
Low As Long
High As Long
End Type
Private Sub SwapString(a As String, b As String)
Dim tmp As String
tmp = a: a = b: b = tmp
End Sub
Private Function RandInt(Lower As Long, Upper As Long) As Long
RandInt = Int(Rnd * (Upper - Lower + 1)) + Lower
End Function
Public Sub QuickSort(SortArray() As String, Low As Long, High As Long)
Dim RandIndex As Long ', Partition As String
Dim i As Long, j As Long
If Low < High Then
If Abs(High - Low) = 1 Then 'Abs заюзан опять-таки из-за возможности отриц. индексов
' Если у нас два элемента в куске, то правильно их расставляем
' и прекращаем рекурсию:
If SortArray(Low) > SortArray(High) Then SwapString SortArray(Low), SortArray(High)
Else 'Нет, больше двух элементов в куске!
' Выбираем случайный элемент, двигаем его в конец:
RandIndex = RandInt(Low, High)
SwapString SortArray(High), SortArray(RandIndex)
'Partition = SortArray(High)
Do
' Идём с обоих сторон по направлению к "центральному":
i = Low: j = High
Do While (i < j) And (SortArray(i) <= SortArray(High))
i = i + 1
Loop
Do While (j > i) And (SortArray(j) >= SortArray(High))
j = j - 1
Loop
' Если мы не достигли "центрального", это значит, что два
' элемента любой стороне в неправильном порядке, меняем их:
If i < j Then SwapString SortArray(i), SortArray(j)
Loop While i < j
' Двигаем центральный обратно на его место в массиве:
SwapString SortArray(i), SortArray(High)
' Рекурсивно вызываемся (передаём сначала меньший кусок, чтобы занять
' меньше стекового пространства):
If (i - Low) < (High - i) Then
QuickSort SortArray, Low, i - 1
QuickSort SortArray, i + 1, High
Else
QuickSort SortArray, i + 1, High
QuickSort SortArray, Low, i - 1
End If
End If
End If
End Sub
Public Sub QuickSortNonRecursive(SortArray() As String)
Dim i As Long, j As Long, lb As Long, ub As Long
Dim stack() As QuickStack, stackpos As Long, ppos As Long, pivot As String
ReDim stack(1 To 1024)
stackpos = 1
stack(1).Low = LBound(SortArray)
stack(1).High = UBound(SortArray)
Do
'Взять границы lb и ub текущего массива из стека.
lb = stack(stackpos).Low
ub = stack(stackpos).High
stackpos = stackpos - 1
Do
'Шаг 1. Разделение по элементу pivot
ppos = (lb + ub) \ 2
i = lb: j = ub: pivot = SortArray(ppos)
Do
Do While SortArray(i) < pivot: i = i + 1: Loop
Do While pivot < SortArray(j): j = j - 1: Loop
If i <= j Then
SwapString SortArray(i), SortArray(j)
i = i + 1
j = j - 1
End If
Loop While i <= j
'Сейчас указатель i указывает на начало правого подмассива,
'j - на конец левого lb ? j ? i ? ub.
'Возможен случай, когда указатель i или j выходит за границу массива
'Шаги 2, 3. Отправляем большую часть в стек и двигаем lb,ub
If i < ppos Then 'правая часть больше
If i < ub Then
stackpos = stackpos + 1
stack(stackpos).Low = i
stack(stackpos).High = ub
End If
ub = j 'следующая итерация разделения будет работать с левой частью
Else
If j > lb Then
stackpos = stackpos + 1
stack(stackpos).Low = lb
stack(stackpos).High = j
End If
lb = i
End If
Loop While lb < ub
Loop While stackpos
End Sub
'--- нормальная реализация -----------
Private Function partition(a() As String, Low As Long, High As Long) As Long
Dim p As Long, pivot As String, t As String
Dim i As Long, j As Long
p = Low + ((High - Low) \ 2)
pivot = a(p)
a(p) = a(Low)
i = Low + 1
j = High
Do While True
Do While (i < j And (pivot > a(i))): i = i + 1: Loop
Do While (j >= i And (a(j) > pivot)): j = j - 1: Loop
If (i >= j) Then Exit Do
t = a(i)
a(i) = a(j)
a(j) = t
j = j - 1
i = i + 1
Loop
a(Low) = a(j)
a(j) = pivot
partition = j
End Function
Public Sub quick_sort(SortArray() As String, Low As Long, High As Long)
Dim m As Long
Do While Low < High
m = partition(SortArray(), Low, High)
If (m - Low <= High - m) Then
quick_sort SortArray(), Low, m - 1
Low = m + 1
Else
quick_sort SortArray(), m + 1, High
High = m - 1
End If
Loop
End Sub
В форму добавлены 3 листбокса list1, list2, list3 для проверки результатов, если будут сомнения
Ну как, сделаем в 50 раз быстрее?
Ответить
|
Номер ответа: 29 Автор ответа: GSerg
Вопросов: 0 Ответов: 1876
|
Профиль | | #29
|
Добавлено: 14.11.05 01:17
|
Замечание первое.
Выражение "a-la GSerg" уместно не совсем, ибо все приведённые сортировки, кроме быстрой нерекурсивной, написаны в Microsoft и шли в качестве примера.
Замечание второе.
Я не зря отсортированный массив в файл сбрасываю.
Я его потом смотрю. Экселем тем же.
Так вот функция a-la Microsoft сортирует, а функция a-la HOOLIGAN выдаёт в любом порядке, кроме отсортированного.
Небольшой отрывок из середины файла, созданного функцией a-la HOOLIGAN:
"110,9859"
"116,0003"
"119,3966"
"119,9849"
"120,249"
"121,3256"
"121,405"
"122,0798"
"122,1415"
"124,3485"
"786,5334"
"793,9324"
"796,2326"
"797,4592"
"124,5305"
"125,0418"
"128,3532"
"129,395"
"130,2573"
"130,3536"
"131,3873"
"134,2103"
"135,8988"
"139,0187"
Ответить
|
Страница: 1 | 2 | 3 | 4 | 5 |
Поиск по форуму