2016-07-30 2 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_ 해봐. 그 뒤에 _specific_ 질문이있는 경우 귀하가 가지고있는 특정 문제를 명확하게 보여주는 좋은 [mcve]와 함께 새로운 질문을 게시하십시오. –

+0

감사합니다. 나는 그것을 염두에 두겠다. 이것은 나의 첫 질문이므로 바보 같은 질문을해서 미안하다 –

+0

어리석은 질문은 없다. 여기에있는 문제는 가능한 해결책을 연구하는 데 시간을 할애하지 않았으며 어떤 솔루션을 구현하려고 할 때 어떤 특정 문제가 발생했는지 결코 염두에 두지 않는 것입니다. 당신이 명백한 것을 놓친다면 그것은 괜찮습니다. 실제로 그것은 답입니다. 그러나 분명한 대답을 놓친 사람조차도 아마도 _ 무언가를 시도 할 것입니다. 도움을 주신 덕분에 –

답변

2

IComparer<T>의존성으로 처리하여 생성자에게 전달하는 것이 좋습니다. 이 같은 : Button 클래스에 대한 기본 비교가

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

. 하지만 예외를 던지거나 던지면 안 될까요? 내 말은, T를 IComparable로 제한 할 수 있기 때문에 "T"에 기본 비교 자이 없으면 런타임이 아닌 컴파일 타임에 문제를 감지 할 수 있습니다. 내가 틀렸다면 나를 바로 잡아라. –

+0

@AnhHao Trần : 만약 * T가 * default * comparer을 가지지 않는다고해도 * Heap 을 생성하지만 * custom comparer *을 제공하는 것이 합리적이라고 생각합니다. 'List .Sort'를보십시오 : 가능한 경우 기본 비교자를 사용해보십시오. 당신은 관례를 제공 할 수 있으며 제약은 없습니다. –

+0

아, 알겠습니다. 정말 고맙습니다. –

0

당신은 단지 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) => ...)); 

그리고이 것 던져 예외를 만들 수 있습니다 .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; 
     } 
    } 
} 

이 몇 가지 장점이 있습니다 :

  • 당신은 다른 방법에 힙을 참조 할 때 훨씬 더 편리한 비교 자에 대한 별도의 형식 매개 변수가 필요하지 않습니다.
  • TIComparable으로 제한 할 필요가 없습니다.
  • 그러나 (Int32처럼) ICompatable을 구현하면 Comparer<T>.Default이 해당 구현을 사용합니다.
+0

감사합니다. 당신의 솔루션도 나를 위해 일합니다. –

관련 문제