Quadtree với các bản sao


10

Tôi đang thực hiện một phần tư. Đối với những người không biết cấu trúc dữ liệu này, tôi bao gồm mô tả nhỏ sau đây:

Một quadtree là một cấu trúc dữ liệu và nằm trong mặt phẳng Euclide gì một octree là trong một không gian 3 chiều. Một cách sử dụng phổ biến của tứ giác là lập chỉ mục không gian.

Để tóm tắt cách chúng hoạt động, một hình tứ giác là một bộ sưu tập - giả sử hình chữ nhật ở đây - với dung lượng tối đa và hộp giới hạn ban đầu. Khi cố gắng chèn một phần tử vào một phần tư đã đạt đến công suất tối đa của nó, phần tư được chia thành 4 phần tư (một biểu diễn hình học sẽ có diện tích nhỏ hơn bốn lần so với cây trước khi chèn); mỗi phần tử được phân phối lại trong các cây con theo vị trí của nó, nghĩa là. phía trên bên trái bị ràng buộc khi làm việc với hình chữ nhật.

Vì vậy, một phần tư là một chiếc lá và có ít yếu tố hơn khả năng của nó, hoặc một cây có 4 phần tư khi còn nhỏ (thường là tây bắc, đông bắc, tây nam, đông nam).

Mối quan tâm của tôi là nếu bạn cố gắng thêm các mục trùng lặp, có thể là cùng một phần tử nhiều lần hoặc một số phần tử khác nhau có cùng vị trí, tứ giác có vấn đề cơ bản với việc xử lý các cạnh.

Chẳng hạn, nếu bạn làm việc với một hình tứ giác có dung lượng 1 và hình chữ nhật đơn vị làm hộp giới hạn:

[(0,0),(0,1),(1,1),(1,0)]

Và bạn thử chèn hai lần một hình chữ nhật, giới hạn phía trên bên trái là gốc: (hoặc tương tự nếu bạn thử chèn N + 1 lần trong một hình tứ giác có dung lượng N> 1)

quadtree->insert(0.0, 0.0, 0.1, 0.1)
quadtree->insert(0.0, 0.0, 0.1, 0.1)

Chèn đầu tiên sẽ không phải là một vấn đề: Chèn đầu tiên

Nhưng sau đó, lần chèn đầu tiên sẽ kích hoạt một phân mục (vì dung lượng là 1): Chèn thứ hai, phân khu thứ nhất

Cả hai hình chữ nhật do đó được đặt trong cùng một cây con.

Sau đó, một lần nữa, hai phần tử sẽ đến trong cùng một phần tư và kích hoạt một phân nhóm Chèn thứ hai, phân khu thứ hai

Và cứ tiếp tục như vậy, phương thức phân chia sẽ chạy vô thời hạn bởi vì (0, 0) sẽ luôn nằm trong cùng một cây con trong số bốn được tạo, nghĩa là xảy ra sự cố đệ quy vô hạn.

Có thể có một tứ giác với các bản sao? (Nếu không, người ta có thể thực hiện nó như một Set)

Làm thế nào chúng ta có thể giải quyết vấn đề này mà không phá vỡ hoàn toàn kiến ​​trúc của một hình tứ giác?


Bạn muốn nó cư xử như thế nào? Bạn đang thực hiện nó, vì vậy bạn phải quyết định hành vi nào là đúng cho bạn. Có thể mỗi tọa độ duy nhất có thể là một danh sách các yếu tố tại tọa độ đó. Có thể điểm của bạn bị hạn chế là duy nhất. Bạn biết những gì bạn cần, và chúng tôi không.
Vô dụng

@ Vô dụng Điều đó rất đúng. Tuy nhiên, đã có khá nhiều nghiên cứu về chủ đề này và tôi cũng không thực sự muốn phát minh lại cái bánh xe. TBH Tôi vẫn không biết liệu câu hỏi này có thuộc về SO nhiều hơn, đối với các lập trình viên.SE, trên gamedev.SE hay thậm chí là về toán học .Ee
Pierre Arlaud

