Проблема с минимальной двоичной кучей

мне нужна помощь с этим кодом 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();
        }

    };         

Что ж, код делает почти все правильно, за исключением того, что когда он выталкивает последний элемент на экран, он печатает случайное число. Каково ваше мнение?

Спасибо!


person user281073    schedule 25.02.2010    source источник
comment
Добро пожаловать в StackOverflow. Код изделия можно отформатировать, сделав отступ в 4 пробела или 1 табуляцию.   -  person kennytm    schedule 25.02.2010
comment
Кроме того, если это не домашнее задание, вы должны использовать priority_queue. (sgi.com/tech/stl/priority_queue.html).   -  person kennytm    schedule 25.02.2010
comment
ну, кроме того, что я хочу понять это сам, мне нужна кастомная куча для моего алгоритма поиска пути.   -  person user281073    schedule 25.02.2010


Ответы (2)


Отладка

  • Вы можете запустить код с помощью valgrind, чтобы увидеть, сообщает ли он о каких-либо ошибках.
  • Вы можете запустить код в отладчике (отладка занимает больше времени, но больше шансов на успех).

Кодирование. Вы должны использовать утверждения. Например, первая строка функции swap может быть assert(i >= 0 && i < 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) вышел за пределы.

person amit    schedule 25.02.2010
comment
ну, после того, как вы поставили эти два, он говорит, что утверждение не удалось, и программа вылетает, есть идеи, почему? - person user281073; 25.02.2010
comment
@vladdx Я пытался запустить код, но у меня он работает (без сбоев). Не могли бы вы добавить тестовый пример или функцию main() в свой вопрос, чтобы я мог воспроизвести сбой? - person amit; 26.02.2010
comment
@vladdx В противном случае вы можете попробовать запустить код (с установленным утверждением) внутри отладчика gdb (если вы используете Linux, но для работы в gdb вам необходимо скомпилировать код с помощью g++ -g3). В месте сбоя вы можете просмотреть стек с помощью команды bt. Вы можете перемещаться по стеку с помощью команд вверх и вниз и печатать значение переменной с помощью команды p ‹имя переменной›. Таким образом, вы можете увидеть, имеют ли смысл значения i и j. - person amit; 26.02.2010
comment
Да, теперь это работает, Амит, большое спасибо! Теперь нужно закодировать алгоритм поиска пути! :) - person user281073; 26.02.2010

У вас есть две похожие проблемы, одна в push() и одна в pop(). В push вам нужно проверить это id != 0, прежде чем смотреть на v[parent(id)]. Если id == 0вы находитесь в корне и вам следует остановиться. Точно так же в pop() вы должны проверить, находится ли right(f) (или left(f)) в пределах вектора, прежде чем обращаться к v[right(f)] (или v[left(f)]). Если это не так, вы достигли дна кучи и должны остановиться.

person Ari    schedule 25.02.2010
comment
Ну, после того, как вы сделали то, что вы сказали, например, 13, 5, 1, 3, 17 печатает 1, 3, -xxxxxxx, 5, 13, так что другая проблема. Что вы думаете? - person user281073; 26.02.2010