2016-11-16 9 views
2

私はデータ構造クラスの学生です。私の現在の割り当ては、私が行ってテストした最小の優先度キューを作ることでした。私の問題は、クラスの時間を計り、Big-Oの複雑さを分析する必要があることです。私は、タイミングクラス(これまでの割り当てに関して行ったこと)を設計し、データを収集し、それをプロットしました。私のdeleteMinとaddメソッドは複雑でO(logn)で、findMinにはO(c)が必要ですが、何らかの理由でaddメソッドがO(c)を返しています。私はminPQを繰り返しテストしてきたので、問題は私がタイミングを取る方法と関係があると思われますが、私は困惑しており、ここで誰かが見落としてしまったことを拾うことができると願っています。最小プライオリティキューの複雑さ問題

TLD; addメソッドがより高速に実行されているか、addメソッドをテストするための方法論に問題があります。

編集:タイマーの仕組みに関する追加情報。基本的には、乱数をキューに追加して正しいサイズにしてから、もう1つを追加するのにかかる時間を計測するだけです。サイズ2^startPowから2^stopPowになり、各サイズiterCount回のタイミングを繰り返し平均を出力します。ここで

は私のキュークラスです:

package assignment11; 

import java.io.IOException; 
import java.io.PrintWriter; 
import java.util.Comparator; 
import java.util.NoSuchElementException; 

/** 
* Represents a priority queue of generically-typed items. 
* The queue is implemented as a min heap. 
* The min heap is implemented implicitly as an array. 
* 
* @author Christopher Nielson 
* @uid u0777607 
*/ 
@SuppressWarnings("unchecked") 
public class PriorityQueue<AnyType> { 

    private int currentSize; 

    private AnyType[] array; 

    private Comparator<? super AnyType> cmp; 

    /** 
    * Constructs an empty priority queue. Orders elements according 
    * to their natural ordering (i.e., AnyType is expected to be Comparable) 
    * AnyType is not forced to be Comparable. 
    */ 

    public PriorityQueue() { 
     currentSize = 0; 
     cmp = null; 
     array = (AnyType[]) new Object[10]; // safe to ignore warning 
    } 

    /** 
    * Construct an empty priority queue with a specified comparator. 
    * Orders elements according to the input Comparator (i.e., AnyType need not 
    * be Comparable). 
    */ 
    public PriorityQueue(Comparator<? super AnyType> c) { 
     currentSize = 0; 
     cmp = c; 
     array = (AnyType[]) new Object[10]; // safe to ignore warning 
    } 

    /** 
    * @return the number of items in this priority queue. 
    */ 
    public int size() { 
     return currentSize; 
    } 

    /** 
    * Makes this priority queue empty. 
    */ 
    public void clear() { 
     currentSize = 0; 
    } 

    /** 
    * @return the minimum item in this priority queue. 
    * @throws NoSuchElementException if this priority queue is empty. 
    * 
    * (Runs in constant time.) 
    */ 
    public AnyType findMin() throws NoSuchElementException { 
     if (currentSize == 0) { 
      throw new NoSuchElementException(); 
     } 
     return array[0]; 
    } 


    /** 
    * Removes and returns the minimum item in this priority queue. 
    * 
    * @throws NoSuchElementException if this priority queue is empty. 
    * 
    * (Runs in logarithmic time.) 
    */ 
    public AnyType deleteMin() throws NoSuchElementException { 
     if (currentSize == 0) { 
      throw new NoSuchElementException(); 
     } 
     AnyType tmp = array[0]; 

     array[0] = array[currentSize - 1]; 
     array[currentSize - 1] = null; 
     --currentSize; 

     downHeap(0); 

     return tmp; 
    } 


    /** 
    * Adds an item to this priority queue. 
    * 
    * (Runs in logarithmic time.) Can sometimes terminate early. 
    * 
    * @param x -- the item to be inserted 
    */ 
    public void add(AnyType x) { 
     if (currentSize == array.length) { 
      AnyType[] tmp = array; 
      array = (AnyType[]) new Object[array.length * 2]; 
      for (int currentIndex = 0; currentIndex < tmp.length; currentIndex++) { 
       array[currentIndex] = tmp[currentIndex]; 
      } 
     } 
     array[currentSize] = x; 
     ++currentSize; 

     upHeap(currentSize - 1); 
    } 

