Khóa tăng và khóa giảm trong một heap nhị phân


16

Trong nhiều cuộc thảo luận về heap nhị phân, thông thường chỉ có phím giảm được liệt kê là hoạt động được hỗ trợ cho heap tối thiểu. Ví dụ, CLR chương 6.1 và trang wikipedia này . Tại sao không tăng khóa thường được liệt kê cho heap tối thiểu? Tôi tưởng tượng có thể làm điều đó trong O (chiều cao) bằng cách hoán đổi phần tử tăng (x) với mức tối thiểu của các con của nó, cho đến khi không có con nào của nó lớn hơn x.

ví dụ

IncreaseKey(int pos, int newValue)
{
   heap[pos] = newValue;
   while(left(pos) < heap.Length)
   {
      int smallest = left(pos);
      if(heap[right(pos)] < heap[left(pos)])
         smallest = right(pos);
      if(heap[pos] < heap[smallest])
      { 
         swap(smallest, pos);
         pos= smallest;
      }
      else return;
   }   
}

Là đúng trên? Nếu không, tại sao? Nếu có, tại sao không tăng khóa được liệt kê cho heap tối thiểu?


1
Sau khi đọc tất cả các câu trả lời, tôi muốn nói, đó là một thiếu sót kỳ lạ, có thể là do lần đầu tiên sử dụng min-heap trong thuật toán Dijkstra.
maaartinus

3
Tất nhiên, bạn luôn có thể thực hiện khóa tăng bằng cách xóa theo sau là chèn và tự xóa có thể được thực hiện dưới dạng phím giảm (đến -∞) theo sau là xóa-min.
davmac

@maaartinus bình luận là câu trả lời đúng.
tối đa

Câu trả lời:


6

Thuật toán bạn đề xuất chỉ đơn giản là heapify. Và thực tế - nếu bạn tăng giá trị của một phần tử trong một heap nhỏ, và sau đó heapify cây con của nó, thì bạn sẽ kết thúc với một heap hợp pháp.


sau đó không tại sao danh sách CLR hoặc Wikipedia Tăng khóa là một hoạt động được hỗ trợ? Nó khiến tôi lầm tưởng rằng điều đó là không thể trong một đống nhỏ
GatotPujo

Tôi đồng ý rằng nó sai lệch, nhưng tôi không thấy bất kỳ sai lầm nào trong thuật toán.
Shaull

5

Lý do mà hoạt động của bạn không được liệt kê, là vì người ta không chỉ quan tâm đến tất cả các hoạt động có thể dễ dàng thực hiện bằng cách sử dụng một cấu trúc dữ liệu nhất định, mà là cách khác. Đưa ra một tập hợp các hoạt động, cách hiệu quả nhất (về không gian và thời gian) để thực hiện các hoạt động này là gì. (Nhưng tôi sẽ bổ sung thêm vào phần này sau)

Heaps nhị phân thực hiện hàng đợi ưu tiên cấu trúc dữ liệu trừu tượng, yêu cầu các hoạt động là_empty, add_element (một khóa có mức độ ưu tiên của nó), find_min và xóa_min. Hàng đợi nâng cao hơn cũng cho phép một người giảm mức độ ưu tiên của khóa (trong một min_heap) hoặc thậm chí tăng nó. Trong thực tế, bạn đã đưa ra một thực hiện.

Hai nhận xét. Hoạt động của bạn được sử dụng trong hàm heapify, có hiệu quả xây dựng một heap từ một mảng. Trong heapify hoạt động của bạn được lặp lại (bắt đầu từ khóa cuối cùng).

Sau đó, quan trọng nhất, mã của bạn sử dụng vị trí của nút. Đối với hàng đợi ưu tiên cấu trúc dữ liệu thuần túy là gian lận. Cấu trúc dữ liệu đó yêu cầu thực hiện một thao tác nhất định được cung cấp một khóa. Vì vậy, để giảm hoặc tăng mức độ ưu tiên của một yếu tố, trước tiên bạn sẽ phải xác định vị trí của nó. Tôi nghĩ đó là lý do chính nó không được liệt kê.


1
Cảm ơn đã giải thích. Tuy nhiên, trong khóa giảm CLR cũng có vị trí là nút làm tham số.
GatotPujo

Bạn đúng rồi. Tôi không thể tìm thấy lý do cho sự bất cân xứng này trong định nghĩa về hàng đợi ưu tiên trong Sect.6.5 của CLRS. Lưu ý khóa tăng không được sử dụng trong Heapsort, ứng dụng của chương này. Có vẻ như sự bất cân xứng giữa tăng và giảm chỉ liên quan đến cách sử dụng cấu trúc dữ liệu trong thuật toán của Dijkstra. Ở đó (sử dụng một heap nhỏ), một số nút được chọn có thể trở nên khẩn cấp hơn và được di chuyển 'lên' trong heap.
Hendrik ngày 1 tháng

0

Tôi nghĩ rằng điều đầu tiên cần xem xét là một hoạt động được hỗ trợ là gì?

Có phải "chèn một giá trị với một khóa cố định, cụ thể" (ví dụ: đối với các khóa được lấy từ cõi số nguyên, chèn với khóa = 3) có tương ứng với thao tác được hỗ trợ cho heap min không?

Không, bởi vì hoạt động đó có thể được thực hiện tầm thường với các hoạt động được hỗ trợ chung hơn. Tương tự như vậy, chèn 2 phần tử cùng một lúc có thể được thực hiện với insertthao tác hiện tại .

Mặt khác, inserthoạt động không thể được định nghĩa khác hơn là bằng cách tiết lộ chi tiết thực hiện. Nó khá giống nhau đối với các hoạt động được liệt kê trên trang wikipedia, heapifyngoại trừ, có thể được thực hiện bởi một chuỗi insert.

Nói cách khác, có các hoạt động cơ bản được cung cấp trên loại, liên kết chặt chẽ với các chi tiết triển khai để chúng hoạt động tốt và có các hoạt động khác không tuân thủ quy tắc đó và do đó có thể được thực hiện dưới dạng kết hợp của những người kinh điển.

Với định nghĩa đó, bạn có nghĩ rằng khóa tăng có thể được thực hiện với các hoạt động được hỗ trợ khác một cách triệt để mà không làm giảm hiệu suất không? Nếu vậy, thì đó không phải là một hoạt động được hỗ trợ theo định nghĩa trên, nếu không, bạn có thể đúng.

Có thể cho rằng, định nghĩa của một hoạt động được hỗ trợ mà tôi cung cấp là của tôi, theo như tôi biết. Nó không chính thức, và do đó có thể thảo luận (mặc dù nó có vẻ khá rõ ràng đối với tôi). Tuy nhiên, tôi sẽ rất vui nếu ai đó có thể cung cấp một nguồn xác định rõ ràng và rõ ràng một hoạt động được hỗ trợ cho các kiểu dữ liệu, hoặc ít nhất là định nghĩa nó theo thuật ngữ tốt hơn của tôi (định nghĩa được đưa ra trong CLR? Tôi không có bản sao ).

Điểm thứ hai của tôi sẽ là về cách chúng tôi xác định hàng đợi ưu tiên (đó là lý do của các đống nhị phân). Là increase_keymột hoạt động cần thiết cho kiểu dữ liệu đó, tức là để sử dụng đúng cách của nó?

Như bạn có thể thấy góc độ của tôi là tất cả về định nghĩa. Tôi không thực sự cung cấp câu trả lời cho câu hỏi của bạn, chỉ đơn thuần là một số gợi ý, vì vậy các cải tiến đều được chào đón.


1
trường hợp sử dụng mẫu có thể là nếu tôi muốn duy trì hàng đợi ưu tiên của đối tượng dựa trên việc sử dụng ít nhất gần đây (ví dụ để tôi có thể xóa các đối tượng được sử dụng gần đây một cách dễ dàng). Tôi có thể sử dụng một heap với ngày truy cập cuối cùng làm khóa. Nếu một đối tượng được truy cập, khóa của nó sẽ cần phải được tăng lên.
GatotPujo

Điểm rất tốt. Quan điểm của tôi có vẻ hơi hạn chế. Thực sự, câu trả lời @HendrikJan mang đến một lời giải thích rất tốt.
didierc
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.