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




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

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

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

<?php // Полная загрузка сервисных книжек, создан 2024-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 не будет опубликован. Обязательные поля помечены *