Khi nào sử dụng chiến lược Đặt hàng trước, Đặt hàng sau và Inorder Giao dịch cây tìm kiếm nhị phân


97

Gần đây, tôi nhận ra rằng mặc dù đã sử dụng rất nhiều BST trong cuộc sống của mình, tôi thậm chí chưa bao giờ nghĩ đến việc sử dụng bất cứ thứ gì ngoài Inorder traversal (trong khi tôi nhận thức và biết việc điều chỉnh một chương trình để sử dụng pre / post-order traversal dễ dàng như thế nào).

Khi nhận ra điều này, tôi đã lôi ra một số sách giáo khoa về cấu trúc dữ liệu cũ của mình và tìm kiếm lý do đằng sau tính hữu ích của việc duyệt đơn hàng trước và sau - mặc dù chúng không nói gì nhiều.

Một số ví dụ về thời điểm sử dụng đặt hàng trước / đặt hàng sau thực tế là gì? Khi nào nó có ý nghĩa hơn theo thứ tự?

Câu trả lời:


135

Khi nào sử dụng Chiến lược chuyển đổi đơn hàng trước, trong đơn hàng và sau khi đặt hàng

Trước khi bạn có thể hiểu trong những trường hợp nào nên sử dụng đặt trước, theo thứ tự và đặt sau cho cây nhị phân, bạn phải hiểu chính xác cách hoạt động của mỗi chiến lược truyền tải. Sử dụng cây sau đây làm ví dụ.

Gốc của cây là 7 , nút nhất bên trái là 0 , nút gần nhất bên phải là 10 .

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

Đặt hàng trước truyền tải :

Tóm tắt: Bắt đầu từ gốc ( 7 ), kết thúc ở nút ngoài cùng bên phải ( 10 )

Trình tự duyệt: 7, 1, 0, 3, 2, 5, 4, 6, 9, 8, 10

Truyền theo thứ tự :

Tóm tắt: Bắt đầu ở nút ngoài cùng bên trái ( 0 ), kết thúc ở nút ngoài cùng bên phải ( 10 )

Trình tự truyền: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

Duyệt đơn hàng sau:

Tóm tắt: Bắt đầu bằng nút ngoài cùng bên trái ( 0 ), kết thúc bằng nút gốc ( 7 )

Trình tự duyệt: 0, 2, 4, 6, 5, 3, 1, 8, 10, 9, 7

Khi nào sử dụng Đặt hàng trước, Đặt hàng trước hoặc Đặt hàng sau?

Chiến lược truyền tải mà lập trình viên lựa chọn phụ thuộc vào nhu cầu cụ thể của thuật toán được thiết kế. Mục tiêu là tốc độ, vì vậy hãy chọn chiến lược mang lại cho bạn các nút bạn yêu cầu nhanh nhất.

  1. Nếu bạn biết rằng bạn cần phải khám phá rễ trước khi kiểm tra bất kỳ lá nào, bạn hãy chọn đặt hàng trước vì bạn sẽ bắt gặp tất cả các rễ trước tất cả các lá.

  2. Nếu bạn biết bạn cần khám phá tất cả các lá trước bất kỳ nút nào, bạn chọn thứ tự sau vì bạn không mất thời gian kiểm tra rễ để tìm kiếm lá.

  3. Nếu bạn biết rằng cây có một trình tự vốn có trong các nút và bạn muốn làm phẳng cây trở lại trình tự ban đầu của nó, thì bạn nên sử dụng phương pháp duyệt theo thứ tự . Cái cây sẽ bị san phẳng giống như cách nó được tạo ra. Việc truyền đơn đặt hàng trước hoặc đặt hàng sau có thể không kéo cây trở lại trình tự đã được sử dụng để tạo ra nó.

Thuật toán đệ quy cho Thứ tự trước, Thứ tự và Sau (C ++):

struct Node{
    int data;
    Node *left, *right;
};
void preOrderPrint(Node *root)
{
  print(root->name);                                  //record root
  if (root->left != NULL) preOrderPrint(root->left);  //traverse left if exists
  if (root->right != NULL) preOrderPrint(root->right);//traverse right if exists
}

void inOrderPrint(Node *root)
{
  if (root.left != NULL) inOrderPrint(root->left);   //traverse left if exists
  print(root->name);                                 //record root
  if (root.right != NULL) inOrderPrint(root->right); //traverse right if exists
}

void postOrderPrint(Node *root)
{
  if (root->left != NULL) postOrderPrint(root->left);  //traverse left if exists
  if (root->right != NULL) postOrderPrint(root->right);//traverse right if exists
  print(root->name);                                   //record root
}

3
Điều gì về truyền tải không đệ quy? Đối với tôi, việc duyệt qua một cây không đệ quy theo thứ tự trước dễ dàng hơn nhiều so với theo thứ tự / sau thứ tự, vì nó không yêu cầu quay lại các nút trước đó.
bluenote10

@ bluenote10 Bạn có thể giải thích thêm về ý của bạn được không? Theo thứ tự trước, bạn vẫn "quay lại" một nút để xử lý nút con bên phải của nó sau khi xử lý nút con bên trái của nó. Chắc chắn, bạn có thể sử dụng hàng đợi "các nút chưa được truy cập", nhưng đó thực sự chỉ là giao dịch lưu trữ (ngăn xếp) ngầm định cho một hàng đợi rõ ràng. Trong tất cả các phương thức truyền tải, cả phần tử con bên trái và bên phải đều phải được xử lý, có nghĩa là sau khi thực hiện một trong số chúng, bạn phải "quay trở lại" với phương thức chính.
Joshua Taylor

