2013-03-29 98 views
13

Đây là câu hỏi tôi đã được hỏi gần đây trong một cuộc phỏng vấn. Một cây nhị phân được đưa ra với một điều kiện mà mỗi con trái là 1 nhỏ hơn so với gốc và con phải là 1 lớn hơn. Đây là một cây mẫuSắp xếp các phần tử trong cây nhị phân

A tree

Sắp xếp nó trong thời gian O (1) và O (n) thời gian phức tạp.

Dưới đây là những phương pháp tôi đề nghị:

  1. Sử dụng một số lượng để duy trì số lượng của mỗi nguyên tố và sau đó trở về một lần toàn bộ traversal được thực hiện O (n) thời gian và O (n) không gian phức tạp.
  2. Sử dụng mã hóa độ dài chạy. Tạo thành một chuỗi khi phần tử được lặp lại với số là khóa và được tính là giá trị. Yêu cầu không gian để đếm chỉ khi không được lặp lại và do đó không yêu cầu thêm không gian ngoài mảng nhưng độ phức tạp thời gian sẽ là O (n log n) vì chúng ta phải đi qua mảng để xem nó có ở đó hay không.
  3. Cuối cùng, tôi đã đề xuất sự di chuyển đầu tiên trên bề rộng. Chúng tôi yêu cầu không gian O (log n) cho hàng đợi và độ phức tạp thời gian O (n) (Giả sử chèn là O (1) danh sách liên kết).

Phương pháp tiếp cận của bạn là gì?

+2

Ý của bạn là gì theo độ phức tạp 'O (1) và O (n)'? Bạn có nghĩa là O (1) không gian? Tôi có thể tưởng tượng rằng có một thuật toán O (n) bằng cách cân bằng cây theo cách tương tự với cây AVL và sau đó thực hiện một quá trình truyền tải theo thứ tự. –

+0

Sắp xếp chính xác có nghĩa là gì? Phương thức cần trả về một danh sách được sắp xếp? printf? Chúng ta có thể sửa đổi cái cây không? – Knoothe

+0

Không gian O (1) là một yêu cầu thực sự? Chỉ cần làm bất kỳ traversal có vẻ khó khăn (nếu chúng ta không thể sửa đổi cây) để làm trong O (1) không gian. Có lẽ nó là O (chiều cao)? btw, bfs mất không gian Omega (n). Không O (log n). – Knoothe

Trả lời

1

Sửa một số nút lá của cây đã cho dưới dạng NewHead.

Viết hàm Pop() xóa một số nút khỏi cây đã cho ..!

Viết nút bật lên sao cho bạn chỉ xóa nút đó khi có! bằng NewHead.

Vì vậy, giá trị pop từ cây, hãy chèn nó vào cây tìm kiếm nhị phân mới với Đầu mới làm nút Đầu.

Vì vậy, u sẽ xóa phần tử khỏi cây, thêm phần đó vào cây tìm kiếm mới.

Cho đến điểm đầu cây NewHead.

Vì vậy, tất cả các yếu tố của bạn giờ đây trong cây tìm kiếm nhị phân trỏ đến đầu Mới, sẽ là

rõ ràng theo thứ tự được sắp xếp.

Cách này hứa với bạn sắp xếp trong O (NlogN).

+0

Điều này có vẻ là một giải pháp tốt hơn. Làm chiều sâu traversal đầu tiên nhưng với việc di chuyển trực tiếp đến nút từ hàng đợi là một giải pháp. Sử dụng nó cùng với danh sách (o (1) chèn) sẽ cung cấp cho o (n) giải pháp với không gian phức tạp của o (h). – user2223032

-1

Tôi không nhận được câu hỏi. Không phải cây nhị phân đã được sắp xếp chưa? Nếu bạn muốn in các mục theo thứ tự (hoặc truy cập chúng theo thứ tự), mã này sẽ hoạt động

/** 
* Show the contents of the BST in order 
*/ 
public void show() { 
show(root); 
System.out.println(); 
} 
private static void show(TreeNode node) { 
if (node == null) return; 
show(node.lchild); 
System.out.print(node.datum + " "); 
show(node.rchild); 
} 

Tôi tin rằng điều này là o (n) phức tạp. Để trả lại danh sách thay vì in, chỉ cần tạo một danh sách và thay thế từng câu lệnh hiển thị bằng cách thêm con vào danh sách

+0

Không có số nào không theo thứ tự sắp xếp.! Bạn cần sắp xếp chúng và thay đổi vị trí của các số .. !! – MissingNumber

+3

@Jessica bạn đang bị nhầm lẫn giữa "cây tìm kiếm nhị phân" và "cây nhị phân". Câu hỏi một cách rõ ràng nói rằng "phân loại trong cây nhị phân" và mã bạn đề cập là Inorder traversal của BST mà không phải là trường hợp ở đây. – JackSparrow

0

Sử dụng sắp xếp nhanh.

Các nút được sắp xếp ở mức thấp nhất trong nhiều mảng & các mảng phần tử được sắp xếp này được hợp nhất vào cuối.

