Профессия — 1С

Рукопашный бой Карташ

Категории

Очередь

рубрики: Структуры данных | Дата: 23 августа, 2026
Скачать обработку с примерами из статьи: professia1c_queue.epf
Платформа: 8.3; Тип формы: управляемая.

Определение

Сегодня мы рассмотрим еще одну структуру данных, которая называется очередь. Каждый человек хоть раз в жизни стоял в очереди. Поэтому принцип ее работы понятен всем. Работает она по принципу FIFO: First In, First Out. То есть, первый вошел, первый вышел. Новый элемент помещается в конец (хвост) очереди, а извлекается с ее начала (головы).

queue fifo

Области применения

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

Конечно, при серьезном обмене между системами очередь обычно хранится не в оперативной памяти одного сеанса 1С. Для этого применяют таблицы базы данных или специальные брокеры сообщений. Они позволяют не потерять задания после перезапуска и дают возможность нескольким обработчикам работать одновременно. Но структура данных внутри таких решений остается той же: новые сообщения приходят в конец, а обработка начинается с головы.

Есть у очереди и чисто алгоритмическое применение. С ее помощью выполняется обход графа в ширину, который обычно обозначается как BFS (Breadth-First Search). При таком обходе мы сначала обходим вершины первого уровня, затем второго, третьего и т.д. Хорошо известное разработчикам 1С ДеревоЗначений также можно обойти подобным образом.

Реализации очереди средствами 1С

В качестве примера мы как раз и рассмотрим Обход дерева значений в ширину (BFS). Скорее всего многим из вас приходилось ранее делать обход дерева в глубину — DFS (Depth-First Search), когда мы от корня спускаемся вниз по узлам с помощью рекурсии. А сейчас мы реализуем обход в ширину с помощью очереди.

В языке 1С нет отдельного типа данных с названием Очередь. Поэтому реализуем ее искусственно с помощью массива. Самое очевидное решение — добавлять элементы методом Добавить(), а при чтении получать элемент с индексом ноль и сразу удалять его. Работать такой вариант будет, но у него есть недостаток. После удаления первого элемента платформе придется сдвинуть оставшиеся элементы массива. Чем длиннее очередь, тем дороже обходится такая операция.

Чтобы не передвигать данные при каждом чтении, будем хранить индекс головы. При извлечении элемента просто увеличим этот индекс на единицу. Таким образом при извлечении элемента из очереди мы получаем алгоритмическую сложность O(1), вместо О(n), если бы мы удаляли нулевой элемент массива. Можно также дополнительно сделать некоторые оптимизации, чтобы ограничить размер массива используемого очередью. Но в рамках нашего примера мы этим заниматься не будем, чтобы не увеличивать объем кода, который затруднит понимание самого принципа работы с очередью. Очередь у нас будет представлена в виде структуры с двумя полями: Элементы и ИндексГоловы. Ниже представлен минимально необходимые процедуры и функции для создания очереди, а также для работы с ней путем добавления и извлечения элементов.


&НаСервере
Функция СоздатьОчередь()

	Возврат Новый Структура(
		"Элементы, ИндексГоловы",
		Новый Массив, 0);

КонецФункции

&НаСервере
Процедура ПоместитьВОчередь(Очередь, Значение)

	Очередь.Элементы.Добавить(Значение);

КонецПроцедуры

&НаСервере
Функция ИзвлечьИзОчереди(Очередь)

	Если Очередь.ИндексГоловы >= Очередь.Элементы.Количество() Тогда
		Возврат Неопределено;
	КонецЕсли;

	ЭлементОчереди = Очередь.Элементы[Очередь.ИндексГоловы];
	Очередь.ИндексГоловы = Очередь.ИндексГоловы + 1;

	Возврат ЭлементОчереди;

КонецФункции

Использование очереди при обходе дерева в ширину

В первую очередь создадим само дерево значений. В качестве примера будем рассматривать вымышленную структуру некой организации. Дерево значений создадим программно и поместим его в соответствующий элемент управления на форме.


