我按照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定义为int
,string
如下:
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;
}
}
答案 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)
我同时使用Queue
和Priority Queue
但如果你必须......
而不是一个键使用2个键作为元素
第一个键priority
将成为优先事项
第二个键time
将是一个类似于时间戳的计数器。
对于常规行为,请使用priority
键。
当堆已满时,HEAPIFY
按time
键
然后删除所需的n
元素
现在HEAPIFY
再次使用priority
键返回常规行为。