プライオリティキューとヒープソート

プライオリティキュー

定義

多くの場合、我々は現在の最大の重要な要素に対処して、より多くの要素を収集します、または彼らは、ソートを必要としないだろう、;処理する多くのアプリケーションでは、多くの要素を命じたが、必ずしもそれらのすべてが注文する必要はありません。最大の要素、または各アプリケーションに割り当てられた優先順位、そして常に治療の下での取り扱いの際の優先順位が最も高いです。

、最大の要素を削除する要素を挿入します。この場合には、適切なデータ構造は、2つの動作モードをサポートしなければなりません。このデータ構造は、プライオリティキューと呼ばれています。プライオリティキュー、キューと同様のスタックを使用します。ヒープソート - 要素を一つずつ挿入してから最小の要素を削除することで、我々は、プライオリティキューがソートアルゴリズムを実装して使用することができます。

 

API

我々の要素は、Comparableインタフェースを実装して動作させる必要があります。

MaxPQ():プライオリティキューを作成します

MaxPQ():最大優先キューの初期容量を作成します。

MaxPQは(キー[] a)要素の配列を使用して優先度キューを作成します。

空の挿入(キーv)の要素を挿入します。

キーの最大は、()プライオリティキュー内の最大の要素を返します。

キーdelMax()プライオリティキューで最大の要素を削除します。

 

実現

ヒープの定義

バイナリヒープデータ構造はよくプライオリティキューの基本的な動作を実現することができ、バイナリヒープ配列値で、各要素は、他の2つの位置で保証されなければなりません。従って、これらの要素の位置が、少なくとも配列に等しいが、他の二つの要素よりも大きい場合に示されるように、これらの要素は、バイナリツリーに描画されます

 

順序付けられたスタック:各ノードのバイナリツリーは、その子ノードよりも大きい2に等しいです。

 

(以下、単にスタックと呼ばれる)は、バイナリヒープ表します

各ノードは、3つの基準(親ノードへのポインタ、2つの子供ノードを指す)を維持しなければならないように、我々は、リンクリストを表すことができます。我々は非常に単純なバイナリツリーを(上記)を使用する場合は、我々は、アレイ階層順に特定のバイナリツリーノードの配列を、完了する必要がある、ルートノード1(配列インデックス位置0 )にはありません。次いで、ノードKの親ノードのスタック位置に、K / 2であり、左右の子ノードは、2K、2K + 1です。

 

ヒープアルゴリズム

N 1 + N []長さPQのアレイを使用することなく、[0] PQ、スタックの大きさを表してみましょう。私たちは、比較するために、民間のヘルパー関数を必要とし、次のように交換位置にあります

 

プライベートブール値以下(INT I、int型のJ)
{戻りPQ [I] .compareTo(PQ [J])<0。
}

プライベートボイドEXCH(I、int型のjの値int)
{
キー、キー= pqと[i]は、
PQ [I] = PQ [J]。
PQ [J] =キー。
}

発注プロセスでは、我々は両方のケースが発生します、低い嵩たちは下から順に復元する必要がある新しい要素を追加したノードの上昇の優先順位など、ドロップノードの優先順位、例えば、ルートノードは、我々は上から下への順序を復元する必要がある小さな要素の優先順位に置き換えられ、

 

下からの回復のために(フロート)

ノードが大きいが壊れている、親よりも大きくなるので、ヒープの状態が注文された場合は、その後、私たちは、ヒープを修復することや、親を交換する必要があり、交換はまだ新しい親よりも大きくすることができる、私たちのようにする必要がありそれは、親よりも大きな出会うまで交換を継続するか、ルートノードに到達。

コードの実装:

 

プライベートボイド水泳(int型K)
{
一方(K> 1 &&以下(K / 2、k))を
{
EXCH(K / 2、K);
K = K / 2。
}
}

上から下への順番(シンク)を復元します

ノードは、その2人の子供よりも大きくなると、または1つ少し壊れている、そして我々は、ヒープを修復することと二つのサブノードの大きい方を交換する必要があるため、ヒープの状態が注文した場合、交換がまだ発生する可能性があります上記の場合には、交換機は、その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