2016-07-30 38 views
1

我是C#中的新成員。我試圖創建一個堆結構,並提出了這個問題:如何將「比較類」傳遞給我的堆結構?我的意思是,我想創建一個如下所示的堆:Heap<int, cmp<int>> heap = new Heap<int, cmp<int>>();其中「cmp」是一個按照優先級順序堆棧的比較類(我使用C++中的priority_queue)。我有成功的(我認爲)在作出堆,需要一個最大最小比較器:C#傳遞一個比較類作爲通用類型

public class Heap<T, Priority> 
    where Priority : IPriority<T>, new() 
    where T : IComparable 
{ 
    private List<T> storage = new List<T>();   
    private Priority HeapPriority = new Priority(); 
    private void UpHeap(int position) 
    {    
     for(var i = position; i > 0; i = (i - 1) >> 1) 
     { 
      // Check whether storage[i] is more Priority than storage[(i - 1) >> 1] 
      if (HeapPriority.MorePriority(storage[i], storage[(i - 1) >> 1]) 
       .CompareTo(storage[i]) == 0) 
      { 
       storage.Swap(i, (i - 1) >> 1); 
      } 
      else break; 
     } 
    } 
} 

這裏是IPriority接口:

public interface IPriority<T> 
    where T : IComparable 
{ 
    T MorePriority(T a, T b); 
} 

,我用堆是這樣的:

public class Min<T> : IPriority<T> 
     where T : IComparable 
    { 
     public Min() { } 
     public T MorePriority(T a, T b) 
     { 
      return a.CompareTo(b) <= 0 ? a : b; 
     } 
    } 
static public void TestHeap() 
    { 
     var heap = new Heap<Pair<long, int>, Min<Pair<long, int>>>();    
     heap.Add(Pair<long, int>(10, 20)); 
     heap.Add(Pair<long, int>(21, 100)); 
     // ... 
    } 

但我想要一個堆,通過任何我想要的方式排序項目,不僅是最大最小訂單。此外,有沒有辦法使用「Ipriority.MorePriority」作爲靜態方法?,因爲它的工作方式與靜態方法一樣。任何人都可以給我一些建議嗎? 對不起,我的英語不好。

+1

顯而易見的答案是使用'IComparer '。你爲什麼不呢?有許多可能的方法來解決這個問題。請嘗試_something_。如果你之後有一個具體的問題,用一個好的[mcve]發表一個新問題,清楚地表明你正在遇到的具體問題。 –

+0

謝謝。我會記住這一點。這是我的第一個問題,所以我很抱歉提出一些愚蠢的問題 –

+0

沒有問題是愚蠢的。這裏的問題是,沒有任何跡象表明您花時間研究可能的答案,不必介意在嘗試實施任何解決方案時遇到的具體問題。如果你錯過了顯而易見的事實並且事實上就是答案,那很好,但即使有人錯過了明顯的答案,也可能會嘗試_something_。 –

回答

2

我建議將IComparer<T>視爲依賴並將其傳遞給構造函數;是這樣的:

// You can create a heap of any type, right? 
    // But in some cases (e.g. Heap<Button>) you should provide a comparer: 
    // how to compare Button instances 
    public class Heap<T> { 
    //TODO: implement here Heap as well as Unheap method having IComparer<T> m_Comparer 
    ... 
    private IComparer<T> m_Comparer; 

    // comparer = null - if comparer is not provided, try to use default one 
    // if it's possible (e.g. in case of Heap<double>) 
    public Heap(IComparer<T> comparer = null): base() { 
     // Do we have a default comparer (e.g. for int, double, string)? 
     if (null == comparer) 
     if (typeof(IComparable).IsAssignableFrom(typeof(T)) || 
      typeof(IComparable<T>).IsAssignableFrom(typeof(T))) 
      comparer = Comparer<T>.Default; 

     if (null == comparer) 
     throw new ArgumentNullException("comparer", string.Format(
      "There's no default comparer for {0} class, you should provide it explicitly.", 
      typeof(T).Name)); 

     m_Comparer = comparer; 
    } 
    ... 
    } 

所以,你可以創建堆

// heap of integers, default comparer 
    Heap<int> heap1 = new Heap<int>(); 

    // heap of integers, custom comparer (via lambda) 
    Heap<int> heap2 = new Heap<int>(Comparer<int>.Create((x, y) => -x.CompareTo(y))); 

    // heap of Buttons, custome comparer 
    Heap<Button> heap3 = new Heap<Button>(Comparer<Button>.Create((x, y) => ...)); 

,這將拋出異常:爲Button類沒有默認的比較

Heap<Button> heapErr = new Heap<Button>(); 
+0

感謝您的幫助。但是,我應該拋出還是不拋出異常?我的意思是,我可以將T約束爲IComparable,所以如果「T」沒有默認比較器,我將能夠在編譯時檢測問題,而不是運行時。如果我錯了,請糾正我。 –

+0

@AnhHaoTrần:我懷疑你是否應該*限制*:即使'T'沒有默認的*比較器,創建'Heap '似乎是合理的,但是提供一個*自定義比較器*。請查看'List .Sort':可以嘗試使用默認比較器;你可以提供一個自定義的約束。 –

+0

啊,我明白了。非常感謝。 –

0

你應該只使用IComparer<T>,這就是.NET中所有的集合所使用的。例如:

public class Heap<T> 
{ 
    private IComparer<T> comparer; 
    private List<T> storage = new List<T>();  

    public Heap() : this(Comparer<T>.Default) 
    { 
    } 

    public Heap(IComparer<T> comparer) 
    { 
     this.comparer = comparer; 
    } 

    private void UpHeap(int position) 
    {    
     for(var i = position; i > 0; i = (i - 1) >> 1) 
     { 
      // Check whether storage[i] is more Priority than storage[(i - 1) >> 1] 
      if (comparer.Compare(storage[i], storage[(i - 1) >> 1]) > 0) 
      { 
       storage.Swap(i, (i - 1) >> 1); 
      } 
      else break; 
     } 
    } 
} 

這有幾個優點:

  • 你不需要的比較器,引用其他方法堆時,這是方便多了額外的類型參數。
  • 沒有必要將T限制爲IComparable
  • 但是,如果確實執行ICompatable(如Int32那樣),則Comparer<T>.Default將使用該實現。
+0

謝謝。您的解決方案也適用於我。 –