Я пишу дерево B + по целому ряду причин, и я пришел сюда, чтобы задать вопрос о реализации его узлов. Мои узлы в настоящее время выглядят следующим образом:B + tree implementation, * * vs *
struct BPlusNode
{
public:
//holds the list of keys
keyType **keys;
//stores the number of slots used
size_t size;
//holds the array of pointers to lower nodes NULL if this is a leaf node
BPlusNode **children;
//holds the pointer to the next load to the 'left'
BPlusNode *next;
//Data page pointers NULL if this is a branch node
Bucket **pages;
};
Как вы можете видеть, что моя текущая реализация использует * * в том месте, где мне интересно, должен ли я использовать * или *.
Мне хорошо известно, что * * требует двух операций разыменования и, следовательно, медленнее, чем просто использование *, однако этот класс использует большую рекурсию, и гораздо более удобно передавать указатели на подвыборы рекурсивных функций. Для этого с помощью * мне нужно будет выполнить арифметику указателя и передать полученный указатель.
С **
someFunction(BPlusNode* currNode)
{
......
someFunction(currNode->children[ChildIndex]);
}
с *
someFunction(BPlusNode* currNode)
{
......
someFunction((currNode->children) + ChildIndex);
}
Я могу видеть, что есть дополнительное чтение из памяти для получения указателя на нужный * * версии, но * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Есть ли у кого-нибудь мысли так или иначе? Предложения по третьему варианту? Доказательство того, почему человек превосходит другого? и т.д?
Edit:
Я мог бы отправить это как ответ ниже, но я просто понял, что с * * схемами не нужно скопировать все содержимое каждого подузла или ведро должен я хочу вставить одну в середину массив (т. е. изменить размер массива). Если для схемы * есть 20 поднодов, когда я перераспределяю массив, мне нужно будет копировать байты 20 * sizeof (BPlusNode), а не байты размером 20 * sizeof (BPlusNode *) для схемы * *.
С другой стороны, мне пришло в голову, что, поскольку я выполняю все вставки и разбиения страниц, возможно, это увеличивает эффективность при их исполнении, а преимущества * over * * в поисках перевешивают его.
Как это отмечено на C++, есть ли какая-то причина, по которой вы не можете передавать указатели по ссылке вместо выполнения арифметики указателя? – greyfade
Как я понимаю, он делает что-то вроде someFunction (BPlusNode * и currNode) .... и затем вызывает его через someFunction (currNode-> children [ChildIndex]), будет даже хуже, чем * *. [] В основном совпадает с * (currNode-> children + ChildIndex), таким образом, то же, что и схема * *, есть арифметика указателя, а затем разыменование. В отличие от схемы * *, этот указатель на объект должен быть извлечен и передан. Поэтому мне кажется, что с точки зрения эффективности он по крайней мере эквивалентен схеме * *. Может быть, хуже. –
@James: Я уверен, что greyfade предлагает подпись 'someFunction (BPlusNode & currNode)'. Это функционально (и с точки зрения производительности), идентичное 'someFunction (BPlusNode * currNode)', но выглядит более чистым и позволяет избежать ошибок, которые могут быть вызваны случайным изменением указателя (вместо объекта pointee). –