Vba excel быстрая сортировка массива

You didn’t want an Excel-based solution but since I had the same problem today and wanted to test using other Office Applications functions I wrote the function below.

Limitations:

  • 2-dimensional arrays;
  • maximum of 3 columns as sort keys;
  • depends on Excel;

Tested calling Excel 2010 from Visio 2010


Option Base 1


Private Function sort_array_2D_excel(array_2D, array_sortkeys, Optional array_sortorders, Optional tag_header As String = "Guess", Optional tag_matchcase As String = "False")

'   Dependencies: Excel; Tools > References > Microsoft Excel [Version] Object Library

    Dim excel_application As Excel.Application
    Dim excel_workbook As Excel.Workbook
    Dim excel_worksheet As Excel.Worksheet

    Set excel_application = CreateObject("Excel.Application")

    excel_application.Visible = True
    excel_application.ScreenUpdating = False
    excel_application.WindowState = xlNormal

    Set excel_workbook = excel_application.Workbooks.Add
    excel_workbook.Activate

    Set excel_worksheet = excel_workbook.Worksheets.Add
    excel_worksheet.Activate
    excel_worksheet.Visible = xlSheetVisible

    Dim excel_range As Excel.Range
    Set excel_range = excel_worksheet.Range("A1").Resize(UBound(array_2D, 1) - LBound(array_2D, 1) + 1, UBound(array_2D, 2) - LBound(array_2D, 2) + 1)
    excel_range = array_2D


    For i_sortkey = LBound(array_sortkeys) To UBound(array_sortkeys)

        If IsNumeric(array_sortkeys(i_sortkey)) Then
            sortkey_range = Chr(array_sortkeys(i_sortkey) + 65 - 1) & "1"
            Set array_sortkeys(i_sortkey) = excel_worksheet.Range(sortkey_range)

        Else
            MsgBox "Error in sortkey parameter:" & vbLf & "array_sortkeys(" & i_sortkey & ") = " & array_sortkeys(i_sortkey) & vbLf & "Terminating..."
            End

        End If

    Next i_sortkey


    For i_sortorder = LBound(array_sortorders) To UBound(array_sortorders)
        Select Case LCase(array_sortorders(i_sortorder))
            Case "asc"
                array_sortorders(i_sortorder) = XlSortOrder.xlAscending
            Case "desc"
                array_sortorders(i_sortorder) = XlSortOrder.xlDescending
            Case Else
                array_sortorders(i_sortorder) = XlSortOrder.xlAscending
        End Select
    Next i_sortorder

    Select Case LCase(tag_header)
        Case "yes"
            tag_header = Excel.xlYes
        Case "no"
            tag_header = Excel.xlNo
        Case "guess"
            tag_header = Excel.xlGuess
        Case Else
            tag_header = Excel.xlGuess
    End Select

    Select Case LCase(tag_matchcase)
        Case "true"
            tag_matchcase = True
        Case "false"
            tag_matchcase = False
        Case Else
            tag_matchcase = False
    End Select


    Select Case (UBound(array_sortkeys) - LBound(array_sortkeys) + 1)
        Case 1
            Call excel_range.Sort(Key1:=array_sortkeys(1), Order1:=array_sortorders(1), Header:=tag_header, MatchCase:=tag_matchcase)
        Case 2
            Call excel_range.Sort(Key1:=array_sortkeys(1), Order1:=array_sortorders(1), Key2:=array_sortkeys(2), Order2:=array_sortorders(2), Header:=tag_header, MatchCase:=tag_matchcase)
        Case 3
            Call excel_range.Sort(Key1:=array_sortkeys(1), Order1:=array_sortorders(1), Key2:=array_sortkeys(2), Order2:=array_sortorders(2), Key3:=array_sortkeys(3), Order3:=array_sortorders(3), Header:=tag_header, MatchCase:=tag_matchcase)
        Case Else
            MsgBox "Error in sortkey parameter:" & vbLf & "Maximum number of sort columns is 3!" & vbLf & "Currently passed: " & (UBound(array_sortkeys) - LBound(array_sortkeys) + 1)
            End
    End Select


    For i_row = 1 To excel_range.Rows.Count

        For i_column = 1 To excel_range.Columns.Count

            array_2D(i_row, i_column) = excel_range(i_row, i_column)

        Next i_column

    Next i_row


    excel_workbook.Close False
    excel_application.Quit

    Set excel_worksheet = Nothing
    Set excel_workbook = Nothing
    Set excel_application = Nothing


    sort_array_2D_excel = array_2D


End Function

This is an example on how to test the function:

Private Sub test_sort()

    array_unsorted = dim_sort_array()

    Call msgbox_array(array_unsorted)

    array_sorted = sort_array_2D_excel(array_unsorted, Array(2, 1, 3), Array("desc", "", "asdas"), "yes", "False")

    Call msgbox_array(array_sorted)

End Sub


Private Function dim_sort_array()

    Dim array_unsorted(1 To 5, 1 To 3) As String

    i_row = 0

    i_row = i_row + 1
    array_unsorted(i_row, 1) = "Column1": array_unsorted(i_row, 2) = "Column2": array_unsorted(i_row, 3) = "Column3"

    i_row = i_row + 1
    array_unsorted(i_row, 1) = "OR": array_unsorted(i_row, 2) = "A": array_unsorted(i_row, 3) = array_unsorted(i_row, 1) & "_" & array_unsorted(i_row, 2)

    i_row = i_row + 1
    array_unsorted(i_row, 1) = "XOR": array_unsorted(i_row, 2) = "A": array_unsorted(i_row, 3) = array_unsorted(i_row, 1) & "_" & array_unsorted(i_row, 2)

    i_row = i_row + 1
    array_unsorted(i_row, 1) = "NOT": array_unsorted(i_row, 2) = "B": array_unsorted(i_row, 3) = array_unsorted(i_row, 1) & "_" & array_unsorted(i_row, 2)

    i_row = i_row + 1
    array_unsorted(i_row, 1) = "AND": array_unsorted(i_row, 2) = "A": array_unsorted(i_row, 3) = array_unsorted(i_row, 1) & "_" & array_unsorted(i_row, 2)

    dim_sort_array = array_unsorted

End Function


Sub msgbox_array(array_2D, Optional string_info As String = "2D array content:")

    msgbox_string = string_info & vbLf

    For i_row = LBound(array_2D, 1) To UBound(array_2D, 1)

        msgbox_string = msgbox_string & vbLf & i_row & vbTab

        For i_column = LBound(array_2D, 2) To UBound(array_2D, 2)

            msgbox_string = msgbox_string & array_2D(i_row, i_column) & vbTab

        Next i_column

    Next i_row

    MsgBox msgbox_string

End Sub

If anybody tests this using other versions of office please post here if there are any problems.

Сортировка одномерного массива в VBA Excel по возрастанию или убыванию с числовым или текстовым сравнением числовых элементов. Сортировка выбором.

Сортировка массива выбором

Функция, осуществляющая сортировку выбором одномерного массива по возрастанию с числовым сравнением числовых элементов массива:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

Function SortArray(myArray As Variant) As Variant

Dim l As Long, u As Long, i1 As Long, i2 As Long, im As Long, tmp As Variant

‘Определение наименьшего индекса массива

l = LBound(myArray)

‘Определение наибольшего индекса массива

