2011-08-29 187 views
6

我一直在寻找一种像年龄记录列表一样工作的数据结构。如果没有一个年轻人有更高的分数,那么你就有一个年龄记录。因此,我想要一个对(a,b)的列表,其中对于所有对(a1,b1)和(a2,b2)中的所有对(在蕴涵之后)成立a1> a2 => b1> b2。“年龄记录”数据结构

如果不存在一对(a_k,b_k)使得a_k不是a_new而是b_k> b_new,则应该存在插入(a_new,b_new)的插入方法插入(a_new,b_new)。如果满足该条件,则插入新对,并从列表中删除所有a_k> a_new,但删除b_k。

数据结构不需要支持删除。

+0

我的第一个想法是保持排序的数据结构(可能是堆)为夫妇的第一个元素和一个并联一个第二元素,一旦你在第一数据结构中插入一个元素你应该能够将第二个元素插入相应的位置(堆的位置相同,树的路径相同),否则就意味着必须丢弃该元素。 – Teudimundo

+0

你需要什么样的表现?我注意到渐近地插入方法将是O(n),因为它可能需要删除集合中的所有其他数据。如果插入总是线性的,O(n)是可以的吗?如果是这样,我只是使用链表。如果不是,我们可能需要某种树结构,我们会写更多的代码! – PaulF

回答

3

以下是我认为能为您完成这项工作的通用解决方案。它没有针对性能进行优化,也没有特别好的测试

public class AgePair<T, Y> 
    where T : IComparable<T> 
    where Y : IComparable<Y> 
{ 
    public T A { get; set; } 

    public Y B { get; set; } 
} 

public class AgeRecordList<T, Y> : IEnumerable<AgePair<T,Y>> 
    where T : IComparable<T> 
    where Y : IComparable<Y> 
{ 
    private List<AgePair<T, Y>> m_List = new List<AgePair<T, Y>>(); 

    public void Add(T a, Y b) 
    { 
     AgePair<T, Y> newPair = new AgePair<T, Y> { A = a, B = b }; 

     // Get all elements that are younger 
     var younger = GetYounger(newPair.A); 

     // Find any of the younger with a higher score 
     // If found, return without inserting the element 
     foreach (var v in younger) 
     { 
      if (v.B.CompareTo(newPair.B) >= 0) 
      { 
       return; 
      } 
     } 

     // Cache elements to delete 
     List<AgePair<T, Y>> toDelete = new List<AgePair<T, Y>>(); 

     // Find all the elder elements  
     var elder = GetElder(newPair.A); 

     // Find all elder elements with a lower B 
     foreach (var v in elder) 
     { 
      if (v.B.CompareTo(newPair.B) <= 0) 
      { 
       // Mark for delete 
       toDelete.Add(v); 
      } 
     } 

     // Delete those elements found above 
     foreach (var v in toDelete) 
     { 
      m_List.Remove(v); 
     } 

     // Add the new element 
     m_List.Add(newPair); 

     // Sort the list (ascending by A) 
     m_List.Sort(CompareA); 
    } 

    private List<AgePair<T, Y>> GetElder(T t) 
    { 
     List<AgePair<T, Y>> result = new List<AgePair<T, Y>>(); 

     foreach (var current in m_List) 
     { 
      if (t.CompareTo(current.A) <= 0) 
      { 
       result.Add(current); 
      } 
     } 

     return result; 
    } 

    private List<AgePair<T, Y>> GetYounger(T t) 
    { 
     List<AgePair<T, Y>> result = new List<AgePair<T, Y>>(); 

     foreach (var current in m_List) 
     { 
      if (t.CompareTo(current.A) > 0) 
      { 
       result.Add(current); 
      } 
     } 

     return result; 
    } 

    private static int CompareA(AgePair<T,Y> item1, AgePair<T,Y> item2) 
    { 
     return item1.A.CompareTo(item2.A); 
    } 


    public IEnumerator<AgePair<T, Y>> GetEnumerator() 
    { 
     return m_List.GetEnumerator(); 
    } 

} 

编辑1:算法的高级概述

  1. 找到所有年轻或等于元素,
  2. 对于所有年轻的或相同的元件,看是否有一个以上B
  3. 如果(2)返回
  4. 查找所有老年人元素
  5. 如果任何老年人元素得分较低,请删除
  6. 排序列表按升序(按A)

编辑2:速度可以很容易地通过增加),一旦你找到了年轻的元素,你可以从该点寻找老人元素,而不是在继续b)不用使用List的排序方法对它排序,而是使用InsertAt(0或第一个长辈的索引)

+2

您可以提供关于代码如何工作的高级描述,或者至少在代码中描述它的注释?现在这个答案并不是特别有用,因为它没有阐明你是如何处理这个问题的,或者你用什么方法来解决这个问题。 – templatetypedef

+0

的psudocode是这样的: 1.找到所有年轻或等于元素 2.对所有年轻的或等于元素,看看是否有任何一个以上B 3.如果(2)返回 4.找到所有长辈元素 5.如果有任何老人元素的分数较低,请从列表中移除 – havardhu

+0

这似乎是一个非常好的起点;我只想到两个可能的改进: 在检查是否应该添加新元素时,只需检查最旧的年轻元素是否具有更高的分数(因为列表已经是年龄记录列表)。 类似地,如果要插入元素,我们只需要检查较低分数的旧元素。 如果列表保持排序(注意如果在年龄后排序,它也将在分数后排序)我认为可以改进。但我会稍后回来 –

0

这个AgeList跟踪每个年龄的最佳记录,然后忽略当被问及获胜者时,他们没有年龄记录。

虽然并非所有的输家在插入时都被删除(不确定这是否是一个强大的要求),但它应该通过懒惰来节省时间。 OrderBy的最大弱点是呼叫。如果在空间可用的情况下这种排序过于昂贵,可能会弹出一个SortedList来保存所有插入的a。

如果在时间可用的情况下空间有限,那么编写类似于GetWinners方法的清理方法很简单。甚至可以在InsertMethod中调用以在每次插入后清理。

public class AgeList<T, U> where T:IComparable<T> where U:IComparable<U> 
{ 
    Dictionary<T, U> store = new Dictionary<T, U>(); 

    public void Insert(T a, U b) 
    { 
     if (!store.ContainsKey(a) || store[a].CompareTo(b) < 0) 
     { 
      store[a] = b; 
     } 
     //else discard by doing nothing 
    } 

    public IEnumerable<KeyValuePair<T, U>> GetWinners() 
    { 
     bool first = true; 
     U record = default(U); 
     foreach(T key in store.Keys.OrderBy(t => t)) 
     { 
      U newValue = store[key]; 
      if (first) 
      { 
       first = false; 
       record = newValue; 
       yield return new KeyValuePair<T, U>(key, record); 
      } 
      else if (record.CompareTo(newValue) < 0) 
      { 
       record = newValue; 
       yield return new KeyValuePair<T, U>(key, record); 
      } 
     } 
    } 
}