我一直在寻找一种方法来避免每次想要找到一个节点时从列表的头部开始,所以我想到为节点分配索引,保持指向随机的指针(不完全随机;见下文)节点,然后找到最接近我想要找到的索引的指针。请允许我用代码解释:
// head and last are pointers to the first and last items of a doubly-linked list
// current is a pointer that will change over time. It's used as a temporary pointer
template <class T>a
Node<T>* List<T>::get_closest(Node<T> node, int& difference) {
int curr_to_i = current->index - node->index;
int last_to_i = last->index - node->index;
Node* closest = node->index < abs(curr_to_i) ? head : current;
closest = closest->index < abs(last_to_i) ? closest : last;
difference = closest->index - node->index;
return closest;
}
/*
* This functions adds a node with the given value to the given index. The node at that
* index and all the following are moved, and the new node is inserted before them.
*/
template <class T>
bool List<T>::add(T value, int index) {
if (index < 0) { //Invalid index
return false;
} else if (index == last->index +1) {
push(value);
return true;
} else if (index > 0) {
Node* new_n = new Node;
new_n->value = value;
new_n->index = index;
int difference;
Node* closest = get_closest(new_n, difference);
if (difference < 0) {
for (int i = 0; i < abs(difference); i++) {
current = current->previous;
}
} else if (difference > 0) {
for (int i = 0; i < abs(difference); i++) {
current = current->next;
}
} /* current now points to the node we want to move */
new_n->previous = current->previous;
new_n->next = current;
current->previous->next = new_n;
current->previous = new_n;
if (index == 0) {
root = new_n;
}
new_n = new_n->next;
while (new_n != null) {
new_n->index++;
new_n = new_n->next;
}
return true;
}
}
这比从头部开始并向前推进多次更有效吗?
答案 0 :(得分:4)
听起来像你正试图发明Skip Lists,这是一种平衡的排序树。
你真正想要的是使用boost :: multi_index之类的东西,它允许你使用索引的组合来获得一系列操作的良好性能。 examples中的一个与你想要做的事情有着非常相似的感觉。
在尝试使用这样的东西之前,你应该描述你的实际用途,以确定优化你的代码部分是否有任何实际好处,然后如果它成为瓶颈,尝试许多不同的结构组合看看哪一个在您的特定用途上实际上表现最佳。除非您的数据集非常大,否则std::vector
几乎总是最快的,因为地点。
答案 1 :(得分:2)
如果您需要访问列表中间的元素,那么最好使用数组。列表是可以以各种方式实现的抽象数据结构(ADT)。您基本上所做的是创建一个具有两种方法开销的冗余表示。
链表的优点是列表的头部插入速度非常快 - 对于数组,O(1)对O(n)。但是,由于您必须维护索引,因此无论如何都会有插入O(N)开销。
如果您需要建立索引,只需使用数组即可。更简单,更快捷。
答案 2 :(得分:0)
看起来插入会变得更加昂贵。为什么不写一个测试程序和时间差异?
答案 3 :(得分:0)
您的伪随机索引可能接近列表的开头(仅用于说明),从而导致列表中每个元素的移位。这使得插入链表非常昂贵,以至于拥有一个链表变得毫无意义,你可以只使用一个数组。