我的自定义 BinaryHeap 的顺序并不总是正确的

发布于 2025-01-05 15:33:01 字数 4039 浏览 0 评论 0原文

我创建了一个 BinaryHeap 类。

public class BinaryHeap<T>
{
    private List<T> _heap;

    // Constructor
    public BinaryHeap(int capacity, IComparer<T> comparer)
    {
        this._heap = new List<T>(capacity);
        Comparer = comparer ?? Comparer<T>.Default;
    }

    // Constructor
    public BinaryHeap(int capacity) : this(capacity, (IComparer<T>)null) { }

    // Gets/sets IComparer
    public IComparer<T> Comparer { get; private set; }

    // Gets/sets the capacity
    public int Capacity
    {
        get { return this._heap.Capacity; }
        set { this._heap.Capacity = value; }
    }

    // Gets the number of elements
    public int Count
    {
        get { return this._heap.Count; }
    }

    // Inserts the specified element within this BinaryHeap.
    public void Insert(T element)
    {
        // Add the element as the last element.
        this._heap.Add(element);

        // Index of last added element.
        int last = this._heap.Count - 1;

        int parent;
        T swap;
        while (last > 0)
        {
            parent = (last - 1) >> 1;   // parent(i) = (i-1)/2

            if (Comparer.Compare(this._heap[parent], this._heap[last]) <= 0)
                break;   // exit while if the current node is lesser than its parent.

            swap = this._heap[last];                // If the parent is greater
            this._heap[last] = this._heap[parent];  // than the current node,
            this._heap[parent] = swap;              // then swap them.

            last = parent;   // Updates index of last added element.
        }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    public T Remove()
    {
        if (this._heap.Count > 0)
        {
            // Save the element.
            T result = this._heap[0];

            int lastIndex = this._heap.Count - 1;   // The last element moves
            this._heap[0] = this._heap[lastIndex];  // moves to the root
            this._heap.RemoveAt(lastIndex);         // of this tree.
            lastIndex--;   // Update position of last element.

            int i = 0;   // Position of moved node.
            while (i < lastIndex)
            {
                int minIndex = i;

                int left = (i << 1) + 1;   // left(i) = (i*2)+1
                if (left < lastIndex && Comparer.Compare(this._heap[left], this._heap[minIndex]) < 0)
                {
                    minIndex = left;
                }

                int right = left + 1;   // right(i) = (i*2)+2
                if (right < lastIndex && Comparer.Compare(this._heap[right], this._heap[minIndex]) < 0)
                {
                    minIndex = right;
                }

                if (minIndex != i)
                {
                    // If one of the two children is lesser than the parent,
                    // then swap the latter with the lesser child.
                    T temp = this._heap[i];
                    this._heap[i] = this._heap[minIndex];
                    this._heap[minIndex] = temp;
                    i = minIndex;
                }
                else break;
            }

            // Return the minimum element that has been removed.
            return result;
        }
        else throw new InvalidOperationException("BinaryHeap is empty.");
    }
}

在执行一些测试时,例如以下测试作为简单队列。

BinaryHeap<int> q = new BinaryHeap<int>(0);
int count = 50;
for (int i = 0; i < count; i++)
    q.Insert(i);
for (int i = 0; i < count; i++)
    Console.WriteLine(q.Remove());
Console.ReadLine();

返回的元素应该按升序排列,但倒数第三个元素和倒数第二个元素几乎总是顺序错误。例如,对于 count = 50,输出为:

// previous element are in correct order
44
45
46
48   // wrong order
47   // wrong order
49

测试多个 count 值,此问题并不总是发生。 为什么? 我该如何解决这个问题?

I created a BinaryHeap<T> class.

public class BinaryHeap<T>
{
    private List<T> _heap;

    // Constructor
    public BinaryHeap(int capacity, IComparer<T> comparer)
    {
        this._heap = new List<T>(capacity);
        Comparer = comparer ?? Comparer<T>.Default;
    }

    // Constructor
    public BinaryHeap(int capacity) : this(capacity, (IComparer<T>)null) { }

    // Gets/sets IComparer
    public IComparer<T> Comparer { get; private set; }

    // Gets/sets the capacity
    public int Capacity
    {
        get { return this._heap.Capacity; }
        set { this._heap.Capacity = value; }
    }

    // Gets the number of elements
    public int Count
    {
        get { return this._heap.Count; }
    }

    // Inserts the specified element within this BinaryHeap.
    public void Insert(T element)
    {
        // Add the element as the last element.
        this._heap.Add(element);

        // Index of last added element.
        int last = this._heap.Count - 1;

        int parent;
        T swap;
        while (last > 0)
        {
            parent = (last - 1) >> 1;   // parent(i) = (i-1)/2

            if (Comparer.Compare(this._heap[parent], this._heap[last]) <= 0)
                break;   // exit while if the current node is lesser than its parent.

            swap = this._heap[last];                // If the parent is greater
            this._heap[last] = this._heap[parent];  // than the current node,
            this._heap[parent] = swap;              // then swap them.

            last = parent;   // Updates index of last added element.
        }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    public T Remove()
    {
        if (this._heap.Count > 0)
        {
            // Save the element.
            T result = this._heap[0];

            int lastIndex = this._heap.Count - 1;   // The last element moves
            this._heap[0] = this._heap[lastIndex];  // moves to the root
            this._heap.RemoveAt(lastIndex);         // of this tree.
            lastIndex--;   // Update position of last element.

            int i = 0;   // Position of moved node.
            while (i < lastIndex)
            {
                int minIndex = i;

                int left = (i << 1) + 1;   // left(i) = (i*2)+1
                if (left < lastIndex && Comparer.Compare(this._heap[left], this._heap[minIndex]) < 0)
                {
                    minIndex = left;
                }

                int right = left + 1;   // right(i) = (i*2)+2
                if (right < lastIndex && Comparer.Compare(this._heap[right], this._heap[minIndex]) < 0)
                {
                    minIndex = right;
                }

                if (minIndex != i)
                {
                    // If one of the two children is lesser than the parent,
                    // then swap the latter with the lesser child.
                    T temp = this._heap[i];
                    this._heap[i] = this._heap[minIndex];
                    this._heap[minIndex] = temp;
                    i = minIndex;
                }
                else break;
            }

            // Return the minimum element that has been removed.
            return result;
        }
        else throw new InvalidOperationException("BinaryHeap is empty.");
    }
}

In performed some test, for example the following test as simple queue.

BinaryHeap<int> q = new BinaryHeap<int>(0);
int count = 50;
for (int i = 0; i < count; i++)
    q.Insert(i);
for (int i = 0; i < count; i++)
    Console.WriteLine(q.Remove());
Console.ReadLine();

The returned elements should be in ascending order, but the third-last element and the penultimate element are almost always in wrong order. For example, with count = 50, the output is:

// previous element are in correct order
44
45
46
48   // wrong order
47   // wrong order
49

Testing several count values, this problem does not always occur.
Why?
How can I resolve this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

陪我终i 2025-01-12 15:33:01

该症状表明Remove() 方法中存在问题。

您的 lastIndex 变量指向最后一项,因此在 minIndex 的 2 次计算中,您应该使用 <=

 // if (left < lastIndex && ...)
    if (left <= lastIndex && ...)

,对于 也是如此>对

The symptom indicates a problem in the Remove() method.

Your lastIndex var is pointing at the last item, so in the 2 calculations of minIndex you should use <=

 // if (left < lastIndex && ...)
    if (left <= lastIndex && ...)

and the same for right.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文