Heap - Đưa ra thuật toán thời gian


15

Rất có thể, câu hỏi này được hỏi trước. Đó là từ vấn đề CLRS (2nd Ed) 6.5-8 -

Đưa ra thuật toán thời gian để hợp nhất các danh sách được sắp xếp vào một danh sách được sắp xếp, trong đó là tổng số phần tử trong tất cả các danh sách đầu vào. (Gợi ý: Sử dụng một đống nhỏ để hợp nhất -way.)O(nlgk)knk

Vì có danh sách được sắp xếp và tổng số giá trị, chúng ta giả sử mỗi danh sách chứa các số , hơn nữa, mỗi danh sách được sắp xếp theo thứ tự tăng dần và kết quả cũng sẽ được lưu theo thứ tự tăng dần đặt hàng.knnk

Mã giả của tôi trông như thế này -

    list[k]   ; k sorted lists
    heap[k]   ; an auxiliary array to hold the min-heap
    result[n] ; array to store the sorted list
    for i := 1 to k                 ; O(k)
    do
        heap[i] := GET-MIN(list[i]) ; pick the first element 
                                    ; and keeps track of the current index - O(1)
    done
    BUILD-MIN-HEAP(heap) ; build the min-heap - O(k)
    for i := 1 to n
    do
        array[i] := EXTRACT-MIN(heap)   ; store the min - O(logk)
        nextMin := GET-MIN(list[1])     ; get the next element from the list 1 - O(1)
        ; find the minimum value from the top of k lists - O(k)
        for j := 2 to k                 
        do
            if GET-MIN(list[j]) < nextMin
                nextMin := GET-MIN(list[j]) 
        done
        ; insert the next minimum into the heap - O(logk)
        MIN-HEAP-INSERT(heap, nextMin)
    done

Độ phức tạp tổng thể của tôi trở thành . Tôi không thể tìm thấy bất kỳ cách nào để tránh vòng lặp bên trong vòng lặp để tìm phần tử tối thiểu tiếp theo từ danh sách k. Có cách nào khác không? Làm thế nào để có được thuật toán ?O ( k ) O ( n ) O ( n lg k )O(k)+O(k)+O(n(k+2lgk))O(nk+nlgk)O(nk)O(k)O(n)O(nlgk)

Câu trả lời:


13

Mục đích của heap là cung cấp cho bạn mức tối thiểu, vì vậy tôi không chắc mục đích của vòng lặp for này là gì - for j := 2 to k.

Tôi nhận mã giả:

lists[k][?]      // input lists
c = 0            // index in result
result[n]        // output
heap[k]          // stores index and applicable list and uses list value for comparison
                 // if i is the index and k is the list
                 //   it has functions - insert(i, k) and deleteMin() which returns i,k
                 // the reason we use the index and the list, rather than just the value
                 //   is so that we can get the successor of any value

// populate the initial heap
for i = 1:k                   // runs O(k) times
  heap.insert(0, k)           // O(log k)

// keep doing this - delete the minimum, insert the next value from that list into the heap
while !heap.empty()           // runs O(n) times
  i,k = heap.deleteMin();     // O(log k)
  result[c++] = lists[k][i]
  i++
  if (i < lists[k].length)    // insert only if not end-of-list
    heap.insert(i, k)         // O(log k)

Tổng mức độ phức tạp thời gian là do đó O(klogk+n2logk)=O(nlogk)

Bạn cũng có thể, thay vì deleteMininsert, có getMin( ) và ( O ( log k ) ), điều này sẽ làm giảm hệ số không đổi, nhưng không phức tạp.O(1)incrementIndexO(logk)

Ví dụ:
(sử dụng giá trị thay vì chỉ mục và chỉ mục danh sách và heap được biểu diễn dưới dạng mảng được sắp xếp cho rõ ràng)

Input: [1, 10, 15], [4, 5, 6], [7, 8, 9]

Initial heap: [1, 4, 7]

Delete 1, insert 10
Result: [1]
Heap: [4, 7, 10]

