左式堆学习

今天学习了一下左式堆,总结一下。

一、左式堆定义:

具有,如下性质

1、父节点属性值小于子节点属性值;

2、堆中的任何节点,其左儿子的零路径长>=右儿子的零路径长;

的二叉树。

注:零路径长(npl)是指:从一个节点X开始到一个不具有两个儿子的Y节点的最短路径的长,可以看出有0个或者一个儿子的节点的npl=0,并且定义npl(null)=-1;

二、左式对的节点定义:

Java代码   收藏代码
  1. class Node<T> {  
  2.   
  3.         // 元素  
  4.         T element;  
  5.         // 左节点  
  6.         Node<T> left;  
  7.         // 右节点  
  8.         Node<T> right;  
  9.         // 零路径长  
  10.         int npl;  
  11.   
  12.         public Node(T element) {  
  13.             this(element, nullnull);  
  14.         }  
  15.   
  16.         public Node(T element, Node<T> left, Node<T> right) {  
  17.             this.element = element;  
  18.             this.left = left;  
  19.             this.right = right;  
  20.             this.npl = 0;  
  21.         }  
  22.     }  

 三、左式对的操作:

对于左式堆主要操作是“合并”,因为合并会破坏左式堆的特性,而insert、delete等操作,都会涉及到堆的合并,例如:delete根节点,相当于将一棵树边为了两个树,在将两棵树合并为一棵树。这里我们使用了一种递归的思想,若h1,h2本身是左式堆,则其子树也一定是左式堆,其子树的子树也一定是左式堆,一直退到树的每个叶子节点,都符合这个规则,那么我们合并时就可以从反方向思考,先形成一个个的小左式堆,然后在形成一棵大的左式堆。

四、左式堆定义代码:

Java代码   收藏代码
  1. public class LeftistHeap<T extends Comparable<T>> {  
  2.     // 左式堆节点定义  
  3.     private static class Node<T> {  
  4.   
  5.         // 元素  
  6.         T element;  
  7.         // 左节点  
  8.         Node<T> left;  
  9.         // 右节点  
  10.         Node<T> right;  
  11.         // 零路径长  
  12.         int npl;  
  13.   
  14.         public Node(T element) {  
  15.             this(element, nullnull);  
  16.         }  
  17.   
  18.         public Node(T element, Node<T> left, Node<T> right) {  
  19.             this.element = element;  
  20.             this.left = left;  
  21.             this.right = right;  
  22.             this.npl = 0;  
  23.         }  
  24.     }  
  25.   
  26.     private Node<T> root;  
  27.   
  28.     public LeftistHeap() {  
  29.         this.root = null;  
  30.     }  
  31.   
  32.     // 合并兩個左式堆  
  33.     public void merge(LeftistHeap<T> rhs) {  
  34.         if (rhs == null)  
  35.             return;  
  36.         root = merge(root, rhs.root);  
  37.         rhs.root = null;  
  38.     }  
  39.   
  40.     // 向左式堆中添加元素  
  41.     public void insert(T element) {  
  42.         root = merge(new Node<T>(element), root);  
  43.     }  
  44.   
  45.     // 找寻左式堆中最小节点  
  46.     public T findMin() {  
  47.         if (isEmpty())  
  48.             return null;  
  49.         return root.element;  
  50.     }  
  51.   
  52.     /** 
  53.      * 删除堆中最小节点,由于堆的最小节点就在根上,所以可以直接删除,但是删除根后,需要在将左右子树合并 
  54.      *  
  55.      * @return 
  56.      */  
  57.     public T deleteMin() {  
  58.         if (isEmpty())  
  59.             return null;  
  60.         T minItem = root.element;  
  61.         root = merge(root.left, root.right);  
  62.         return minItem;  
  63.     }  
  64.   
  65.     // 判断左式堆是否为空  
  66.     public boolean isEmpty() {  
  67.         return root == null;  
  68.     }  
  69.   
  70.     // 将左式堆设置为空堆  
  71.     public void makeEmpty() {  
  72.         this.root = null;  
  73.     }  
  74.   
  75.     /** 
  76.      * 1、若第一个根节点为空,则返回第二个根节点; 2、若第一个不为空第二个为空,则返回第一个根节点; 
  77.      * 3、一、二节点都不为空时,判断那个是根较小的节点,将根较小的节点作为第一个参数传递给merge1方法 
  78.      *  
  79.      * @param h1 
  80.      * @param h2 
  81.      * @return 
  82.      */  
  83.     private Node<T> merge(Node<T> h1, Node<T> h2) {  
  84.         if (h1 == null)  
  85.             return h2;  
  86.         if (h2 == null)  
  87.             return h1;  
  88.         if (h1.element.compareTo(h2.element) < 0) {  
  89.             return merge1(h1, h2);  
  90.         } else {  
  91.             return merge1(h2, h1);  
  92.         }  
  93.     }  
  94.   
  95.     /** 
  96.      * 将根节点较大的树合并到根节点较小的树上去: 1、若根节点较小的树无左子树,则将根节点较大的树作为其左子树 
  97.      * 2、若根节点较小的树有左子树,则将根节点较大的树和根节点较小的树的右子树合并,作为根节点较小的树的右子树 
  98.      * 3、若左子树的零路径长小于右子树的零路径长,则交换左右子树 4、根节点较小的树的零路径长修正为其右子树的零路径长度+1 
  99.      *  
  100.      * @param h1 
  101.      * @param h2 
  102.      * @return 
  103.      */  
  104.     private Node<T> merge1(Node<T> h1, Node<T> h2) {  
  105.         if (h1.left == null)  
  106.             h1.left = h2;  
  107.         else {  
  108.             h1.right = merge(h1.right, h2);  
  109.             if (h1.left.npl < h1.right.npl)  
  110.                 swapChildren(h1);  
  111.             h1.npl = h1.right.npl + 1;  
  112.         }  
  113.         return h1;  
  114.     }  
  115.   
  116.     // 交换两个子树  
  117.     private void swapChildren(Node<T> t) {  
  118.         Node<T> tmp = t.left;  
  119.         t.left = t.right;  
  120.         t.right = tmp;  
  121.     }  
  122. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值