u = UBound(myArray)

    For i1 = l To u

        im = i1

        For i2 = i1 To u

            ‘Поиск наименьшего элемента массива, начиная с элемента myArray(i1)

            If myArray(i2) < myArray(im) Then im = i2

        Next

        ‘Если наименьший элемент не является текущим (im <> i1),

        ‘тогда наименьший элемент и текущий меняются местами

        If im <> i1 Then

            tmp = myArray(i1)

            myArray(i1) = myArray(im)

            myArray(im) = tmp

        End If

    Next

SortArray = myArray

End Function

Внешний цикл сравнивает по очереди каждый элемент массива с наименьшем элементом, найденным вложенным циклом среди оставшихся элементов (с бóльшими индексами), и, если наименьший элемент myArray(im) не является текущим элементом myArray(i1), они меняются местами.

Функция с выбором вида сортировки

Функция сортировки одномерного массива с дополнительным параметром mySort, который позволяет выбрать сортировку по возрастанию или убыванию и с числовым или текстовым сравнением числовых элементов массива:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

Function SortArrayNew(myArray As Variant, mySort As Long) As Variant

Dim l As Long, u As Long, i1 As Long, i2 As Long, im As Long, tmp As Variant

l = LBound(myArray)

u = UBound(myArray)

    For i1 = l To u

        im = i1

            For i2 = i1 To u

                Select Case mySort

                    Case Is = 0

                        If myArray(i2) < myArray(im) Then im = i2

                    Case Is = 1

                        If CStr(myArray(i2)) < CStr(myArray(im)) Then im = i2

                    Case Is = 2

                        If myArray(i2) > myArray(im) Then im = i2

                    Case Is = 3

                        If CStr(myArray(i2)) > CStr(myArray(im)) Then im = i2

                End Select

            Next

        If im <> i1 Then

            tmp = myArray(i1)

            myArray(i1) = myArray(im)

            myArray(im) = tmp

        End If

    Next

SortArrayNew = myArray

End Function

Значения, которые может принимать параметр mySort:

Значение Вид сортировки
0 по возрастанию с числовым сравнением чисел
1 по возрастанию с текстовым сравнением чисел
2 по убыванию с числовым сравнением чисел
3 по убыванию с текстовым сравнением чисел

Пример сортировки массива

Пример использования разных видов сортировки одномерного массива в VBA Excel с выводом результатов на рабочий лист:

Sub Primer()

Dim myArr As Variant, x As Variant, i As Long, n As Long

    For i = 1 To 4

        myArr = Array(46, 25, «Лето», 508, 35, «лес», 11, 5, «25ф», «Лес», 45, 58, «лето», 350)

                myArr = SortArrayNew(myArr, i 1)

        n = 1

            For Each x In myArr

                Cells(n, i) = myArr(n 1)

                n = n + 1

            Next

    Next

End Sub

Результаты разных видов сортировки массива myArr:

 

слэн

Пользователь

Сообщений: 5192
Регистрация: 16.01.2013

кроме как на листе, конечно..

 

Вообще есть куча разнообразных способов и методов… Вот еще один:

http://www.vbrussian.com/Article.asp?ID=97  

P.S. Google рулит)

 

слэн

Пользователь

Сообщений: 5192
Регистрация: 16.01.2013

а с использованием стандартных функций( Сишных, например) никто не видел?  

  я тоже надыбал одну ссылку по реализации алгоритма quicksort на VBA, но уже нашел там ошибку..

 

New

Пользователь

Сообщений: 4581
Регистрация: 06.01.2013

 

New

Пользователь

Сообщений: 4581
Регистрация: 06.01.2013

 

В VBA насколько я понимаю, ф-ции swap нету. Значит, напрямую преобразовать Си-пример в код VBA не получится. Вот в этой теме —

http://www.planetaexcel.ru/forum.php?thread_id=5274

(была указана выше) — Турбо-Ёж впроде бы предлагал подогнаный под Excel метод Fast Quick Sort.

 

Блин, до конца не разобрался) Swap — это ж отдельная процедура) Тогда пример Турбо-Ежа — точно Fast Quick Sort.

 

Потестил 2 способа Ежа и по ссылке

http://www.vbrussian.com/Article.asp?ID=97  

с помощью  
Sub TestSort()  
   Dim iEntry()  
   Dim j: j = 1000000  
   ReDim iEntry(1 To j)  
   For iOuter = LBound(iEntry()) To UBound(iEntry())  
       iEntry(iOuter) = Int((20 * Rnd) — 10)  
   Next  
  Start1 = Timer  
  Call ShellSort2(iEntry())  
  MsgBox Format((Timer — Start1), «00:00»)  
End Sub  

  Так вот, сортировка Ежа на миллионе случайных чисел — 21 секунда, вторая сортировка — 7 секунд..  
Кстати, может кто-нибудь знает алгоритм извлечения уникальных элементов,кроме последовательного перебора отсортированного массива

 

слэн

Пользователь

Сообщений: 5192
Регистрация: 16.01.2013

скачал алгоритм qsort с

www.cpearson.com  

только там в «NumberOfArrayDimensions» надо заменить как минимум  
Dim Res As Integer    на           Dim Res As long  
а лучше вообще так:  
Private Function NumberOfArrayDimensions(arr As Variant) As Integer  
»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»­»»»»»»»»»»»»»»»»»»»»  
‘ NumberOfArrayDimensions  
‘ This function returns the number of dimensions of an array. An unallocated dynamic array  
‘ has 0 dimensions. This condition can also be tested with IsArrayEmpty.  
»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»­»»»»»»»»»»»»»»»»»»»»’  
Dim Ndx As Long  
On Error GoTo ex  
‘ Loop, increasing the dimension index Ndx, until an error occurs.  
‘ An error will occur when Ndx exceeds the number of dimension  
‘ in the array. Return Ndx — 1.  
Do  
    Ndx = Ndx + 1  
   If UBound(arr, Ndx) Then:  
Loop  

   ex: NumberOfArrayDimensions = Ndx — 1  

   End Function  

  а так довольно быстро работает.

 

слэн

Пользователь

Сообщений: 5192
Регистрация: 16.01.2013

{quote}{login=Артем}{date=09.01.2009 07:35}{thema=}{post}Потестил 2 способа Ежа и по ссылке

http://www.vbrussian.com/Article.asp?ID=97  

с помощью  
Sub TestSort()  
   Dim iEntry()  
   Dim j: j = 1000000  
   ReDim iEntry(1 To j)  
   For iOuter = LBound(iEntry()) To UBound(iEntry())  
       iEntry(iOuter) = Int((20 * Rnd) — 10)  
   Next  
  Start1 = Timer  
  Call ShellSort2(iEntry())  
  MsgBox Format((Timer — Start1), «00:00»)  
End Sub  

  Так вот, сортировка Ежа на миллионе случайных чисел — 21 секунда, вторая сортировка — 7 секунд..  
Кстати, может кто-нибудь знает алгоритм извлечения уникальных элементов,кроме последовательного перебора отсортированного массива{/post}{/quote}  

    по извлечению уникальных элементов посмотрите здесь:

http://sql.ru/forum/actualthread.aspx?bid=46&tid=333152&pg=-1  

сортировать не надо..  
лучший способ с scripting.dictionary  
но и с коллекциями очень неплохо..  

  на миллионе не пробовал, но на 60000(в 2003 икселе) доли секунды..

 
 

