2012-02-17 10 views
5

Có vấn đề sau đây có tên và có thuật toán để giải quyết không? : Cho một đồ thị, hoặc là đạo diễn hay không, tất cả những con đường mà đáp ứng các đặc điểm kỹ thuật do: tìm biểu đồ con bằng cách sử dụng danh sách các nút bao gồm ký tự đại diện

  1. một danh sách các nút chính xác, hoặc
  2. '*?' biểu thị chỉ 'bất kỳ nút hoặc không có nút nào cả', hoặc
  3. '* {n}' mà biểu thị 'bất kỳ n liên tiếp kết nối các nút'

ví dụ

A -> B -> *? -> D which results in ABXD and ABYD and ABD etc. 

hoặc

A -> *{1} -> D -> *? -> E which results in ABXDZE and ABYDZE and ABDZE etc. etc. 

nhờ

tái bút: Có ai biết một thư viện đồ thị làm điều này hoặc trong R hoặc perl hoặc C?

+0

Đây là tất cả những gì tôi có thể tìm thấy: http: //www.vldb.org/conf/1989/P185.PDF – Diego

+0

Các đường dẫn có phải là đường dẫn đơn giản không? Hoặc họ có thể có chu kỳ? – templatetypedef

+0

Có chu kỳ sẽ ngụ ý một tập hợp vô hạn của giải pháp. – Faylixe

Trả lời

1

Những gì tôi đã làm ở cuối là:

  1. Vấn đề là để tìm tất cả những con đường có chiều dài N giữa 2 nút. Chu kỳ được loại trừ.
  2. đọc dữ liệu dưới dạng edgelist, ví dụ: các cặp từ-> đến các nút (tên của các nút được giả định là duy nhất)
  3. tạo một hashtable (hoặc unordered_map trong boost và stl, C++) của các tên nút làm khóa và một hashtable dưới dạng một giá trị.
  4. thứ hai có thể bắt đầu này sẽ chứa tất cả các nút mà nút đầu tiên dẫn đến dưới dạng khóa.

Ví dụ

A->B 
A->C 
B->D 
C->E 
E->D 

cấu trúc dữ liệu kết quả tổ chức các dữ liệu đầu vào trong ký hiệu perl trông như thế này sau khi đọc trong tất cả các dữ liệu như là một 'edgelist':

my %hash = (
'A' => {'B' => 1, 'C' => 1}, 
'B' => {'D' => 1}, 
'C' => {'E' => 1}, 
'E' => {'D' => 1}, 
); 

tìm nếu một cặp nút được kết nối TRỰC TIẾP có thể được thực hiện gần như (perl):

sub search { 
    my ($from,$to) = @_; 
    if($to eq '*'){ return defined($x=$hash{$from}) ? [keys $hash{$from}] : [] } 
    return defined($x=$hash{$from}) && defined($x{$to}) ? [$to] : [] 
} 

Trong hàm trên có điều khoản trả về tất cả các nút mà nút 'từ' được kết nối, bằng cách đặt $ thành '*'. Sự trở lại là một mảng ref của các nút kết nối trực tiếp với tham số $ from.

Tìm kiếm đường dẫn giữa hai nút yêu cầu sử dụng hàm ở trên một cách đệ quy.

ví dụ:

sub path { 
    my ($from,$to, $hops, $save_results) = @_; 
    if($hops < 0){ return 0 } 
    $results = search($from, '*'); 
    if(""[email protected]$results == 0){ return 0 } 
    $found = 0; 
    foreach $result (@$results){ 
     $a_node = new Tree::Nary($result); 
     if(path($result, $to, $hops-1, $a_node) == 1){ 
      $save_results->insert($save_results, -1, $a_node); 
      $found = 1; 
     } 
    } 
    return $found; 

}

Đó là ok để sử dụng đệ quy nếu độ sâu không phải là quá nhiều (ví dụ: $ nhảy < 6?) Vì stack overflow [sic].

Phần khó khăn nhất là đọc qua các kết quả và trích xuất các nút cho mỗi đường dẫn. Sau nhiều lần cân nhắc, tôi quyết định sử dụng Tree :: Nary (n-ary tree) để lưu trữ kết quả. Cuối cùng chúng ta có cây sau:

 |-> B -> D 
A -> |-> C -> E -> D 

Để trích xuất tất cả các đường dẫn, làm:

  1. tìm tất cả các nút lá
  2. bắt đầu từ mỗi nút lá di chuyển ngược qua mẹ vào nút gốc và lưu tên nút.

Ở trên đã được triển khai bằng cách sử dụng perl, nhưng cũng đã thực hiện nó trong C++ bằng cách sử dụng boost :: unordered_map cho hashtable. Tôi chưa thêm một cấu trúc cây vào sau đó mã C++.

Kết quả: cho 3281415 cạnh và 18601 nút duy nhất, perl mất 3 phút để tìm A -> '*' -> '*' -> B. Tôi sẽ cập nhật mã C++ khi sẵn sàng.

+0

Ồ, btw đọc một tệp lớn cũng là một chủ đề. Fileformat là cặp các tên nút được phân tách bằng khoảng trống trên một dòng riêng của chúng. Trong perl, nó là ok để đọc từng dòng và sau đó chia từng dòng như nó được đọc. Đọc tập tin trong bộ nhớ đầu tiên và sau đó lặp qua một regex mất khoảng thời gian tương tự. Trong C++, tôi đã sử dụng boost :: split để tách một dòng thành các tên node.Đọc một dòng tập tin (sử dụng fopen và fgets của C) chậm hơn một chút so với đọc nó trong bộ nhớ (sử dụng C's read()) và sau đó tách nó trong bộ nhớ bằng cách sử dụng boost :: split, chậm hơn khoảng 10%. – bliako

1

I dunno bất kỳ thư viện cho rằng, nhưng bạn phải tách này trong hai phần:

  • các truy vấn người dùng phân tích
  • Các thuật toán để tìm thấy những gì bạn đang tìm kiếm

Đối việc phân tích cú pháp, tôi cho phép bạn tìm thấy những gì bạn cần làm (sử dụng thư viện phân tích cú pháp hoặc bằng chính bản thân bạn)

Liên quan đến phần thuật toán tôi đề nghị bạn xác định cấu trúc đặc biệt (giống như một danh sách liên kết) để đại diện cho bạn truy vấn, trong đó mỗi phần tử có thể biểu thị một nút thực, số x nút hoặc số lượng nút không giới hạn.

Vấn đề duy nhất trên thuật toán của bạn là tìm tất cả đường dẫn từ nút A đến nút B, sử dụng số không giới hạn hoặc số lượng nút trung gian giới hạn. Bạn có thể làm điều này bằng cách sử dụng lập trình động hoặc thuật toán tìm kiếm như DFS hoặc BFS.