用比较器的java heapify方法

时间:2015-01-14 02:51:20

标签: java algorithm data-structures heap priority-queue

我正在尝试写一个班级HeapQueue。我将root的左子项存储在2 * indexOfRoot + 1索引,将右子项存储在2 * indexOfRoot + 2

public class HeapQueue implements PriorityQueue, BinaryHeap {

public List<Task> queue;
public Comparator comparator;

public HeapQueue() {
    queue = new ArrayList();
}

public void setComparator(Comparator comparator) {
    this.comparator = comparator;
    heapify(0);
}

public Comparator getComparator() {
    return comparator;
}

public void offer(Task task) {
    int currentElement, previousElement;
    queue.add(task);
    currentElement = queue.size() - 1;
    previousElement = (currentElement - 1) / 2;
    while (previousElement >= 0 && 
             getComparator().compare(queue.get(currentElement), queue.get(previousElement)) > 0) {
        swap(currentElement, previousElement);
        currentElement = previousElement;
        previousElement = (currentElement - 1) / 2;
    }
}

private void swap(int i, int j) {
    Task t1 = queue.get(i);
    Task t2 = queue.get(j);
    Task t3 = t1;
    queue.set(i, t2);
    queue.set(j, t3);
}
}

排队Task的存储对象。

public class Task {

private final String name;
private final int priority;

public Task(String name, int priority) {
    this.name = name;
    this.priority = priority;
}

public int getPriority() {
    return priority;
}

@Override
public String toString() {
    return name + "\tpriority = " + priority;
}
}

我在heapify()中有一个方法HeapQueue

public void heapify(int root) {
    int leftChild, rightChild;
    leftChild = 2 * root + 1;
    if (leftChild < queue.size()) {
        rightChild = leftChild + 1;
        if ((rightChild < queue.size())
                && getComparator().compare(queue.get(rightChild), queue.get(leftChild)) > 0) {
            leftChild = rightChild;
        }
        if (getComparator().compare(queue.get(leftChild), queue.get(root)) > 0) {
            swap(root, leftChild);
            heapify(leftChild);
        }
    }

}

通过我的任务,在将任务添加到队列后,可以通过方法setComparator()更改比较器。 默认Comparator是:

public class Comparator{
    public int compare(Task t1, Task t2) {
        if (t1.getPriority() == t2.getPriority()) {
            return 0;
        } else if (t1.getPriority() < t2.getPriority()) {
            return -1;
        } else {
            return 1;
        } //sorting max
    }
 }

例如,其他比较器可能是:

public class otherComparator{
    public int compare(Task t1, Task t2) {
        if (t1.getPriority() == t2.getPriority()) {
            return 0;
        } else if (t1.getPriority() < t2.getPriority()) {
            return 1;
        } else {
            return -1; 
        } //sorting min
    }
 }

我创建了我的HeapQueue并添加了一些元素。

HeapQueue heap = new HeapQueue();
heap.setComparator(comparator);
Task t1 = new Task("a", 1);
Task t2 = new Task("b", 2);
Task t3 = new Task("c", 3);
Task t4 = new Task("d", 4);
System.out.println(heap.queue.toString());

结果是:

[d priority = 4, c  priority = 3, b priority = 2, a priority = 1]

    4
   / \
  3   2
 /
1 

没错。但是当我将Comparator更改为otherComparator时:

otherComparator newComparator = new otherComparator();
heap.setComparator(newComparator);
System.out.println(heap.queue.toString());

结果是:

[b priority = 2, c  priority = 3, d priority = 4, a priority = 1]

    2
   / \
  3   4
 /
1 

这是错的。正确答案是这样的:

[a priority = 1, b priority = 2, c  priority = 3, d priority = 4]

    1
   / \
  2   3
 /
4 

我认为我的heapify()功能存在问题。但我找不到错误。有人可以帮忙吗?

3 个答案:

答案 0 :(得分:1)

您只需从 max heap更改为min heap ,这会破坏整个堆结构!。

问题是,当您更改比较器时,调用heapify(0)是不够的,因为,例如,这个结构:

             4
            / \
           3   2
          /
         1

heapify之后,1将不会向上移动,因为在heapify(0)之后,程序会跳转到正确的孩子,这是2,我们无法达到1。

你可以创建另一个堆!

你可以看看这个answer,基本上,在更改比较器时,你只是破坏了堆结构!

答案 1 :(得分:1)

你需要做的不仅仅是堆缩(就像你在heapify中一样 - 将一个节点推到树下)或堆积起来(就像你在offer方法中那样 - 将节点拉到树上)。这些只会分别用于修复删除或添加的单个节点。堆的其余部分必须已经遵守堆规则。

您需要完全重新定义结构。这可以通过从结构的底部开始并将每个根向下推到正确的子树来以线性时间完成。可以把它想象成为每个节点运行heapify,子节点从完整树的尾部/末尾开始。

rehapify arraynodes:
    for i from arraynodes.length / 2:
      heapifydown( arraynodes, i )

heapifydown是你的heapify函数。

答案 2 :(得分:1)

我通过创建函数function SSO($key,$uid){ $lenth=32; $aZ09 = array_merge(range('A', 'Z'), range('a', 'z'),range(0, 9)); $randphrase =''; for($c=0;$c < $lenth;$c++) { $randphrase .= $aZ09[mt_rand(0,count($aZ09)-1)]; } //echo "Key: ".$key."<br/>"; //echo "Phrase: ".$randphrase."<br/>"; //Append key onto phrase end $randkey=$randphrase.$key; // SHA512 Hash $toencode= utf8_encode($randkey); // Pass 3rd, optional parameter as TRUE to output raw binary data $output = hash("sha512", $toencode, true); //base 64 encode the hash binary data $sso = base64_encode($output); $length = mb_strlen($sso); $characters = 2; $start = $length - $characters; $last2 = substr($sso , $start ,$characters); // Yes, Strip the extra == if($last2 == "==") {$ssocode = substr($sso,0,-2);} // No, just pass the value to the next step else{$ssocode=$sso;} // Prepend the random phrase to the encrypted code. $ssocode = $randphrase.$ssocode; //echo "SSO: ".$ssocode."<br/>"; //Use first 22 charecters of random. $shortphrase=substr($randphrase,0,22); //Append uid & key onto shortened phrase end $uidv=$uid.$shortphrase.$key; // SHA512 Hash $idencode= utf8_encode($uidv); // Pass 3rd, optional parameter as TRUE to output raw binary data $idoutput = hash("sha512", $idencode, true); // Base64 Encode of hash binary data $idssoe = base64_encode($idoutput); //Determine if we need to strip the zeros $idlength = mb_strlen($idssoe); $idcharacters = 2; $idstart = $idlength - $idcharacters; $idlast2 = substr($idssoe , $idstart ,$idcharacters); if($idlast2 == "==") {$ssouidv = substr($idssoe,0,-2);} // No, just pass the value to the next step else{$ssouidv=$idssoe;} //echo "SSOID: ".$ssouidv; return array($ssocode, $ssouidv); } 来解决问题:

rebuild()