Cách hiệu quả nhất về không gian để thực hiện cấu trúc dữ liệu đồ thị là gì?


14

Tôi thường triển khai các biểu đồ dưới dạng các danh sách được liên kết đôi nhưng điều này khá không hiệu quả theo kinh nghiệm của tôi vì tôi cần k con trỏ / tham chiếu cho k hàng xóm, vì vậy đối với một biểu đồ không bị chặn tôi sẽ có ~ 2k liên kết hàng xóm trong danh sách nếu toán của tôi đúng. Có cách nào tốt hơn để tiết kiệm không gian? Tôi biết rằng một số liên kết có thể được tạo thành số ít nếu biểu đồ được định hướng nhưng có cách nào để thực hiện công việc này tốt hơn không?

Câu trả lời:


12

Chà, nếu hiệu quả không gian là tất cả những gì bạn quan tâm thì cấu trúc dữ liệu nén sẽ là tốt nhất - nhưng tất nhiên điều này không hiệu quả lắm đối với việc truy cập hoặc cập nhật .....

Nếu biểu đồ của bạn có số lượng nút tương đối nhỏ và khá dày đặc (giả sử có ít nhất 5% tất cả các kết nối có thể tồn tại) thì bạn có thể thấy nó hiệu quả hơn về không gian để tạo ma trận kề thay vì sử dụng danh sách cạnh. Điều này sẽ chỉ cần một bit cho mỗi kết nối (có hướng) có thể và tổng số bit n * n trong đó bạn có n nút.

Mặt khác, nếu bạn cần sử dụng các liên kết hàng xóm thì bạn không thể dễ dàng làm tốt hơn một tham chiếu cho mỗi liên kết vì đây là nội dung thông tin tối thiểu bạn cần lưu trữ. Nếu bạn muốn liên kết ngược, bạn sẽ cần gấp đôi số liên kết.

Có một số thủ thuật bạn có thể thử trên đầu trang này. Ví dụ: bạn có thể thử chia sẻ tập hợp con của các liên kết (nếu A và B tham chiếu đến từng C, D, E thì chỉ lưu trữ danh sách các liên kết C, D, E một lần .....). Tuy nhiên, điều này sẽ trở nên phức tạp khá nhanh chóng và tôi nghi ngờ rằng nó sẽ có giá trị nỗ lực trong hầu hết các trường hợp.

Một mẹo khác - giả sử đồ thị của bạn có số lượng nút hợp lý, bạn chắc chắn sẽ tiết kiệm không gian bằng cách lập chỉ mục - ví dụ: sử dụng số chỉ mục nút 16 bit thay vì con trỏ / tham chiếu đầy đủ.


Nếu tất cả các liên kết là không có hướng, người ta có thể tiết kiệm một nửa không gian bằng cách chỉ lưu cạnh từ nút thấp đến nút cao.
Ded repeatator

6

Nó sẽ phụ thuộc vào cấu trúc dữ liệu của bạn.

Đối với một biểu đồ dày đặc với các cạnh không được xác định, bạn thực sự không thể đánh bại một danh sách các mảng bit biểu thị một ma trận tam giác. Một List<BitArray>ví dụ. Theo logic, nó sẽ trông như thế này:

 0123
0
11
211
3001
41010

Từ đó, bạn có thể sử dụng chỉ mục của BitArray gốc để lập chỉ mục vào danh sách lưu trữ dữ liệu nút của bạn.

Ví dụ: nhận được tất cả các hàng xóm của một nút sẽ như sau:

// C#
List<Node> Nodes = /* populated elsewhere */
List<BitArray> bits = /* populated elsewhere */
public static IEnumerable<Node> GetNeighbours(int x)    
{
    for (int i = 0; i < bits[idx].Count; i++)
    {
        if (this.bits[idx][i])
            yield return this.Nodes[i];
    }

    for (int i = 0; i < this.Nodes.Count; i++)
    {
        if (idx < this.bits[i].Count && this.bits[i][idx])
            yield return this.Nodes[i];
    }    
}

(lưu ý rằng bạn cũng có thể chọn loại chỉ mục, tùy thuộc vào lượng dữ liệu, là byte hoặc ushort hoặc thứ gì đó dọc theo các dòng đó vì tất cả các chỉ mục sẽ dương. Tôi không coi đây là tối ưu hóa vi mô vì nó tầm thường)

Đối với biểu đồ có hướng, bạn sẽ đi theo tuyến của một mảng * n để lưu trữ kết nối ... trừ khi nó rất thưa so với số lượng nút, nơi bạn có thể đi đến danh sách các chỉ số kề.

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.