#c# #priority-queue #heapsort #binary-heap
#c# #приоритетная очередь #кучная сортировка #двоичный файл-куча
Вопрос:
Я пытаюсь написать свою собственную очередь приоритетов с минимальной сортировкой кучи, но я не получаю правильный вывод.
Мои входные данные — это 8 элементов с разными приоритетами:
[0] : 14
[1] : 5
[2] : 10
[3] : 9
[4] : 6
[5] : 3
[6] : 1
[7] : 2
Очевидно, что выходные данные должны отображать эти приоритеты в порядке (от наименьшего к наибольшему), но получается так:
[0] => Priority 1
[1] => Priority 14
[2] => Priority 5
[3] => Priority 10
[4] => Priority 9
[5] => Priority 6
[6] => Priority 3
[7] => Priority 2
По крайней мере, первый элемент правильный, но после этого все неверно.
Вот как я добавляю свои данные:
public void Add(T item)
{
_data.Add(item); // add to end of list
SortUp(); // bubble the element up the heap
}
private void SortUp()
{
// the last element we just added
int itemIndex = _data.Count - 1;
while (true)
{
int parentIndex = (itemIndex - 1) / 2;
//the lower the priority number, the higher the priority
if (_data[itemIndex].Priority < _data[parentIndex].Priority)
{
//swap with parent
T temp = _data[parentIndex];
_data[parentIndex] = _data[itemIndex];
_data[itemIndex] = temp;
// update item index to parent index for next loop
itemIndex = parentIndex;
}
else
{
break;
}
}
}
Затем я пытаюсь удалить элементы из очереди, и именно здесь порядок получается неправильным в зависимости от приоритетов:
public T Pop()
{
item = _data[0];
//get the last element and set it to front of queue
int lastIndex = Count - 1;
_data[0] = _data[lastIndex];
_data.RemoveAt(lastIndex);
SortDown();
return item;
}
private void SortDown()
{
// item we are sorting is at front of the queue
int itemIndex = 0;
while (true)
{
int leftChildIndex = 2 * itemIndex 1;
int rightChildIndex = 2 * itemIndex 2;
// check if priority is higher than left child node
if (leftChildIndex < Count amp;amp; _data[itemIndex].Priority < _data[leftChildIndex].Priority)
{
int swapIndex;
// check if priority is also higher than right child node
if (rightChildIndex < Count amp;amp; _data[itemIndex].Priority <_data[rightChildIndex].Priority)
{
swapIndex = rightChildIndex;
}
else
{
swapIndex = leftChildIndex;
}
//swap with child swapIndex
T temp = _data[swapIndex];
_data[swapIndex] = _data[itemIndex];
_data[itemIndex] = temp;
//update itemIndex to swapIndex for next loop
itemIndex = swapIndex;
}
else
{
break;
}
}
}
Кто-нибудь знает, где моя логика отключена, кажется, я не вижу, что я сделал не так.
Комментарии:
1. Вы должны сравнить левый дочерний элемент и правый дочерний элемент и поменять местами с элементом, который имеет меньшую приоритетность, когда вы удаляете элемент из очереди. Я думаю, что ваш код просто выбирает правый дочерний элемент без сравнения с левым дочерним элементом.
2. Я не уверен, что следую, сначала проверяется левый дочерний элемент, а затем проверяется правый дочерний элемент и выбирается левый дочерний элемент, если у правого дочернего элемента нет более низкого приоритета…. если я вас не неправильно понял.
3. Если оба дочерних элемента допустимы для замены, ваш код всегда будет выбирать правильный дочерний элемент, потому что правый дочерний элемент будет проверен после левого дочернего элемента. Таким образом, операция deque может протекать неправильно. Например, если вы переставляете очередь типа [ * 9 2 5 ] с более низким приоритетом, ваш код выберет 5 для замены на 9 вместо 2.
4. В конце концов, у меня получилось 🙂 Спасибо
Ответ №1:
public T Deque()
{
T retval = _data[0];
_data[0] = _data[Count - 1];
_data.RemoveAt(Count - 1);
int cnt = 0;
while(cnt < Count - 1)
{
int lcmp = 0, rcmp = 0;
if(cnt * 2 1 < Count)
{
lcmp = _data[cnt].CompareTo(_data[cnt * 2 1]);
}
if(cnt * 2 2 < Count)
{
rcmp = _data[cnt].CompareTo(_data[cnt * 2 2]);
}
int target = -1;
if(lcmp == -1 amp;amp; rcmp == -1)
{
if(_data[cnt * 2 1].CompareTo(_data[cnt * 2 2]) != -1)
{
target = cnt * 2 1;
}
else
{
target = cnt * 2 2;
}
}
else if(lcmp == -1)
{
target = cnt * 2 1;
}
else if(rcmp == -1)
{
target = cnt * 2 2;
}
else
{
break;
}
T temp = _data[cnt];
_data[cnt] = _data[target];
_data[target] = temp;
cnt = target;
}
return retval;
}
Получите результат сравнения обоих дочерних элементов, и если обе стороны допустимы для замены, выберите элемент с более низким приоритетом.
Комментарии:
1. Хм, ваш код немного сложен для понимания по сравнению с моим собственным..