Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
1980 / 836 / 115
Регистрация: 01.10.2012
Сообщений: 5,222
Записей в блоге: 2

Удалить близкие точки

01.09.2026, 17:22. Показов 7088. Ответов 63
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день

Есть массив/контейнер точек, напр
C++
1
2
3
4
5
struct Point {
 float x, y, z;
};
 
std::vector<Point> points;
Требуется удалить часть точек так чтобы расстояние между любыми двумя не превышало заданное, напр 1.0e-5

Спасибо
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
01.09.2026, 17:22
Ответы с готовыми решениями:

Найти точки наиболее близкие друг к другу
В файле записано количество точек на плоскости и их координаты. Поместить эти координаты в...

Найти две точки, наиболее близкие друг к другу
В файле записано количество точек на плоскости и их координаты. Поместить эти координаты в...

Найти три точки, наиболее близкие к известной точке
Координаты (целые числа) из n точек (3 &lt;n &lt;101) в координатной плоскости хранятся в массивах....

63
 Аватар для MallSerg
101 / 69 / 15
Регистрация: 16.11.2018
Сообщений: 324
03.09.2026, 02:38
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Igor3D Посмотреть сообщение
Рекомендации всяких вумных деревьев - перегиб в другую, не тот это случай когда нужно подходить столь фундаментально. Решение должно быть достаточно простым/дешевым и приличным, пусть и не самым быстрым по скорости. Можно заводить доп данные (с умом), сортировать и.т.п. но не "размахиваться слишком широко"
На мой взгляд все довольно просто три строчки кода (если использовать готовую реализацию в boost boost::geometry::index::rtree)
Объявить переменную индекса
Построить индекс над данными
и выполнить запрос.

По сути алгоритм индексации не такой уж и сложный вся сложность в балансировке узлов древовидной структуры областей а ее лучше заранее подогнать под механизм получения информации или параллелирование вычислений.
0
5534 / 2887 / 573
Регистрация: 07.11.2019
Сообщений: 4,813
03.09.2026, 18:45
Зачем вообще использовать sqrt или hypot, если проще сразу сравнивать с квадратом расстояния... ? 1.0e-10
0
фрилансер
 Аватар для Алексей1153
6506 / 5756 / 1134
Регистрация: 11.10.2019
Сообщений: 15,404
03.09.2026, 18:51
u235, это следующий этап оптимизации, не надо торопить события
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13233 / 6865 / 1827
Регистрация: 18.10.2014
Сообщений: 17,398
03.09.2026, 19:34
Лучший ответ Сообщение было отмечено Igor3D как решение

Решение

Цитата Сообщение от u235 Посмотреть сообщение
Зачем вообще использовать sqrt или hypot, если проще сразу сравнивать с квадратом расстояния... ? 1.0e-10
Логично. Об этом слоне я и не подумал. <cmath> не нужен...

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <list>
#include <vector>
#include <unordered_map>
#include <limits>
#include <random>
#include <iostream>
 
struct Point
{
  float x, y, z;
 
  friend float distance2(const Point &a, const Point &b)
  { 
    float dx = a.x - b.x, dy = a.y - b.y, dz = a.z - b.z;
    return dx * dx + dy * dy + dz * dz; 
  }
};
 
struct MeshKey
{
  int ix, iy, iz;
 
  friend MeshKey operator +(const MeshKey &lhs, const MeshKey &rhs)
    { return { lhs.ix + rhs.ix, lhs.iy + rhs.iy, lhs.iz + rhs.iz }; }
 
  friend bool operator ==(const MeshKey &, const MeshKey &) = default;
 
  struct Hash
  {
    std::size_t operator ()(const MeshKey &key) const
      {  return ((std::hash<int>()(key.ix) << 1) ^ std::hash<int>()(key.iy) << 1) ^ std::hash<int>()(key.iz); }
  };
};
 
using Points = std::list<Point>;
using Mesh = std::unordered_map<MeshKey, std::vector<Points::iterator>, MeshKey::Hash>;
using MeshNode = Mesh::value_type;
 