Câu trả lời:


3

Bạn đang thực hiện cấu trúc dữ liệu, vì vậy bạn phải đưa ra quyết định thực hiện.

Trừ khi phần tư có một cái gì đó cụ thể để nói về tính duy nhất - và tôi không biết rằng nó có - đây là một quyết định thực hiện. Nó trực giao với định nghĩa của một phần tư và bạn có thể chọn xử lý nó theo cách bạn muốn. Bộ tứ cho bạn biết cách chèn và cập nhật khóa, nhưng không phải là chúng phải là duy nhất hay bạn có thể đính kèm vào mỗi nút.

Đưa ra quyết định thực hiện không phải là phát minh lại bánh xe , ít nhất là không hơn là viết việc thực hiện của riêng bạn ở nơi đầu tiên.

Để so sánh, thư viện chuẩn C ++ cung cấp một bộ duy nhất, một bộ đa không duy nhất, một bản đồ duy nhất (về cơ bản là một bộ các cặp giá trị khóa được đặt hàng & chỉ được so sánh bằng khóa) và một bộ đa phương thức không duy nhất. Tất cả chúng thường được triển khai bằng cách sử dụng cùng một cây đỏ đen và không ai phá vỡ kiến ​​trúc , đơn giản vì định nghĩa của cây đỏ đen không có gì để nói về tính duy nhất của các khóa hoặc các loại được lưu trữ trong các nút lá.

Cuối cùng, nếu bạn nghĩ rằng có nghiên cứu về điều này, hãy tìm nó, và sau đó chúng ta có thể thảo luận về nó. Có thể có một số bất biến tứ giác mà tôi đã bỏ qua, hoặc một số ràng buộc bổ sung cho phép hiệu suất tốt hơn.


Vấn đề của tôi là tôi không thể tìm thấy bất kỳ tài liệu nào nói rằng tính duy nhất là một yêu cầu. Tuy nhiên, nếu bạn đã xem ví dụ của tôi, bạn có thể thấy đó là một vấn đề thực sự nếu bạn bao gồm nhiều lần cùng một yếu tố.
Pierre Arlaud

Đối với các loại cấu trúc cây, đôi khi nút có giá trị cũng được cung cấp trường "đếm" chỉ tăng và giảm cho các bản sao?
J Trana

2

Tôi nghĩ rằng có một sự hiểu lầm ở đây.

Theo tôi hiểu, mỗi nút tứ giác chứa một giá trị được lập chỉ mục bởi một điểm. Nói cách khác, nó chứa bộ ba (x, y, value).

Nó cũng chứa 4 con trỏ tới các nút con, có thể là null. Có một mối quan hệ thuật toán giữa các khóa và các liên kết con.

Chèn của bạn sẽ trông như thế này.

quadtree->insert(0.0, 0.0, value1)
quadtree->insert(0.0, 0.0, value2)

Chèn đầu tiên tạo một nút (cha) và chèn một giá trị vào nó.

Chèn thứ hai tạo một nút con, liên kết với nó và chèn một giá trị vào nó (có thể xảy ra giống với giá trị đầu tiên).

Nút con nào được khởi tạo phụ thuộc vào thuật toán. Nếu thuật toán có dạng [x) và không gian tọa độ nằm trong phạm vi [0,1) thì mỗi đứa trẻ sẽ trải rộng phạm vi [0,0,5) và điểm sẽ được đặt trong con NA.

Tôi thấy không có đệ quy vô hạn.


Vì vậy, bạn đang nói cách của tôi để phân phối lại các nút cho các phần tư con khi chia nhỏ là điều gì sai với ý nghĩa của tôi?
Pierre Arlaud

Có lẽ vấn đề là bạn đang cố gắng di chuyển một giá trị từ nơi nó (ở cha mẹ) đến một nơi tốt hơn (ở một đứa trẻ). Đây thực sự không phải là cách nó được thực hiện. Giá trị là tốt nơi nó là. Nhưng điều đó dẫn đến kết quả thú vị là hai điểm giống nhau có thể được đặt trong các nút khác nhau (nhưng luôn luôn liên quan đến cha mẹ và con cái).
david.pfx

