尝试为最近邻搜索实现优先级队列

时间:2015-05-28 03:53:32

标签: c# generics tree tuples nearest-neighbor

所以给出一些背景知识:

  • 我正在尝试使用最近邻搜索来实现k-d树。
  • 要实现NN搜索,我需要创建一个优先级队列。
  • 优先级队列必须有点坐标和距离。
  • 所以我决定把这两个组合成一个元组。

结果证明C#与我以前使用的其他语言略有不同。

这是我执行此操作时收到的错误消息:

PriorityQueue<Tuple<Point, double>> pq = new PriorityQueue<Tuple<Point, double>>();
  

错误CS0311:类型System.Tuple<Tree.Point,double>' cannot be used as type parameter T&#39;在泛型类型或方法中   PriorityQueue.PriorityQueue<T>'. There is no implicit reference conversion from System.Tuple&#39;至   `System.IComparable&GT;&#39;

我研究了很长一段时间,因为我是C#的新手,我不太明白为什么会这样。我想用Python编程可以让生活变得轻松。

我的优先级队列类如下所示:

public class PriorityQueue<T> where T : IComparable<T>
{
    private List<T> dataHeap;

    public PriorityQueue()
    {
        this.dataHeap = new List<T>();
    }

    public void Enqueue(T value)
    {
        this.dataHeap.Add(value);
        BubbleUp();
    }

    public T Dequeue()
    {
        if (this.dataHeap.Count <= 0)
        {
            throw new InvalidOperationException("Cannot Dequeue from empty queue!");
        }

        T result = dataHeap[0];
        int count = this.dataHeap.Count - 1;
        dataHeap[0] = dataHeap[count];
        dataHeap.RemoveAt(count);
        ShiftDown();

        return result;
    }

    private void BubbleUp()
    {
        int childIndex = dataHeap.Count - 1;

        while (childIndex > 0)
        {
            int parentIndex = (childIndex - 1) / 2;

            if (dataHeap[childIndex].CompareTo(dataHeap[parentIndex]) >= 0)
            {
                break;
            }

            SwapAt(childIndex, parentIndex);
            childIndex = parentIndex;
        }
    }

    private void ShiftDown()
    {
        int count = this.dataHeap.Count - 1;
        int parentIndex = 0;

        while (true)
        {
            int childIndex = parentIndex * 2 + 1;
            if (childIndex > count)
            {
                break;
            }

            int rightChild = childIndex + 1;
            if (rightChild <= count && dataHeap[rightChild].CompareTo(dataHeap[childIndex]) < 0)
            {
                childIndex = rightChild;
            }
            if (dataHeap[parentIndex].CompareTo(dataHeap[childIndex]) <= 0)
            {
                break;
            }

            SwapAt(parentIndex, childIndex);
            parentIndex = childIndex;
        }
    }

    public T Peek()
    {
        if (this.dataHeap.Count == 0)
        {
            throw new InvalidOperationException("Queue is empty.");
        }

        T frontItem = dataHeap[0];
        return frontItem;
    }

    public int Count()
    {
        return dataHeap.Count;
    }

    /// <summary>Removes all elements from the queue.</summary>
    public void Clear()
    {
        this.dataHeap.Clear();
    }

    public void CopyToArray(T[] array, int index)
    {
        if (array == null)
        {
            throw new ArgumentNullException("Array");
        }

        int length = array.Length;
        if (index < 0 || index >= length)
        {
            throw new IndexOutOfRangeException("Index must be between zero and array length.");
        }
        if (length - index < this.dataHeap.Count-1)
        {
            throw new ArgumentException("Queue is bigger than array");
        }

        T[] data = this.dataHeap.ToArray();
        Array.Copy(data, 0, array, index, data.Length);
    }

    public bool IsConsistent()
    {
        if (dataHeap.Count == 0)
        {
            return true;
        }

        int lastIndex = dataHeap.Count - 1; 
        for (int parentIndex = 0; parentIndex < dataHeap.Count; ++parentIndex) 
        {
            int leftChildIndex = 2 * parentIndex + 1; 
            int rightChildIndex = 2 * parentIndex + 2;

            if (leftChildIndex <= lastIndex && dataHeap[parentIndex].CompareTo(dataHeap[leftChildIndex]) > 0)
            {
                return false;
            }
            if (rightChildIndex <= lastIndex && dataHeap[parentIndex].CompareTo(dataHeap[rightChildIndex]) > 0)
            {
                return false;
            }
        }

        return true;
    }

    private void SwapAt(int first,int second)
    {
        T value = dataHeap[first];
        dataHeap[first] = dataHeap[second];
        dataHeap[second] = value;
    }

    public override string ToString()
    {
        string queueString = string.Join(" ", dataHeap.ToArray());
        return queueString;
    }
}

My Point课程:

class Point : IComparable
{
    private double x;
    private double y;

    public Point(double xCoord, double yCoord)
    {
        SetPoint(xCoord, yCoord);
    }

    ~Point() {}

    public int CompareTo(object obj) 
    {
        if (obj == null) return 1;

        Point p = obj as Point;
        if (p != null) 
            return (this.x.CompareTo(p.x) & this.y.CompareTo(p.y));
        else 
           throw new ArgumentException("Object is not a Point");
    }

    public static bool operator ==(Point a, Point b)
    {
        if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) return true;
        if (a[0] == b[0] && a[1] == b[1]) return true;
        else return false;
    }

    public static bool operator !=(Point a, Point b)
    {
        if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) return true;
        if (a[0] != b[0] || a[1] != b[1]) return true;
        else return false;
    }

    public double this[int index]
    {
        get
        {
            if (index == 0) return x;
            else if (index == 1) return y;
            else throw new System.IndexOutOfRangeException("index " + index + " is out of range");
        }
        set
        {
            if (index == 0) x = value;
            else if (index == 1) y = value;
            else throw new System.IndexOutOfRangeException("index " + index + " is out of range");
        }

    }

    public void SetPoint(double xCoord, double yCoord)
    {
        x = xCoord;
        y = yCoord;
    }

    public override string ToString()
    {
        return "(" + x + ", " + y + ")";
    }
}

1 个答案:

答案 0 :(得分:1)

我建议您删除T上的约束,然后在IComparer<T>的构造函数中使用明确的PriorityQueue。如果没有提供,则现有构造函数可以提供Comparer<T>.Default作为比较器。

然后,您需要在obj.CompareTo(other)中将comp.Compare(obj, other)更改为PriorityQueue

public class PriorityQueue<T>
{
    private List<T> dataHeap;
    private readonly IComparer<T> comp;

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

    public PriorityQueue(IComparer<T> comp)
    {
        this.dataHeap = new List<T>();
        this.comp = comp;
    }
    ...
    private void BubbleUp() {
        if (this.comp.Compare(dataHeap[childIndex], dataHeap[parentIndex]) >= 0)
   }
}