2011-06-23 72 views
6

Tôi thường thấy mình cần phải đi qua cây của các đối tượng phân cấp và thực hiện các thao tác trên mỗi mục trên đường đi. Có một tên được chấp nhận chung cho loại hoạt động này trong danh sách tiếng địa phương không? Tôi hỏi bởi vì tôi nhớ lần đầu tiên tìm hiểu về python's zip function trở lại trước khi nó có một tương đương trong khuôn khổ .net và nghĩ rằng nó có một cái tên khác thường nhưng thích hợp.Có tên được chấp nhận cho loại hoạt động này không?

Dưới đây là một vài phương pháp tổng quát giúp tái cấu trúc cây lên và xuống và mang lại từng mục khi chúng gặp phải.

public static IEnumerable<T> Ancestors<T>(T source, Func<T, T> selector) 
{ 
    do 
    { 
     yield return source; 
     source = selector(source); 
    } while (!Equals(source, default(T))); 
} 

public static IEnumerable<T> Descendents<T>(T source, 
              Func<T, IEnumerable<T>> selector) 
{ 
    var stack = new Stack<T>(); 
    stack.Push(source); 
    while (stack.Count > 0) 
    { 
     source = stack.Pop(); 
     yield return source; 
     var items = selector(source); 
     if (items != null) 
     { 
      foreach (var item in items) 
      { 
       stack.Push(item); 
      } 
     } 
    } 
} 
+0

Một số loại cây ngang qua được lọc? Tôi không biết nếu điều này có một tên cụ thể. Tôi không nghĩ là nó có. –

+0

Cách thứ hai là thực hiện tìm kiếm theo chiều sâu. Không chắc tên thứ hai có tên, vì mặc dù nó được gọi là "Ancestors' tùy thuộc vào chức năng chọn, nó không cần phải thực sự theo 'cha mẹ' chút nào (ví dụ: nó có thể làm bất cứ điều gì, ví dụ như chọn một con" tốt nhất " node) –

+0

@George: Chính xác, 'Tổ tiên' ngụ ý một loại quan hệ phân cấp nhất định. Trong thực tế nó có thể dễ dàng được sử dụng để đi qua một danh sách liên kết gấp đôi theo một trong hai hướng hoặc theo bất kỳ loại đường mòn tùy ý nào. –

Trả lời

1

Đây là các chức năng tiêu chuẩn Tree Traversal, còn được gọi là "đi bộ trên cây". Rất khó để đưa ra các ví dụ tiêu chuẩn hóa của bạn bởi vì chiến lược đi bộ cụ thể không được biết rõ:

7

Giả sử rằng bộ chọn cung cấp cho các nút con, phương pháp thứ hai của bạn là giao điểm "đúng đầu tiên đầu tiên". Tức là, nếu bạn đã có

 A 
    /\ 
    B  C 
/\ /\ 
D E F G 

Sau đó, bạn nhận được "G" trước "B" bởi vì "độ sâu đầu tiên" đi sâu đến mức có thể trước khi nó thử nhánh khác. Trong ví dụ cụ thể của bạn, bạn sẽ nhận được C trước B vì nó ưu tiên quyền qua trái.

Nếu bạn thay đổi nó để

foreach (var item in items.Reverse()) 

sau đó bạn sẽ nhận được một traversal trái đầu tiên chuyên sâu-đầu tiên, đó là cách mà hầu hết mọi người nghĩ về chiều sâu traversal đầu tiên.

Nếu bạn thay đổi ngăn xếp thành một hàng đợi thì nó sẽ trở thành một "chiều ngang" đầu tiên. A, B, C, D, E, F, G. Bạn thực hiện toàn bộ "cấp độ" tại một thời điểm.

Ngoài ra còn có các giao diện khác. Lưu ý rằng các tìm kiếm theo chiều sâu và lần đầu tiên có cả thuộc tính mà các nút cha đến trước các nút con. Bạn cũng có thể có các lần duyệt qua "sau thứ tự" trong đó mọi nút đến sau con của nó.

Cây nhị phân cũng có giao thoa "inorder". Sự đi ngược lại của cây này là D, B, E, A, F, C, G. Đó là, mọi đứa trẻ trái đều đến trước tất cả tổ tiên của nó, và mọi đứa trẻ đều đến sau tất cả tổ tiên của nó. Như là một bài tập, bạn có thể viết một traversal theo thứ tự trên một cây nhị phân?

+1

Phản hồi tập thể dục PseudoCode: 'Inorder chức năng (Tree) {if (Tree == null) {return;} Inorder (Tree.Left); Đầu ra (Tree.Value); Inorder (Tree.Right);} ' – Brian

+0

@Brian: Siêu. Bạn có thể làm điều đó mà không cần đệ quy không? –

+0

@Eric, bạn cần mô phỏng ngăn xếp cuộc gọi bằng cách sử dụng các nút bình thường và địa chỉ trả về bằng cách sử dụng cờ cho mỗi nút trên ngăn xếp. Khi bạn bật ngăn xếp, bạn kiểm tra cờ xem liệu 1. "recurse" trái hoặc 2. (yield) trả về nút hiện tại và "recurse" ngay. Không cần thiết cho một nhà nước thứ ba, mà về cơ bản là một tối ưu hóa cuộc gọi đuôi. – svick

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