Delete 4, insert 5
Result: [1, 4]
Heap: [5, 7, 10]

Delete 5, insert 6
Result: [1, 4, 5]
Heap: [6, 7, 10]

Delete 6, insert nothing
Result: [1, 4, 5, 6]
Heap: [7, 10]

Delete 7, insert 8
Result: [1, 4, 5, 6, 7]
Heap: [8, 10]

Delete 8, insert 9
Result: [1, 4, 5, 6, 7, 8]
Heap: [9, 10]

Delete 9, insert nothing
Result: [1, 4, 5, 6, 7, 8, 9]
Heap: [10]

Delete 10, insert 15
Result: [1, 4, 5, 6, 7, 8, 9, 10]
Heap: [15]

Delete 15, insert nothing
Result: [1, 4, 5, 6, 7, 8, 9, 10, 15]
Heap: []

Done

giả sử bạn có các danh sách này để hợp nhất, liệt kê [1] = [1, 10, 15], danh sách [2] = [4, 5, 6] và danh sách [3] = [7, 8, 9]. Ở lần lặp đầu tiên, giá trị từ heap sẽ là 1 và tiếp theo thuật toán của bạn sẽ chèn 10 vào heap, nhưng 10 là giá trị lớn nhất trong tất cả các danh sách - bạn sẽ tránh điều đó như thế nào?
ramgorur

@ramgorur Không có vấn đề gì khi 10 trong đống. 4,5,6,7,8 và 9 tất cả sẽ được xử lý trước khi chúng tôi luôn nhận được giá trị nhỏ nhất từ ​​heap và tiếp tục thay thế các giá trị bị xóa bằng mục tiếp theo từ cùng một danh sách. Chỉnh sửa câu trả lời với ví dụ.
Dukeling

tốt, nếu đây là trường hợp, chúng ta không thực sự phải nhớ cùng một danh sách cho lần đẩy phần tử tiếp theo. Chúng ta có thể chọn một danh sách ngẫu nhiên mỗi lần và đẩy phần tử tiếp theo thành đống - điều này cũng được cho là sẽ cho kết quả tương tự, phải không? Hoặc có bất kỳ lý do đặc biệt khác để theo cùng một đối số danh sách ?
ramgorur

Khi xóa 4, nếu bạn chọn một danh sách ngẫu nhiên, cuối cùng bạn có thể chèn 8, do đó, heap sẽ [7, 8, 10], từ đó bạn sẽ chèn 7thay vì 5vào tập kết quả, điều này sẽ sai.
Dukeling

Nhận xét của @ AshwaniGautam về câu trả lời khác là apt: tạo heap ban đầu có thể được thực hiện trong thời gian . O(k)
Raphael

13

Trước hết, tôi nghĩ rằng giả định của bạn về tất cả các danh sách có mục nhập là không hợp lệ nếu thời gian chạy của thuật toán phụ thuộc vào độ dài của danh sách dài nhất .n/k

Đối với vấn đề của bạn, thuật toán sau nên thực hiện thủ thuật:

  1. Đặt các phần tử đầu tiên của danh sách trong một h-min có kích thước k . Hãy nhớ cho mỗi phần tử danh sách l m nó thuộc về. ( O ( k lg k ) )HklmO(klgk)
  2. Đối với từ 1 đến n làm: i1n
    • Trích xuất tối thiểu từ H và lưu trữ trong r e s u l t [ i ] ( O ( lg k ) )mHresult[i]O(lgk)
    • mlmHO(lgk)

O(klgk+nlgk)=O(nlgk)result

iresultHiresult[1..i]i

resultHresultr1lr1l[1]r1r1l[1]<r1r1result

iriHHmllHresultrimll

result[1..n]


Trên thực tế độ phức tạp thời gian chặt chẽ hơn sẽ là O (K + 2 * NlogK) = O (NlogK) . O (K) bị ràng buộc chặt chẽ hơn O (KlogK), khi tạo Heap. Tham khảo điều này để làm rõ thêm.
Ashwani Gautam

O(k)O(klogk)k
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.