【问题标题】:Min Binary Heap issue最小二进制堆问题
【发布时间】:2010-02-25 09:17:55
【问题描述】:

我需要有关此 minheap 代码的帮助:

#include < vector>

using namespace std;

class heap {

    vector <int> v;

    public:

        int hSize()
        {
            return v.size();
        }

        int rsize()
        {
            return  hSize() - 1;
        }    

        int parent(int i) 
        {
            return (i - 1) / 2;
        }

        int left(int i)
        {
            return i * 2 + 1;
        }

        int right(int i)
        {
            return i * 2 + 2;
        }

        void swap(int i, int j)
        {
            int temp = v[j];
            v[j] = v[i];
            v[i] = temp;
        }

        void push(int e)
        {

            v.push_back(e);
            int id = rsize(); 

            if (hSize() > 1)
                while (v[parent(id)] > v[id]) {               
                    swap(parent(id), id);
                    id = parent(id);
                }
        }

        int pop ()
        {

          int f = 0;  
          int p = v[0];

          v[0] = v[rsize()];

          if (hSize() > 1) {
              while (v[left(f)] < v[f] || v[right(f)] < v[f]) {
                    if (v[left(f)] < v[f] && v[right(f)] < v[f]) {
                        if (v[left(f)] < v[right(f)]) {
                            swap(left(f), f);
                            f = left(f);
                    }
                    else { 
                            swap(right(f), f);
                            f = right(f);
                    }
                }

                else {
                    if (v[left(f)] < v[f]){
                         swap(left(f), f);
                         f = left(f);
                    }
                    else {
                         swap(right(f), f);
                         f = right(f);
                        }
                    }
                } 
          }
          else { }

          v.resize(rsize());
          return p;
        }

        void show()
        {
            if (hSize() > 0) {
                cout << "Heap content: ";
                for (int i = 0; i < hSize(); i++) cout << v[i] << " ";
            }
            else cout << "\nHeap successfully emptied!";  
            cout << "\n";          
        }

        bool Empty()
        {
            return v.empty();
        }

        ~heap()
        {
            v.clear();
        }

    };         

好吧,代码几乎做对了所有事情,除了当它弹出屏幕上的最后一个元素时,它会打印一个随机数。你有什么意见?

谢谢!

【问题讨论】:

  • 欢迎来到 StackOverflow。您可以通过缩进 4 个空格或 1 个制表符来格式化片段代码。
  • 另外,除非是家庭作业,否则您应该使用priority_queue。 (sgi.com/tech/stl/priority_queue.html)。
  • 好吧,除了想自己理解之外,我还需要一个自定义的 minheap 用于我的寻路算法。

标签: c++ algorithm heap binary-heap


【解决方案1】:

你有两个类似的问题,一个在push(),一个在pop()。在推送中,您需要在查看v[parent(id)] 之前检查id != 0。如果id == 0你是根,你应该停止。同样,在pop() 中,您应该在访问v[right(f)](或v[left(f)])之前检查right(f)(或left(f))是否在向量内。如果不是,你已经到达堆的底部,你应该停下来。

【讨论】:

  • 按照您所说的,即 13, 5, 1, 3 ,17 打印 1, 3, -xxxxxxx, 5, 13 之后,还有另一个问题。你怎么看?
【解决方案2】:

调试

  • 您可以使用 valgrind 运行代码以查看它是否报告任何错误。
  • 您可以在调试器中运行代码(调试时间更长,但成功的可能性更大)。

编码 你应该使用断言。例如,swap 函数的第一行可以是 assert(i &gt;= 0 &amp;&amp; i &lt; v.size());j 也是如此。我怀疑把这两个断言放进去会告诉你错误。完成后,如果您愿意,可以注释掉断言(尽管有些人喜欢始终保留一些断言)。

更新 你的代码没问题。只需要在交换中添加边界检查,如果不满意就返回。这是代码和测试用例(我跑的时候通过了):

