0
已采纳
黄俊博
资深光能
资深光能
斜堆(Skew Heap)基于左倾堆的概念,也是一个用于快速合并的堆结构,但它可自我调整(self-adjusting),每一个merge操作的平摊成本仍为O(logN),其中N为结点数,而且和左倾堆相比,每个结点没有npl属性,从而节省了空间。斜堆并不能保证左倾,但是每一个合并操作(也是采取右路合并)同时需要无条件交换(而左倾堆中只是根据左右子树的npl值不符合要求时才交换)左右子树,让新合并的右子树变成左子树,原来的左子树变成新的右子树(这有点类似于Splay Tree中的做法),从而可以达到平摊意义上的左倾效果。注意:一颗子树r和NULL子树合并时并不需要交换r子树的左右子树。
由于斜堆并不是严格的左倾堆,最坏的情况下右路长度可能为N,因此采用递归调用merge的风险是出现stack overflow。尽管如此,在下面的实现中还是提供了递归和非递归的两个版本。测试时使用的是非递归版本。
斜堆中除merge之外的其他操作跟左倾堆类似,具体情况参考以下代码,在此不再赘述。
实现:
[java] view plain copy
- import java.util.LinkedList;
- import java.util.Stack;
- /**
- *
- * Skew Heap
- *
- * Copyright (c) 2011 ljs (http://blog.csdn.net/ljsspace/)
- * Licensed under GPL (http://www.opensource.org/licenses/gpl-license.php)
- *
- * @author ljs
- * 2011-08-25
- *
- */
- public class SkewHeap {
- static class Node{
- int key;
- Node left;
- Node right;
- public Node(int key){
- this.key = key;
- }
- public String toString(){
- return String.valueOf(this.key);
- }
- public Node recursiveMerge(Node rhsRoot){
- if(rhsRoot==this || rhsRoot == null) {
- //Note: no need to swap the left and right children of this tree
- //Node tmp = this.left;
- //this.left = this.right;
- //this.right = tmp;
- return this;
- }
- Node root1 = null; //the root of the merged tree
- Node root2 = null;
- if(rhsRoot.key<this.key){
- //merge this with rhsRoot's right child
- root1 = rhsRoot;
- root2 = this;
- }else{
- //merge rhsRoot with this's right child
- root1 = this;
- root2 = rhsRoot;
- }
- Node tmpRoot = root2.recursiveMerge(root1.right);
- root1.right = root1.left;
- root1.left = tmpRoot;
- //or equivalently: we may first merge recursively, then swap left and right children.
- //Node right = root1.right;
- //root1.right = root1.left;
- //root1.left = root2.merge(right);
- return root1;
- }
- }
- private Node root;
- public SkewHeap(Node root){
- this.root = root;
- }
- //version 1: recursive merge: not recommended because skew heap is
- //unlike leftist heap to be deterministically leftist, so it can cause
- //stack overflow in extreme cases.
- private static Node recursiveMerge(Node root1,Node root2){
- if(root1 == null) return root2;
- if(root2 == null) return root1;
- return root1.recursiveMerge(root2);
- }
- //version 2: non-recursive merge
- private static Node iterativeMerge(Node root1,Node root2){
- if(root1 == null) return root2;
- if(root2 == null) return root1;
- Stack<Node> stack = new Stack<Node>();
- Node r1 = root1;
- Node r2 = root2;
- while(r1 != null && r2 != null){
- if(r1.key<r2.key){
- stack.push(r1);
- r1 = r1.right;
- }else{
- stack.push(r2);
- r2 = r2.right;
- }
- }
- //at this point, exactly one of r1 and r2 is null
- //Again we don't need to swap the left and right children of r
- Node r = (r1 != null)?r1:r2;
- //merge
- while(!stack.isEmpty()){
- Node node = stack.pop();
- node.right = node.left;
- node.left = r;
- r = node;
- }
- return r;
- }
- public static SkewHeap merge(SkewHeap h1,SkewHeap h2){
- Node rootNode = iterativeMerge(h1.root,h2.root);
- return new SkewHeap(rootNode);
- }
- public static SkewHeap buildHeap(int[] A){
- LinkedList<Node> queue = new LinkedList<Node>();
- int n = A.length;
- //init: queue all elements as a single-node tree
- for(int i=0;i<n;i++){
- Node node = new Node(A[i]);
- queue.add(node);
- }
- //merge adjacent heaps and enqueue the merged heap afterward
- while(queue.size()>1){
- Node root1 = queue.remove(); //dequeue
- Node root2 = queue.remove();
- Node rootNode = iterativeMerge(root1,root2);
- queue.add(rootNode);
- }
- Node rootNode = queue.remove();
- return new SkewHeap(rootNode);
- }
- public void insert(int x){
- this.root = SkewHeap.iterativeMerge(new Node(x), this.root);
- }
- public Integer extractMin(){
- if(this.root == null) return null;
- int min = this.root.key;
- this.root = SkewHeap.iterativeMerge(this.root.left, this.root.right);
- return min;
- }
- public static void main(String[] args) {
- int[] A = new int[]{4,8,10,9,1,3,5,6,11};
- SkewHeap heap = SkewHeap.buildHeap(A);
- heap.insert(7);
- Integer min = null;
- while((min = heap.extractMin()) != null){
- System.out.format(" %d", min);
- }
- System.out.println();
- System.out.println("********************");
- A = new int[]{3,10,8,21,14,17,23,26};
- Node a0 = new Node(A[0]);
- Node a1 = new Node(A[1]);
- Node a2 = new Node(A[2]);
- Node a3 = new Node(A[3]);
- Node a4 = new Node(A[4]);
- Node a5 = new Node(A[5]);
- Node a6 = new Node(A[6]);
- Node a7 = new Node(A[7]);
- a0.left = a1;
- a0.right = a2;
- a1.left = a3;
- a1.right = a4;
- a4.left = a6;
- a2.left = a5;
- a5.left = a7;
- SkewHeap h1 = new SkewHeap(a0);
- int[] B = new int[]{6,12,7,18,24,37,18,33};
- Node b0 = new Node(B[0]);
- Node b1 = new Node(B[1]);
- Node b2 = new Node(B[2]);
- Node b3 = new Node(B[3]);
- Node b4 = new Node(B[4]);
- Node b5 = new Node(B[5]);
- Node b6 = new Node(B[6]);
- Node b7 = new Node(B[7]);
- b0.left = b1;
- b0.right = b2;
- b1.left = b3;
- b1.right = b4;
- b4.left = b7;
- b2.left = b5;
- b2.right = b6;
- SkewHeap h2 = new SkewHeap(b0);
- heap = SkewHeap.merge(h1,h2);
- while((min = heap.extractMin()) != null){
- System.out.format(" %d", min);
- }
- System.out.println();
- System.out.println("********************");
- A = new int[]{1,4,23,63,24,44,28};
- a0 = new Node(A[0]);
- a1 = new Node(A[1]);
- a2 = new Node(A[2]);
- a3 = new Node(A[3]);
- a4 = new Node(A[4]);
- a5 = new Node(A[5]);
- a6 = new Node(A[6]);
- a0.left = a1;
- a0.right = a2;
- a1.left = a3;
- a1.right = a4;
- a2.left = a5;
- a2.right = a6;
- h1 = new SkewHeap(a0);
- B = new int[]{13,17,99,57,49,105,201};
- b0 = new Node(B[0]);
- b1 = new Node(B[1]);
- b2 = new Node(B[2]);
- b3 = new Node(B[3]);
- b4 = new Node(B[4]);
- b5 = new Node(B[5]);
- b6 = new Node(B[6]);
- b0.left = b1;
- b0.right = b2;
- b1.left = b3;
- b1.right = b4;
- b2.left = b5;
- b2.right = b6;
- h2 = new SkewHeap(b0);
- heap = SkewHeap.merge(h1,h2);
- while((min = heap.extractMin()) != null){
- System.out.format(" %d", min);
- }
- System.out.println();
- }
- }
测试输出:
1 3 4 5 6 7 8 9 10 11
********************
3 6 7 8 10 12 14 17 18 18 21 23 24 26 33 37
********************
1 4 13 17 23 24 28 44 49 57 63 99 105 201
0
0
0