New

Пользователь

Сообщений: 4581
Регистрация: 06.01.2013

В приложенном архиве 3 файла  

  1) сортировка от Chip Pearson, которую дал Слэн  
2) сортировка по методу Шелла с сайта

http://www.vbrussian.com/Article.asp?ID=97  

3) сортировка взятая отсюда

http://www.vbnet.ru/forum/show.aspx?id=90781&page=1  

  По моим результатам 3-й вариант самый быстрый. Если я не прав, поправьте меня.

 

ZVI

Пользователь

Сообщений: 4328
Регистрация: 23.12.2012

Добрый вечер, Слэн! и всем ;-)  

  Алгоритмов VBA-сортировки опубликовано достаточно много.    
Прилагаю небольшой архивчик методов сортировки, когда-то надёрганных из Интернета.  

  Вот здесь хороший ресурс по методам сортировки на нескольких языках программирования:  

http://alglib.sources.ru/sorting/  

Там же есть и статья по сравнению эффективности алгоритмов сортировки массивов:  

http://alglib.sources.ru/articles/sort.php  

Только советую творчески отнестись к коду и оценкам, так как из-за универсальности код не оптимизирован. И на VB (VBA) можно получить иные результаты эффективности.  
Кстати, на этом же сайте приведено множество интересных методов матобработки.  

  Эффективность сортировки  сильно зависит от размера массива, типа данных, метода сортировки, компилятора и/или среды программирования. В частности, по моим оценкам, на обработках длинных строк при прочих равных условиях  компилятор Borland C++ в 2 … 2.5 раза быстрее компилятора Visual C++.  Но и функциями VBA можно написать код, который обрабатывает строки в несколько раз быстрее, чем некоторые другие встроенные VBA-функции, написанные на C(++), если вместо автоматизации по скорости компилятора для конкретной задачи написать более оптимальный код, понимая, где реальные тормоза: memory reallocation, adjusting of addresses etc.  

   Известны также  методы сортировки коллекций, но они неэффективны на больших массивах:    

http://www.dailydoseofexcel.com/archives/2004/06/02/sort-a-collection/  
http://www.freevbcode.com/ShowCode.asp?ID=3645  

Впрочем, использование дополнительного индексного массива заслуживает внимания:  

http://www.source-code.biz/snippets/vbasic/  

Индексный массив особенно насущен и для сортировки многомерных массивов.  

  На мой взгляд, в дополнение к использованию индексного массива представляет интерес свопинг не самих переменных, а их адресов с помощью API CopyMemory  (RtlMoveMemory). Подозреваю, что Excel как и поступает, но реальных тестов эффективности этого метода я не проводил.

 

согласен с Павлом, метод с Vbnet самый быстрый — на моем ПК миллион значений обрабытывает за 5 сек, пирсоновский аж 34 секунды.(Не смотрел пока то что выложил ZVI)

 

метод бинарных деревьев(при прочих равных) — 6,6 секунд однако…

 

New

Пользователь

Сообщений: 4581
Регистрация: 06.01.2013

Хм, а кто знает, как запустить этот метод бинарных деревьев с одномерным массивом? ))  

  Объявил массив  

  Dim MyArr() As Double, i As Long  

     ReDim MyArr(0 To 50000)  
   For i = 0 To 50000  
       MyArr(i) = Round(Rnd * 50000, 0)  
   Next i  

    Вызываю процедуру сортировки    

  HeapSort MyArr(), 1    

  1 — т.е. одномерный массив (в процедуре написано указывать размерность)  

  но процедура сразу заканчивается, т.к. в начале процедуры написано    

     If N = 1# Then  
       Exit Sub  
   End If  

  С размерностью 0 — выходит ошибка (ну, это логично)  
с размерностю 2 — сортировка не происходит.    

  Файл прилагаю.

 

New

Пользователь

Сообщений: 4581
Регистрация: 06.01.2013

ZVI, в твоём архиве в файле Sort_Routines.xls (где представлены различные методы сортировки) в модуле modHeapSort (метод бинарных деревьев) неправильно объявлены многие переменные, типа  

  Dim base, n, nn, i, m As Long  
Dim base, nDiv2, i, k As Long  

  При таком объявлении, при сортировке 50000 целых чисел у меня был лучший результат 1500 мс, при правильном объявлении всех этим переменных лучшим результатом стало 1047 мс, т.е. почти 500 мс выигрыш.  

  Я понимаю, это камень не в твой огород, а в огород автора файла.  

  Но всё равно очень долго работает этот метод бинарных деревьев  
— сперва циклом заполняется массив значениями с листа  
— почему-то долго сортируется  
— циклом долго выводим результат обратно на лист  

  Кстати, в этом же файле в модуле modMain, автор файла явно пишет, что он предпочитает из всех методов QuickSort, вот эта строка  

  varray2 = modQuickSort.Quicksort(varray) ‘Preferred Method of Sorting  

  Ох, что-то я не пойму. Все говорят, что метод бинарных деревьев самый быстрый, но при тестировании он почему-то самый долгий ))  

  Может у меня руки кривые? Разъясни, плиз )  

  Файл с мет. Бинар. деревьев из твоего файла прилагаю.  

    Я пытаюсь найти самый максимально быстрый способ сортировки массивов на листе Excel, как текстовых, так и числовых.

 

New

Пользователь

Сообщений: 4581
Регистрация: 06.01.2013

Потестировал я сортировку QuickSort из файла Sort_Routines.xls, которую так полюбил автор этого файла. При тестировании я чуть не умер… лучший результат … эм вам в миллисекундах сказать или лучше в минутах? )) В общем 252312 мс, на сколько я понимаю, это 4,2 минуты.    

  Файл прикладываю.  

  На сколько я понимаю, всё-таки самый быстрый пока остаётся 3-й вариант из моего поста post_44028.xls (

http://www.planetaexcel.ru/docs/forum_upload/post_44028.rar

), который я выложил выше в этой теме. Так?  

  так… 5 утра … надо ложиться спать. Всем споки.

 

New

Пользователь

Сообщений: 4581
Регистрация: 06.01.2013

По моему посту выше, где я не мог запустить сортировку с методом бинарных деревьев. Я просто неправильно прочитал название аргумента. Надо читать N — размер массива, а я прочитал «размерность массива» — из-за этого не мог запустить процедуру.  

  В общем, я сегодня потестировал две версия сортировки методом бинарных деревьев. Оба они оказались не самыми лучшими. Или я, может, что-то делаю не так.  

  Как я уже и сказал, пока лучшим остаётся 3-й вариант файла в посте    

http://www.planetaexcel.ru/docs/forum_upload/post_44028.rar  

  2 файла с бинарными деревьями выкладываю на вашего тестирования и анализа  

  а я спать, всем споки

 

ZVI

Пользователь

Сообщений: 4328
Регистрация: 23.12.2012

Насчет оценок методов я предупреждал :) в VBA результаты методов иные, чем на C++. Коды, что приложил в архиве, не мои, рассматривайте их просто как (до)исторические :-)  
А метод, выбранный Павлом, действительно работает очень шустро.    
Да и сам Павел поработал этой ночкой очень плодотворно, за что ему большое спасибо.    
Интересно было бы, конечно, достичь в VBA скорости сортировки Excel-я.  
А то в определенных случаях все же приходится сортировать в ячейках.

 

