【问题标题】:Linked List: Is this solution good?链表:这个解决方案好吗?
【发布时间】:2010-11-08 00:55:12
【问题描述】:

我一直在寻找一种方法来避免每次我想找到一个节点时从列表的头部开始,所以我想为节点分配索引,保持一个指向随机的指针(不完全随机;见下文)节点,然后找到最接近我要查找的索引的指针。请允许我用代码解释一下:

// 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;        
    }
}

这是否比从头开始,向前推进多次更有效率?

【问题讨论】:

  • 没有上下文就很难回答……听起来像是“跳过列表”。

标签: c++ algorithm performance linked-list


【解决方案1】:

看起来插入会变得更加昂贵。为什么不写个测试程序和时间差?

【讨论】:

    【解决方案2】:

    如果您需要访问列表中间的元素,那么您最好使用数组。列表是一种抽象数据结构 (ADT),可以通过多种方式实现。您实际上所做的是创建具有两种方法开销的冗余表示。

    链表的优点是在链表的头部插入可以非常快——对于数组来说 O(1) 与 O(n)。但是,由于您必须维护您的索引,因此无论如何插入都有 O(N) 开销。

    如果您需要索引,只需使用数组即可。更简单、更快捷。

    【讨论】:

    • 似乎向量也很合适。它维护一个指向节点的指针索引以进行随机访问。
    • 嗯,这主要是一个理论问题,因为我这样做是为了练习。如果我需要一个容器来实际使用,我会使用 STL。
    • @opello:拉里所说的“数组”也被称为“向量”。您所说的“向量”通常称为“指针向量”,或者(我猜更常见)“指针数组”
    • @Javier:我指的是特定的 STL 向量。
    【解决方案3】:

    您的伪随机索引可能接近列表的开头(仅用于说明),从而导致列表中的每个元素随后发生移位。这使得插入链表非常昂贵,以至于拥有链表变得毫无意义,您可以使用数组。

    【讨论】:

      【解决方案4】:

      在我看来,您正在尝试发明Skip Lists,这是一种平衡的、排序的树。

      您真正想要的可能是使用 boost::multi_index 之类的东西,这将允许您使用索引组合在一系列操作中获得良好的性能。其中一个examples 与您正在尝试做的事情非常相似。

      在尝试使用类似的东西之前,您应该分析您的实际使用情况,以确定优化这部分代码是否有任何真正的好处,然后如果它被证明是一个瓶颈,请尝试多种不同的结构组合看看哪一个实际上在您的特定用途上表现最好。除非您的数据集非常大,否则 std::vector 几乎总是最快的,因为它具有局部性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多