우선 순위 큐와 힙 정렬

우선 순위 큐

정의

, 이상의 요소를 수집 그들은 일종의을 필요로하지 않습니다 많은 경우에 우리는 다음 현재 최대의 핵심 요소를 다루는 것, 많은 응용 프로그램이 많은 요소를 주문 처리,하지만 반드시 그들 모두 주문한 필요하지 않습니다 가장 큰 요소 또는 각 응용 프로그램에 할당 된 우선 순위, 항상 처리에서 처리의 경우에 가장 높은 우선 순위입니다.

가장 큰 요소를 제거하는 요소를 삽입이 경우, 적절한 데이터 구조는 두 가지 동작 모드를 지원한다. 이 데이터 구조들은 우선 순위 대기열이라고한다. 우선 순위 큐와 큐와 비슷한 스택을 사용합니다. 힙 정렬 - 요소 하나 하나를 삽입 한 후 작은 요소를 삭제함으로써, 우리는 우선 순위 큐 정렬 알고리즘을 구현 사용할 수 있습니다.

 

API

작동해야합니다 우리 요소는 Comparable 인터페이스를 구현합니다.

MaxPQ () : 우선 순위 큐를 생성

MaxPQ () : 최대 우선 순위 큐의 초기 용량을 만듭니다.

MaxPQ는 (키 [] a) 소자 어레이 우선 순위 큐를 생성한다. ,

요소를 삽입하는 삽입 공간 (키 V).

키 최대 ()는 우선 순위 큐에 가장 큰 요소를 반환

키 delMax () 우선 순위 큐에있는 가장 큰 요소를 삭제합니다.

 

실현

힙 정의

또한 이진 힙 배열 값의 우선 순위 큐의 기본적인 동작을 달성 할 수있는 이진 힙 데이터 구조는, 각 요소는 두 개의 다른 위치에서 확보되어야한다. 따라서, 이들 구성 요소의 위치는 적어도 배열과 동일하지만, 도시 된 바와 같이 또 다른 두 요소를,이 요소는 이진 트리로 그려진 것보다 크다

 

정렬 된 스택 : 각 노드의 이진 트리가 자식 노드보다 큰 경우 2와 같다.

 

(이하, 스택이라고) 이진 힙 나타낸다

각 노드 (두 아이 노드를 가리키는, 부모 노드에 대한 포인터) 세 가지 기준을 유지해야합니다 있도록 우리는 목록을 연결 나타낼 수 있습니다. 우리는 매우 간단한 이진 트리 (위)를 사용하는 경우, 우리는 배열 계층 순서로 특정 이진 트리 노드의 배열을 완료하는 데 필요한, 루트 노드 1 (배열 인덱스 위치 0 )하지 않습니다. 그런 다음 노드 K의 부모 노드의 스택 위치에, K / 2 왼쪽과 오른쪽 자식 노드는 2K, 2K + 1이다.

 

힙 알고리즘

, PQ [0] []는 N + 1 PQ 길이의 배열을 이용하지 않고, 스택의 크기를 나타내는 N하자. 우리는 비교하기 위해 개인 도우미 기능을 필요로하고 다음과 같이 교환 위치입니다

 

전용 부울 이하 INT (I, J의 INT)
{복귀 PQ [I] .compareTo (PQ [J]) <0;
}

개인 공극 EXCH (I, J의 INT INT)
{
주요 키의 PQ = [I];
PQ [I]의 PQ = [J]
PQ [J]를 키 =;
}

주문 과정에서 우리는 두 가지 경우가 발생합니다, 낮은 벌크 우리가 바닥에서 순서를 복원해야 할 새로운 요소를 추가 노드의 상승의 우선 순위와 같은 드롭 노드의 우선 순위, 예를 들어, 루트 노드는 우리가 위에서 아래로 순서를 복원해야하는 작은 요소의 우선 순위로 대체,

 

바닥에서 복구하기 위해 (플로트)

노드가 큰이 끊어 부모보다 크게되기 때문에 힙이 상태를 주문한 경우, 우리가 힙을 복구 할 부모를 교환 할 필요가 교환이 여전히 새 부모보다 클 수 있습니다, 우리는 필요 그것의 부모보다 더 큰 만날 때까지 교환을 계속하거나 루트 노드에 도달합니다.

코드 구현 :

 

개인 무효 수영 (INT의 K)
{
하면서 (K> 1 && 이하 (K / 2, K))
{
EXCH (K / 2, K);
K = K / 2;
}
}

위에서 아래로 순서 (침몰) 복원

