2009-04-16 35 views
8

Chúng tôi có một ứng dụng lưu trữ ma trận thưa thớt. Ma trận này có các mục chủ yếu tồn tại xung quanh đường chéo chính của ma trận. Tôi đã tự hỏi nếu có bất kỳ thuật toán hiệu quả (hoặc các thư viện hiện có) có hiệu quả có thể xử lý ma trận thưa thớt loại này? Tốt hơn, đây sẽ là một sự thực thi chung trong đó mỗi mục nhập ma trận có thể là một kiểu do người dùng định nghĩa.Cách tốt nhất để lưu trữ ma trận thưa thớt trong .NET

Chỉnh sửa để đáp ứng với một câu hỏi/trả lời:

Khi tôi nói chủ yếu xung quanh đường chéo chính tôi có nghĩa là những đặc điểm của hầu hết các ma trận sẽ thấy hầu hết mục được cụm tắt của đường chéo chính nhưng có thể là zeroes gần đường chéo và có thể có giá trị khác không xa từ đường chéo. Tôi muốn một cái gì đó hiệu quả cho 'hầu hết' trường hợp ở đây.

Tôi sẽ sử dụng điều này để làm gì? Tôi cần có khả năng truy cập hiệu quả vào tất cả các giá trị trong một hàng hoặc tất cả các giá trị trong một cột. Các giá trị được lưu trữ sẽ là các giá trị Boolean. Một ví dụ sẽ là:

  1. Đối với tất cả các giá trị đích thực trong một hàng, cột foreach một sự thật xuất hiện trong thiết lập tất cả các mục của cột một cái gì đó
  2. Đối với tất cả các giá trị sai trong một hàng, thiết lập các mục nhập vào một cái gì đó

Điều này được thực hiện với các danh sách được liên kết trước đây nhưng rất khó thực hiện. Tôi đã hy vọng rằng với một ma trận thưa thớt tôi có thể cải thiện các thuật toán nhưng việc tìm kiếm 'đúng' loại thuật toán ma trận thưa thớt đã chứng minh khó khăn.

p.s. Cảm ơn bạn đã trả lời cho đến nay

+0

Tôi đã cập nhật câu trả lời của mình. Vậy hiệu quả hoạt động có quan trọng hơn hiệu quả không gian? Bạn nói "cách hiệu quả để xử lý các ma trận thưa thớt" và trong các trường hợp sử dụng của bạn, hãy nói về nhiều cách để truy cập dữ liệu. –

+0

Tôi cho rằng hiệu suất là quan trọng hơn hiệu quả của không gian. Chúng tôi sẽ xử lý một lượng lớn dữ liệu anyways vì vậy tôi không nhớ sử dụng nhiều không gian cho ma trận miễn là nó đi nhanh hơn –

Trả lời

7

Bạn có thể sử dụng chỉ mục dựa trên [hàng, col] của ô. Vì dữ liệu nằm trên đường chéo, cách tiếp cận điển hình để lưu trữ chỉ mục hàng và phân đoạn cột được liên kết với dữ liệu không phải là tối ưu. Dưới đây là một số mã bạn có thể sử dụng để làm điều đó:

public class SparseMatrix<T> 
    { 
     public int Width { get; private set; } 
     public int Height { get; private set; } 
     public long Size { get; private set; } 

     private Dictionary<long, T> _cells = new Dictionary<long, T>(); 

     public SparseMatrix(int w, int h) 
     { 
      this.Width = w; 
      this.Height = h; 
      this.Size = w * h; 
     } 

     public bool IsCellEmpty(int row, int col) 
     { 
      long index = row * Width + col; 
      return _cells.ContainsKey(index); 
     } 

     public T this[int row, int col] 
     { 
      get 
      { 
       long index = row * Width + col; 
       T result; 
       _cells.TryGetValue(index, out result); 
       return result; 
      } 
      set 
      { 
       long index = row * Width + col; 
       _cells[index] = value; 
      } 
     } 
    } 

    static void Main() 
    { 
     var sm = new SparseMatrix<int>(512, 512); 
     sm[42, 42] = 42; 
     int val1 = sm[13, 13]; 
     int val2 = sm[42, 42]; 

     Console.WriteLine("VAL1 = " + val1); // prints out 0 
     Console.WriteLine("VAL2 = " + val2); // prints out 42 

     Console.ReadLine(); 
    } 

Lưu ý rằng khi T là một cấu trúc, bạn có thể phải gọi IsCellEmpty kể từ khi nhận được nội dung của một tế bào sẽ không được null và sẽ có giá trị mặc định cho loại đó. Bạn cũng có thể mở rộng mã để cung cấp cho bạn một "SparseRatio" nhanh chóng dựa trên thuộc tính Size_cells.Count.

EDIT:

Vâng, nếu bạn thú vị là tốc độ, bạn có thể thực hiện giao dịch không gian so với tốc độ. Thay vì chỉ có một từ điển, có ba từ! Nó tăng gấp ba không gian của bạn, nhưng nó làm cho liệt kê theo bất kỳ cách nào bạn muốn thực sự dễ dàng. Dưới đây là một số mã mới cho thấy rằng:

