解析のヒープソートアルゴリズム

ヒープソート

ヒープはソートそれはアルゴリズムが設計された機能のヒープを使用してソートの一種です。(完全二分木、各ノードの値)は約超える(または未満の子ノードです)

 

ビルドとヒープソート:ヒープソート処理は、大きく分けて2つの段階に分けることができます。

 

内蔵ヒープ

私たちは、ヒープ配列の場所を構築することができます。すなわち、内蔵ヒープの元の配列で動作し、他のアレイとのin situでの助けなしに、あります

2つの方法がある:元の配列は、Nデータ、それは仮定することができるしている場合、最初に、インデックスデータは、1つのみのデータアレイである含んでいます。

その後、インデックスは、nは2から順次スタックに挿入されたデータです。そのような配列が含まれているn個のデータ、およびスタックに編成します。

このプロセスは、スタックの構築プロセスの底部からスタックである前面から背面にデータを処理スタックを、構築されています

 

第二の方法とは対照的に、プロセスは、バックからのプロセスデータです。各データのスタックからスタックの下に挿入される場合には、です。

なぜならリーフノードではないヒープ上から下に、これのターンヒープに、最初の非リーフ・ノードで開始することができます。

 

 

 

シーケンス

ヒープの建設後、配列の最初の要素は、最大要素であるヒープの最上部です。

これは、最後の要素交換、添字nの位置を置く最大の要素となります。

スタックの最上位に、要素の添字n「をスタック要素の上部を削除」し、その後道のスタックを介して、n-1個の再構成されたパイルの残りの要素にソート似。

スタックが完了したら、我々は、インデックスがn-1である位置に要素のスタックの最上位を取ります、。

最後のヒープのみラベル要素1、仕事の並べ替えが完了するまで、このプロセスが繰り返されます。

 

 

 

 

ヒープソート処理

効率ヒープソート

内蔵ヒープ

リーフノードのスタックは、最後から二番目の層のノードのスタックから開始する必要がある、必要はありません。

プロセス・スタックの各ノードは、ノードの数は、このノードkに比例した高さと比較して、交換する必要があります。

 

各非リーフノードの高さの合計は、以下の式であります:

減算転位

左と右の式は2を乗じて、我々は別の式S2を取得します。我々は、Sが得られ、S1およびS2とS2が減算されるずれ整列します

 

そして、Sは等比数列を合計する、幾何学的なシーケンスの一部であります

Hので= LOG2 nは、式Sに、S = O(n)を得ることができ、従って、スタック構造の時間複雑度は、O(N)です。 

 

シーケンス

ソート処理の時間複雑度はO(nlogn)になるようにプロセスをソートする、「ヒープ要素の削除上部」に類似しています

 

ソート二ソート処理を含むスタック構造、プロセス時間の構築スタックはO(N)の時間計算量で、ソート処理の複雑さは、O(nlogn)です。

したがって、ヒープ全体のソート時間の複雑さは、O(nlogn)です。

 

ヒープの並べ替えスペースの消費量

ヒープは、ソート、構築されたか、ヒープソートするかどうか、それは元の配列で行われ、ごく少数の一時的な保管スペースが必要なので、場所は、ソート・ヒープソートアルゴリズムです。

 

安定性のヒープの並べ替え

ヒープはソートソートアルゴリズム安定していません。

ソート処理ので、動作ノードと交換スタックのスタック上の最後のノードの存在は、それが同じ相対的な順序の元データの値を変更することが可能となります。

 

ヒープソートコードの実装


public class Heap {
  private int[] a; // 数组,从下标1开始存储数据
  private int n;  // 堆可以存储的最大数据个数
  private int count; // 堆中已经存储的数据个数
 
  public Heap(int capacity) {
    a = new int[capacity + 1];
    n = capacity;
    count = 0;
  }
  //对于完全二叉树来说,下标从 2n​+1 到 n 的节点都是叶子节点。叶子结点不需要堆化
  private static void buildHeap(int[] a, int n) {
    for (int i = n/2; i >= 1; --i) {
      heapify(a, n, i);
    }
  }

  private static void heapify(int[] a, int n, int i) {
    while (true) {
      int maxPos = i;
      if (i*2 <= n && a[i] < a[i*2]) maxPos = i*2;
      if (i*2+1 <= n && a[maxPos] < a[i*2+1]) maxPos = i*2+1;
      if (maxPos == i) break;
      swap(a, i, maxPos);
      i = maxPos;
    }
  }  
  // n表示数据的个数,数组a中的数据从下标1到n的位置。
  public static void sort(int[] a, int n) {
    buildHeap(a, n);
    int k = n;
    while (k > 1) {
      swap(a, 1, k);
      --k;
      heapify(a, k, 1);
    }
  }
}

 

上記のコードは、データスタック配列の添字1から想定される開始位置として記憶されます。

それが0ストレージで起動した場合は、アイデアを処理することは、実際には変更はありません。

コードがターゲット子を計算するための式の下に、実施されており、親ノードが変更された唯一の変更。

ノードが添字私の場合は、2である左の子ノードのインデックスがI + 1、右の子の添字は2 * I + 2である*、添字は、親ノード(I-1)/ 2です。

公開された113元の記事 ウォン称賛25 ビュー30000 +

おすすめ

転載: blog.csdn.net/qq_42006733/article/details/104694805