我的代码现在有O(N)插入时间和O(1)删除时间。我需要改变这个。 我正在尝试实现O(1)插入时间和O(N)删除时间。
图例:
nItems =项目/对象的数量。最初设置为0。
queArray 是我的长整数数组。
这是我的两种方法。插入方法完成所有排序工作。删除方法只需一行 - 由于我们的Insert方法,删除数组中第一个恰好是最小数字的元素。
如果我要将插入时间更改为O(1),我是否需要提供“排序任务”来删除方法?毕竟它是一个优先级队列,我们必须对它进行排序,否则它只是一个随机顺序排列的常规队列。
请,任何帮助都会很好!!!
public void insert(long item) {
int j;
if(nItems==0) // if no items,
queArray[nItems++] = item; // insert at 0
else {
for(j=nItems-1; j>=0; j--) { // start at the end
if( item > queArray[j] ) // if new item larger,
queArray[j+1] = queArray[j]; // shift upward
else // if smaller,
break; // done shifting
} // end for
queArray[j+1] = item; // insert it
nItems++;
} // end else (nItems > 0)
}
public long remove() // remove minimum item
{ return queArray[--nItems]; }
答案 0 :(得分:5)
如果您想要O(1)插入时间和O(N)移除时间,只需将未分类的新元素添加到内部数组的末尾,然后通过列表进行O(N)线性搜索以进行移除,移动阵列的其余部分下来一个。
或者为了更好的实施,您可能需要考虑Fibonacci heap。
答案 1 :(得分:3)
我不确定您是否可以为基于阵列的优先级队列实现O(1)
插入时间。您可以使用最小/最大堆结构获得O(log n)
。
这是在内部使用List<>
的实现(但可以很容易地交换到数组实现。
using System;
using System.Collections;
using System.Collections.Generic;
namespace HeapADT
{
public class Heap<T> : ICollection, IEnumerable<T>
where T : IComparable<T>
{
#region Private Members
private readonly List<T> m_Items;
private readonly IComparer<T> m_Comparer;
#endregion
#region Constructors
public Heap()
: this(0)
{}
public Heap( int capacity )
: this( capacity, null )
{}
public Heap( IEnumerable<T> items )
: this( items, null )
{}
public Heap( int capacity, IComparer<T> comparer )
{
m_Items = new List<T>(capacity);
m_Comparer = comparer ?? Comparer<T>.Default;
}
public Heap( IEnumerable<T> items, IComparer<T> comparer )
{
m_Items = new List<T>(items);
m_Comparer = comparer ?? Comparer<T>.Default;
BuildHeap();
}
#endregion
#region Operations
public void Add( T item )
{
m_Items.Add( item );
var itemIndex = Count - 1;
while( itemIndex > 0 )
{
var parentIndex = ParentIndex(itemIndex);
// are we a heap? If yes, then we're done...
if( m_Comparer.Compare( this[parentIndex], this[itemIndex] ) < 0 )
return;
// otherwise, sift the item up the heap by swapping with parent
Swap( itemIndex, parentIndex );
itemIndex = parentIndex;
}
}
public T RemoveRoot()
{
if( Count == 0 )
throw new InvalidOperationException("Cannot remove the root of an empty heap.");
var rootItem = this[0];
ReplaceRoot(RemoveLast());
return rootItem;
}
public T RemoveLast()
{
if( Count == 0 )
throw new InvalidOperationException("Cannot remove the tail from an empty heap.");
var leafItem = this[Count - 1];
m_Items.RemoveAt( Count-1 );
return leafItem;
}
public void ReplaceRoot( T newRoot )
{
if (Count == 0)
return; // cannot replace a nonexistent root
m_Items[0] = newRoot;
Heapify(0);
}
public T this[int index]
{
get { return m_Items[index]; }
private set { m_Items[index] = value; }
}
#endregion
#region Private Members
private void Heapify( int parentIndex )
{
var leastIndex = parentIndex;
var leftIndex = LeftIndex(parentIndex);
var rightIndex = RightIndex(parentIndex);
// do we have a right child?
if (rightIndex < Count)
leastIndex = m_Comparer.Compare(this[rightIndex], this[leastIndex]) < 0 ? rightIndex : leastIndex;
// do we have a left child?
if (leftIndex < Count)
leastIndex = m_Comparer.Compare(this[leftIndex], this[leastIndex]) < 0 ? leftIndex : leastIndex;
if (leastIndex != parentIndex)
{
Swap(leastIndex, parentIndex);
Heapify(leastIndex);
}
}
private void Swap( int firstIndex, int secondIndex )
{
T tempItem = this[secondIndex];
this[secondIndex] = this[firstIndex];
this[firstIndex] = tempItem;
}
private void BuildHeap()
{
for( var index = Count/2; index >= 0; index-- )
Heapify( index );
}
private static int ParentIndex( int childIndex )
{
return (childIndex - 1)/2;
}
private static int LeftIndex( int parentIndex )
{
return parentIndex*2 + 1;
}
private static int RightIndex(int parentIndex)
{
return parentIndex*2 + 2;
}
#endregion
#region ICollection Members
public void CopyTo(Array array, int index)
{
m_Items.CopyTo( (T[])array, index );
}
public int Count
{
get { return m_Items.Count; }
}
public bool IsSynchronized
{
get { return false; }
}
public object SyncRoot
{
get { return null; }
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return m_Items.GetEnumerator();
}
#endregion
}
}
答案 2 :(得分:2)
未排序的链表听起来符合规定的要求(尽管对于大多数实际应用来说它们看起来有些愚蠢)。你有不断的插入时间(坚持到最后或开始)和线性删除时间(扫描最小元素的列表)。
答案 3 :(得分:2)
为了将插入时间更改为O(1),您可以将元素插入到未排序的数组中。然后,您可以创建一个minPeek()方法,使用线性搜索搜索最小的键,然后在删除/删除方法中调用它并删除最小的键。
以下是如何实现这一目标。
public void insert(int item) {
queArray[nItems++] = item;
}
public int remove() {
int removeIndex = minPeek();
if (nItems - 1 != removeIndex) {
for (int i = removeIndex; i < nItems - 1; i++) {
queArray[i] = queArray[i + 1];
}
}
return queArray[--nItems];
}
public int minPeek() {
int min = 0;
for (int i = 0; i < maxSize; i++) {
if (queArray[i] < queArray[min]) {
min = i;
}
}
return min;
}
通过这样做,您的优先级队列具有O(1)插入时间,删除方法具有O(N)时间。
答案 4 :(得分:1)
无法实现O(1)插入方法并保持数组排序。如果您将排序传递给delete方法,那么您可以快速执行O(N log(n))快速排序或其他操作。 或者您可以在插入方法中执行O(log n)算法,如LBushkin建议。