слэн

Пользователь

Сообщений: 5192
Регистрация: 16.01.2013

да, вариант qsort без рекурсии — лучший, но почти в два раза медленнее икселевской сортировки  

  непонятки:  

  когда вызываю как процедуру, т.е например: call qsort(arr)  
отсортированный  массив не передается обратно в процедуру и , соответственно, не отображается на листе..  

  если же вызывать как функцию: if qsort(arr) then:  
то все нормально.  

  и второе — оправдано ли оформление функцией простых действий? типа swap — в одном месте в коде употребляется  — не проще ли прямо там и записать алгоритм swap?  
в другом месте — сравнение двух величин оформлено функцией.. я понимаю, когда пишется универсальный код, заранее неизвестны типы данных, тогда в процедуру сортировки передается УКАЗАТЕЛЬ на функцию сравнения, кот вы выбираете сами(или можно выбирать автоматически, но это хуже).  

  хотя, конечно, это и несущественное замедление.. но если таких функций насовать туда поболе..

 

ZVI

Пользователь

Сообщений: 4328
Регистрация: 23.12.2012

В варианте Павла, работает и  Call QuickSortNonRecursive(Rng) и просто QuickSortNonRecursive Rng.  

  Насчет swap все правильно: для уменьшения времени лучше явно вписать перестановку в общую процедуру, чем многократно вызывать функцию. Сам вызов функции на любом языке программирования — это время, не говоря уже о времени на создание локальных переменных внутри функции при каждом вызове и еще, возможно, на приведение типов данных.  
Например, в С, когда нужна скорость, вместо вызова функций используют макросы типа #define isdigit(x) ((x) >= ‘0’ && (x) <= ‘9’), которые компилятор подсовывает в каждое место, откуда вызывался макрос. Но, с другой стороны, это увеличивает размер кода.  
В VBA тоже код увеличивается в размере, если подстановку (swap) потребуется вписать в несколько мест, зато сэкономится время тем большее, чем больше обрабатывемый массив.

 

New

Пользователь

Сообщений: 4581
Регистрация: 06.01.2013

Может кто-нибудь изменит макрос (QuickSort без рекурсии), как вы считаете будет быстрее, т.е. swap вставите внутрь процедуры? Чтобы, как говорится, вышла максимально быстрая процедура? (а то у меня что-то голова сегодня не работает)

 

слэн

Пользователь

Сообщений: 5192
Регистрация: 16.01.2013

крутил-крутил.. кроме swap ничего улучшить не получается. ну памяти чуть сэкономил, но и это еще вопрос :)  
Public Sub QuickSortNonRecursive(SortArray As Variant)  
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 Variant, swp  
   ReDim stack(1 To 64)  
   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  
                While SortArray(i) < pivot: i = i + 1: Wend  
                While pivot < SortArray(j): j = j — 1: Wend  
                If i <= j Then  
                    swp = SortArray(i): SortArray(i) = SortArray(j): SortArray(j) = swp  
                    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  
                   If stackpos > UBound(stack) Then ReDim Preserve stack(1 To UBound(stack) + 32)  
                   stack(stackpos).Low = i  
                   stack(stackpos).High = ub  
               End If  
               ub = j        ‘следующая итерация разделения будет работать с левой частью  
           Else  
               If j > lb Then  
                   stackpos = stackpos + 1  
                   If stackpos > UBound(stack) Then ReDim Preserve stack(1 To UBound(stack) + 32)  
                   stack(stackpos).Low = lb  
                   stack(stackpos).High = j  
               End If  
               lb = i  
           End If  
       Loop While lb < ub  
   Loop While stackpos  
End Sub

 

New

Пользователь

Сообщений: 4581
Регистрация: 06.01.2013

Да, действительно быстрее. Спасибо, Слэн.  

  Итак, выкладываю 2 варианта  
1) Самый быстрый для текста  
2) Самый быстрый для чисел  

  Они оба основаны на сортировке QuickSort без рекурсий, но с разными типами переменных в функции Swap (в одном случае переменные типа Variant, в другом String)  

  P.S. Совместить два в одном, чтобы макрос быстро обрабатывал и текст и числа. У меня не вышло.

 

ZVI

Пользователь

Сообщений: 4328
Регистрация: 23.12.2012

Павел, у Слэна как раз и сделан вариант как для строк, так и для чисел.  
Только если вместо:  
Public Sub QuickSortNonRecursive(SortArray As Variant)  
написать:  
Public Sub QuickSortNonRecursive(SortArray() As Variant)  
то будет примерно в 1.6 раза быстрее.  
Всего лишь 2 скобки добавили :-)  

  В приложении немного переделанный файл для совместной сортировки строк и чисел.

 

слэн

Пользователь

Сообщений: 5192
Регистрация: 16.01.2013

вот так вот :)  спасибо , научили..  

  осталось чуть-чуть

 

слэн

Пользователь

Сообщений: 5192
Регистрация: 16.01.2013

интересно, ZVI, почему именно умножать на 2 при увеличении массива stack?  

  это не слишком? ведь выход за пределы массива вовсе не обозначает, что потребуется еще столько же уровней, скорее наоборот.. можно даже предположить сколько понадобится по формуле:  
например, для                 If i < ub Then  
                   stackpos = stackpos + 1  

  можно оценить как:  (ub-i)/(ub-lb)*stackpos  

  да и на самом деле, для случайных чисел , количество уровней колеблется в пределах: 10-11  
а при изначально упорядоченном массиве, возрастает лишь до 14  

  на массиве из 65000 значений  

  ps  не лень вам ждать каждый раз пока массив создается? да икак в таком случае сравнивать методы?  

  свой файл прилагаю. перед первой сортировкой(ну и , соответственно, по желанию) нажать «поменять массив»

 

слэн

Пользователь

Сообщений: 5192
Регистрация: 16.01.2013

#30

11.01.2009 15:56:31

или умножение просто быстрее сложения?

Живи и дай жить..

Here’s a multi-column and a single-column QuickSort for VBA, modified from a code sample posted by Jim Rech on Usenet.

Notes:

You’ll notice that I do a lot more defensive coding than you’ll see in most of the code samples out there on the web: this is an Excel forum, and you’ve got to anticipate nulls and empty values… Or nested arrays and objects in arrays if your source array comes from (say) a third-party realtime market data source.

Empty values and invalid items are sent to the end of the list.

To sort multi-column arrays, your call will be:

 QuickSortArray MyArray,,,2

…Passing ‘2’ as the column to sort on and excluding the optional parameters that pass the upper and lower bounds of the search domain.

Sorting single-column arrays (vectors), instead use:

QuickSortVector Myarray

Here too excluding the optional parameters.

[EDITED] — fixed an odd formatting glitch in the <code> tags, which seem to have a problem with hyperlinks in code comments.

The Hyperlink I excised was Detecting an Array Variant in VBA.