    /** 
    * Generates a DOT file for visualizing the binary heap. 
    */ 
    public void generateDotFile(String filename) { 
     try(PrintWriter out = new PrintWriter(filename)) { 
      out.println("digraph Heap {\n\tnode [shape=record]\n"); 

      for(int i = 0; i < currentSize; i++) { 
       out.println("\tnode" + i + " [label = \"<f0> |<f1> " + array[i] + "|<f2> \"]"); 
       if(((i*2) + 1) < currentSize) 
        out.println("\tnode" + i + ":f0 -> node" + ((i*2) + 1) + ":f1"); 
       if(((i*2) + 2) < currentSize) 
        out.println("\tnode" + i + ":f2 -> node" + ((i*2) + 2) + ":f1"); 
      } 
      out.println("}"); 
     } catch (IOException e) { 
      System.out.println(e); 
     } 
    } 

    /** 
    * Internal method for comparing lhs and rhs using Comparator if provided by the 
    * user at construction time, or Comparable, if no Comparator was provided. 
    */ 
    private int compare(AnyType lhs, AnyType rhs) { 
     if (cmp == null) { 
      return ((Comparable<? super AnyType>) lhs).compareTo(rhs); // safe to ignore warning 
     } 
     // We won't test your code on non-Comparable types if we didn't supply a Comparator 

     return cmp.compare(lhs, rhs); 
    } 

    /** 
    * Internal method to reheapify upward. 
    * 
    * @param root Item where reheapifying will begin 
    */ 
    private void upHeap(int root) { 
     // check if root is less than parent 
     if (root >= 0 && compare(array[root], array[(root - 1)/2]) < 0) { 
      AnyType tmp = array[(root - 1)/2]; 
      array[(root - 1)/2] = array[root]; 
      array[root] = tmp; 
      upHeap((root - 1)/2); 
     } 
    } 

    /** 
    * Internal method to reheapify downward. 
    * 
    * @param root Item where reheapifying will begin. 
    */ 
    private void downHeap(int root) { 
     // check if left child is less than root 
     if ((root * 2) + 1 < currentSize && array[(root * 2) + 1] != null && compare(array[(root * 2) + 1], array[root]) < 0) { 
      // check if right child is less than left child 
      if ((root * 2) + 2 < currentSize && array[(root * 2) + 2] != null && compare(array[(root * 2) + 2], array[(root * 2) + 1]) < 0) { 
       // swap with right child 
       AnyType tmp = array[root]; 
       array[root] = array[(root * 2) + 2]; 
       array[(root * 2) + 2] = tmp; 
       downHeap((root * 2) + 2); 
      } else { 
       // swap with left child 
       AnyType tmp = array[root]; 
       array[root] = array[(root * 2) + 1]; 
       array[(root * 2) + 1] = tmp; 
       downHeap((root * 2) + 1); 
      } 
     } else if ((root * 2) + 2 < currentSize && array[(root * 2) + 2] != null && compare(array[(root * 2) + 2], array[root]) < 0) { 
      // swap with right child 
      AnyType tmp = array[root]; 
      array[root] = array[(root * 2) + 2]; 
      array[(root * 2) + 2] = tmp; 
      downHeap((root * 2) + 2); 
     } 
    } 

    // LEAVE IN for grading purposes 
    public Object[] toArray() {  
     Object[] ret = new Object[currentSize]; 
     for(int i = 0; i < currentSize; i++) { 
      ret[i] = array[i]; 
     } 
     return ret; 
    } 
} 

そしてここでは、私のタイミングクラスです:事前に Timing Results

ありがとう:

package assignment11; 

import java.io.File; 
import java.io.FileOutputStream; 
import java.io.OutputStreamWriter; 
import java.util.Random; 

/** 
* @author Christopher Nielson 
* @uid u0777607 
*/ 
public class PriorityQueueTimer { 

    private static int startPow = 10; 
    private static int stopPow = 24; 
    private static int iterCount = 10000; 
    private static Random rand; 
    private static OutputStreamWriter fileOut; 