void populate(Mesh &mesh, float step, Points &points)
{
  for (auto it = points.begin(); it != points.end(); ++it)
    mesh[{ (int) (it->x / step), (int) (it->y / step), (int) (it->z / step) }].push_back(it);
}
 
const MeshKey HALF_ADJ_DXYZ[] = 
{
  { -1, +1,  0 }, {  0, +1,  0 }, { +1, +1,  0 }, 
                                  { +1,  0,  0 },
 
  { -1, +1, +1 }, {  0, +1, +1 }, { +1, +1, +1 }, 
  { -1,  0, +1 },                 { +1,  0, +1 }, 
  { -1, -1, +1 }, {  0, -1, +1 }, { +1, -1, +1 }
};
 
std::size_t count_violations(const Mesh &mesh, const MeshKey &key, const Point &point, float min_dist2,
                             std::size_t n_violations = 0,
                             std::size_t n_limit = std::numeric_limits<std::size_t>::max())
{
  for (const MeshKey &dxyz : HALF_ADJ_DXYZ)
  {
    auto it_adj_node = mesh.find(key + dxyz);
    if (it_adj_node == mesh.end())
      continue;
 
    for (auto it_adj_point : it_adj_node->second)
    {
      float dist2 = distance2(point, *it_adj_point);
      if (dist2 < min_dist2)
        if (++n_violations > n_limit)
          return n_violations;
    }
  }
 
  return n_violations;
}
 
std::size_t count_violations(const Mesh &mesh, float min_dist)
{
  float min_dist2 = min_dist * min_dist;
 
  std::size_t n_violations = 0;
 
  for (const MeshNode &node : mesh)
    for (auto it_point : node.second)
      n_violations = count_violations(mesh, node.first, *it_point, min_dist2, n_violations);
 
  return n_violations;
}
 
void cleanup(Points &points, Mesh &mesh, float min_dist)
{
  float min_dist2 = min_dist * min_dist;
 
  for (auto it_node = mesh.begin(); it_node != mesh.end(); )
  {
    for (auto itit_point = it_node->second.begin(); itit_point != it_node->second.end(); )
    {
      auto it_point = *itit_point;
      if (count_violations(mesh, it_node->first, *it_point, min_dist2, 0, 0) > 0)
      {
        points.erase(it_point);
        itit_point = it_node->second.erase(itit_point);
      }
      else
        ++itit_point;
    }
 
    if (it_node->second.empty())
      it_node = mesh.erase(it_node);
    else
      ++it_node;
  }
}
 
int main()
{
  Points points(1000000);
 
  std::random_device rd;
  std::mt19937 gen(rd());
  std::uniform_real_distribution<float> dis(0.f, 1.f);
  for (Point &point : points)
    point = { dis(gen), dis(gen), dis(gen) };
 
  const float MIN_DIST = 1.e-2f;
 
  Mesh mesh;
  populate(mesh, MIN_DIST, points);
 
  std::size_t n_initial = points.size();
  std::cout << "Initial points: " << n_initial << std::endl;
  std::cout << "Violating pairs: " << count_violations(mesh, MIN_DIST) << std::endl;
 
  cleanup(points, mesh, MIN_DIST);
 
  std::cout << "Points after cleanup: " << points.size() << std::endl;
  std::cout << "Removed points: " << n_initial - points.size() << std::endl; 
 
  std::cout << "Violating pairs after cleanup: " << count_violations(mesh, MIN_DIST) << std::endl;
}
0
5534 / 2887 / 573
Регистрация: 07.11.2019
Сообщений: 4,813
03.09.2026, 20:15
TheCalligrapher, слон это квадратичный алгоритм..
Ваша программа для 100000 точек у меня на телефоне работает примерно минуту.
А питоновский скрипт с использованием KD-tree - около 1 секунды.
Кликните здесь для просмотра всего текста
Python
1
2
3
4
5
6
import numpy as np
from scipy.spatial import KDTree
points=np.random.random((100000, 3))
kd_tree = KDTree(points)
pairs = kd_tree.query_pairs(r=0.01)
print(f'num pairs: {len(pairs)}')