Public Sub QuickSortArray(ByRef SortArray As Variant, Optional lngMin As Long = -1, Optional lngMax As Long = -1, Optional lngColumn As Long = 0)
    On Error Resume Next

    'Sort a 2-Dimensional array

    ' SampleUsage: sort arrData by the contents of column 3
    '
    '   QuickSortArray arrData, , , 3

    '
    'Posted by Jim Rech 10/20/98 Excel.Programming

    'Modifications, Nigel Heffernan:

    '       ' Escape failed comparison with empty variant
    '       ' Defensive coding: check inputs

    Dim i As Long
    Dim j As Long
    Dim varMid As Variant
    Dim arrRowTemp As Variant
    Dim lngColTemp As Long

    If IsEmpty(SortArray) Then
        Exit Sub
    End If
    If InStr(TypeName(SortArray), "()") < 1 Then  'IsArray() is somewhat broken: Look for brackets in the type name
        Exit Sub
    End If
    If lngMin = -1 Then
        lngMin = LBound(SortArray, 1)
    End If
    If lngMax = -1 Then
        lngMax = UBound(SortArray, 1)
    End If
    If lngMin >= lngMax Then    ' no sorting required
        Exit Sub
    End If

    i = lngMin
    j = lngMax

    varMid = Empty
    varMid = SortArray((lngMin + lngMax)  2, lngColumn)

    ' We  send 'Empty' and invalid data items to the end of the list:
    If IsObject(varMid) Then  ' note that we don't check isObject(SortArray(n)) - varMid *might* pick up a valid default member or property
        i = lngMax
        j = lngMin
    ElseIf IsEmpty(varMid) Then
        i = lngMax
        j = lngMin
    ElseIf IsNull(varMid) Then
        i = lngMax
        j = lngMin
    ElseIf varMid = "" Then
        i = lngMax
        j = lngMin
    ElseIf VarType(varMid) = vbError Then
        i = lngMax
        j = lngMin
    ElseIf VarType(varMid) > 17 Then
        i = lngMax
        j = lngMin
    End If

    While i <= j
        While SortArray(i, lngColumn) < varMid And i < lngMax
            i = i + 1
        Wend
        While varMid < SortArray(j, lngColumn) And j > lngMin
            j = j - 1
        Wend

        If i <= j Then
            ' Swap the rows
            ReDim arrRowTemp(LBound(SortArray, 2) To UBound(SortArray, 2))
            For lngColTemp = LBound(SortArray, 2) To UBound(SortArray, 2)
                arrRowTemp(lngColTemp) = SortArray(i, lngColTemp)
                SortArray(i, lngColTemp) = SortArray(j, lngColTemp)
                SortArray(j, lngColTemp) = arrRowTemp(lngColTemp)
            Next lngColTemp
            Erase arrRowTemp

            i = i + 1
            j = j - 1
        End If
    Wend

    If (lngMin < j) Then Call QuickSortArray(SortArray, lngMin, j, lngColumn)
    If (i < lngMax) Then Call QuickSortArray(SortArray, i, lngMax, lngColumn)
    
End Sub

… And the single-column array version:

Public Sub QuickSortVector(ByRef SortArray As Variant, Optional lngMin As Long = -1, Optional lngMax As Long = -1)
    On Error Resume Next

    'Sort a 1-Dimensional array

    ' SampleUsage: sort arrData
    '
    '   QuickSortVector arrData

    '
    ' Originally posted by Jim Rech 10/20/98 Excel.Programming


    ' Modifications, Nigel Heffernan:
    '       ' Escape failed comparison with an empty variant in the array
    '       ' Defensive coding: check inputs

    Dim i As Long
    Dim j As Long
    Dim varMid As Variant
    Dim varX As Variant

    If IsEmpty(SortArray) Then
        Exit Sub
    End If
    If InStr(TypeName(SortArray), "()") < 1 Then  'IsArray() is somewhat broken: Look for brackets in the type name
        Exit Sub
    End If
    If lngMin = -1 Then
        lngMin = LBound(SortArray)
    End If
    If lngMax = -1 Then
        lngMax = UBound(SortArray)
    End If
    If lngMin >= lngMax Then    ' no sorting required
        Exit Sub
    End If

    i = lngMin
    j = lngMax

    varMid = Empty
    varMid = SortArray((lngMin + lngMax)  2)

    ' We  send 'Empty' and invalid data items to the end of the list:
    If IsObject(varMid) Then  ' note that we don't check isObject(SortArray(n)) - varMid *might* pick up a default member or property
        i = lngMax
        j = lngMin
    ElseIf IsEmpty(varMid) Then
        i = lngMax
        j = lngMin
    ElseIf IsNull(varMid) Then
        i = lngMax
        j = lngMin
    ElseIf varMid = "" Then
        i = lngMax
        j = lngMin
    ElseIf VarType(varMid) = vbError Then
        i = lngMax
        j = lngMin
    ElseIf VarType(varMid) > 17 Then
        i = lngMax
        j = lngMin
    End If

    While i <= j

        While SortArray(i) < varMid And i < lngMax
            i = i + 1
        Wend
        While varMid < SortArray(j) And j > lngMin
            j = j - 1
        Wend

        If i <= j Then
            ' Swap the item
            varX = SortArray(i)
            SortArray(i) = SortArray(j)
            SortArray(j) = varX

            i = i + 1
            j = j - 1
        End If

    Wend

    If (lngMin < j) Then Call QuickSortVector(SortArray, lngMin, j)
    If (i < lngMax) Then Call QuickSortVector(SortArray, i, lngMax)

End Sub

I used to use BubbleSort for this kind of thing, but it slows down, severely, after the array exceeds 1024 rows. I include the code below for your reference: please note that I haven’t provided source code for ArrayDimensions, so this will not compile for you unless you refactor it — or split it out into ‘Array’ and ‘vector’ versions.

Public Sub BubbleSort(ByRef InputArray, Optional SortColumn As Integer = 0, Optional Descending As Boolean = False)
' Sort a 1- or 2-Dimensional array.

Dim iFirstRow   As Integer
Dim iLastRow    As Integer
Dim iFirstCol   As Integer
Dim iLastCol    As Integer
Dim i           As Integer
Dim j           As Integer
Dim k           As Integer
Dim varTemp     As Variant
Dim OutputArray As Variant

Dim iDimensions As Integer

iDimensions = ArrayDimensions(InputArray)

    Select Case iDimensions
    Case 1

        iFirstRow = LBound(InputArray)
        iLastRow = UBound(InputArray)
        
        For i = iFirstRow To iLastRow - 1
            For j = i + 1 To iLastRow
                If InputArray(i) > InputArray(j) Then
                    varTemp = InputArray(j)
                    InputArray(j) = InputArray(i)
                    InputArray(i) = varTemp
                End If
            Next j
        Next i
        
    Case 2

        iFirstRow = LBound(InputArray, 1)
        iLastRow = UBound(InputArray, 1)
        
        iFirstCol = LBound(InputArray, 2)
        iLastCol = UBound(InputArray, 2)
        
        If SortColumn  InputArray(j, SortColumn) Then
                    For k = iFirstCol To iLastCol
                        varTemp = InputArray(j, k)
                        InputArray(j, k) = InputArray(i, k)
                        InputArray(i, k) = varTemp
                    Next k
                End If
            Next j
        Next i

    End Select
        

    If Descending Then
    
        OutputArray = InputArray
        
        For i = LBound(InputArray, 1) To UBound(InputArray, 1)
        
            k = 1 + UBound(InputArray, 1) - i
            For j = LBound(InputArray, 2) To UBound(InputArray, 2)
                InputArray(i, j) = OutputArray(k, j)
            Next j
        Next i
 
        Erase OutputArray
        
    End If

End Sub