    public static void main(String[] args) { 
     timeAdd(); 
//  timeDeleteMin(); 
//  timeFindMin(); 
     System.out.println("Finished timing!"); 
    } 

    /** 
    * Times add method of PriorityQueue for different data sizes and outputs results to a file. 
    */ 
    private static void timeAdd() { 
     try { 
      fileOut = new OutputStreamWriter(new FileOutputStream(new File("assignment11-addTimer.csv"))); 
      PriorityQueue<Integer> addTimer; 
      for (int currentPow = startPow; currentPow <= stopPow; currentPow++) { 
       int dataSize = (int) Math.pow(2, currentPow); 
       System.out.print("Timing add on datasize " + dataSize + " (Power: " + currentPow + ")..."); 
       long totalTime = 0; 
       long stopTime; 

       addTimer = new PriorityQueue<Integer>(); 
       rand = new Random(13); 

       for (int currentRand = 0; currentRand < dataSize; currentRand++) { 
        addTimer.add(rand.nextInt()); 
       } 

       long startTime = System.nanoTime(); 
       while (System.nanoTime() - startTime < 1000000){} 

       for (int currentIter = 0; currentIter < iterCount; currentIter++) { 
        startTime = System.nanoTime(); 
        addTimer.add(rand.nextInt()); 
        stopTime = System.nanoTime(); 
        addTimer.deleteMin(); 
        totalTime += stopTime - startTime; 
       } 
       System.out.println("Finished!"); 
       fileOut.write(dataSize + "\t" + (totalTime/iterCount) + "\n"); 
       fileOut.flush(); 
      } 
      fileOut.close(); 
     } catch(Exception e) { 
      System.err.println(e.getMessage()); 
      e.printStackTrace(); 
     } 
    } 

    /** 
    * Times deleteMin method of PriorityQueue for different data sizes and outputs results to a file. 
    */ 
    private static void timeDeleteMin() { 
     try { 
      fileOut = new OutputStreamWriter(new FileOutputStream(new File("assignment11-deleteMinTimer.csv"))); 
      PriorityQueue<Integer> deleteTimer; 
      for (int currentPow = startPow; currentPow <= stopPow; currentPow++) { 
       int dataSize = (int) Math.pow(2, currentPow); 
       System.out.print("Timing deleteMin on datasize " + dataSize + " (Power: " + currentPow + ")..."); 
       long totalTime = 0; 
       long stopTime; 

       deleteTimer = new PriorityQueue<Integer>(); 
       rand = new Random(13); 

       for (int currentRand = 0; currentRand < dataSize; currentRand++) { 
        deleteTimer.add(rand.nextInt()); 
       } 

       long startTime = System.nanoTime(); 
       while (System.nanoTime() - startTime < 1000000){} 

       for (int currentIter = 0; currentIter < iterCount; currentIter++) { 
        startTime = System.nanoTime(); 
        deleteTimer.deleteMin(); 
        stopTime = System.nanoTime(); 
        deleteTimer.add(rand.nextInt()); 
        totalTime += stopTime - startTime; 
       } 
       System.out.println("Finished!"); 
       fileOut.write(dataSize + "\t" + (totalTime/iterCount) + "\n"); 
       fileOut.flush(); 
      } 
      fileOut.close(); 
     } catch(Exception e) { 
      System.err.println(e.getMessage()); 
      e.printStackTrace(); 
     } 
    } 

    /** 
    * Times findMin method of PriorityQueue for different data sizes and outputs results to a file. 
    */ 
    private static void timeFindMin() { 
     try { 
      fileOut = new OutputStreamWriter(new FileOutputStream(new File("assignment11-findMinTimer.csv"))); 
      PriorityQueue<Integer> findTimer; 
      for (int currentPow = startPow; currentPow <= stopPow; currentPow++) { 
       findTimer = new PriorityQueue<Integer>(); 
       int dataSize = (int) Math.pow(2, currentPow); 
       System.out.print("Timing findMin on datasize " + dataSize + " (Power: " + currentPow + ")..."); 
       long totalTime = 0; 
       long stopTime; 

       rand = new Random(13); 

       for (int currentRand = 0; currentRand < dataSize; currentRand++) { 
        findTimer.add(rand.nextInt()); 
       } 

       long startTime = System.nanoTime(); 
       while (System.nanoTime() - startTime < 1000000){} 

       for (int currentIter = 0; currentIter < iterCount; currentIter++) { 
        startTime = System.nanoTime(); 
        findTimer.findMin(); 
        stopTime = System.nanoTime(); 
        totalTime += stopTime - startTime; 
       } 
       System.out.println("Finished!"); 
       fileOut.write(dataSize + "\t" + (totalTime/iterCount) + "\n"); 
       fileOut.flush(); 
      } 
      fileOut.close(); 
     } catch(Exception e) { 
      System.err.println(e.getMessage()); 
      e.printStackTrace(); 
     } 
    } 
} 