노드가 두 자녀 이상이된다, 또는 약간 파손하는 일 때문에 힙이 상태를 주문한 경우, 우리는 그것을 교환 할 필요가 있고 두 개의 하위 노드의 큰 힙을 수리, 교환 가능성이 있습니다 전술 한 경우, 교환기는 두 개의 자식 노드까지 계속하거나 스택의 바닥에 도달보다 작다.

코드 구현

private void sink(int k)
{
while(2*k<=N)
{
int j=2*k;
if(j<N&&less(j,j+1)) j++;
if(!less(k,j)) break;
exch(k,j);
k=j;

}
}

插入元素

我们将新元素放到数组的末尾,增加堆的大小并让这个元素上浮到合适的位置。

 

删除最大元素

我们从数组顶端删除最大元素并将数组的最后一个元素放到顶端,减少堆的大小并将这个元素下沉到合适的位置。

这两种操作如图所示:

完整代码:

 1 public class MaxPQ<Key extends Comparable<Key>> {
 2     private Key pq[];
 3     private int N=0;
 4     public MaxPQ(int max)
 5     {
 6         pq=(Key[])new Comparable[max];
 7     }
 8     
 9     private boolean less(int i,int j)
10     {return pq[i].compareTo(pq[j])<0;
11     }
12 
13     private void exch(int i,int j)
14     {
15        Key key=pq[i];
16        pq[i]=pq[j];
17        pq[j]=key;
18     }
19     
20     private void swim(int k)
21     {
22         while(k>1&&less(k/2,k))
23         {
24             exch(k/2,k);
25             k=k/2;
26         }
27     }
28     
29     private void sink(int k)
30     {
31         while(2*k<=N)
32         {
33             int j=2*k;
34             if(j<N&&less(j,j+1)) j++;
35             if(!less(k,j)) break;
36             exch(k,j);
37             k=j;
38                 
39         }
40     }
41     
42     public boolean isEmpty()
43     {
44         return N==0;
45     }
46     
47     public int size()
48     {
49         return N;
50     }
51     
52     public void insert(Key key)
53     {
54         pq[++N]=key;
55         swim(N);
56     }
57     
58     public Key delMax()
59     {
60         Key max=pq[1];
61         exch(1,N--);//传递的参数为N,当函数执行完后再执行N--;
62         pq[N+1]=null;
63         sink(1);
64         return max;
65         
66     }
67 
68 
69 }
View Code

 

注意:本代码没有考虑数组越界问题,所有操作都是理想的,不会发生异常

 

堆排序

 对于上面的优先队列,只要我们改变一下less()函数的判断条件,就可以就可以将他变为一个删除最小元素的优先队列。

堆排序分为两个阶段,在堆的构造阶段,我们将原始数组重新组织安排到一个堆中,然后在下沉排序阶段,我们从堆中按照递减顺序取出所有元素并得到排序结果,为了排序的需要,我们将直接使用swim()和sink()方法。

 

堆的构造

关于如何构造堆,我们有两种方式

(1)采用swim()方法,从左往右扫描数组,这样可以保证指针左侧的元素都是堆有序的,这种方式类似于创建一个空堆,然后不断调用insert()方法。

(2)采用sink()方法,从右往左扫描数组,对于一个给定的数组,每一个元素都可以看成是一个已经排好的堆,如果一个结点的两个子节点都已经是堆了,那么在该节点上调用sink()方法也能将他们变成堆。使用这种方法我们只需要扫描一办的数组

 

代码实现

 

 1 public class Heap {
 2     private Heap() { }
 3 
 4   
 5     public static void sort(Comparable[] pq) {
 6         int n = pq.length;
 7         for (int k = n/2; k >= 1; k--)
 8             sink(pq, k, n);
 9         while (n > 1) {
10             exch(pq, 1, n--);
11             sink(pq, 1, n);
12         }
13     }
14 
15   
16 
17     private static void sink(Comparable[] pq, int k, int n) {
18         while (2*k <= n) {
19             int j = 2*k;
20             if (j < n && less(pq, j, j+1)) j++;
21             if (!less(pq, k, j)) break;
22             exch(pq, k, j);
23             k = j;
24         }
25     }
26 
27  
28     private static boolean less(Comparable[] pq, int i, int j) {
29         return pq[i-1].compareTo(pq[j-1]) < 0;
30     }
31 
32     private static void exch(Object[] pq, int i, int j) {
33         Object swap = pq[i-1];
34         pq[i-1] = pq[j-1];
35         pq[j-1] = swap;
36     }
37 
38 
39  }
View Code

下沉排序:

我们将堆中最大的元素删除,然后放入堆缩小后空出的位置

算法行为:

 

추천

출처www.cnblogs.com/lls101/p/11230379.html