This answer may have arrived a bit late to solve your problem when you needed to, but other people will pick it up when they Google for answers for similar problems.

Вступление

В отличие от платформы .NET, библиотека Visual Basic для приложений не включает процедуры сортировки массивов.

Существует два типа обходных путей: 1) реализация алгоритма сортировки с нуля или 2) использование подпрограмм сортировки в других общедоступных библиотеках.

Реализация алгоритма — Быстрая сортировка по одномерному массиву

Из функции сортировки массива VBA?

Public Sub QuickSort(vArray As Variant, inLow As Long, inHi As Long)

  Dim pivot   As Variant
  Dim tmpSwap As Variant
  Dim tmpLow  As Long
  Dim tmpHi   As Long

  tmpLow = inLow
  tmpHi = inHi

  pivot = vArray((inLow + inHi)  2)

  While (tmpLow <= tmpHi)

     While (vArray(tmpLow) < pivot And tmpLow < inHi)
        tmpLow = tmpLow + 1
     Wend

     While (pivot < vArray(tmpHi) And tmpHi > inLow)
        tmpHi = tmpHi - 1
     Wend

     If (tmpLow <= tmpHi) Then
        tmpSwap = vArray(tmpLow)
        vArray(tmpLow) = vArray(tmpHi)
        vArray(tmpHi) = tmpSwap
        tmpLow = tmpLow + 1
        tmpHi = tmpHi - 1
     End If

  Wend

  If (inLow < tmpHi) Then QuickSort vArray, inLow, tmpHi
  If (tmpLow < inHi) Then QuickSort vArray, tmpLow, inHi

End Sub

Использование библиотеки Excel для сортировки одномерного массива

Этот код использует класс Sort в библиотеке объектов Microsoft Excel.

Для дальнейшего ознакомления см .:

  • Скопировать диапазон в виртуальный диапазон

  • Как скопировать выбранный диапазон в заданный массив?

Sub testExcelSort()

Dim arr As Variant

InitArray arr
ExcelSort arr

End Sub

Private Sub InitArray(arr As Variant)

Const size = 10
ReDim arr(size)

Dim i As Integer

' Add descending numbers to the array to start
For i = 0 To size
    arr(i) = size - i
Next i

End Sub

Private Sub ExcelSort(arr As Variant)

' Ininitialize the Excel objects (required)
Dim xl As New Excel.Application
Dim wbk As Workbook
Set wbk = xl.Workbooks.Add
Dim sht As Worksheet
Set sht = wbk.ActiveSheet

' Copy the array to the Range object
Dim rng As Range
Set rng = sht.Range("A1")
Set rng = rng.Resize(UBound(arr, 1), 1)
rng.Value = xl.WorksheetFunction.Transpose(arr)

' Run the worksheet's sort routine on the Range
Dim MySort As Sort
Set MySort = sht.Sort
    
With MySort
    .SortFields.Clear
    .SortFields.Add rng, xlSortOnValues, xlAscending, xlSortNormal
    .SetRange rng
    .Header = xlNo
    .Apply
End With

' Copy the results back to the array
CopyRangeToArray rng, arr

' Clear the objects
Set rng = Nothing
wbk.Close False
xl.Quit

End Sub

Private Sub CopyRangeToArray(rng As Range, arr)

Dim i As Long
Dim c As Range

' Can't just set the array to Range.value (adds a dimension)
For Each c In rng.Cells
    arr(i) = c.Value
    i = i + 1
Next c

End Sub

Example

From VBA array sort function?

Public Sub QuickSort(vArray As Variant, inLow As Long, inHi As Long)

  Dim pivot   As Variant
  Dim tmpSwap As Variant
  Dim tmpLow  As Long
  Dim tmpHi   As Long

  tmpLow = inLow
  tmpHi = inHi

  pivot = vArray((inLow + inHi)  2)

  While (tmpLow <= tmpHi)

     While (vArray(tmpLow) < pivot And tmpLow < inHi)
        tmpLow = tmpLow + 1
     Wend

     While (pivot < vArray(tmpHi) And tmpHi > inLow)
        tmpHi = tmpHi - 1
     Wend

     If (tmpLow <= tmpHi) Then
        tmpSwap = vArray(tmpLow)
        vArray(tmpLow) = vArray(tmpHi)
        vArray(tmpHi) = tmpSwap
        tmpLow = tmpLow + 1
        tmpHi = tmpHi - 1
     End If

  Wend

  If (inLow < tmpHi) Then QuickSort vArray, inLow, tmpHi
  If (tmpLow < inHi) Then QuickSort vArray, tmpLow, inHi

End Sub

Trojan52

0 / 0 / 0

Регистрация: 24.06.2013

Сообщений: 71

1

Метод быстрой сортировки

03.07.2013, 13:57. Показов 9927. Ответов 38

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Как отсортировать одномерный массив методом Быстрой сортировки?
Вот код записи данных в массив!

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
intI = 1
    intCountCells = 0
    For intI = 1 To intCnt
        If Sheets(2).Cells(intI, 2).Value <> "" Then
            intCountCells = intCountCells + 1   
        End If
    Next intI
    intI = 0
    ReDim intArr(intCountCells)   
    For intI = 0 To intCountCells
        intArr(intI) = Sheets(2).Cells(intI + 1, 2).Value  
    Next intI



0



Programming

Эксперт

94731 / 64177 / 26122

Регистрация: 12.04.2006

Сообщений: 116,782

03.07.2013, 13:57

Ответы с готовыми решениями:

Алгоритм быстрой сортировки для двумерного массива. Получается, чем меньше столбцов, тем быстрее сортировка
Написал процедуру для сортировки двумерного массива.
Для того, чтобы можно было менять число строк…

Как расписать «по шагам» процесс быстрой сортировки массива.
По сортировке: дан массив 5,1,4,7,6,9,2,8
Распишите &quot;по шагам&quot; процесс его быстрой сортировки….

Отсортировать массив, используя метод сортировки выборками
Задан массив вещественных чисел А. Выполнить сортировку элементов массива, т.е. расположить…

Предложить метод сортировки текстового массива, отличный от WordBasic.SortArray
Доброго времени суток!
Помогите !:
Есть одномерный текстовый массив m() содержащий набор…

38

6875 / 2807 / 533

Регистрация: 19.10.2012

Сообщений: 8,562

03.07.2013, 14:08

2

И чего бы не отсортировать диапазон на листе и не взять в массив верхушку (в двумерный)?
Или взять всё в двумерный, отсортировать как угодно готовой функцией (их много всяких), затем переложить верхушку (или пользовать как есть, отбросив хвост)?
Оба способа думаю будут быстрее самой «Быстрой сортировки» после того, что в примере. Если брать весь процесс в целом.
И зачем непременно нужен одномерный массив?



0



0 / 0 / 0

Регистрация: 24.06.2013

Сообщений: 71

03.07.2013, 14:19

 [ТС]

3

Цитата
Сообщение от Hugo121
Посмотреть сообщение

И чего бы не отсортировать диапазон на листе и не взять в массив верхушку (в двумерный)?
Или взять всё в двумерный, отсортировать как угодно готовой функцией (их много всяких), затем переложить верхушку (или пользовать как есть, отбросив хвост)?
Оба способа думаю будут быстрее самой «Быстрой сортировки» после того, что в примере. Если брать весь процесс в целом.
И зачем непременно нужен одномерный массив?