#include <vector>
#include <iostream>
#include <cassert>
#include <cstdlib>

using namespace std;

class heap {

    vector <int> v;

    public:

        int hSize()
        {
            return v.size();
        }

        int rsize()
        {
            return  hSize() - 1;
        }

        int parent(int i)
        {
            return (i - 1) / 2;
        }

        int left(int i)
        {
            return i * 2 + 1;
        }

        int right(int i)
        {
            return i * 2 + 2;
        }

        void swap(int i, int j)
        {
            //assert(i >= 0 && i < v.size()); 
            //assert(j >= 0 && j < v.size()); 
            if(i >= v.size() || j >= v.size()) return;
            int temp = v[j];
           v[j] = v[i];
            v[i] = temp;
        }

        void push(int e)
        {

            v.push_back(e);
            int id = rsize();

            if (hSize() > 1)
                while (v[parent(id)] > v[id]) {
                    swap(parent(id), id);
                    id = parent(id);
                }
        }

        int pop ()
        {

          int f = 0;
          int p = v[0];

          v[0] = v[rsize()];

          if (hSize() > 1) {
                  while (v[left(f)] < v[f] || v[right(f)] < v[f]) {
                          if (v[left(f)] < v[f] && v[right(f)] < v[f]) {
                                  if (v[left(f)] < v[right(f)]) {
                                          swap(left(f), f);
                                          f = left(f);
                                  }
                                  else {
                                          swap(right(f), f);
                                          f = right(f);
                                  }
                          }

                          else {
                                  if (v[left(f)] < v[f]){
                                          swap(left(f), f);
                                          f = left(f);
                                  }
                                  else {                                         swap(right(f), f);
                                          f = right(f);
                                  }
                          }
                  }
          }
          else { }

          v.resize(rsize());
          return p;
        }

        void show()
        {
                if (hSize() > 0) {
                        cout << "Heap content: ";
                        for (int i = 0; i < hSize(); i++) cout << v[i] << " ";
                }
                else cout << "\nHeap successfully emptied!";
                cout << "\n";
        }

        bool Empty()
        {
                return v.empty();
        }

        ~heap()
        {
                v.clear();
        }

};


int main()
{
        heap h;
        for(int i = 0; i < 10; i++) {
        h.push(rand()%10);
        h.push(4);
        h.push(3);
        h.push(2);
        h.push(1);
        h.push(0);
        h.push(5);
        h.push(-6);
        h.push(7);
        h.show();
        h.pop();
        h.pop();
        h.pop();
        h.pop();
        h.pop();
        h.pop();
        h.pop();
        h.pop();
        h.pop();
        h.show();
        }
}

插入断言后,我在调试器中运行代码,发现崩溃发生在swap(right(f), f);right(f)超出范围。

【讨论】:

  • 在放了这两个之后它说“断言失败”并且程序崩溃了,知道为什么吗?
  • @vladdx 我尝试运行代码,但它对我有用(没有崩溃)。您能否在您的问题中添加一个测试用例或 main() 函数,以便我重现崩溃?
  • @vladdx 否则您可以尝试在 gdb 调试器中运行代码(使用断言)(如果您使用的是 linux;但要在 gdb 上运行,您需要使用“g++ -g3”编译代码”)。在它崩溃的地方,您可以使用“bt”命令查看堆栈。您可以使用“up”和“down”命令遍历堆栈,并使用“p ”命令打印变量的值。所以你可以看看ij的值是否有意义。
  • 是的,它现在可以工作了,阿米特,非常感谢!现在编写寻路算法! :)
猜你喜欢
  • 1970-01-01
  • 2019-05-28
  • 2012-05-18
  • 2018-04-13
  • 1970-01-01
  • 2020-03-09
  • 2017-09-07
  • 1970-01-01
  • 2019-08-18
相关资源
最近更新 更多