これは私が現在持っているグラフの結果です!

+0

最初の質問は動作しますか? 2番目の質問:* O(c)* - O *(1)*のようなものはありませんか? – EJP

+0

はい、私が言ったように、私はそれをかなり徹底的にテストしました。ここではJUnitを使用してアップロードしなかったテストクラスがあり、すべてのメソッドに対して複数のテストを記述しました。そして、はい、私はO(1)、一定の時間を意味します。 – Kofu

+0

@KaidulIslamを修正してください。明らかに、プロットは異常のために完全ではないだろうが、追加のプロットはまったく上がらない。 – Kofu

答えて

1

これは、挿入がO(1)平均(および最悪の場合はもちろんO(log n))であるという効果を手に入れた議論です。

最小値をルートとして割り当て、残りの要素をランダムなサブセットに分割し、各サブセットにルートの子となるサブツリーを構築することで、ランダムな要素セットにランダムなバイナリヒープを構築します。 (ランダム挿入で作成されたヒープの実際の分布はこれとは異なるかもしれませんが、私はそれほど重大ではないと推測しています)

このヒープにはランダム要素xを挿入します。配列を拡張するとO(1)が償却されるので、メインコストはアップヒープであり、置き換えられた要素の数に比例します。期待値を計算しましょう。

ヒープに既存の要素がn存在すると、新しい要素がルートよりも小さい確率は1/(n+1)であり、最大でlog (n+1)の置換要素になります。そうでなければ、変位は(n-1)/2要素の1つのサブツリーに限定されます。どちらもxとそのサブツリーの要素は根よりも大きいことを条件としているので、我々が見つけ、そこで私たちは、予想コストが

 log (n+1) 
T(n) = --------- + T((n - 1)/2) 
     n + 1 

T(0) = 0, 

であることを見つけるために、誘導理由ができ、その、n = 2^k - 1ため

T(2^k - 1) = k/2^k + T(2^(k-1) - 1) 
      = sum_{j=0}^k j/2^j 
      = O(1) by standard analysis techniques. 

(すべての対数は、ベース2です。)

+0

私はちょうど間違っていたので、平均して分PQに追加するコストはO(1)であり、O(logn)は最悪の場合ですか?それが事実なら、それは素晴らしいです。私は最悪の場合でもタイマーを作るだけです。 – Kofu

+0

@Kofuおそらく、あなたの変更を与えられました。しかし、ワーストケースのタイマーは、アレイが時折サイズ変更される必要があるため、リニア時間を報告します。私は、要素を降順で挿入する第2のkraskevichの勧告です。 –

+0

私はそれを行い、その後に-9999か何かを挿入して、それがすべてを通過することを確認しました。これらは結果でした:https://i.gyazo.com/811afc8ca356c41d0812475a65f8eb59.png @David – Kofu

0

addメソッドをランダムではない入力(たとえば、増減する配列)で実行しようとしましたか?それは実際に挿入あたりのアクションを~log nすることができます。新たに追加された要素がランダムな要素を追加したときに最大の要素となる可能性は低いので、ランダム入力の場合はそうではないかもしれません(スワップ数の期待値この場合、挿入は定数ですが、実際には計算するつもりはありません)。

+0

ランダム性が原因かもしれないと私は考えましたが、平均複雑度はO(logn)でなければなりません。それとも、私は間違っていますか?O(logn)はmin PQの最悪のケースですか?平均的なケースであるはずだと思っていたので、乱数を使っていました。 – Kofu

関連する問題