Такое уж задание? Сделать диалог выбора сортировки «Пузырьковая и Быстрая». С Пузырьковой разобрался, а вот с Быстрой туплю по-жесткому!



0



6875 / 2807 / 533

Регистрация: 19.10.2012

Сообщений: 8,562

03.07.2013, 14:22

4

Я наизусть не знаю — но где-тут ведь была тема со всеми сортировками.



0



призрак

3261 / 889 / 119

Регистрация: 11.05.2012

Сообщений: 1,702

Записей в блоге: 2

03.07.2013, 21:08

5

ключевое слово для поиска по форуму: quicksort
причём делать это надо было до создания темы.



0



Trojan52

0 / 0 / 0

Регистрация: 24.06.2013

Сообщений: 71

04.07.2013, 10:49

 [ТС]

6

Как отсортировать одномерный массив методом Быстрой сортировки?
Вот код записи данных в массив!

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
intI = 1
    intCountCells = 0
    For intI = 1 To intCnt
        If Sheets(2).Cells(intI, 2).Value <> "" Then
            intCountCells = intCountCells + 1   
        End If
    Next intI
    intI = 0
    ReDim intArr(intCountCells)   
    For intI = 0 To intCountCells
        intArr(intI) = Sheets(2).Cells(intI + 1, 2).Value  
    Next intI



0



Trojan52

0 / 0 / 0

Регистрация: 24.06.2013

Сообщений: 71

04.07.2013, 12:07

 [ТС]

7

При работе скрипта вылетает ошибка «Out of stack space»! Как исправить не понимаю! Может есть какая-нибудь ошибка?
Вот код!

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Public Sub QSort(ByRef intArr() As Integer, ByVal low As Integer, ByVal high As Integer)
    Dim i As Integer, j As Integer
    Dim m, wsp As Double
    low = LBound(intArr)
    high = UBound(intArr)
    i = low
    j = high
    m = intArr((i + j)  2)
    Do While i < j
        Do While intArr(i) < m
            i = i + 1
        Loop
        Do While intArr(j) > m
            j = j - 1
        Loop
        If i <= j Then
            wsp = intArr(i)
            intArr(i) = intArr(j)
            intArr(j) = wsp
            i = i + 1
            j = j - 1
        End If
    Loop
    If low < j Then Call QSort(intArr, low, j)
    If i < high Then Call QSort(intArr, i, high)
    frmList.lstCells.List = intArr
End Sub



0



Dragokas

Эксперт WindowsАвтор FAQ

17992 / 7618 / 890

Регистрация: 25.12.2011

Сообщений: 11,351

Записей в блоге: 17

04.07.2013, 12:54

8

и не одна.

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Sub QSort(intArr(), optional low As Integer, optional high As Integer)
  Dim m As long
  Dim wsp As integer, i As Integer, j As Integer
  i = low
  j = high
  m = intArr((i + j)  2)
  Do While (i <= j)
    Do While (intArr(i) < m And i < high)
      i = i + 1
    Loop
    Do While (m < intArr(j) And j > low)
      j = j - 1
    Loop
    If i < j Then
      wsp = intArr(i)
      intArr(i) = intArr(j)
      intArr(j) = wsp
    End If
    If i <= j Then
      i = i + 1
      j = j - 1
    End If
  Loop
  If low < j Then Call (QSort intArr, low, j)
  If i < high Then Call (QSort intArr, i, high)
End Sub

Добавлено через 4 минуты
Trojan52, а зачем дубли темы создаете, а? Нехорошо.



1



Trojan52

0 / 0 / 0

Регистрация: 24.06.2013

Сообщений: 71

04.07.2013, 13:03

 [ТС]

9

Цитата
Сообщение от Dragokas
Посмотреть сообщение

и не одна.

Не работает! Мой скрипт должен выполнять «Быструю сортировку»! Твой скрипт не сортирует ее до конца!

Добавлено через 1 минуту

Цитата
Сообщение от Dragokas
Посмотреть сообщение

Trojan52, а зачем дубли темы создаете, а? Нехорошо

В той теме никто не отвечал, а как удалять их я не знаю, ибо новичок!

Добавлено через 3 минуты
Может есть какие-то поправки у меня Excel 2007 и, например,

Visual Basic
1
If low < j Then Call (QSort intArr, low, j)

Работает только так:

Visual Basic
1
If low < j Then Call QSort (intArr, low, j)



0



4377 / 661 / 36

Регистрация: 17.01.2010

Сообщений: 2,134

04.07.2013, 13:36

10

Вчера была Ваша тема про переменные. Я там как раз и говорил Вам ( и Султанов) про передачу аргументов в процедуру. А здесь Вы именнто это делаете, но используете сокращенную запись ( без присваивания :=), что тоже правильно по синтаксису языка. Ваша запись

Call QSort (intArr, low, j)

звучит так — вызвать процедуру QSort и передать ей аргументы intArr, low, j.
А запись Call (QSort intArr, low, j) — вызвать не понятно что, но это непонятное должно иметь аргументы QSort, intArr, low, j. Поэтому и ругается.



0



Trojan52

0 / 0 / 0

Регистрация: 24.06.2013

Сообщений: 71

04.07.2013, 13:47

 [ТС]

11

Цитата
Сообщение от Igor_Tr
Посмотреть сообщение

Вчера была Ваша тема про переменные. Я там как раз и говорил Вам ( и Султанов) про передачу аргументов в процедуру. А здесь Вы именнто это делаете, но используете сокращенную запись ( без присваивания :=), что тоже правильно по синтаксису языка. Ваша запись
Call QSort (intArr, low, j)
звучит так — вызвать процедуру QSort и передать ей аргументы intArr, low, j.
А запись Call (QSort intArr, low, j) — вызвать не понятно что, но это непонятное должно иметь аргументы QSort, intArr, low, j. Поэтому и ругается.

Не совсем понял что значит «(без присваивания :=)»

Добавлено через 6 минут

Цитата
Сообщение от Igor_Tr
Посмотреть сообщение

Вчера была Ваша тема про переменные. Я там как раз и говорил Вам ( и Султанов) про передачу аргументов в процедуру. А здесь Вы именнто это делаете, но используете сокращенную запись ( без присваивания :=), что тоже правильно по синтаксису языка. Ваша запись

