更改自定义优先级队列中的优先级

时间:2012-02-10 18:07:41

标签: c# .net algorithm data-structures

我按照this question(Jason的回答)中的说明,使用PriorityQueue<T>来编写SortedList。我知道这个类中的count字段用于确保唯一的优先级,并在相同的优先级中保留入队顺序。

但是,当count达到其最大值并且我将其加1时,后者将从0开始,因此后续项的优先级将高于先前项的优先级。使用这种方法我可能需要一种“安全”重置计数器count的方法......实际上,假设有以下队列状态(格式为 priority | count | item ):

0 | 123 |一个
 0 | 345 |乙
 1 | 234 | ç
 2 | 200 | D

现在假设计数器限制已达到,所以我必须将其重置为0:因此,下一个插入的项目将具有计数器0:例如,如果我插入优先级等于1的元素,它将是在 1 |之前错误插入234 | d

0 | 123 |一个
 0 | 345 |乙
  1 | 000 |新元素
 1 | 234 | ç
 2 | 200 | D

优先级问题可以通过实现堆来解决:我创建了一个Heap类,然后我使用了Heap<KeyValuePair<TPriority, TElement>和一个自定义PriorityComparer,以便按{{{{}}对元素进行排序1}}。 将TPriority定义为TPriority,将TElement定义为intstring如下:

PriorityComparer

更新 通过这种方式(使用public class MyComparer : IComparer<KeyValuePair<int, string>> { public int Compare(KeyValuePair<int, string> x, KeyValuePair<int, string> y) { return x.Key.CompareTo(y.Key); } } ... int capacity = 10; Heap<KeyValuePair<int, string>> queue; queue = new Heap<KeyValuePair<int, string>>(capacity, new PriorityComparer()); ... ),我成功实现了优先级队列。 现在我想添加支持以在运行时修改其行为,即从 FIFO 切换到优先级排序,反之亦然。由于我的优先级队列实现具有PriorityComparer字段,我认为添加IComparer属性来编辑此字段就足够了,如下所示:

Comparer

与此同时,我认为我采取了不同的方法:不是使用二进制堆来管理优先级,而是可以包装不同的队列(每个队列引用给定的优先级),如下所示。

public IComparer
{
    set
    {
        this._comparer = value;
    }
}
  1. 当默认队列中还有元素时,如何管理从 FIFO模式优先模式的转换?我可以根据项目优先级将它们复制到优先级队列中...其他更好的解决方案?
  2. 如何管理从优先模式 FIFO模式的转换?在这种情况下,我会有几个优先级队列,可能包含元素,但不再需要根据优先级管理它们,甚至不知道原始的到达顺序......
  3. 如何管理不同队列的容量?
  4. 上述两种解决方案的表现如何?哪个会占用更多内存?

3 个答案:

答案 0 :(得分:1)

编辑:您对编辑的要求有所改变。你从提出一个问题到做一个新方法并提出一个新问题。应该为你的新方法开一个新问题,因为这个问题现在让人对于什么问题/评论的答案/回答感到困惑。我相信你原来关于排序相同优先级的问题已得到解答。

您可以使用long来允许更多值。您将始终最终达到目的,因此您需要使用新模式来获取唯一值,或者在达到最大值时“重新计算”项目(循环遍历每个模式并重置唯一计数值)。

也许为每个项目使用GUID?

Guid.NewGuid()

编辑:

要在编辑后添加:如果要将新1放在现有值之后,在比较覆盖中,当值相等时返回大于结果(1)。这样会发生以下情况:

1 > 0, return greater (1), continue
1 > 0, return greater (1), continue
1 == 1, return greater (1), continue
1 < 2, return less than (-1), insert

编辑2:

如果第二个参数仅用于唯一值,则可以始终使用字符串并将值设置为数字字符串。这样你永远不会达到上限,只需相应地解析字符串。您可以使用代表新集的前导Alpha值。

我没有测试过这段代码,只是想知道你能做些什么。

static string leadingStr = "";
static char currentChar = 'a';
static Int32 currentId = Int32.MinValue;

static string getNextId()
{
    if (currentId >= Int32.MaxValue)
    {
        currentId = Int32.MinValue;
        if (currentChar >= 'z')
        {
            currentChar = 'a';
            leadingStr = leadingStr.Insert(0, "X");
        }
        else
            currentChar++;
    }
    else
        currentId++;

    return String.Format("{0}{1}-{2}", leadingStr, currentChar, currentId);
}

编辑3:重置值

static Int64 currentValue = Int64.MinValue;
static void AddItem(object item)
{
    if (currentValue == Int64.MaxValue)
        RecountItems();

    item.counter = currentValue++;
    SortedList.Add(item);
}

static void RecountItems()
{
    currentValue = 0;
    foreach (var item in SortedList)
    {
        item.counter = currentValue++;
    }
}

编辑4:关于第二个问题:

您可以像往常一样使用FIFO堆栈,但也有一个优先级List,它只存储项目的唯一ID。但是,每次从FIFO堆栈中删除时,您都需要从列表中删除该项目。

static Object RemoveNextFIFO()
{
    if (fifoList.Count > 0)
    {
        var removedItem = fifoList[0];
        fifoList.RemoveAt(0);
        RemoveItemFromPriority(removedItem);
        return removedItem;
    }
}

static void RemoveItemFromPriority(Object itemToRemove)
{
    foreach (var counter in priorityQueue)
    {
        if (counter == itemToRemove.counter)
        {
            priorityQueue.remove(item);
            break;
        }
    }
}

static Object RemoveFromFIFO(int itemCounter)
{
    foreach (var item in fifoList)
    {
        if (item.counter == itemCounter)
        {
            fifoList.Remove(item);
            return item;   
        }
    }
}

static Object RemoveNextPriority()
{
    if (priorityQueue.Count > 0)
    {
        var counter = priorityQueue.Pop();
        return RemoveFromFIFO(counter);
    }
}

答案 1 :(得分:1)

你可以“欺骗”并使用BigInteger,这样你就不会“用完数字”。这当然导致性能逐渐恶化,但可能不够重要。

将其与基于heap的优先级队列相结合,即可设置!


不要试图“从FIFO切换到优先级排序,反之亦然” - 只需将元素放在适合任务(Queue和优先级队列)的两个数据结构中。

答案 2 :(得分:1)

我同时使用QueuePriority Queue 但如果你必须......

而不是一个键使用2个键作为元素 第一个键priority将成为优先事项 第二个键time将是一个类似于时间戳的计数器。

对于常规行为,请使用priority键。

当堆已满时,HEAPIFYtime键 然后删除所需的n元素 现在HEAPIFY再次使用priority键返回常规行为。