&НаСервере
Процедура ЗаполнитьДеревоНаСервере()

	Дерево = Новый ДеревоЗначений;
	Дерево.Колонки.Добавить("Наименование");

	Организация = Дерево.Строки.Добавить();
	Организация.Наименование = "Организация";

	ОтделПродаж = Организация.Строки.Добавить();
	ОтделПродаж.Наименование = "Отдел продаж";

	Разработка = Организация.Строки.Добавить();
	Разработка.Наименование = "Разработка";

	Бухгалтерия = Организация.Строки.Добавить();
	Бухгалтерия.Наименование = "Бухгалтерия";

	Москва = ОтделПродаж.Строки.Добавить();
	Москва.Наименование = "Продажи в Москве";

	Казань = ОтделПродаж.Строки.Добавить();
	Казань.Наименование = "Продажи в Казани";

	СервернаяРазработка = Разработка.Строки.Добавить();
	СервернаяРазработка.Наименование = "Серверная разработка";

	Интерфейсы = Разработка.Строки.Добавить();
	Интерфейсы.Наименование = "Разработка интерфейсов";

	РасчетЗарплаты = Бухгалтерия.Строки.Добавить();
	РасчетЗарплаты.Наименование = "Расчет зарплаты";

	МенеджерМосква = Москва.Строки.Добавить();
	МенеджерМосква.Наименование = "Иванов";

	МенеджерКазань = Казань.Строки.Добавить();
	МенеджерКазань.Наименование = "Петров";

	Программист = СервернаяРазработка.Строки.Добавить();
	Программист.Наименование = "Сидоров";

	Дизайнер = Интерфейсы.Строки.Добавить();
	Дизайнер.Наименование = "Смирнова";

	ЗначениеВРеквизитФормы(Дерево, "ДеревоОрганизации");
	
КонецПроцедуры

На форме это дерево выглядит вот так:

tree hierarchy

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

Обход в ширину для приведенного дерева должен происходить следующим образом:

queue tree search

И непосредственно код в котором это реализуется:


&НаСервере
Процедура ОбойтиДеревоВШиринуНаСервере()

	Очередь = СоздатьОчередь();

	Для Каждого КорневаяСтрока Из РеквизитФормыВЗначение("ДеревоОрганизации").Строки Цикл

		ПоместитьВОчередь(Очередь, КорневаяСтрока);

	КонецЦикла;

	Пока Истина Цикл

		ТекущаяСтрока = ИзвлечьИзОчереди(Очередь);
		
		Если ТекущаяСтрока = Неопределено Тогда
			Прервать;
		КонецЕсли;
		
		Сообщение = Новый СообщениеПользователю;
		Сообщение.Текст = ТекущаяСтрока.Наименование;
		Сообщение.Сообщить();

		Для Каждого ПодчиненнаяСтрока Из ТекущаяСтрока.Строки Цикл

			ПоместитьВОчередь(Очередь, ПодчиненнаяСтрока);

		КонецЦикла;

	КонецЦикла;

КонецПроцедуры

Пара слов о том, что происходит в этой процедуре. В первую очередь мы помещаем в очередь все корневые элементы дерева значений. В нашем случае такой элемент один — это Организация

Далее мы запускаем бесконечный цикл, который работает до тех пор пока в очереди есть хоть один элемент. На каждой итерации цикла из головы очереди извлекается (и при этом удаляется) очередной элемент, выводится сообщение с его наименованием, а в хвост очереди складываются его потомки. И такой подход как раз и позволяет вывести наименования по уровням, как было показано на рисунке ранее.

Заключение

Очередь — это структура данных с очень простым правилом: элементы обслуживаются в порядке поступления. Но именно это правило лежит в основе множества практических решений, начиная с последовательной обработки заданий и заканчивая обходом графов в ширину. В 1С отдельного типа Очередь нет, однако для локальных алгоритмов ее нетрудно построить на массиве и индексе головы.

Главное здесь не запомнить названия нескольких процедур, а научиться узнавать саму задачу. Если новые элементы должны обрабатываться после поступивших ранее, скорее всего перед нами очередь. И использование этой структуры сделает код понятнее, чем набор индексов, удалений и специальных признаков, смысл которых придется каждый раз восстанавливать заново.

Обсуждение закрыто.

   

2014 - 2026г. Профессия — 1С. Обмен опытом по программированию в 1С