Ví dụ:

Chức năng quick_sort (nút n)
1.Chuyển sang chế độ bên trái, nếu không phải là null, hãy gọi quick_sort trên đó.
2. Chuyển đến phần tử bên phải, nếu không phải là null, hãy gọi quick_sort trên đó.
3. Hợp nhất các kết quả của nút bên trái sắp xếp & sắp xếp nút phải & nút hiện tại.
4. Trả về mảng đã hợp nhất.

1

Phân tích

Với định nghĩa của bạn của một cây nhị phân chúng ta có những điều sau đây,

Mỗi Node có một phụ huynh, L-con, và R-con .. nơi:

L < N 

R > N 

P > N 

Chúng tôi cũng có thể làm điều này:

L < N AND R > N => L < N < R => L < R 

L < N AND P > N => L < N < P => L < P 

R > N AND P > N => N < MIN(P,R) 

N < MIN(P,R) AND L < N => L < N < MIN(P,R) 

Và bây giờ chúng ta hãy thử mở rộng nó, N.L = Left-child of N:

N.L < N 
N.R > N 
N.P > N 

N.L.L < N.L < MIN(N, N.L.R) 
N.L.R > N.L > N.L.L 

N.R.L < N.R < MIN(N, N.R.R) 
N.R.R > N.R > N.R.L 

IF N IS N.P LEFT-CHILD: N < N.P < MIN(N.P.P, N.P.R) 

IF N IS N.P RIGHT-CHILD: N > N.P.R 

đề xuất giải pháp

vấn đề này có vẻ phức tạp, nhưng giải pháp của tôi sẽ được sử dụng hợp nhất phân loại sau khi chèn giá trị theo một thứ tự traversal trái Đúng-cha mẹ sẽ giúp sắp xếp hợp nhất để có được một thời gian phức tạp một nơi nào đó giữa trường hợp trung bình và tối ưu của nó, nhưng với một thủ thuật nhỏ bằng cách sử dụng so sánh tôi đã thực hiện ở trên.

Đầu tiên chúng tôi thu thập các nút cây trong một danh sách, sử dụng traversal Left-Right-phụ huynh, do thực tế là: N.L < N < MIN(N.R, N.P) và cho phụ huynh một trọng lượng cao hơn giả O(N.R) <= O(N.P) với giá trị giảm tuyến tính khi chúng tôi đi lại phía mỗi lần .. > N.R.R > N.R > N > N.L > N.L.L > .. .

Sau khi thu thập các nút cây theo thứ tự truyền tải đó, danh sách có một số khối được sắp xếp, sẽ giúp sắp xếp hợp nhất mà chúng ta sẽ sử dụng tiếp theo.

Giải pháp này làm việc trong: Time = O(n log n + n), Space = O(n)

Đây là thuật toán viết bằng Java (không kiểm tra):

private class Node Comparable<Node> 
{ 
    public Node R; 
    public Node L; 
    public int value; 

    public Node (Node L, int val, Node R) 
    { 
     this.L = L; 
     this.value = val; 
     this.R = R; 
    } 

    @Override 
    public int compareTo(Node other) 
    { 
     return ((other != null) ? (this.value-other.value) : 0); 
    } 
} 

class Main 
{ 
    private static Node head; 

    private static void recursive_collect (Node n, ArrayList<Node> list) 
    { 
     if (n == null) return; 
     if (n.left != null) recursive_collect (n.L, list); 
     if (n.right != null) recursive_collect (n.R, list); 
     list.add(n.value); 
    } 

    public static ArrayList<Node> collect() 
    { 
     ArrayList<Node> list = new ArrayList<Node>(); 
     recursive_collect (head, list); 
     return list; 
    } 

    // sorting the tree: O(n log n + n) 
    public static ArrayList<Node> sortTree() 
    { 
     // Collecting nodes: O(n) 
     ArrayList<Node> list = collect(); 

     // Merge Sort: O(n log n) 
     Collections.sort(list); 

     return list; 
    } 

    // The example in the picture you provided 
    public static void createTestTree() 
    { 
     Node left1 = new Node (new Node(null,-2,null), -1, new Node(null,0,null)); 

     Node left2 = new Node (new Node(null,-1,null), 0, new Node(null,1,null)); 

     Node right = new Node (left2, 1, new Node(null,2,null)); 

     head = new Node (left1, 0, right); 
    } 

    // test 
    public static void main(String [] args) 
    { 
     createTestTree(); 

     ArrayList<Node> list = sortTree(); 

     for (Node n : list) 
     { 
      System.out.println(n.value); 
     } 
    } 
} 
1

tôi đoán, bạn đang tìm kiếm DFS (sâu đầu tiên tìm kiếm) . Trong tìm kiếm chiều sâu, ý tưởng là đi sâu nhất có thể từ hàng xóm đến hàng xóm trước khi quay lại. Điều xác định mức độ sâu sắc có thể là bạn phải tuân theo các cạnh và bạn không truy cập bất kỳ đỉnh nào hai lần.

tăng đã cung cấp: xem here

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