@JoshuaTaylor: Đúng vậy, chúng đều thuộc cùng một lớp phức tạp, nhưng nếu bạn nhìn vào các triển khai điển hình, thứ tự hậu kỳ có lẽ hơi phức tạp hơn một chút.
bluenote 10

2
Đặt hàng trước duyệt cung cấp các giá trị nút trong một chuỗi chèn. Nếu bạn muốn tạo một bản sao của cây, bạn cần phải duyệt qua cây nguồn theo cách này. Đi ngang theo thứ tự cung cấp các giá trị nút được sắp xếp. Đối với việc duyệt theo thứ tự, bạn có thể sử dụng phương pháp này để xóa toàn bộ cây vì nó truy cập các nút lá trước tiên.
albin

Tôi nghĩ nó đúng ngay cả khi cây không được sắp xếp đúng, ý tôi là theo thứ tự sẽ không đưa ra trình tự được sắp xếp nếu trình tự không được sắp xếp lúc đầu.
CodeYogi

29

Đặt hàng trước: Được sử dụng để tạo bản sao của cây. Ví dụ: nếu bạn muốn tạo một bản sao của một cây, hãy đặt các nút trong một mảng có truyền tải thứ tự trước. Sau đó thực hiện thao tác Chèn trên cây mới cho mỗi giá trị trong mảng. Bạn sẽ kết thúc với một bản sao của cây gốc của bạn.

In-order:: Được sử dụng để lấy giá trị của các nút theo thứ tự không giảm trong BST.

Post-order:: Dùng để xóa cây từ lá đến gốc


2
đây là một câu trả lời tuyệt vời, ngắn gọn và giúp tôi hiểu các trường hợp sử dụng đặt hàng trước và sau khi đặt hàng. mặc dù, có thể rõ ràng là câu hỏi đề cập trực tiếp đến vấn đề này, nhưng lưu ý rằng đây là trường hợp của cây TÌM KIẾM nhị phân và không nhất thiết phải hoạt động đối với cây nhị phân chung. ví dụ, bạn không thể nhất thiết phải sử dụng trình duyệt đơn hàng trước để sao chép một cây nhị phân chung, vì logic chèn trong quá trình sao chép sẽ không hoạt động.
markckim

7
Theo thứ tự:: Để nhận các giá trị của nút theo thứ tự "không giảm" - không phải "không tăng"
rahil008

26

Nếu tôi muốn chỉ đơn giản là in ra định dạng phân cấp của cây ở định dạng tuyến tính, tôi có thể sử dụng đặt hàng trước truyền tải. Ví dụ:

- ROOT
    - A
         - B
         - C
    - D
         - E
         - F
             - G

4
Hoặc trong một TreeViewthành phần trong ứng dụng GUI.
svick

4

Thứ tự trước và sau liên quan đến các thuật toán đệ quy từ trên xuống và từ dưới lên tương ứng. Nếu bạn muốn viết một thuật toán đệ quy đã cho trên cây nhị phân theo kiểu lặp lại, đây là những gì bạn sẽ làm về cơ bản.

Quan sát thêm rằng các trình tự trước và sau cùng nhau hoàn toàn xác định cây trong tầm tay, tạo ra một mã hóa nhỏ gọn (ít nhất là đối với cây thưa thớt).


1
Tôi nghĩ bạn đang muốn nói điều gì đó quan trọng, bạn có thể giải thích nửa đầu được không?
CodeYogi

@CodeYogi Bạn cần giải thích cụ thể điều gì?
Raphael

1
"Thứ tự trước và sau liên quan đến thuật toán đệ quy từ trên xuống và từ dưới lên" Tôi nghĩ bạn muốn nói rằng trong trường hợp đầu tiên nút được xử lý trước khi gọi bất kỳ phương thức đệ quy nào và ngược lại trong trường hợp thứ hai, đúng không ?
CodeYogi

@CodeYogi Có, về cơ bản.
Raphael

2

Có rất nhiều nơi bạn thấy sự khác biệt này đóng một vai trò thực sự.

Một điều tuyệt vời mà tôi sẽ chỉ ra là trong việc tạo mã cho trình biên dịch. Hãy xem xét tuyên bố:

x := y + 32

Cách bạn sẽ tạo mã cho điều đó là (tất nhiên) đầu tiên tạo mã để tải y vào một thanh ghi, tải 32 vào một thanh ghi, sau đó tạo một lệnh để thêm hai. Bởi vì một cái gì đó phải có trong một thanh ghi trước khi bạn thao tác nó (giả sử, bạn luôn có thể thực hiện các toán hạng không đổi nhưng bất cứ điều gì) nên bạn phải làm theo cách này.

Nói chung, câu trả lời bạn có thể nhận được cho câu hỏi này về cơ bản giảm xuống mức này: sự khác biệt thực sự quan trọng khi có sự phụ thuộc nào đó giữa việc xử lý các phần khác nhau của cấu trúc dữ liệu. Bạn thấy điều này khi in các phần tử, khi tạo mã (trạng thái bên ngoài tạo ra sự khác biệt, tất nhiên bạn cũng có thể xem điều này đơn nguyên) hoặc khi thực hiện các loại tính toán khác trên cấu trúc liên quan đến tính toán tùy thuộc vào phần tử con được xử lý trước. .

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.