Исходники на C++, функции query_pairs можно посмотреть на github.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13233 / 6865 / 1827
Регистрация: 18.10.2014
Сообщений: 17,398
03.09.2026, 21:13
Цитата Сообщение от u235 Посмотреть сообщение
слон это квадратичный алгоритм..
Разумеется, никакого "квадратичного алгоритма" тут нет. Алгоритм линеен от общего количества исходных точек. Расписывать теорию тут я смысла не вижу - я давал ссылку на источник, там все объясняется.

Алгоритм, разумеется, является квадратичным от количества близких пар, как и любой алгоритм перечисления таких пар. (Понятно, что неквадратичного алгоритма по этой метрике нет и быть не может).

Цитата Сообщение от u235 Посмотреть сообщение
Ваша программа для 100000 точек у меня на телефоне работает примерно минуту.
А питоновский скрипт с использованием KD-tree - около 1 секунды.
Вы, очевидно, сравнивали яблоки с апельсинами, да и в этом сравнении, боюсь накосячили.

Моя программа занимается решением задачи подчета, затем решением задачи удаления, а затем снова решает задачу подсчёта. Ваш питоновский скрипт решает лишь задачу подсчета.

Это уже не говоря о том, что никаких усилий по оптимизации-минимизации мультипликативных и аддитивных констант в этой программе не производилось. Программа лишь иллюстрирует идею алгоритма.

Я не удивлюсь, если решение с KD-tree будет сравнимо по эффективности или даже превосходить по каким-то константам, но, пожалуйста, не надо смешить собравшихся заявлениями в стиле "ваша программа - минуту, а kd-tree - секунду".
0
1980 / 836 / 115
Регистрация: 01.10.2012
Сообщений: 5,222
Записей в блоге: 2
03.09.2026, 22:21  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Программа лишь иллюстрирует идею алгоритма.
Попробую ее прокомментировать, если надо поправьте.

Вы решили не хранить "регулярную" сетку (потенциально огромную), а доставать из хеша (соседние) кубы с данными (по целочисленному ключу). Нормально, но тогда соседей получается 26, плюс нужно сканировать "центральный" куб, ведь "пара" могла просто попасть в один куб. Обычно это делается незатейливыми 3 циклами for.

Ну и с удалением Вы сачканули . "Есть контейнер" совсем не значит "из которого мне удобно удалять". Да, "удалить минимум точек" - такой задачи здесь не ставится, но код должен быть пригоден (с прицелом) на распараллеливание, а с немедленным erase этого нет.

Итого: прилично, квадратичного перебора нет, расход памяти вполне приемлем. Все-таки многовато долбится хеш, хотелось бы большего (как всегда )

Цитата Сообщение от MallSerg Посмотреть сообщение
На мой взгляд все довольно просто..
Если все так просто - то где же Ваш вариант?
Цитата Сообщение от u235 Посмотреть сообщение
Ваша программа для 100000 точек у меня на телефоне работает примерно минуту.
А Ваша?

Да, kd-tree здесь отлично подходит, но необязательно, можно и попроще
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13233 / 6865 / 1827
Регистрация: 18.10.2014
Сообщений: 17,398
03.09.2026, 22:42
Цитата Сообщение от Igor3D Посмотреть сообщение
Вы решили не хранить "регулярную" сетку (потенциально огромную), а доставать из хеша (соседние) кубы с данными (по целочисленному ключу).
Совершенно верно. Именно на этом и держится идея алгоритмов Рабина-Липтона, Куллера-Матиаса и т.п

Цитата Сообщение от Igor3D Посмотреть сообщение
Нормально, но тогда соседей получается 26,
Верно, окрестность Мура в сетке содержит 3k-1 соседей, где k - размерность пространства. Однако так как каждую пару нам достаточно обнаруживать только "в одну сторону", достаточно из каждого узла рассмотреть лишь половину соседей, что я и делаю в своей программе, т.е. рассматриваю 13 соседей.

Цитата Сообщение от Igor3D Посмотреть сообщение
плюс нужно сканировать "центральный" куб, ведь "пара" могла просто попасть в один куб.
Верно, это ошибка в моей программе - я не проверяю точки в одном узле. Если я не ошибаюсь, при таком выборе шага сетки, сканировать/проверять их и не надо - они все являются "нарушителями". (Хотя нет, при таком шаге - надо проверять)

Цитата Сообщение от Igor3D Посмотреть сообщение
Ну и с удалением Вы сачканули . "Есть контейнер" совсем не значит "из которого мне удобно удалять". Да, "удалить минимум точек" - такой задачи здесь не ставится, но код должен быть пригоден (с прицелом) на распараллеливание, а с немедленным erase этого нет.
Удаление? Удаление здесь присутствует лишь в иллюстративных целях, не говоря уже о том, что "уточнённая" постановка задачи вообще не предполагает никакого удаления.
0
5534 / 2887 / 573
Регистрация: 07.11.2019
Сообщений: 4,813
03.09.2026, 22:49
TheCalligrapher, у вас явно квадратичная зависимость n2 времени работы от числа точек. У kd-tree зависимость что-то типа n*log(n).
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Моя программа занимается решением задачи подчета, затем решением задачи удаления, а затем снова решает задачу подсчёта.
Да, все так, можете умножить время работы питоновского скрипта на 3, но сложность алгоритма от этого не поменяется.
Вот результаты теста на моем компе.
ncpppy(kd-tree)
100000.630.06
5000015.30.098
100000650.15
2000002660.32
1000000-2.66
2000000-8.39
4000000-31.2
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13233 / 6865 / 1827
Регистрация: 18.10.2014
Сообщений: 17,398
03.09.2026, 23:58
Цитата Сообщение от u235 Посмотреть сообщение
TheCalligrapher, у вас явно квадратичная зависимость n2 времени работы от числа точек.
Вот времена выполнения моей функции count_violations (только ее) на моем компе для случайно сгенерированных в единичном кубе точек с минимальным расстоянием 1.e-3.

Code
1
2
3
4
5
6
7
8
9
10
100     : 80       : 0
500     : 1058     : 0
1000    : 3030     : 0
5000    : 13227    : 0
10000   : 26499    : 0
50000   : 145727   : 1
100000  : 265209   : 13
500000  : 3462816  : 345
1000000 : 9467919  : 1304
5000000 : 56699416 : 32460
Первое число - количество точек, второе число - время выполнения (в единицах winapi QueryPerformanceCounter), третье число - количество обнаруженных пар.

Где вы тут увидели квадратичную зависимость - в упор не вижу. Тут может быть зависимость от реализации хеш-таблицы (на нижнем конце), зависимость от количества найденных пар (на верхнем) и прочий дребезг, но не более того.

Добавлено через 38 минут
Цитата Сообщение от u235 Посмотреть сообщение
Да, все так, можете умножить время работы питоновского скрипта на 3, но сложность алгоритма от этого не поменяется.
Да, но не забываем, что задача подсчета и задача перечисления - это разные задачи, даже если асимптотика общего случая у них может совпадать. Квадратичная зависимость от количества пар в задаче перечисления - неизбежна, а вот в задаче подсчёта - допускает весомые локальные оптимизации.

В качестве экстремального примера: n точек в круге заданного минимального диаметра - это сразу n(n - 1)/2 пар без необходимости выполнения явного измерения расстояния в парах и подсчета. А вот задаче перечисления это не помогает.

(Это, кстати, можно было бы использовать при выборе шага сетки в рамках моего варианта, если бы нас интересовал лишь подсчет)
0
1980 / 836 / 115
Регистрация: 01.10.2012
Сообщений: 5,222
Записей в блоге: 2
04.09.2026, 21:24  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Удаление? Удаление здесь присутствует лишь в иллюстративных целях, не говоря уже о том, что "уточнённая" постановка задачи вообще не предполагает никакого удаления.
Пусть точки хранятся в обычном std::vector, тогда напрашивается

- пристроить к каждой точке флажок и, вместо реального удаления, как сейчас, взводить этот флажок. Точку с флажком на близость не проверять. А после обсчета всех точек/кубов выполнить удаление одним проходом, типа remove_if

Увы, это будет работать на одном потоке, но для многопоточной реализации такой алгоритм не годится. Тогда какой годится? Не то чтобы сразу же многопоточность, но готовиться к ней надо


И еще интересный момент, пусть за рамками стартового поста. Если данные удаляются, то все ссылки на них должны быть вычищены. Кубик имеет 24 точки (вертекса) и 6 фейсов

{ 0, 1, 2, 3 }, { 4, 5, 6, 7 }, { 8, 9, 10, 11 },
{ 12, 13, 14, 15 }, { 16, 17, 18, 19 }, { 20, 21, 22, 23 }

Напр первая грань - 4-угольник из точек с индексами { 0, 1, 2, 3 } и.т.п. Если мы удаляем точку 3 (например), то вместо нее должен быть подставлен другой индекс из оставшихся, необязательно тоже 3. Др словами wireframe (проволочный каркас) кубика с 8 точками должен рисоваться так же как и с исходными 24

Ну это если есть (здоровый) интерес, в стартовый пост это не входит
0
05.09.2026, 19:03

Не по теме:

Цитата Сообщение от u235 Посмотреть сообщение
Ваша программа для 100000 точек у меня на телефоне работает примерно минуту.
А питоновский скрипт с использованием KD-tree - около 1 секунды.
Для чего-то серьезного однозначно нужно использовать ваш питоновский скрипт или иные готовые решения. Но поскольку эта тема не для серьезного дела, то годится даже самый медленный код, лишь бы он выглядел по-умному и самое главное, чтобы ТС был доволен (а он известный любитель лисапедов с ушатанными shimano)

0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13233 / 6865 / 1827
Регистрация: 18.10.2014
Сообщений: 17,398
05.09.2026, 22:42

Не по теме:

Это не более чем старпёровское интуитивное неприятие O(1) поисковой производительности хэш-таблиц. Я тоже помню, как когда-то, гордо загруженный ахоульмановскими сортировками, сбалансированными деревьями, и прочими высушенными донельзя логарифмами, я, a wee lad, с отвисшей челюстью, глазами как блюдца и желанием закричать "Вы все вретиии!" смотрел на заявления о том, что хэш-таблица реализует ассоциативный массив за невероятное O(1). Но, как ни вертись, со временем понимание приходит. И вот уже дорогие нашему сердцу, элегантные в своей остроумности "разделяй-и-властвуй" заменяются на "тупейшие" и лежащие на поверхности идеи разбрасывания данных по хэшированным ведрам. Дело доходит даже до того, что источники перестают тратить время и место на упоминание древесной классики, а целиком и полностью фокусируются на хэшированных подходах, так как последние кроют первые, как бык овцу (см. ссылку). Но это вот интуитивное неприятие волшебного O(1) еще долго никуда не денется, потому обскурантисты будут продолжать пихать всякие KD-деревья в те темы, к которых они уже давно совершенно неуместны и в которых у них нет никаких шансов.



Кстати, так как, согласно объяснениям TC, понятие "расстояния между точками" не имеет самостоятельной абсолютной ценности, а является лишь способом черно-белого разделения точек на "близко-не близко", можно подумать о том, чтобы заменить метрику расстояния с евклидовой L2 на чебышевскую Linf. Круг станет осеориентированным квадратом, понятие "близко-не близко" для заявленных целей исказится при этом незначительно, а вот возможностей для оптимизации алгоритма на прямоугольной сетке станет больше. Хотя, опять же, особенно ярко блистать эти оптимизации будет скорее в задаче подсчета, а ТС нужно решение задачи перечисления...
0
1980 / 836 / 115
Регистрация: 01.10.2012
Сообщений: 5,222
Записей в блоге: 2
06.09.2026, 13:30  [ТС]

Не по теме:

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
смотрел на заявления о том, что хэш-таблица реализует ассоциативный массив за невероятное O(1).
Достоинства хеша часто преувеличиваются, хотя, несомненно, достоинства есть. В начале нулевых (могу путать) я пытался ускорить "поиск 26 соседей", но ничего особенного не добился, только раза в полтора, а кубы стали пожирнее. Как ни крути, а хеш-ключ строить надо, да и коллизии все-таки имеются. А главное - кратность 26, тут и тормозит
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
потому обскурантисты будут продолжать пихать всякие KD-деревья в те темы, к которых они уже давно совершенно неуместны и в которых у них нет никаких шансов.
Возможно Вы просто не знакомы с этим классическим, гениальным (не побоюсь этого слова) алгоритмом kd-tree, иначе Вы бы так не говорили. При желании можно вообще обойтись без всяких дополнительных данных (кубы с точками и др), а лишь "отсортировать" исходные данные. Но исходный контейнер месить обычно нельзя, поэтому практичнее потратиться на массив указателей + 2 бита на элемент для хранения оси деления (необязательно, ось можно автоматом, будет только немного слабее). И все, это самое компактное дерево. И с производительностью очень неплохо, напр в данной задаче kd-tree заломает хеш как драного кота.

Еще раз замечу что kd-tree - отличный, но не единственный вариант, есть и более простое решение


Цитата Сообщение от TheCalligrapher Посмотреть сообщение
ТС нужно решение задачи перечисления..
ТС хотел поговорить о том что в названии темы "Удалить близкие точки", не надо все сводить к "поиску ближних точек". Да, поиск есть/актуален, но не только. Удалять-то как будем? Дергать вектор за вымя? "Подстелить соломки" std::list? Серьезнее, товарищи, и многопоточность не забываем.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13233 / 6865 / 1827
Регистрация: 18.10.2014
Сообщений: 17,398
07.09.2026, 03:15
Цитата Сообщение от Igor3D Посмотреть сообщение
Возможно Вы просто не знакомы с этим классическим, гениальным (не побоюсь этого слова) алгоритмом kd-tree, иначе Вы бы так не говорили.
(Вы, очевидно, пытаетесь меня насмешить. Я ценю эти усилия, но я уже давно отсмеялся над подлобным юмором.)

KD-tree, в обмен на свою (сравнительную) громоздкость и накладные расходы, дает вам лишь одно преимущество в контексте таких задач: единожды построенное KD-tree можно использовать много раз для решения задачи поиска точек для разных расстояний. То есть параметры препроцессированной структуры данных никак не зависят от того, для какого расстояния мы потом будем решать задачу. В подходе же с сеткой расстояние нужно знать заранее. Но нам в контексте этой задачи это преимущество совершенно не нужно. Потому KD-tree и является таким неповоротливым overkill-ом для ее решения.

Однако стоит заметить еще и то, что исходные алгоритмы по ссылке не являются алгоритмами решения именно данной задачи, а являются алгоритмами решения задачи поиска ближайшей пары точеку, где расстояние заранее неизвестно. И даже там авторы предпринимали усилия для нахождения минимального расстояния в случайной выборке из n пар точек, чтобы потом использовать его для построения сетки и решения всей задачи. То есть даже при заранее неизвестном расстоянии, такой алгоритм все равно работает за ожидаемое время O(n).

Это просто одна из тех задач, где "волшебное" поведение хэш-таблиц действительно срабатывает. Просто оставьте KD-trees для тех задач, где они уместны. А здесь у них нет никаких шансов.
0
1980 / 836 / 115
Регистрация: 01.10.2012
Сообщений: 5,222
Записей в блоге: 2
07.09.2026, 18:24  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
KD-tree, в обмен на свою (сравнительную) громоздкость и накладные расходы
Напротив, kd-tree - самая компактная, минимальная структура поиска, о чем только что говорилось. А вот Ваша реализация "жирновата". Обычно "близких" точек мало, фактически Вы создаете "куб" на каждую точку. Это (еще) допустимо, но расходно. Выходит немалый хеш, а ведь его std:: реализация (unordered_map), мягко говоря, небезупречна (об этом здесь разговор недавно был)
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Это просто одна из тех задач, где "волшебное" поведение хэш-таблиц действительно срабатывает. Просто оставьте KD-trees для тех задач, где они уместны. А здесь у них нет никаких шансов.
Ну переубедить Вас нереально, тратить на это время не стоит Пусть каждый остается при своем мнении, но с задачей/удалением что?
Цитата Сообщение от u235 Посмотреть сообщение
А питоновский скрипт с использованием KD-tree - около 1 секунды.
Python
1
2
kd_tree = KDTree(points)
pairs = kd_tree.query_pairs(r=0.01)
Хорошо, пусть так. Ну и что мне делать с полученным pairs? Мучительно строить какие-то графы? Или как?
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13233 / 6865 / 1827
Регистрация: 18.10.2014
Сообщений: 17,398
07.09.2026, 19:17
Цитата Сообщение от Igor3D Посмотреть сообщение
А вот Ваша реализация "жирновата".
Моя реализация к делу не относится вообще, не надо за нее постоянно так отчаянно хвататься. Как я сказал выше, моя реализация - это лишь иллюстрация. Речь идет об алгоритме, а не моей реализации.

Цитата Сообщение от Igor3D Посмотреть сообщение
Обычно "близких" точек мало, фактически Вы создаете "куб" на каждую точку.
Откуда вы это берете? Не надо выдумывать: никаких "кубов на каждую точку" не создается даже в моей реализации. Совершенно очевидно, что количество материализованных элементов сетки меньше либо равно количеству входных точек.

Цитата Сообщение от Igor3D Посмотреть сообщение
Ну переубедить Вас нереально, тратить на это время не стоит Пусть каждый остается при своем мнении
А я здесь совершенно ни при чем. Приведенные мною алгоритмы и из анализ известны с семидесятых годов. И "мнений" тут тоже никаких нет. Только факты.

P.S. Кстати, опытный читатель также заметит тот факт, что в наших тестах мы использовали случайно сгенерированные и равномерно распределенные точки. Это играет на руку "древесных" реализаций тем, что построенное из таких точек дерево уже само собой получится сбалансированным. Даже если использованная реализация содержит усилия по балансировке строящегося дерева, они все равно будут либо дешевыми, либо вообще практически нулевыми из-за "хорошести" входного потока точек (я не заглядывал в реализацию этого KD-дерева и не могу судить о том, сколько усилий там тратится на банансировку). Но в реальной задаче (в частности - в вашей) точки "хорошими" не будут. Скорее наоборот, они будут проявлять тенденцию к кластеризации. Сеточный алгоритм, однако, совершенно не чувствителен к этому.
0
5534 / 2887 / 573
Регистрация: 07.11.2019
Сообщений: 4,813
07.09.2026, 21:40
Igor3D, если хотели удалить, то удаляйте.

Кликните здесь для просмотра всего текста

Не по теме:

Python
1
2
3
4
5
6
7
8
9
10
 import numpy as np
from scipy.spatial import KDTree
points=np.random.random((1000000, 3))
print(f'num points: {points.shape[0]}')
kd_tree = KDTree(points)
pairs = kd_tree.query_pairs(r=0.001)
print(f'num pairs: {len(pairs)}')
id=np.array(list(pairs))[:,0]
points=np.delete(points, id, axis=0)
print(f'num points after delete: {points.shape[0]}')
на телефоне у меня как-то так:
Code
1
2
3
4
5
6
7
8
~ $ time python test.py
num points: 1000000
num pairs: 2155
num points after delete: 997847
 
real    0m4.666s
user    0m3.543s
sys     0m0.455s


