के बाद प्रश्न
उपयोग दो Red-Black Tree या Skip_list नक्शे को अपडेट करें। दोनों कॉम्पैक्ट स्व-संतुलन डेटा संरचनाएं हैं जो आपको खोज, सम्मिलित करने और हटाने के लिए ओ (लॉग एन) समय देते हैं। एक नक्शा प्रत्येक बिंदु के लिए एक्स-समन्वय का उपयोग एक कुंजी के रूप में करेगा और बिंदु स्वयं को एक मान के रूप में और दूसरा वाई-समन्वय का उपयोग एक कुंजी के रूप में करेगा और बिंदु स्वयं मान के रूप में करेगा।
एक व्यापार-बंद के रूप में, मैं सलाह देता हूं कि शुरुआत में कर्सर के चारों ओर खोज क्षेत्र को एक वर्ग द्वारा प्रतिबंधित करें। सही मिलान के लिए वर्ग की तरफ कर्सर के चारों ओर अपने "संवेदनशीलता सर्कल" के व्यास के बराबर होना चाहिए। यदि आप कर्सर से 10 पिक्सेल त्रिज्या के भीतर केवल निकटतम पड़ोसी में रूचि रखते हैं तो स्क्वायर पक्ष को 20px होना चाहिए। वैकल्पिक विकल्प के रूप में , यदि आप निकटता के बावजूद निकटतम पड़ोसी के बाद हैं तो आप कर्सर के सापेक्ष फर्श और छत का मूल्यांकन करके सीमा को गतिशील रूप से ढूंढने का प्रयास कर सकते हैं।
फिर सीमाओं के भीतर वाले नक्शे से बिंदुओं के दो सबसेट पुनर्प्राप्त करें, दोनों उप सेटों के भीतर केवल अंक शामिल करने के लिए विलय करें।
परिणाम के माध्यम से लूप, प्रत्येक बिंदु (डीएक्स^2 + डीई^2, स्क्वायर रूट से बचें क्योंकि आप वास्तविक दूरी में रुचि नहीं रखते हैं, केवल निकटता), निकटतम पड़ोसी को ढूंढें।
निकटतम पड़ोसी से दूरी मापने के लिए निकटता आंकड़े से रूट वर्ग लें, देखें कि यह "संवेदनशीलता सर्कल" के त्रिज्या से अधिक है, यदि इसका मतलब है कि सर्कल के भीतर कोई बिंदु नहीं है।
मैं हर दृष्टिकोण कुछ बेंचमार्क करने का सुझाव देता हूं; अनुकूलन के साथ शीर्ष पर जाना दो आसान है। मेरे मामूली हार्डवेयर (डुओ कोर 2) पर 10k अंकों के भीतर निकटतम पड़ोसी की भद्दा एकल-थ्रेडेड खोज जावा में 350 मिलीसेकंड लेती है। जब तक कि संपूर्ण यूआई री-एक्शन टाइम 100 मिलीसेकंड के नीचे होता है, यह एक उपयोगकर्ता के लिए तत्काल प्रतीत होता है, यह ध्यान में रखते हुए भी भद्दा खोज आपको पर्याप्त तेज़ प्रतिक्रिया दे सकती है।
जेनेरिक समाधान
सबसे कुशल डेटा संरचना एल्गोरिथ्म आप का उपयोग करने की योजना बना रहे हैं, समय अंतरिक्ष व्यापार बंद और अंक की उम्मीद रिश्तेदार वितरण पर निर्भर करता है यदि अंतरिक्ष कोई मुद्दा नहीं है तो स्क्रीन पर प्रत्येक बिंदु के लिए निकटतम पड़ोसी की पूर्व-गणना करने का सबसे प्रभावी तरीका हो सकता है और फिर स्क्रीन का प्रतिनिधित्व करने वाले दो-आयामी सरणी में निकटतम पड़ोसी अद्वितीय आईडी स्टोर कर सकता है।
यदि समय एक साधारण 2 डी सरणी में 10K अंक संग्रहीत करने और हर बार भद्दा खोज करने में कोई समस्या नहीं है, यानी प्रत्येक बिंदु के माध्यम से लूपिंग और दूरी की गणना करना विकल्प को बनाए रखने के लिए एक अच्छा और सरल आसान हो सकता है। http://dimacs.rutgers.edu/Workshops/MiningTutorial/pindyk-slides.ppt
विभिन्न निकटतम पड़ोसी खोज एल्गोरिदम के लिए अच्छा विस्तृत सामग्री की एक गुच्छा:
दोनों के बीच व्यापार गत के एक नंबर के लिए, यहाँ उपलब्ध विभिन्न निकटतम पड़ोसी खोजें विकल्पों पर एक अच्छी प्रस्तुति है http://simsearch.yury.name/tutorial.html, बस एक चुनना है कि आपकी जरूरतों के अनुरूप सबसे अच्छा है।
इसलिए डेटा संरचना का मूल्यांकन करना वास्तव में असंभव है एल्गोरिदम से अलगाव है जो बदले में कार्य बाधाओं और प्राथमिकताओं के बिना किसी अच्छे विचार के मूल्यांकन करना मुश्किल है।
नमूना जावा कार्यान्वयन
import java.util.*;
import java.util.concurrent.ConcurrentSkipListMap;
class Test
{
public static void main (String[] args)
{
Drawing naive = new NaiveDrawing();
Drawing skip = new SkipListDrawing();
long start;
start = System.currentTimeMillis();
testInsert(naive);
System.out.println("Naive insert: "+(System.currentTimeMillis() - start)+"ms");
start = System.currentTimeMillis();
testSearch(naive);
System.out.println("Naive search: "+(System.currentTimeMillis() - start)+"ms");
start = System.currentTimeMillis();
testInsert(skip);
System.out.println("Skip List insert: "+(System.currentTimeMillis() - start)+"ms");
start = System.currentTimeMillis();
testSearch(skip);
System.out.println("Skip List search: "+(System.currentTimeMillis() - start)+"ms");
}
public static void testInsert(Drawing d)
{
Random r = new Random();
for (int i=0;i<100000;i++)
d.addPoint(new Point(r.nextInt(4096),r.nextInt(2048)));
}
public static void testSearch(Drawing d)
{
Point cursor;
Random r = new Random();
for (int i=0;i<1000;i++)
{
cursor = new Point(r.nextInt(4096),r.nextInt(2048));
d.getNearestFrom(cursor,10);
}
}
}
// A simple point class
class Point
{
public Point (int x, int y)
{
this.x = x;
this.y = y;
}
public final int x,y;
public String toString()
{
return "["+x+","+y+"]";
}
}
// Interface will make the benchmarking easier
interface Drawing
{
void addPoint (Point p);
Set<Point> getNearestFrom (Point source,int radius);
}
class SkipListDrawing implements Drawing
{
// Helper class to store an index of point by a single coordinate
// Unlike standard Map it's capable of storing several points against the same coordinate, i.e.
// [10,15] [10,40] [10,49] all can be stored against X-coordinate and retrieved later
// This is achieved by storing a list of points against the key, as opposed to storing just a point.
private class Index
{
final private NavigableMap<Integer,List<Point>> index = new ConcurrentSkipListMap <Integer,List<Point>>();
void add (Point p,int indexKey)
{
List<Point> list = index.get(indexKey);
if (list==null)
{
list = new ArrayList<Point>();
index.put(indexKey,list);
}
list.add(p);
}
HashSet<Point> get (int fromKey,int toKey)
{
final HashSet<Point> result = new HashSet<Point>();
// Use NavigableMap.subMap to quickly retrieve all entries matching
// search boundaries, then flatten resulting lists of points into
// a single HashSet of points.
for (List<Point> s: index.subMap(fromKey,true,toKey,true).values())
for (Point p: s)
result.add(p);
return result;
}
}
// Store each point index by it's X and Y coordinate in two separate indices
final private Index xIndex = new Index();
final private Index yIndex = new Index();
public void addPoint (Point p)
{
xIndex.add(p,p.x);
yIndex.add(p,p.y);
}
public Set<Point> getNearestFrom (Point origin,int radius)
{
final Set<Point> searchSpace;
// search space is going to contain only the points that are within
// "sensitivity square". First get all points where X coordinate
// is within the given range.
searchSpace = xIndex.get(origin.x-radius,origin.x+radius);
// Then get all points where Y is within the range, and store
// within searchSpace the intersection of two sets, i.e. only
// points where both X and Y are within the range.
searchSpace.retainAll(yIndex.get(origin.y-radius,origin.y+radius));
// Loop through search space, calculate proximity to each point
// Don't take square root as it's expensive and really unneccessary
// at this stage.
//
// Keep track of nearest points list if there are several
// at the same distance.
int dist,dx,dy, minDist = Integer.MAX_VALUE;
Set<Point> nearest = new HashSet<Point>();
for (Point p: searchSpace)
{
dx=p.x-origin.x;
dy=p.y-origin.y;
dist=dx*dx+dy*dy;
if (dist<minDist)
{
minDist=dist;
nearest.clear();
nearest.add(p);
}
else if (dist==minDist)
{
nearest.add(p);
}
}
// Ok, now we have the list of nearest points, it might be empty.
// But let's check if they are still beyond the sensitivity radius:
// we search area we have evaluated was square with an side to
// the diameter of the actual circle. If points we've found are
// in the corners of the square area they might be outside the circle.
// Let's see what the distance is and if it greater than the radius
// then we don't have a single point within proximity boundaries.
if (Math.sqrt(minDist) > radius) nearest.clear();
return nearest;
}
}
// Naive approach: just loop through every point and see if it's nearest.
class NaiveDrawing implements Drawing
{
final private List<Point> points = new ArrayList<Point>();
public void addPoint (Point p)
{
points.add(p);
}
public Set<Point> getNearestFrom (Point origin,int radius)
{
int prevDist = Integer.MAX_VALUE;
int dist;
Set<Point> nearest = Collections.emptySet();
for (Point p: points)
{
int dx = p.x-origin.x;
int dy = p.y-origin.y;
dist = dx * dx + dy * dy;
if (dist < prevDist)
{
prevDist = dist;
nearest = new HashSet<Point>();
nearest.add(p);
}
else if (dist==prevDist) nearest.add(p);
}
if (Math.sqrt(prevDist) > radius) nearest = Collections.emptySet();
return nearest;
}
}
स्रोत
2009-12-17 10:58:43
यह मदद कर सकता है: http://en.wikipedia.org/wiki/Nearest_neighbor_search – Aziz
पुष्टि करें कि उपयोगकर्ता केवल लाइन सेगमेंट एंड पॉइंट संशोधित कर सकता है और अंकों की संख्या एन (उदा। "10000") पर स्थिर है। अधिकांश डेटा संरचना एल्गोरिदम * सामान्य * उपयोग के लिए एसिम्प्टोटिक प्रदर्शन गारंटी प्रदान करने के लिए डिज़ाइन किए गए हैं। – alphazero
स्पष्ट, 10000 यह दिखाने के लिए लगभग संख्या थी कि चित्र बड़े हो सकते हैं, उपयोगकर्ता वांछित लाइनों को जोड़ और हटा सकते हैं, मैं प्रभावी रूप से एक साधारण वेक्टर ड्राइंग प्रोग्राम बनाने और प्रदर्शन को एक प्रमुख विचार बनाने के लिए देख रहा हूं। – Tom