2

Độ phân giải phổ biến mà tôi đã gặp (trong các vấn đề về hình ảnh, không phải trong các trò chơi) là bỏ một trong những điểm, luôn luôn thay thế hoặc không bao giờ thay thế.

Tôi cho rằng điểm chính trong sự ủng hộ là nó dễ làm.


2

Tôi giả sử rằng bạn đang lập chỉ mục các phần tử có cùng kích thước, nếu không, cuộc sống trở nên phức tạp hoặc chậm hoặc cả hai

Một nút Quadtree không cần phải có dung lượng cố định. Công suất được sử dụng để

  • Cho phép mỗi nút cây có kích thước cố định trong bộ nhớ hoặc trên đĩa - không bắt buộc nếu nút cây chứa tập hợp các phần tử có kích thước thay đổi và bạn đang sử dụng hệ thống phân bổ không gian đối phó. (Ví dụ: các đối tượng java / c # trong bộ nhớ.)
  • Quyết định khi nào nên chia một nút.
    • Bạn chỉ có thể xác định lại quy tắc, để một nút được phân chia nếu nó chứa nhiều hơn các phần tử quận huyện niết, trong đó quận được xác định theo vị trí của các phần tử.
    • Hoặc sử dụng một phần tử hỗn hợp của người Viking, vì vậy nếu có nhiều phần tử tại cùng một vị trí, bạn giới thiệu một phần tử mới có chứa danh sách các phần tử nhân này.

2

Khi bạn đang xử lý các vấn đề về lập chỉ mục không gian, tôi thực sự khuyên bạn nên bắt đầu với hàm băm không gian hoặc sở thích cá nhân của tôi: lưới cũ đơn giản.

nhập mô tả hình ảnh ở đây

... và hiểu điểm yếu của nó trước khi chuyển sang cấu trúc cây cho phép biểu diễn thưa thớt.

Một trong những điểm yếu rõ ràng là bạn có thể lãng phí bộ nhớ vào rất nhiều ô trống (mặc dù lưới được triển khai thực hiện không nên yêu cầu nhiều hơn 32 bit cho mỗi ô trừ khi bạn thực sự có hàng tỷ nút để chèn). Một điều nữa là nếu bạn có các phần tử có kích thước vừa phải lớn hơn kích thước của một ô và thường kéo dài, thì, hàng chục ô, bạn có thể lãng phí rất nhiều bộ nhớ để chèn các phần tử cỡ trung bình đó vào nhiều ô hơn lý tưởng. Tương tự như vậy khi bạn thực hiện các truy vấn không gian, bạn có thể phải kiểm tra nhiều ô hơn, đôi khi nhiều hơn so với lý tưởng.

Nhưng điều duy nhất để tinh chỉnh với một lưới để làm cho nó tối ưu nhất có thể chống lại một đầu vào nhất định là cell size, điều đó không khiến bạn phải suy nghĩ nhiều và suy nghĩ, và đó là lý do tại sao đó là cấu trúc dữ liệu của tôi cho các vấn đề lập chỉ mục không gian cho đến khi tôi tìm thấy lý do không sử dụng nó. Thật đơn giản để thực hiện và không yêu cầu bạn phải sử dụng bất cứ thứ gì ngoài một đầu vào thời gian chạy.

Bạn có thể nhận được rất nhiều từ một lưới cũ đơn giản và tôi thực sự đã đánh bại rất nhiều triển khai cây bốn cây và cây kd được sử dụng trong phần mềm thương mại bằng cách thay thế chúng bằng một lưới cũ đơn giản (mặc dù chúng không nhất thiết phải là lưới được triển khai tốt nhất , nhưng các tác giả đã dành nhiều thời gian hơn rất nhiều so với 20 phút tôi dành để làm lưới điện). Đây là một điều nhỏ tôi đã nhanh chóng trả lời một câu hỏi ở nơi khác bằng cách sử dụng lưới để phát hiện va chạm (thậm chí không được tối ưu hóa thực sự, chỉ mất vài giờ làm việc và tôi đã phải dành phần lớn thời gian để tìm hiểu cách hoạt động của tính năng tìm đường để trả lời câu hỏi và đây cũng là lần đầu tiên tôi thực hiện phát hiện va chạm kiểu này):

nhập mô tả hình ảnh ở đây

Một điểm yếu khác của lưới (nhưng chúng là điểm yếu chung cho nhiều cấu trúc lập chỉ mục không gian) là nếu bạn chèn nhiều phần tử trùng hoặc trùng nhau, giống như nhiều điểm có cùng vị trí, chúng sẽ được chèn vào cùng một ô. ) và làm giảm hiệu suất khi đi qua ô đó. Tương tự như vậy nếu bạn chèn nhiều phần tử lớn , lớn hơn nhiều so với kích thước ô, chúng sẽ muốn được chèn vào một khối lượng ô và sử dụng rất nhiều bộ nhớ và làm giảm thời gian cần thiết cho các truy vấn không gian trên bảng .