Вот код, в котором почти в конце вызывается эта процедура!

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
Private Sub cmdPrint_Click()
    frmList.lstCells.Clear
    Sheets(2).Columns("B:B").Value = ""
    Dim rngCell As Range, intI As Integer, intOtvet As Integer, intCnt As Integer, intCountCells As Integer
    intI = 1
    intCnt = Selection.Cells.count
    For Each rngCell In Selection
        Sheets(2).Cells(intI, 2) = rngCell.Value
        '        frmList.lstCells.AddItem rngCell.Value
        intI = intI + 1
    Next
    intI = 1
    intCountCells = 0
    For intI = 1 To intCnt
        If Sheets(2).Cells(intI, 2).Value <> "" Then
            intCountCells = intCountCells + 1    'Óçíàåì êîëè÷åñòâî ÿ÷ååê ñ äàííûìè
        End If
        If intCountCells = 0 Then
            MsgBox "Âûäåëèòå ÿ÷åéêè äëÿ çàïîëíåíèÿ!", vbCritical, "Îøèáêà"
            frmList.Hide
            GoTo EndS
        End If
    Next intI
    intI = 0
    ReDim intArr(intCountCells)    'Ìåíÿåì ðàçìåð ìàññèâà
    For intI = 0 To intCountCells
        intArr(intI) = Sheets(2).Cells(intI + 1, 2).Value  'Çàïîëíÿåì ìàññèâ äàííûìè èç ÿ÷ååê íà 2 ëèñòå
    Next intI
    ReDim Preserve intArr(intCountCells - 1)
 
    intOtvet = MsgBox("Íàæìèòå Äà äëÿ ïóçûðüêîâîé ñîðòèðîâêè." & Chr(10) & "Íàæìèòå Íåò äëÿ áûñòðîé ñîðòèðîâêè(ìåòîä Õîàðà)." & Chr(10) & "Íàæìèòå Îòìåíà äëÿ çàïèñè áåç ñîðòèðîâêè.", 3, "Âûáåðèòå òèï ñîðòèðîâêè")
    Select Case intOtvet
    Case 2
        frmList.lstCells.List = intArr()
        GoTo EndS
    Case 6
        
        Dim intP As Integer, intJ As Integer, intTmp As Integer
        For intP = 0 To intCountCells - 2
            For intJ = (intP + 1) To intCountCells - 1
                If intArr(intP) > intArr(intJ) Then
                    intTmp = intArr(intP)
                    intArr(intP) = intArr(intJ)
                    intArr(intJ) = intTmp
                End If
            Next intJ
        Next intP
        lstCells.List = intArr
        GoTo EndS
    Case 7
        Call QSort(intArr(), low, high)
        
    End Select
EndS:
End Sub

В нем присутствует пузырьковая сортировка и переход к другой процедуре, где должна выполняться «Быстрая сортировка!»Вот эта процедура

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Sub QSort(ByRef intArr() As Integer, Optional low As Integer, Optional high As Integer)
     Dim IntIm As Integer, intJn As Integer
    Dim intM As Integer, intWsp As Integer
    low = LBound(intArr)
    high = UBound(intArr)
    IntIm = low
    intJn = high
    intM = intArr((IntIm + intJn)  2)
    Do While IntIm < intJn
        Do While intArr(IntIm) < intM
            IntIm = IntIm + 1
        Loop
        Do While intArr(intJn) > intM
            intJn = intJn - 1
        Loop
        If IntIm <= intJn Then
            intWsp = intArr(IntIm)
            intArr(IntIm) = intArr(intJn)
            intArr(intJn) = intWsp
            IntIm = IntIm + 1
            intJn = intJn - 1
        End If
    Loop
    low = IntIm
    high = intJn
    If low < intJn Then Call QSort(intArr, low, intJn)
    If IntIm > high Then Call QSort(intArr, IntIm, high)
    
    frmList.lstCells.List = intArr
End Sub

Скорее всего я где-то сильно затупил, но где?



0



4377 / 661 / 36

Регистрация: 17.01.2010

Сообщений: 2,134

04.07.2013, 13:57

12

У Вас есть процедура с обязательными аргументами — Sub QSort(a, b, c). При ее вызове (Call) передаете ей аргументы. Можно разширенно — QSort(a:=intArr, b:=low, c:=j), а можна сокращенно, но обязательно соблюдать очередность (при написании, редактор должен показывать посказку) — QSort (intArr, low, j).

Добавлено через 6 минут
Делаете две процедуры с аргументами (QSort расписано правильно). Одна — для пузырьковой (пусть QSort1(аргументы)), вторая — для быстрой (пусть QSort2(аргументы)). И поочереди вызываете — сохраняете где-то результаты. Можно совместить, но всеравно желательно результары разделить (они должны бы быть одинаковые — но так будет нагляднее). Разница должна быть (не обязательно) в времени.



0



0 / 0 / 0

Регистрация: 24.06.2013

Сообщений: 71

04.07.2013, 14:01

 [ТС]

13

Цитата
Сообщение от Igor_Tr
Посмотреть сообщение

Делаете две процедуры с аргументами (QSort расписано правильно). Одна — для пузырьковой (пусть QSort1(аргументы)), вторая — для быстрой (пусть QSort2(аргументы)). И поочереди вызываете — сохраняете где-то результаты. Можно совместить, но всеравно желательно результары разделить (они должны бы быть одинаковые — но так будет нагляднее). Разница должна быть (не обязательно) в времени.

Не в этом дело! Высвечивается MsgBox, если Нажмешь «Да», то пройдет пузырьковая сортировка, если «Нет», то быстрая, а если нажата отмена, то Идет запись без сортировки!



0



Dragokas

Эксперт WindowsАвтор FAQ

17992 / 7618 / 890

Регистрация: 25.12.2011

Сообщений: 11,351

Записей в блоге: 17

04.07.2013, 14:08

14

Trojan52, да, сорри, не учел момент, что здесь рекурсия:

нужно заменить строку 6 на:

Visual Basic
1
  m = intArr((low + high)  2)



1



4377 / 661 / 36

Регистрация: 17.01.2010

Сообщений: 2,134

04.07.2013, 14:16

15

Киньте лист с данными, которые Вы выделяете и сортируете. Прогоню у себя.

Добавлено через 3 минуты
Поздно увидел, что Dragokas уже разобрался.



1



0 / 0 / 0

Регистрация: 24.06.2013

Сообщений: 71

04.07.2013, 14:16

 [ТС]

16

Цитата
Сообщение от Igor_Tr
Посмотреть сообщение

Киньте лист с данными, которые Вы выделяете и сортируете. Прогоню у себя.

Прилагаю архив! С моим решением!



0



0 / 0 / 0

Регистрация: 24.06.2013

Сообщений: 71

04.07.2013, 14:29

 [ТС]

17

Цитата
Сообщение от Igor_Tr
Посмотреть сообщение

Поздно увидел, что Dragokas уже разобрался.

Не разобрался, это ничего не изменило! Посмотрите код, если не сложно!



0



4377 / 661 / 36

Регистрация: 17.01.2010

Сообщений: 2,134

04.07.2013, 14:35

18

Посмотрю обязательно, ну у меня еще и работа… Не переживайте, все будет нормально. А пока вот-что. Гланул на код. Там работа с выделенным диапазоном (Select). Вы его вручную выделяете? И идет речь о D4:G15?



0



0 / 0 / 0

Регистрация: 24.06.2013

Сообщений: 71

04.07.2013, 14:38

 [ТС]

19

Цитата
Сообщение от Igor_Tr
Посмотреть сообщение

Поздно увидел, что Dragokas уже разобрался.

Все равно не работает! Он ничего не изменил этой строчкой!
Помогите!

Добавлено через 55 секунд

Цитата
Сообщение от Igor_Tr
Посмотреть сообщение

Вы его вручную выделяете?

Да, диапазон выделяется вручную!
Ошибка только в frmList!



0



4377 / 661 / 36

Регистрация: 17.01.2010

Сообщений: 2,134

04.07.2013, 14:53

20

Не могу понять, что Вы имеете ввиду под переменной low?



1



Понравилась статья? Поделить с друзьями:
  • Vba excel буквы в строке
  • Vba excel буква колонки по номеру
  • Vba excel блокировка ячеек
  • Vba excel библиотека макросов
  • Vba excel атрибут файла