public class SparseMatrix<T> 
    { 
     public int Width { get; private set; } 
     public int Height { get; private set; } 
     public long MaxSize { get; private set; } 
     public long Count { get { return _cells.Count; } } 

     private Dictionary<long, T> _cells = new Dictionary<long, T>(); 

     private Dictionary<int, Dictionary<int, T>> _rows = 
      new Dictionary<int, Dictionary<int, T>>(); 

     private Dictionary<int, Dictionary<int, T>> _columns = 
      new Dictionary<int, Dictionary<int, T>>(); 

     public SparseMatrix(int w, int h) 
     { 
      this.Width = w; 
      this.Height = h; 
      this.MaxSize = w * h; 
     } 

     public bool IsCellEmpty(int row, int col) 
     { 
      long index = row * Width + col; 
      return _cells.ContainsKey(index); 
     } 

     public T this[int row, int col] 
     { 
      get 
      { 
       long index = row * Width + col; 
       T result; 
       _cells.TryGetValue(index, out result); 
       return result; 
      } 
      set 
      { 
       long index = row * Width + col; 
       _cells[index] = value; 

       UpdateValue(col, row, _columns, value); 
       UpdateValue(row, col, _rows, value); 
      } 
     } 

     private void UpdateValue(int index1, int index2, 
      Dictionary<int, Dictionary<int, T>> parent, T value) 
     { 
      Dictionary<int, T> dict; 
      if (!parent.TryGetValue(index1, out dict)) 
      { 
       parent[index2] = dict = new Dictionary<int, T>(); 
      } 
      dict[index2] = value; 
     } 
    } 

Nếu bạn muốn lặp qua tất cả các mục nhập, hãy sử dụng _cells. Nếu bạn muốn tất cả các hàng cho một cột nhất định sử dụng _columns. Nếu bạn muốn tất cả các cột trong một hàng nhất định sử dụng _rows.

Nếu bạn muốn lặp lại theo thứ tự sắp xếp, bạn có thể bắt đầu thêm LINQ vào danh sách kết hợp và/hoặc sử dụng danh sách được sắp xếp với lớp bên trong đóng gói một mục nhập (có thể lưu trữ hàng hoặc cột và triển khai IComparable<T> để sắp xếp hoạt động).

+0

Cảm ơn bạn, tôi thích nơi bạn đang đi với điều này. Sử dụng các từ điển không cho phép tôi truy cập hiệu quả vào toàn bộ các hàng hoặc các cột không? (có thể sử dụng LINQ nó ...?). Xem chỉnh sửa của tôi ở trên. –

+0

Xem cập nhật cho một tùy chọn khác.Nếu không gian không phải là vấn đề, hãy thực hiện giao dịch để truy cập nhanh hơn bằng cách có nhiều từ điển. –

+0

Đề xuất tuyệt vời, cảm ơn bạn rất nhiều –

4

Tôi đoán một Dictionary<int, Dictionary<int, object >> sẽ đủ.

1

Tôi nghĩ rằng điều này có thể được thực hiện bằng cách sử dụng một lớp giữ mảng đơn giản, tiết kiệm chênh lệch ngang được áp dụng giữa các hàng ma trận và xác định sọc của một hàng, ví dụ: số mục nhập hợp lệ. Vì vậy, đối với một ma trận lớn, nơi chỉ có đường chéo và hai yếu tố hàng xóm được xác định bạn sẽ tạo một mảng gồm 3 * số hàng và lưu 3 dưới dạng chiều rộng sọc. Sự bù đắp phụ thuộc vào kích thước của ma trận.

Tôi không biết bất kỳ điều gì miễn phí đã thực hiện việc này.

+0

Ý tưởng hay. Tôi có thể thực hiện nó như vậy: Giả sử chỉ có đầu vào dương, chúng tôi có thể xử lý số âm là số lượng 0 mục nhập giữa các mục nhập. Vì vậy, sau ... [1,2, -30,0,1,2, -29] ​​ Mở rộng thành [1,2,0,0 ...] [0,1,2,0 ...] Để bù đắp, mảng [m * hàng + cột] là (hàng, cột) của ma trận mxn –

1

Dưới đây là danh sách tổng quát data structure schemas. Mỗi loại đều có những ưu điểm và nhược điểm của nó, và phù hợp với các loại vấn đề hơi khác nhau mà ma trận thưa thớt phát sinh. Bạn có thể muốn triển khai chúng trên các cấu trúc dữ liệu hiện có, chẳng hạn như Danh sách <> và từ điển <>.

2

Có hai câu hỏi ở đây:

  • "Chủ yếu là xung quanh đường chéo chính" là quá mơ hồ. Nếu các phần tử nằm trong các băng tần, thì hãy sử dụng lưu trữ dải của chính các dải, vì các vectơ được bù đắp từ đường chéo chính.Nếu các phần tử nằm rải rác ngẫu nhiên trong vùng lân cận của đường chéo chính, thì sử dụng dạng dải có thể bao gồm một số số không trong băng hoặc sử dụng dạng thưa thớt chỉ lưu trữ các phần tử và vị trí của chúng trong mảng.

  • Bạn sẽ làm gì với ma trận? Nếu mục tiêu của bạn chỉ là lưu trữ hiệu quả, thì biểu mẫu dải sẽ hiệu quả, với quyền truy cập nhanh vào bất kỳ phần tử nào. Nếu bạn sẽ làm đại số tuyến tính với ma trận, nhưng không bao giờ nhiều hơn ma trận nhân vectơ, thì dạng dải sẽ vẫn hoạt động tuyệt vời. Nếu bạn làm việc với ma trận ma trận nhân hoặc yếu tố ma trận, nơi điền vào trở thành một vấn đề, sau đó một hình thức thưa thớt tinh khiết có thể phù hợp hơn. Ví dụ, sản phẩm của hai ma trận dải sẽ có các băng tần bổ sung, vì vậy sản phẩm của hai ma trận tridiagonal sẽ là pentadiagonal. Đối với một yếu tố, tái sắp xếp đôi khi sẽ hữu ích để giảm thiểu điền vào. (AMD là một sự lựa chọn, hoán vị mức độ tối thiểu gần đúng, nhưng có các phương án khác.)

Các vấn đề liên quan