Tuy nhiên, hai vấn đề tức thời ở trên với các yếu tố trùng khớp và lớn thực sự là vấn đề đối với tất cả các cấu trúc lập chỉ mục không gian. Lưới cũ đơn giản thực sự xử lý các trường hợp bệnh lý này tốt hơn một chút so với nhiều trường hợp khác vì ít nhất nó không muốn phân chia các tế bào theo cách đệ quy nhiều lần.

Khi bạn bắt đầu với lưới và tìm đường đến một cái gì đó như cây bốn hoặc cây KD, thì vấn đề chính bạn muốn giải quyết là vấn đề với các phần tử được chèn vào quá nhiều ô, có quá nhiều ô và / hoặc phải kiểm tra quá nhiều ô với loại biểu diễn dày đặc này.

Nhưng nếu bạn nghĩ về một cây bốn lá như là một tối ưu hóa trên lướiđối với các trường hợp sử dụng cụ thể, thì vẫn giúp nghĩ ra ý tưởng về "kích thước ô tối thiểu", để hạn chế độ sâu của phân chia đệ quy của các nút hình tứ giác. Khi bạn làm điều đó, trường hợp xấu nhất của cây bốn lá vẫn sẽ suy giảm thành lưới dày đặc ở các lá, chỉ kém hiệu quả hơn lưới vì nó sẽ cần thời gian logarit để làm việc theo cách của bạn từ gốc đến ô lưới thay vì thời gian không đổi Tuy nhiên, việc nghĩ đến kích thước ô tối thiểu đó sẽ tránh được kịch bản vòng lặp / đệ quy vô hạn. Đối với các phần tử lớn, cũng có một số biến thể thay thế như các cây tứ giác lỏng lẻo không nhất thiết phải chia đều và có thể có AABB cho các nút con trùng nhau. Các BVH cũng thú vị như các cấu trúc lập chỉ mục không gian không chia nhỏ các nút của chúng. Đối với các yếu tố trùng hợp với cấu trúc cây, điều chính là chỉ áp đặt giới hạn cho phân mục (hoặc như những người khác đề xuất, chỉ cần từ chối chúng hoặc tìm cách đối xử với chúng như thể chúng không đóng góp vào số lượng phần tử duy nhất trong một chiếc lá khi xác định khi nào chiếc lá nên chia nhỏ). Cây Kd cũng có thể hữu ích nếu bạn dự đoán các yếu tố đầu vào có nhiều yếu tố trùng khớp, vì bạn chỉ cần xem xét một chiều khi xác định xem một nút có nên phân chia trung bình hay không.


Là một bản cập nhật cho tứ giác, một người nào đó đã hỏi một câu hỏi khá rộng (nhưng tôi thích những câu hỏi đó) về cách làm cho chúng hiệu quả để phát hiện va chạm, và cuối cùng tôi đã đổ hết vào đó về cách tôi thực hiện chúng. Nó cũng sẽ trả lời câu hỏi của bạn: stackoverflow.com/questions/41946007/ từ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.