Популярные алгоритмы сортировки массивов




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2026-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

43 Comments

  1. Поручик

    Где бы их ещё применить для 1С. Взял на заметку, может где понадобится.

    Reply ↓
  2. Yashazz

    Всю жизнь полагал, что в 1С применяется или быстрая, или шелловская сортировка. Интересно, что там на самом деле. Автор, делались ли замеры скорости, насколько метод списка значений выигрывает?

    Reply ↓
  3. Ekovichev

    Мне думается, что в 1с используется быстрая сортировка. Сравнения делались между сортировкой списком и быстрой сортировкой. Разница в сортировке массива размерностью 10 000 и значениями диапазоном от 0 до 100 при сортировке списком значений и быстрой сортировкой вообще незаметна. А вот на массиве размерностью 100 000 диапазон значений от 0 до 1000, сортировка списком значений показала результат около 2-3 секунд, а быстрая в среднем 6-7 секунд.

    Reply ↓
  4. Поручик

    (0) Вижу исправили. Вчера Был перебор массива в функции СортировкаСпискомЗначений(). Хотел написать, но отвлёкся.

    мСписокЗнч = ЗагрузитьЗначения(Массив);

    Reply ↓
  5. Ekovichev

    Да, вчера сам перечитал статью и заметил, понял, что не стоит писать по ночам)

    Reply ↓
  6. hame1e00n

    Полезная информация, спасибо!

    Reply ↓
  7. EliasShy

    Хорошо было бы написать жадность алгоритмов в нотации большого О.

    Reply ↓
  8. Ekovichev

    Хорошо, добавлю в статью

    Reply ↓
  9. PowerBoy

    Очепятки:

    Если Массив[i-1] — по убыванию

    i = j;

    j = j + 1;

    Иначе

    Если ij Тогда

    Прервать;

    КонецЕсли;

    Reply ↓
  10. Ekovichev

    Исправил, спасибо за замечание

    Reply ↓
  11. juntatalor

    Мне приходилось использовать «свою» сортировку для сортировки дерева значений на управляемой форме. Уж не помню, чем меня не устраивал метод ДанныеФормыДерево -> ДеревоЗначений -> Сортировка -> ДанныеФормыДерево, но быстрая сортировка на клиенте подошла лучше.

    Reply ↓
  12. mikmike

    а метод двоичного дерева?

    У меня в свое время была курсовая по методам сортировки.

    Так метод двоичного дерева на больших массивах сильно быстрей работает

    PS 1C тогда и в проекте не существовало. Алгоритм сложный, рекурсивный, но шустрый на больших массивах.

    Reply ↓
  13. Ekovichev

    Да метод бинарного дерева интересен, я его посмотрел, начал писать на 1С и что-то не закончил 🙂 Но если будет интересно, можно и его рассмотреть

    Reply ↓
  14. ediks

    (0)Небольшой пиар 🙂 — аналогичная статья Классические алгоритмы сортировки данных

    Reply ↓
  15. KAPACEB.AA

    (удалено)

    Reply ↓
  16. KAPACEB.AA

    Если не ошибаюсь, в сортировке вставками вместо:


    Пока j > 0 Цикл

    Если Замена < Массив[j — 1] Тогда

    Массив[j] = Массив[j — 1];

    Замена = j — 1;

    Ключ = j — 1;

    КонецЕсли;

    j = j — 1;

    КонецЦикла;

    в идеале должно быть так:

    Пока j > 0 И Замена < Массив[j — 1] Цикл

    Массив[j] = Массив[j — 1];

    Замена = j — 1;

    Ключ = j — 1;

    j = j — 1;

    КонецЦикла;

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

    Пруфлинк

    Reply ↓
  17. Ekovichev

    (16) Mu_meson, Вы правы, поправил.

    Reply ↓
  18. mikmike

    (13) теоритически конечно интересно — у меня в свое время заметный выигрыш получался на массивах из сотен и более элементов. 10 чисел быстрее всего упорядочивает самый простой алгоритм.

    Но вот на сколько реальна задача? Приведите кто-нибудь пример из жизни, пожалуйста.

    Reply ↓
  19. gruk
    А вот на массиве размерностью 100 000 диапазон значений от 0 до 1000, сортировка списком значений показала результат около 2-3 секунд, а быстрая в среднем 6-7 секунд.

    ИМХО: Дак наверное и не получится «сортировку списком значений» обогнать. Это же функция платформы, а любые самописные алгоритмы требуют время на интерпритацию команд.

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

    Думал, что в конце статьи увижу табличку с замером производительности алгоритмов и потребляемыми ресурсами 🙁

    Но все равно плюсую, познавательно.

    Reply ↓
  20. Ekovichev

    (20) gruk, Сделаю, хорошая идея. Насчет времени все ясно, только как замерить потребляемые ресурсы?

    Reply ↓
  21. DAnry

    Спасибо. Достаточно полный анализ по узкой теме. Однозначно +

    Reply ↓
  22. Evil Beaver

    Еще бы неплохо написать, какой именно алгоритм скрывается за 1С-овским «СортироватьПоЗначению()». Сейчас уже не найду, но вроде бы где-то проскакивало в сети, что там qsort, т.е. быстрая сортировка.

    Reply ↓
  23. gruk

    (21) Я имел ввиду оценить ресурсы приблизительно. Допустим «Сортировка вставками» потребляет мало, т.к. не нужен доп. массив и используется всего 4 переменных. (Кстати, если сделать процедуру и работать не со Знач массив, а со ссылкой, то ресурсов потребуется в 2 раза меньше.) Экономия ресурсов — 5. А «Сортировка слиянием» создает новые массивы. Экономия — 3.

    Почему я заговорил про ресурсы, пишу програмку, там использую 2-х мерные большие массивы. Комп слабоват. Сортирую через таблицы значений и память подъедает заметно, винда начинает использовать файл подкачки и падает производительность.

    Замер памяти я делал так: запускал 1с, консоль программиста, писал код, смотрел потребляемую память через дисп.задач, запускал код(в конце выводил предупреждение, чтоб массив не уничтожился), опять смотрел память.

    Результаты с 100 000 элементов от 0 до 65535 такие: Массив ~800 Кб, СписокЗначений ~9,5 Мб, ТаблицаЗначений с одной колонкой ~5,8 Мб. Еще заметил что после массива память освобождается почти сразу, а после списка или таблицы нет (но если запустить второй раз, увеличение потребления памяти уже намного меньше)

    Reply ↓
  24. gruk

    (21) насчет времени все просто.

    Scr = Новый COMОбъект(«MSScriptControl.ScriptControl»);
    Scr.Language = «javascript»;
    
    ВремяНачалаВыполнения = Scr.Eval(«new Date().getTime()»);
    
    //выполнить код
    
    ВремяКонцаВыполнения = Scr.Eval(«new Date().getTime()»);
    ВремяВыполнения = ВремяКонцаВыполнения — ВремяНачалаВыполнения; //время в милисекундах

    Показать

    Откуда взял, не помню, да простит меня автор.

    Reply ↓
  25. Ekovichev

    Как будет время проведу тест и в таблице опубликую. Замер времени вы взяли отсюда http://infostart.ru/public/71130/ 🙂

    Reply ↓
  26. CagoBHuK

    Однозначный плюс за труд.

    Reply ↓
  27. kasper076
  28. Ekovichev

    (28) kasper076, Я тоже сегодня на хабре прочел, заинтересовался:)

    Reply ↓
  29. mikhailovaew

    эх, где тут ildarovich, он бы еще каждый алгоритм оптимизировал с ускорением работы в 5 раз )

    Reply ↓
  30. saver77

    Спасибо за проделанную работу. Имею два предложения по быстрой сортировке:

    1. Для наглядности вызов ОтобразитьДиаграммуСортировки лучше разместить в цикле, тогда нагляднее будет.

    2. Полагаю, так красивее, если условие выхода из цикла перенести из оператора Если в оператор Пока.

    В итоге код процедуры будет такой

    Процедура б_Сортировка(Массив,НижнийПредел,ВерхнийПредел)
    
    i    = НижнийПредел;
    j    = ВерхнийПредел;
    m    = Массив[Цел((i+j)/2)];
    
    //Пока Истина Цикл
    Пока i<=j Цикл
    
    Пока Массив[i] < m Цикл
    i    = i + 1;
    КонецЦикла;
    
    Пока Массив[j] > m Цикл
    j    = j — 1;
    КонецЦикла;
    
    Если i<=j Тогда
    Замена            = Массив[i];
    Массив[i]    = Массив[j];
    Массив[j]    = Замена;
    i            = i + 1;
    j            = j — 1;
    Если ПрименитьОтображениеСортировки Тогда
    ОтобразитьДиаграммуСортировки(Массив);
    КонецЕсли;
    КонецЕсли;
    
    //Если i>j Тогда
    // Прервать;
    //КонецЕсли;
    
    КонецЦикла;
    
    Если НижнийПредел < j Тогда
    б_Сортировка(Массив,НижнийПредел,j);
    КонецЕсли;
    
    Если i < ВерхнийПредел Тогда
    б_Сортировка(Массив,i,ВерхнийПредел);
    КонецЕсли;
    
    КонецПроцедуры
    

    Показать

    Reply ↓
  31. tarasenkov

    В коде процедуры быстрой сортировки забыли важную часть:

           Если i <= j Тогда
    Замена       = Массив[i];
    Массив[i]    = Массив[j];
    Массив[j]    = Замена;
    i            = i + 1;
    j            = j — 1;
    КонецЕсли;

    (Обработку скачал, там этот код есть)

    Reply ↓
  32. JohnConnor

    однозначна нужная вещь, для изучения алгоритмов

    Reply ↓
  33. Sasha25

    Ну прямо таки даже и не знаю что и сказать. Наверное конечно фундаментальными знаниями нужно владеть

    Reply ↓
  34. pakill

    Когда-то, еще до нашей эры (ДОС, Паскаль) придумал метод сортировки: «разноской по значению» и для сравнения написал маленькую демо-програмку.

    Reply ↓
  35. DoctorRoza

    Отмечусь, может пригодится! Хотя .. обрабатывать в 1С Массив(), да еще и большим количеством элементов .. в какой задаче такое возможно? 🙂

    Reply ↓
  36. AlexO

    (36) DoctorRoza,

    в какой задаче такое возможно?

    Например, в задаче, где в массив запихнута огромная ТЗ ))

    Reply ↓
  37. platon_

    В Алгоритм «Гномья сортировка».

    Упущена часть кода в первом условии

    Если Массив[i-1]  < Массив[i]
    Reply ↓
  38. sadiv

    Добавил управляемую форму.

    Reply ↓
  39. mark_oilbass

    Отличная статья! Спасибо автору)

    Reply ↓
  40. 1Cnik)

    У вас в алгоритме вставками вроде как ошибка, проверьте на маленьких массивах, в теле цикла

    Пока j > 0 И Замена < Массив[j — 1] Цикл
    Массив[j] = Массив[j — 1];
    Замена = j — 1;
    Ключ = j — 1;
    j = j — 1;
    КонецЦикла; 

    Когда замена примет значение 0, то ниже в значение массива просто подставиться 0

    Переделал алгоритм на более логичный, убрал ненужные переменные

    Для i = 1 По Массив.ВГраница() Цикл
    Замена = Массив[i];
    j = i;
    Пока j > 0 И Массив[j — 1] > Замена Цикл
    Массив[j] = Массив[j — 1];
    j = j — 1;
    КонецЦикла;
    Массив[j] = Замена;
    
    КонецЦикла;
    

    Показать

    Reply ↓
  41. 1Cnik)

    Так же в быстрой сортировке в теле

    Если i<=j Тогда
    Замена            = Массив[i];
    Массив[i]    = Массив[j];
    Массив[j]    = Замена;
    i            = i + 1;
    j            = j — 1;
    КонецЕсли;
    
    Если i>j Тогда
    Прервать;
    КонецЕсли;
    

    Показать

    Когда i = j, то элемент массива просто заменит сам себя. Это глупо по логике, можно добавить условие для красоты.

    Если i<=j Тогда
    Если М[i] = М[j] Тогда
    i = i + 1;
    j = j — 1;
    Иначе
    Замена = М[i];
    М[i] = М[j];
    М[j] = Замена;
    i = i + 1;
    j = j — 1;
    КонецЕсли;
    КонецЕсли;
    
    Если i>j Тогда
    Прервать;
    КонецЕсли;
    

    Показать

    Reply ↓
  42. vlakur1

    .Алгоритм «Сортировка выбором» можно добавить -1 во внешний цикл

    Для i = 0 По Массив.ВГраница() Цикл -1

    …..

    Reply ↓
  43. Астиг

    (32) А я смотрю на быструю сортировку, и не понимаю, где же тут обмен элементами то?))

    Reply ↓

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *