Ошибка неправильного выделения вектора C++

Я уже довольно давно работаю над деревом avl, основанным на векторе. Я должен брать входные данные из файла, но на 4118-м вводе выдает ошибку bad_alloc. Я провел небольшое исследование и собрал данные, которые мне также нужны для резервирования места. Но даже когда я выделяю место, все равно выдает ту же ошибку.

части моего кода:

Я вызываю эту функцию:

void insert(T d, unsigned int c = 1);

find(T d) находит позицию newNode в vector<node<T>*> myVector; он вернет позицию, даже если не найдет newNode. Вставка позаботится о возвращаемом целом числе (показано ниже)

вставка:

template<typename T>
void binaryTree<T>::insert(T d, unsigned int c)
//inserts type T with count c into vector
{
    node<T>* newNode = new node<T>(d,c);

    if(myVector.empty())
    {
        myVector.push_back(newNode);
    }
    else
    {
        int r = find(d);
        total++;
        //if newNode has same data as the data in position r
        if(r < myVector.size() && myVector[r] && *newNode == *myVector[r])
        {
            myVector[r]->data.loc.push_back(newNode->data.loc[0]);
            myVector[r]->count += newNode->count;
            delete newNode;
            return;
        }
        //insert into vector normally
        else
        {
            checkSpace(r);
            myVector[r] = newNode;
            //reParent(r);
        }
    }
}

с checkSpace:

template<typename T>
void binaryTree<T>::checkSpace(int i)
//resizes the vector if needed
{
    if(i >= myVector.size())
    {
        myVector.resize(rightOi(i),NULL);
    }
}

и void reParent(r) является основной функцией, которая выполняет все повороты и балансировку. Я закомментировал reParent(r) и, возможно, выделил проблему только в функции вставки. Я довольно новичок в этом, и я ценю любую помощь. Заранее спасибо.

правая функция:

template<typename T>
//return the right position of i
int binaryTree<T>::rightOi(int i)
{
    return i*2 + 2;
}

person Jordan Huang    schedule 07.04.2014    source источник
comment
Это выглядит невероятно неэффективно. Не вызывайте resize для вектора. Используйте push_back или insert.   -  person Kerrek SB    schedule 07.04.2014
comment
Можете ли вы показать свою правую функцию?   -  person The Dark    schedule 07.04.2014
comment
^ сделано. В основном он возвращает позицию правого потомка определенной позиции.   -  person Jordan Huang    schedule 07.04.2014
comment
Очень странно, что вам не хватает памяти, если только вы не работаете на какой-то очень ограниченной платформе. Возможно ли, что вы попадаете в бесконечную рекурсию, которая заканчивается тем, что у вас заканчивается память?   -  person Simon    schedule 07.04.2014
comment
Итак, вы передаете newNode. Что происходит, когда он уже находится в дереве? Вы сравниваете разыменованный узел и узел с прорезями и просто увеличиваете количество узлов дерева. Как вызывающий узнает, что вы не вставили newNode и, следовательно, ему нужно его удалить? Вы возвращаете void, поэтому я не вижу никаких признаков того, что вызывающему абоненту сообщают, что newNode все еще горячо на их стороне и не принадлежит дереву.   -  person WhozCraig    schedule 07.04.2014
comment
Зачем вам вектор указателей, если вы используете векторы в качестве контейнера базовых данных? (т.е. что не так с std::vector<node<T> >?)   -  person Jonathan H    schedule 07.04.2014
comment
@Simon: у меня нет рекурсий и i7 win 8. Для меня это тоже очень странно.   -  person Jordan Huang    schedule 07.04.2014
comment
@WhozCraig: я обязательно перепишу эту функцию, чтобы удалить необработанный указатель. Спасибо.   -  person Jordan Huang    schedule 07.04.2014
comment
В дополнение к моему предыдущему комментарию, насколько я вижу, ваша реализация не основана на векторе; вектор, который вы используете, не обрабатывает распределение узлов, вы делаете распределения вручную каждый раз, когда хотите вставить новый узел (вероятно, используя new?), и я хотел бы убедиться, что вы удалили их правильно. Это очень неэффективно, с векторами указателей не всегда просто обращаться, и в этом случае я уверен, что они не нужны.   -  person Jonathan H    schedule 07.04.2014
comment
@Sh3ljohn vector‹node‹T›› работает слишком медленно. Если я правильно помню в классе, он дважды вызывает конструктор копирования каждый раз, когда вы его используете... Я могу ошибаться. Но я попробовал vector‹node‹T››, и он действительно очень медленный. Кстати, void insert(int r, node‹word› *newNode) — это закрытая функция. Я переписываю его сейчас, чтобы правильно удалить newNode.   -  person Jordan Huang    schedule 07.04.2014
comment
@SamHuang Что вы помните о двойном вызове конструктора копирования, так это когда вы возвращаете std::vector<node<T> >. Я не предлагаю вам возвращать вектор узлов в любом месте, вектор должен быть атрибутом вашего класса, который служит контейнером (т. е. основанная на векторе реализация); в этом случае нет причин, по которым я могу видеть, когда вам придется вызывать конструктор копирования. Если вы придумали медленную реализацию, я бы хотел ее увидеть. Если вы говорите о конструкторе копирования node<T>, вы должны использовать ссылки. Если вы вставляете новые узлы по значению, рассмотрите вместо этого emplace.   -  person Jonathan H    schedule 07.04.2014
comment
@SamHuang Я верю вам, когда вы говорите, что ваша реализация была неэффективной. Это не имеет ничего общего с использованием правильного контейнера (к сожалению). Мой совет: вернитесь на правильный путь, а потом посмотрим, почему он неэффективен. Векторы указателей определенно не подходят, и это может быть корнем ваших проблем. Не стоит тратить время на исправление этого.   -  person Jonathan H    schedule 07.04.2014
comment
Мне удалось это исправить. Проблема была с чекспейсом. Размер вектора был слишком велик, и мне пришлось изменить его размер другим способом. Теперь все работает!   -  person Jordan Huang    schedule 16.04.2014


Ответы (2)


Я могу ошибаться и немного оффтопить, но мне кажется, что вектор не очень хорошая идея для динамических деревьев, я бы создал дерево по старинке, вот так:

struct Node
{
    T value;
    Node* right;
    Node* left;
}

int main()
{
    Node<int>* root = new Node<int>();
    root->value = 10;
    root->right = NULL;
    root->left = NULL;

    Node<int>* someNode = new Node<int>();
    someNode->value = 5;
    someNode->right = NULL;
    someNode->left = NULL;

    root->left = someNode;
}

Таким образом, он может быть заключен в такие функции, как AddElement, Rebalance, Traverse, Delete по вашим правилам. Спросите, если вам нужно более подробное описание.

person INait    schedule 07.04.2014
comment
Я бы предпочел создать двоичное дерево со связанным списком, но требуется вектор. - person Jordan Huang; 07.04.2014

Итак, я обнаружил проблему, которая заключается в том, что функция checkspace() (которая изменяет размер вектора) заставляет вектор изменять размер до огромного числа. Вот почему программа продолжала давать мне ошибку. Исправление для этого заключается в изменении размера только при необходимости. Вот как я исправил свой проект.

person Jordan Huang    schedule 03.05.2014