如何获取在 C++ 中排序后保留的列表元素的指针

Posted

技术标签:

【中文标题】如何获取在 C++ 中排序后保留的列表元素的指针【英文标题】:How to get a pointer of list element that stays after sorting in C++ 【发布时间】:2019-04-15 16:13:41 【问题描述】:

我在列表中保存了一些带有 x-y 坐标的二维点。我有一个方法,它根据点与光标的距离对数组进行排序,该方法将指针返回到离光标最近的点。

但是我使用 &points.first() 并且它总是指向列表的第一个元素。但是,在我使用列表后指针会发生变化。如何获得指向特定 ELEMENT 的指针,而不是列表的第一个元素。

我试过了: &points.first()

QList<Point2> points;


Point2 *DrawingWidget::closestToCursor()
    // Current mouse position
    Point2 pos(m_x, m_y);

    // There are no points
    if(points.isEmpty())
        return NULL;
    

    // Sorts according to distance to the cursor
    std::sort(std::begin(points), std::end(points), [&pos](Point2 a, Point2 b) 
            return pos.distanceFrom(a) < pos.distanceFrom(b);
    );

    // We dont allow points closer than 50px appart
    if(pos.distanceFrom(points.first()) > 50)
        return NULL;
    

    // Even after the resort, this always points to the first element of the vector. How do I get this elements pointer instead? 
    // Currently it seems that the pointer is basically LIST+0x0, however if the element shifts to whatever position, how do I still have its pointer?
    return &points.first();


每次我在新点附近调用此方法时,指针都会移动到列表的第一个元素,这是它应该做的,我知道这一点。但是我该怎么做呢?

【问题讨论】:

不要忘记,C++ 强烈鼓励使用nullptr 而不是NULL 如果不是绝对必要,不要使用列表。他们即使不是邪恶的,也是地狱般的。 列表中的元素就是元素。容器存储值而不是引用,因此如果您希望您的对象在列表之外有一些身份,那么您可以在列表中存储指针,但这通常不是一个好主意,所以最好使用答案中提出的内容跨度> 【参考方案1】:

您可能应该进行线性搜索以找到该元素,因为排序更昂贵。

线性搜索是O(N)

排序为O(N*log2(N))

例如:

auto& found = *std::min_element(std::begin(points), std::end(points),
                                [&pos](Point a, Point b)  return pos.distanceFrom(a) < pos.distanceFrom(b); );
return pos.distanceFrom(found) > 50 ? 0 : &found;

【讨论】:

【参考方案2】:

由于您的列表最终排序,您可以使用二分搜索在log2(n) 步骤中找到原始的第一个点:

#include <algorithm>

Point2 *DrawingWidget::closestToCursor() 
    if (points.isEmpty())
        return NULL;
    Point2 pos(m_x, m_y);
    auto cmpfun = [&pos](Point2 a, Point2 b) 
            return pos.distanceFrom(a) < pos.distanceFrom(b);
    );
    auto firstPoint = points.first();

    std::sort(std::begin(points), std::end(points), cmpfun);
    if (pos.distanceFrom(points.first()) > 50)
        return NULL;

    // return a pointer to the original first point
    return &*std::lower_bound(std::begin(points), std::end(points),
                              firstPoint, cmpfun);

还有其他方法,例如 decorate-sort-undecorate 对指针进行排序并真正保留原始点,但这些方法最终可能会大大增加执行成本。

【讨论】:

以上是关于如何获取在 C++ 中排序后保留的列表元素的指针的主要内容,如果未能解决你的问题,请参考以下文章

使用“克隆”助手执行可拖动事件后,如何删除原始元素?

在C中反转双链表的元素

如何在保留顺序的同时删除列表中的重复元素?

c++实现直接插入排序

Visual C++编程技巧之五

在 C++ 中,如何获取指向向量的指针?