pairs - упорядоченные пары индексов точек, у которых расстояние менее заданого.
Т.е. можно удалить только точки, соответствующие первым индексам из пар (как я и сделал). Или вообще все индексы (и первые, и вторые). В изначальном вопросе это специально не оговаривается. Также не оговаривается случай, если, например, три или более точки находятся близко, какие из них удалять?
0
737 / 704 / 110
Регистрация: 29.05.2015
Сообщений: 4,350
08.09.2026, 08:16
Цитата Сообщение от u235 Посмотреть сообщение
Также не оговаривается случай, если, например, три или более точки находятся близко, какие из них удалять?
А в задании не указано удалить так, чтобы в результате их осталось максимальное количество?
0
Нарушитель
Эксперт функциональных языков программированияЭксперт С++
6341 / 3075 / 1064
Регистрация: 01.06.2021
Сообщений: 11,826
08.09.2026, 12:25
u235, а мне вот интересно, какое может быть прикладное значение у данного задания. Интересует ваше мнение, возможно вы уже сталкивались с этим на практике?

Вот в этой симуляции https://royalxxx.itch.io/abstraction-benchmark изначально я удалял точки, которые отдалялись на некое расстояние. Однако, поскольку в игровых движках добавление и удаление объектов на сцену тяжелая и ресурсозатратная операция, которая понижает fps, я перестал удалять точки, а начал их просто перемещать (хотя, визуально кажется, что точки уничтожаются, но это не так). Грубо говоря, я реализовал паттерн объектного пула, чтобы переиспользовать ресурсы.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
08.09.2026, 12:25

Определить две самые близкие к началу координат точки из n имеющихся
Здравствуйте, подскажите пожалуйста как можно перебрать весь вектор pair и выбрать оттуда и две...

Значения близкие к нулю
Накидал табулирование функции. Одна только проблемка: при задании достаточно малого шага, начиная с...

Определить наиболее близкие из точек координаты которых записаны в двумерный массив
Дано натуральное число n. С помощью двумерного действительного числового массива i=1,2; j=1,...,n...

Найти близкие по значению элементы матрицы
Дана матрица А размером M x N , в которой нет повторяющихся элементов. Нужно найти наиболее близкие...

Вывести все возможные числа, которые при возведении в квадрат дадут результаты, наиболее близкие к N
На вход поступает неотрицательное число N. Необходимо вывести все возможные числа, которые при...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
GitHub Copilot в JetBrains: модель по умолчанию, Fix и контроль MCP
and_y87 12.10.2026
10 октября 2026 года GitHub обновил Copilot для JetBrains: добавил настройки стартовой модели, исправления из диагностики и управление автозапуском MCP. Поддержка IDE 2025. 1 прекращена — требуется. . .
День 5 из 28: Codex подсказывает следующий запрос
and_y87 12.10.2026
9 октября 2026 года OpenAI запустила бету Composer predictions — подсказок следующего сообщения в текущем диалоге Codex. Это помощь с формулировкой запроса, а не автоматическое продолжение задачи. . . .
Запустил конкурс "тем и промптов для текстовых квестов созданных почти чисто ИИ"
Adler 06.10.2026
Всем привет! За последние три-четыре дня я создал более 16 текстовых квестовых игр используя преимущественно по одному запросу к ИИ на игру. Мне так понравилось смотреть все ветки/ сцены во всех. . .
ИИ не может найти нужный язык в списке
Supersumestria 05.10.2026
Я ему даю вот такое изображение и прошу найти и подчеркнуть немецкий язык. Возвращает он вот это: https:/ / i. **********/ vqBWLe2. png Нужную строчку в 3й колонке просто выдумал. . Это. . .
Новая последняя моя музыка в SUNO
zorxor 05.10.2026
Здравствуйте, дорогие мои друзья! С большой радостью я хотел бы представить вам свою новую последнею музыку, которую сгенерировала мне по моей просьбе нейросеть SUNO. С уважением, zorxor. Это. . .
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru