Алгоритм. Очередь с приоритетом

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

В этой статье я покажу очередь с приоритетом с использованием linked list. Алгоритм простой и позволяет получить приоритетные сообщения раньше, чем остальные сообщения.

Я сначала поискал в интернете реализацию такого алгоритма. Первое, что я нашел, это решение на c++ с обычными массивами. То есть создается шаблонный класс и в нем создается два массива, один для чисел, другой для приоритетности. Мне показалось, что решение не очень хорошее, потому что при добавлении нового числа, создается новый массив и из старого копируются данные в новый массив. Чем больше очередь, тем больше копирования каждый раз. Ещё проблема при использовании массива - это что нельзя использовать в другом потоке очередь, пока ты не выполнишь полностью функцию вставки данных в очередь, так как смениться указатель на массив и так далее.

Алгоритм - очередь с приоритетом достаточно простой, мы создаем структуру, я опять буду показывать пример кода на C, и входящие данные будут числа. итак.

struct queue {
	unsigned long number;
	unsigned long priority;
	struct queue *parent;
	struct queue *child;
};

Также создаем глобальный указатель на начало очереди, прошу заметить, это всего лишь пример, разумеется в C++ можно создать это в классе, но так как в C будет только одна очередь, то она становиться глобальной как само собой разумеющееся.

struct queue *root;

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

static void add_number (int number, int priority)
{
	register struct queue *n = root;
	register struct queue *prev = NULL;
	register struct queue *temp = NULL;
	register struct queue *temp1 = NULL;

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

		if (n == NULL)
		{
			n = calloc (1, sizeof (struct queue));
			n->number = number;
			n->priority = priority;
			if (prev)
			{
				prev->child = n;
				n->parent = prev;
			}
			if (root == NULL) root = n;
			return;
		}

Здесь в указываем чтобы root указывал на него как на начало. Отсюда начнется следующий отсчет.

Далее мы смотрим, если добавляемый приоритет выше, чем наше сообщение в очереди, то перед ним установим новый приоритет.

		while (n->priority < priority)
		{
			temp = n;
			prev = n;
			n = n->parent;
			if (n == NULL)
			{
				n = calloc (1, sizeof (struct queue));
				n->number = number;
				n->priority = priority;
				n->child = temp;
				temp->parent = n;
				root = n;
				return;
			}
		}

Также можно заметить, что в этом случае root опять меняет свою позицию, указав себя как начало в списке.

Далее смотрим если добавляемый приоритет ниже чем текущий приоритет.

		while (n->priority > priority) 
		{
			temp = n;
			prev = n;
			n = n->child;
			if (n == NULL)
			{
				n = calloc (1, sizeof (struct queue));
				n->number = number;
				n->priority = priority;
				n->parent = temp;
				temp->child = n;
				return;
			} else if (n->priority <= priority)
			{
				temp = n->parent;
				temp1 = n;
				n = calloc (1, sizeof (struct queue));
				n->number = number;
				n->priority = priority;
				n->parent = temp;
				n->child = temp1;
				temp->child = n;
				temp1->parent = n;
				return;
			}
		}

Здесь всё должно быть понятно, что мы добавляем наше число куда нужно.

И осталось последнее.

		while (n->priority == priority)
		{
			temp = n;
			prev = n;
			n = n->child;
			if (n == NULL)
			{
				n = calloc (1, sizeof (struct queue));
				n->number = number;
				n->priority = priority;
				n->child = NULL;
				n->parent = n;
				temp->child = n;
				return;
			} else if (n->priority != priority)
			{
				temp = n->parent;
				temp1 = n;
				n = calloc (1, sizeof (struct queue));
				n->number = number;
				n->priority = priority;
				n->parent = temp;
				n->child = temp1;
				return;
			}
		}

Здесь мы смотрим, если он равен нашему приоритету, то дадим сначала выйти из очереди первому добавленному с таким приоритетом, а этот добавим за ним.

Теперь создадим функцию по выдачи из очереди нашего числа.

static int get_number_from_queue ()
{
	if (!root) return -1;
	register struct queue *n = root;
	root = root->child;
	register unsigned long number = n->number;
	free (n);
	return number;
}

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

Теперь создадим остальное.

struct arr {
	int num;
	int priority;
} arr[] = {
	{ 0, 0 },
	{ 1, 1 },
	{ 2, 2 },
	{ 3, 3 },
	{ 4, 4 },
	{ 5, 5 },
	{ 14, 14 },
	{ 26, 26 },
	{ 5, 5 },
	{ 6, 6 },
	{ 7, 7 },
	{ 8, 8 },
	{ 9, 9 },
	{ 10, 10 }
};

int main (int argc, char **argv)
{
	int size = sizeof (arr) / sizeof (struct arr);
	for (int i = 0; i < size; i++)
	{
		add_number (arr[i].num, arr[i].priority);
	}

	for (int i = 0; i < size; i++)
	{
		printf ("%d: %d\n", i, get_number_from_queue());
	}
}

Чтобы было удобней проверить код, то выкладываю полный код.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

struct queue {
	unsigned long number;
	unsigned long priority;
	struct queue *parent;
	struct queue *child;
};

struct queue *root;

static void add_number (int number, int priority)
{
	register struct queue *n = root;
	register struct queue *prev = NULL;
	register struct queue *temp = NULL;
	register struct queue *temp1 = NULL;
	while (1)
	{
		if (n == NULL)
		{
			n = calloc (1, sizeof (struct queue));
			n->number = number;
			n->priority = priority;
			if (prev)
			{
				prev->child = n;
				n->parent = prev;
			}
			if (root == NULL) root = n;
			return;
		}
		while (n->priority < priority)
		{
			temp = n;
			prev = n;
			n = n->parent;
			if (n == NULL)
			{
				n = calloc (1, sizeof (struct queue));
				n->number = number;
				n->priority = priority;
				n->child = temp;
				temp->parent = n;
				root = n;
				return;
			}
		}
		while (n->priority > priority) 
		{
			temp = n;
			prev = n;
			n = n->child;
			if (n == NULL)
			{
				n = calloc (1, sizeof (struct queue));
				n->number = number;
				n->priority = priority;
				n->parent = temp;
				temp->child = n;
				return;
			} else if (n->priority <= priority)
			{
				temp = n->parent;
				temp1 = n;
				n = calloc (1, sizeof (struct queue));
				n->number = number;
				n->priority = priority;
				n->parent = temp;
				n->child = temp1;
				temp->child = n;
				temp1->parent = n;
				return;
			}
		}
		while (n->priority == priority)
		{
			temp = n;
			prev = n;
			n = n->child;
			if (n == NULL)
			{
				n = calloc (1, sizeof (struct queue));
				n->number = number;
				n->priority = priority;
				n->child = NULL;
				n->parent = n;
				temp->child = n;
				return;
			} else if (n->priority != priority)
			{
				temp = n->parent;
				temp1 = n;
				n = calloc (1, sizeof (struct queue));
				n->number = number;
				n->priority = priority;
				n->parent = temp;
				n->child = temp1;
				return;
			}
		}
	}
}

static int get_number_from_queue ()
{
	if (!root) return -1;
	register struct queue *n = root;
	root = root->child;
	register unsigned long number = n->number;
	free (n);
	return number;
}

struct arr {
	int num;
	int priority;
} arr[] = {
	{ 0, 0 },
	{ 1, 1 },
	{ 2, 2 },
	{ 3, 3 },
	{ 4, 4 },
	{ 5, 5 },
	{ 14, 14 },
	{ 26, 26 },
	{ 5, 5 },
	{ 6, 6 },
	{ 7, 7 },
	{ 8, 8 },
	{ 9, 9 },
	{ 10, 10 }
};

int main (int argc, char **argv)
{
	int size = sizeof (arr) / sizeof (struct arr);
	for (int i = 0; i < size; i++)
	{
		add_number (arr[i].num, arr[i].priority);
	}

	for (int i = 0; i < size; i++)
	{
		printf ("%d: %d\n", i, get_number_from_queue());
	}
}
Источник: https://habr.com/ru/post/590499/


Интересные статьи

Интересные статьи

Решения для больших компаний обычно должны выдерживать высокие нагрузки. Когда в штате много десятков тысяч человек, и значительная доля из них ежедневно пользуются ...
Я давно знаком с Битрикс24, ещё дольше с 1С-Битрикс и, конечно же, неоднократно имел дела с интернет-магазинами которые работают на нём. Да, конечно это дорого, долго, местами неуклюже...
В этой статье мы рассмотрим, как система управления 1С-Битрикс справляется с большими нагрузками. Данный вопрос особенно актуален сегодня, когда электронная торговля начинает конкурировать по обороту ...
Если честно, к Д7 у меня несколько неоднозначное отношение. В некоторых местах я попискиваю от восторга, а в некоторых хочется топать ногами и ругаться неприличными словами.
Автокэширование в 1с-Битрикс — хорошо развитая и довольно сложная система, позволяющая в разы уменьшить число обращений к базе данных и ускорить выполнение страниц.