- 浏览: 149298 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (166)
- Spring (7)
- JavaSE (16)
- web (1)
- Struts2 (2)
- Maven (1)
- 面试 (8)
- Hibernate (4)
- mysql (2)
- WebSerice (2)
- 工作心得 (23)
- 北京 (1)
- 上海 (27)
- groovy (1)
- 生活 (9)
- Linux (12)
- junit (1)
- oracle (5)
- h2db嵌入式数据库 (1)
- redis (14)
- 生活感悟 (1)
- cron (1)
- tomcat (4)
- 设计模式 (7)
- 正则表达式 (1)
- html5 (2)
- 网络编程 (3)
- 微信公众号 (1)
- Java nio (5)
- jdbc (1)
- 框架漏洞 (1)
- 安全 (8)
- 分布式 (2)
- 数据结构 (5)
- xml,json (0)
- xml (1)
- json (1)
- netty (0)
- java8 (1)
- javascript (1)
- 2016计划 (1)
- Java集合源码分析 (1)
- 工作心得,jvm性能调优 (3)
- 转载 (14)
- 产品 (1)
- JVM (10)
最新评论
-
oplife:
都不太难
返利网面试 -
飞翔神话:
谢谢 7 楼 cnrainbing
联想中望面试心得体会 -
飞翔神话:
5 楼 home198979,相比您可能还差点,但是我还是有一 ...
联想中望面试心得体会 -
cnrainbing:
支持小伙子
联想中望面试心得体会 -
jahu:
这简单啊,
联想中望面试心得体会
[size=x-small]这周学习了二叉搜索树和堆的原理。
一、二叉搜索树
1、定义
二叉搜索树又称二叉查找树,它是一棵空树,或者是一棵具有如下特征的非空二叉树:
1)若它的左子树非空,则左子树上所有结点的关键字均小于根结点的关键字。
2)若它的右子树非空,则右子树上所有结点的关键字均大于根结点的关键字。
3)左右子树本身又各是一棵二叉查找树。
特殊情况:如果树中允许存在关键字相同的结点,那么1和2两个特征应改为小于等于和大于等于。
2、二叉搜索树的抽象数据类型和链接存储类
二叉搜索树的抽象数据类型除了与一般二叉树的抽象数据类型完全相同外,还需要有自己的特殊方法,如查找、更新、插入和删除。
下面给出二叉搜索树的接口类:
实现类,二叉搜索树应该继承一般二叉树的链接存储类和LinkBinaryTree(这个类参考我的上一篇关于二叉树的博文http://xiaoyun34286136.iteye.com/blog/2313079)并实现二叉搜索树的接口,具体定义如下:
3、测试类
执行结果:
二叉搜索树的广义表表示:
23(12(,20),45(40(,44),89(73(49(,72)))))
前序遍历:
23 12 20 45 40 44 89 73 49 72
中序遍历:
12 20 23 40 44 45 49 72 73 89
后序遍历:
20 12 44 40 72 49 73 89 45 23
层次遍历:
23 12 45 20 40 89 44 73 49 72
升序输出:
12 20 23 40 44 45 49 72 73 89
二叉树的深度:6
二叉树的结点数:10
查找结点值为38的结果:null
删除 73 的结果:true
删除 40 的结点:true
删除 23 的结点:true
删除73,40,23后,该二叉搜索树的广义表形式:
20(12,45(44,89(49(,72))))
4、应用:
1、信息检索。
2、mysql索引(二叉搜索树的衍生树B树)。
二、堆
1、堆的定义
堆分为大根堆和小根堆两种。对于小根堆,是具有如下性质的完全二叉树:
1)若根结点存在左孩子,则根结点的值小于等于左孩子结点的值。
2)若根结点存在右孩子,则根结点的值小于等于右孩子结点的值。
3)以左右孩子为根的子树又各是一个堆。
对于大根堆,只需把上面的性质的小于等于改为大于等于即可。
2、堆的接口类
堆是满足一定条件要求的完全二叉树,需要有自己的插入和删除方法,所以堆的接口类要继承一般二叉树的接口类,同时定义自己的插入和删除。如下所示:
3、堆的存储结构和顺序存储类,插入、删除和广义表输出算法
由于堆是一棵完全二叉树,所以适宜用顺序存储,这样既能充分利用存储空间,又便于访问孩子结点和双亲结点。
具体插入和删除的实现原理和算法,我写在了代码相关方法注释中,堆的存储结构代码定义如下:
测试类:
运行结果:
建立堆的原始数据:
[23, 45, 89, 40, 73, 12, 49, 72, 20, 44, 86, 33]
堆的广义表表示形式:
12(20(40(72,45),44(73,86)),23(33(89),49))
堆的深度:4
堆中的元素个数:12
12,20,23,33,40,44,45,49,72,73,86,89,
4、堆的应用场景
1)在海量数据分析中,找前n大,前n小数据等。
2)用堆合并多个有序数组
总结:二叉搜索树和堆是学习哈夫曼树、B树、红黑树的基础,也是想深入研究数据结构的基础知识,必经之路,努力吧,小伙子,说给我自己听,也说给努力的人,对数据结构有兴趣同学可以加我好友,一起学习探讨,为了更好的明天。我的qq号:391720181。
下次博文将介绍哈夫曼树,平衡二叉树,B树和红黑树的学习情况和原理,代码可能不写了。[/size]
一、二叉搜索树
1、定义
二叉搜索树又称二叉查找树,它是一棵空树,或者是一棵具有如下特征的非空二叉树:
1)若它的左子树非空,则左子树上所有结点的关键字均小于根结点的关键字。
2)若它的右子树非空,则右子树上所有结点的关键字均大于根结点的关键字。
3)左右子树本身又各是一棵二叉查找树。
特殊情况:如果树中允许存在关键字相同的结点,那么1和2两个特征应改为小于等于和大于等于。
2、二叉搜索树的抽象数据类型和链接存储类
二叉搜索树的抽象数据类型除了与一般二叉树的抽象数据类型完全相同外,还需要有自己的特殊方法,如查找、更新、插入和删除。
下面给出二叉搜索树的接口类:
package com.data.tree.po.search; import com.data.tree.po.BinaryTree; /** * 二叉搜索树接口定义 * 说明:二叉搜索树的抽象数据类型除了与一般二叉树的抽象数据类型完全相同外,还需要有自己的特殊方法, * 如查找、更新、插入、删除元素等方法 * Created by admin on 2016/7/24. */ public interface BinarySearchTree extends BinaryTree { /** * 从二叉搜索树中查找值为obj的结点,如果存在则返回结点值,否则返回null * @param obj * @return */ Object find(Object obj); /** * 从二叉树中更新值为obj的结点,如果更新成功则返回原值否则返回空 * @param obj * @return */ Object update(Object obj); /** * 向二叉树中插入值为obj的结点,使得插入后仍是一课二叉搜索树,插入成功则返回true,如果遇到相同结点,则插入失败返回false * @param obj * @return */ boolean insert(Object obj); /** * 从二叉搜索树中删除值为obj的结点,如果成功则返回true,否则返回false * @param obj * @return */ boolean delete(Object obj); /** * 按照关键字从小到大的次序遍历输出一棵二叉搜索树中的所有结点值 */ void ascend(); }
实现类,二叉搜索树应该继承一般二叉树的链接存储类和LinkBinaryTree(这个类参考我的上一篇关于二叉树的博文http://xiaoyun34286136.iteye.com/blog/2313079)并实现二叉搜索树的接口,具体定义如下:
package com.data.tree.po.search; import com.data.tree.po.BTreeNode; import com.data.tree.po.LinkBinaryTree; /** * 二叉搜索树的链接存储类需要继承一般二叉树的链接存储类,并实现二叉搜索树的接口类 * Created by admin on 2016/7/24. */ public class LinkBinarySearchTree extends LinkBinaryTree implements BinarySearchTree { /** * 无参构造器 */ public LinkBinarySearchTree(){ super(); // 初始化为一棵空树 } /** * 含参构造器 * @param root */ public LinkBinarySearchTree(BTreeNode root) { super(root); // 把已知二叉搜索树的树根引用赋给root } /** * 从二叉搜索树中查找值为obj的结点,如果存在则返回结点值,否则返回null, * 时间复杂度:若该二叉搜索树是一课理想平衡二叉树或者接近理想二叉树,那么进行查找的时间复杂度为0(㏒₂N),N为树的总结点数; * 极端情况下,如果为一棵单支树(这是最极端和最坏的情况),则其时间复杂度为O(n)。所以,综合来看,二叉搜索树在查找 * 上比在集合或者线性表上进行顺序查找的的时间复杂度O(n)要快很多,这也是二叉搜索树的优势所在,当然,建立搜索二叉树花费的时间也要更多 * 空间复杂度:O(1) * @param obj * @return */ public Object find(Object obj) { if(root == null) { return null; } // 定义局部变量存放迭代结点,初始化为根结点 BTreeNode node = root; while (node != null) { if(((Comparable)obj).compareTo(node.element) == 0) { // 查找成功返回结点值 return node.element; }else if(((Comparable)obj).compareTo(node.element) < 0) { // 如果该值小于根结点,那么像左子树查找 node = node.left; }else { // 如果该值大于跟结点,那么查找右子树 node = node.right; } } return null; // 没有对应的值则返回空 } /** * 从二叉树中更新值为obj的结点,如果更新成功则返回原值否则返回空 * 时间复杂度:0(㏒₂N) * 空间复杂度:O(1) * @param obj * @return */ public Object update(Object obj) { // 如果二叉树为空直接返回空 if (root == null) { return null; } /** * 1、将根结点值赋给临时结点 * 2、根据要更新的结点值查找该结点的位置,如果等于则直接更新该结点值,如果小于该结点值,那么迭代左子树,否则,迭代右子树,如果还是未找到,那么返回空 */ BTreeNode node = root; while(root != null) { int result = ((Comparable)obj).compareTo(node.element); if(result == 0) { Object target = node.element; node.element = obj; return target; }else if(result < 0) { node = node.left; } else { node = node.right; } } return null; } /** * 向二叉树中插入值为obj的结点,使得插入后仍是一课二叉搜索树,插入成功则返回true,如果遇到相同结点,则插入失败返回false * 思路:查找插入位置从根结点开始,若树根指针为空,那么新结点就是根结点;否则,若obj等于根结点,则表明具有obj值的结点已经存在, * 不允许进行插入,返回false表示插入失败;若obj小于根结点,则根据根的左指针指向的左子树继续查找插入位置;若obj大于根结点, * 则沿着根的右指针在右子树上继续查找插入位置。依次逐层向下查找,当查找到一个结点的左指针或者右指针为空,那么这个空的指针 * 位置就是obj新结点的插入位置。插入链接完成后返回true * 时间复杂度:0(㏒₂N) * 空间复杂度:O(1) * @param obj * @return */ public boolean insert(Object obj) { BTreeNode node = root; BTreeNode pt = null; int result = 0; // 第一步,查找插入位置 while(node != null) { pt = node; result = ((Comparable)obj).compareTo(node.element); if(result == 0) { return false; }else if(result < 0) { // 查找左子树 node = node.left; }else { node = node.right; } } // 第二步,执行插入操作 BTreeNode s = new BTreeNode(obj); // 如果为空树,那么将该结点作为根结点插入 if(pt == null) { root = s; }else if(result < 0) { pt.left = s; }else { pt.right = s; } return true; } /** * 从二叉搜索树中删除值为obj的结点,如果成功则返回true,否则返回false * 思路:分为三种情况 * 第一种:删除叶子结点,此种操作很简单,只需将其双亲结点链接到它的指针去掉。 * 第二种:删除单支结点,这种删除操作也比较简单,删除该结点时,只需要将唯一的一个后继指针链接到它所在的链接位置即可 * 第三种:删除双支结点,这种删除比较复杂,因为待删除的结点有两个后继指针,需要妥善处理。删除这种结点的常用方法是: * 首先把它的中序前驱结点(即结点左子树中最右下的一个结点)的值赋给该结点的值域,然后再删除它的中序前驱结点,因为它的中序前驱结点的右指针必为空, * 所以只要把中序前驱结点的左指针链接到中序前驱结点所在的链接位置即可。 * @param obj * @return */ public boolean delete(Object obj) { if(root == null) { return false; } // 初始化根结点 BTreeNode node = root; // 该结点指向node的双亲 BTreeNode pt = null; // 比较值结果:0-相同 小于零查找左子树,大于零查找右子树 int result = 0; // 从树根开始逐层向下查找待删除的值为obj的结点 while(node != null) { result = ((Comparable)obj).compareTo(node.element); if(result == 0) { break; }else if(result < 0) { // 小于零,查找左子树 pt = node; node = node.left; }else { // 大于零,查找右子树 pt = node; node = node.right; } } // 分3中不同情况删除已查找到的结点 // 1、node为叶子结点 if(node.left == null && node.right == null) { if(node == root) { root = null; }else if(pt.left == node){ pt.left = null; }else { pt.right = null; } }//2、删除单支结点的情况 else if(node.left == null || node.right == null) { // node为根结点的处理情况 if(node == root) { if (node.left == null) { root = node.right; }else { root = node.left; } }else if(pt.left == node && node.left == null) { pt.left = node.right; }else if(pt.left == node && node.right == null) { pt.left = node.left; }else if(pt.right == node && node.left == null) { pt.right = node.right; }else if(pt.right == node && node.right == null) { pt.right = node.left; } } // 3、该结点为双分支节点的处理情况 else { BTreeNode s1 = node; BTreeNode s2 = node.left; // 验证该结点左孩子的右子树查找中序前驱结点 while(s2.right != null) { s1 = s2; s2 = s2.right; } // 将该结点的中序前驱结点s2的值域赋给node结点 node.element = s2.element; // 删除右子树为空的s2结点,使它的左子树链接到它所在的链接位置 if(s1 == node) { // 对node的中序前驱结点时node的左孩子时的情况进行处理 node.left = s2.left; }else{ s1.right = s2.left; } } return true; } /** * 按照关键字从小到大的次序遍历输出一棵二叉搜索树中的所有结点值 */ public void ascend() { // 通过调用中序遍历方法实现 traverseBTree("inOrder"); } }
3、测试类
import com.data.tree.po.search.BinarySearchTree; import com.data.tree.po.search.LinkBinarySearchTree; /** * 二叉搜索树测试算法 * Created by admin on 2016/7/25. */ public class Example7_1 { public static void main(String[] args) { // 1、定义并创建链接存储的空二叉搜索树 BinarySearchTree bst = new LinkBinarySearchTree(); // 2、用数组a保存带插入的二叉搜索树的一批整数 Integer[] a = {23,45,89,40,73,12,49,72,20,44}; // 3、根据数组a建立链接存储结构的二叉搜索树 for (Integer i : a) { bst.insert(i); } // 4、以广义表形式输入链接存储结构的二叉搜索树 System.out.println("二叉搜索树的广义表表示:"); bst.printBTree(); System.out.println(); // 5、前序遍历二叉搜索树 System.out.println("前序遍历:"); bst.traverseBTree("preOrder"); // 6、中序遍历二叉搜索树 System.out.println("中序遍历:"); bst.traverseBTree("inOrder"); // 7、后序遍历二叉搜索树 System.out.println("后序遍历:"); bst.traverseBTree("postOrder"); // 8、层次遍历二叉搜索树 System.out.println("层次遍历:"); bst.traverseBTree("levelOrder"); // 9、按结点值升序输出二叉搜索树的所有结点 System.out.println("升序输出:"); bst.ascend(); // 10、计算二叉搜索树的深度 System.out.println("二叉树的深度:" + bst.depthBTree()); // 11、计算二叉搜索树的结点数 System.out.println("二叉树的结点数:" + bst.countBTree()); // 12、从二叉搜索树中查找并输出值为38的结点 System.out.println("查找结点值为38的结果:" + bst.find(38)); // 13、从二叉搜索树中删除值为73的结点 System.out.println("删除 73 的结果:" + bst.delete(73)); // 14、从二叉搜索树中删除值为40的结点 System.out.println("删除 40 的结点:" + bst.delete(40)); // 15、从二叉搜索树中删除值为23的结点 System.out.println("删除 23 的结点:" + bst.delete(23)); // 16、以广义表的形式重新输出二叉搜索树 System.out.println("删除73,40,23后,该二叉搜索树的广义表形式:"); bst.printBTree(); } }
执行结果:
二叉搜索树的广义表表示:
23(12(,20),45(40(,44),89(73(49(,72)))))
前序遍历:
23 12 20 45 40 44 89 73 49 72
中序遍历:
12 20 23 40 44 45 49 72 73 89
后序遍历:
20 12 44 40 72 49 73 89 45 23
层次遍历:
23 12 45 20 40 89 44 73 49 72
升序输出:
12 20 23 40 44 45 49 72 73 89
二叉树的深度:6
二叉树的结点数:10
查找结点值为38的结果:null
删除 73 的结果:true
删除 40 的结点:true
删除 23 的结点:true
删除73,40,23后,该二叉搜索树的广义表形式:
20(12,45(44,89(49(,72))))
4、应用:
1、信息检索。
2、mysql索引(二叉搜索树的衍生树B树)。
二、堆
1、堆的定义
堆分为大根堆和小根堆两种。对于小根堆,是具有如下性质的完全二叉树:
1)若根结点存在左孩子,则根结点的值小于等于左孩子结点的值。
2)若根结点存在右孩子,则根结点的值小于等于右孩子结点的值。
3)以左右孩子为根的子树又各是一个堆。
对于大根堆,只需把上面的性质的小于等于改为大于等于即可。
2、堆的接口类
堆是满足一定条件要求的完全二叉树,需要有自己的插入和删除方法,所以堆的接口类要继承一般二叉树的接口类,同时定义自己的插入和删除。如下所示:
package com.data.tree.po.heap; import com.data.tree.po.BinaryTree; /** * 堆的定义:堆是具有以下特性的完全二叉树(完全二叉树是指除最后一层外,其余层都是满的,并且最后一层或者是满的,或者是在最右边缺少连续若干个结点),对于小根堆,具有以下特性: * 1)若树根结点存在左孩子,则根结点的值小于等于左孩子结点的值。 * 2)若根结点存在右孩子,则根结点的值也小于等于右孩子结点的值。 * 3)以左、右孩子为根的子树又各是一个堆。 * 大根堆的定义与上述类似,只需把条件“小于等于”改为“大于等于”即可。 * 定义堆的接口,需要有自己的插入和删除方法。 * Created by admin on 2016/7/26. */ public interface Heap extends BinaryTree { /** * 向堆中插入一个元素,并保持插入后仍然是一个堆 * @param obj */ void insert(Object obj); /** * 删除堆顶元素并返回,并保证删除堆顶元素后仍然是一个堆 * @return */ Object delete(); }
3、堆的存储结构和顺序存储类,插入、删除和广义表输出算法
由于堆是一棵完全二叉树,所以适宜用顺序存储,这样既能充分利用存储空间,又便于访问孩子结点和双亲结点。
具体插入和删除的实现原理和算法,我写在了代码相关方法注释中,堆的存储结构代码定义如下:
package com.data.tree.po.heap; /** * 堆同一般的二叉树一样既可以采用顺序存储,也可以采用链接存储,但是由于堆是一棵完全二叉树,所以适宜采用顺序存储, * 这样既能充分利用存储空间,也便于访问孩子节点和双亲结点 * * 顺序存储结构堆类的定义 * Created by admin on 2016/7/26. */ public class SequenceHeap implements Heap { /** 数组初始长度 */ final int minSize = 10; /** 数组声明,元素类型为系统根基类 */ private Object[] heapArray; /** 当前堆的实际长度 */ private int len; /** * 无参构造器,初始化堆长度为minSize,实际长度为0 */ public SequenceHeap(){ this.len = 0; this.heapArray = new Object[minSize]; } public SequenceHeap(int n) { if(n < minSize) { n = minSize; } this.len = 0; this.heapArray = new Object[n]; } /** * 插入步骤:向堆中插入一个元素时,首先将该元素写入到堆尾,即堆中最后一个元素的后面,也就是下标为len的位置上,然后经调整成为一个新堆。由于在原有堆上插入一个新元素后, * 可能导致原来以该元素的双亲结点为根的子树不为堆,从而使整个树不为堆,所以必须进行调整使之成为一个堆。调整的方法如下:若新元素小于双亲结点的值,就让它们互换位置, * 新元素换到双亲位置后,似的该位置为根的子树成为堆,但新元素依然可能小于此位置的双亲结点的值,从而使以上一层的的双亲结点为根的子树不为堆,还需要按照上述方法继续调整, * 这样持续下去,直到以此新位置的双亲结点为根的子树为一个堆或者调整到堆顶为止,此时得到的整个完全二叉树又成为了一个新的堆。 * @param obj * 时间复杂度:此算法的运行时间主要取决于while循环执行的次数,它等于新元素向双亲位置逐层上移的次数,该次数最多等于树的深度减1,所以该算法的时间复杂度为O(log₂N),其中N为堆的大小 */ public void insert(Object obj) { // 堆满时对堆的顺序存储进行扩容,分配大一倍的空间并进行复制操作 if(len == heapArray.length) { Object[] p = new Object[len*2]; for(int i = 0; i < len; i++) { p[i] = heapArray[i]; } heapArray = p; } // 向堆尾添加新元素 heapArray[len++] = obj; // 给i初始值,用i指向待调整元素的当前位置 int i = len - 1; // 寻找新元素的最终位置 while(i != 0) { int j = (i-1)/2; // j指向下标为i的元素的双亲结点 int result = ((Comparable)obj).compareTo(heapArray[j]); // 如果该结点的值大于等于双亲结点的值,那么这个堆调整结束,退出循环 if(result >= 0) break; // 将新插入的结点的值赋值给双亲结点,双亲结点下移 heapArray[i] = heapArray[j]; // 继续向上一层寻找插入位置 i = j; } heapArray[i] = obj; } /** * 从堆顶删除元素并返回 * 思路:从堆顶删除元素就是删除堆顶元素并使之返回。堆顶元素被删除后,留下的堆顶位置应由堆尾元素来填补,这样既保持了顺序存储结构的特点,有不需要移动其他任何元素。 * 把堆尾元素移动到堆顶位置后,它可能不小于左右孩子结点的值,是整个二叉树不为堆,所以需要一个调整过程,使之变为一个含有n-1个元素的堆。调整过程如下:首先从 * 根结点开始,若树根结点的值(即原堆尾元素)大于两个孩子结点中的最小值,就将它与最小值的孩子结点互换值,使得根结点的值小于两个孩子结点的值;根结点的值互换后, * 在检查新位置的左右孩子的值,如果大于等于其中的最小值,那么仍然需要互换位置,如此,检查对调,直到其左右孩子的最小值大于该点的值。 * @return */ public Object delete() { if(len == 0) { return null; } Object temp = heapArray[0]; // 将堆顶元素暂存temp中以便返回 len--; // 堆长度减一 if(len == 0) { // 如果删除后变为空堆,则直接返回 return temp; } Object x = heapArray[len]; int i = 0; int j = 1; while(j <= len - 1) { // 先找出左右孩子的最小值 // 如果右孩子比较小,应该是j指向右孩子 if(((Comparable)heapArray[j]).compareTo(heapArray[j+1]) > 0 && j < len - 1) { j++; } if(((Comparable)x).compareTo(heapArray[j]) <= 0){ break; } // 把孩子元素移到双亲位置 heapArray[i] = heapArray[j]; // 使i和j分别指向下一层结点 i = j; j = 2*i + 1; } heapArray[i] = x; return temp; } public boolean createBTree(String gt) { System.out.println("在堆中不需要使用一般二叉树的建立算法,直接返回假"); return false; } public boolean isEmpty() { return len == 0; } public void traverseBTree(String s) { System.out.println("在堆中不需要使用一般二叉树的遍历算法!"); } public Object findBTree(Object obj) { System.out.println("在堆中不需要使用一般二叉树的查找算法,返回空!"); return null; } public int depthBTree() { return (int)(Math.log10(len)/ (Math.log10(2))+1); } public int countBTree() { return len; } public void printBTree() { // 以树根元素的下标0为参数调用相应的递归函数进行输出 output(0); System.out.println(); } private void output(int ht) { if(ht < len) { System.out.print(heapArray[ht]); if(2*ht+1 < len) { System.out.print('('); output(2*ht+1); if(2*ht+2 < len) { System.out.print(','); output(2*ht+2); } System.out.print(')'); } } } public void clearBTree() { len = 0; heapArray = null; } }
测试类:
import com.data.tree.po.heap.Heap; import com.data.tree.po.heap.SequenceHeap; import java.util.Arrays; /** * 堆算法测试类 * Created by admin on 2016/7/29. */ public class Example7_2 { public static void main(String[] args) { // 1、定义并创建一个空堆hp Heap hp = new SequenceHeap(); // 2、用数组a保存带插入堆中的一批整数 Integer[] a = {23,45,89,40,73,12,49,72,20,44,86,33}; System.out.println("建立堆的原始数据:"); System.out.println(Arrays.toString(a)); // 3、根据数组a建立一个堆hp for (int i : a) { hp.insert(i); } // 4、以广义表形式输出堆hp System.out.println("堆的广义表表示形式:"); hp.printBTree(); // 5、得到hp的深度 System.out.println("堆的深度:" + hp.depthBTree()); // 6、得到hp中元素的个数 System.out.println("堆中的元素个数:" + hp.countBTree()); // 7、依次删除堆hp中的元素并输出 while(!hp.isEmpty()) { System.out.print(hp.delete() + ","); } System.out.println(); } }
运行结果:
建立堆的原始数据:
[23, 45, 89, 40, 73, 12, 49, 72, 20, 44, 86, 33]
堆的广义表表示形式:
12(20(40(72,45),44(73,86)),23(33(89),49))
堆的深度:4
堆中的元素个数:12
12,20,23,33,40,44,45,49,72,73,86,89,
4、堆的应用场景
1)在海量数据分析中,找前n大,前n小数据等。
2)用堆合并多个有序数组
总结:二叉搜索树和堆是学习哈夫曼树、B树、红黑树的基础,也是想深入研究数据结构的基础知识,必经之路,努力吧,小伙子,说给我自己听,也说给努力的人,对数据结构有兴趣同学可以加我好友,一起学习探讨,为了更好的明天。我的qq号:391720181。
下次博文将介绍哈夫曼树,平衡二叉树,B树和红黑树的学习情况和原理,代码可能不写了。[/size]
发表评论
-
快速排序算法
2016-08-18 00:10 618[size=small]排序是数据处理领域一种最常用的运算,排 ... -
散列表的demo实现,二分查找
2016-08-06 16:00 553散列表,散列算法 [size= ... -
二叉树基础-定义、创建、遍历、属性计算(深度,结点数)、查找算法
2016-07-23 15:02 4136一、概念和定义 ... -
散列算法,冲突解决方法分析
2016-07-09 12:11 1594哈希法又称散列法、杂凑法以及关键字地址计算法等,相应的表称为哈 ... -
需要学习的东西
2016-01-24 23:56 0spring,ioc,aop,23种设计模式。
相关推荐
在给定的文件中,我们关注的是数据结构相关的C++代码,特别是涉及到二叉树、二叉搜索树和堆的概念。下面将详细解释这些概念及其在C++中的实现。 首先,二叉树是一种特殊的图,其中每个节点最多有两个子节点,通常...
二叉搜索树在各种数据结构和算法问题中都有广泛的应用,例如数据库索引、文件系统、排序算法(如二叉堆排序)以及搜索算法等。它们也被用于实现动态集合和映射,其中键可以随时添加、删除或修改。 总之,理解和掌握...
- 堆(如最大堆、最小堆)是特殊的二叉树,可以用于优先队列等操作,但不是严格的二叉搜索树。 7. **结点数量**: - 对于n个不同关键字的二叉搜索树,可能的形态数量是多种多样的,这取决于插入元素的顺序。最坏...
二叉搜索树(Binary Search Tree,BST)是二叉树的一种特殊形式,它满足以下性质: 1. 对于任意节点,其左子树中的所有节点的值都小于该节点的值。 2. 对于任意节点,其右子树中的所有节点的值都大于该节点的值。 3...
- **Treap**:随机化的平衡二叉搜索树,结合了堆和二叉搜索树的特性,每个节点有一个优先级,通过优先级保持平衡。 4. **平衡调整策略**: - AVL树的平衡调整主要通过四种旋转操作:左旋、右旋、左右旋和右左旋,...
从给定的代码片段和描述中,我们可以提炼出与数据结构相关的几个关键知识点:二叉搜索树(BST)的基本操作和堆排序算法。下面将详细解释这些知识点。 ### 二叉搜索树(BST) 二叉搜索树是一种特殊的二叉树,其中每...
结合二叉排序树和堆的概念,可以设计出更高效的数据结构和算法,例如二叉堆(一种同时满足二叉排序树和堆性质的数据结构)。 在L1214WBinarySortTree这个压缩包中,可能包含了关于二叉排序树和堆的练习题、代码示例...
【二叉树与二叉搜索树】 在计算机科学中,二叉树是一种特殊的树结构,其中每个节点最多有两个子节点,通常称为左子节点和右子节点。二叉树经常被用于实现各种算法,如搜索、排序等。二叉搜索树(Binary Search Tree...
链表、双链表、队列、Stack、哈希表、堆 - 最大和最小堆、优先队列、Trie、树、二叉搜索树、AVL树、红黑树、区段树 - 包含最小/最大/总和范围查询示例、Fenwick Tree(二叉索引树)、图形(有向和无向)、 Disjoint ...
Treap树,也被称为二叉搜索树堆,是一种二叉搜索树,它将堆(Heap)的性质与二叉搜索树(Binary Search Tree)的性质结合起来。Treap树中的每个节点都同时拥有一个搜索键(search key)和一个优先级(priority)。它...
Treap结合了二叉搜索树和堆的特性,每个节点有一个优先级,优先级是随机生成的。通过优先级保持树的平衡,即使插入顺序导致不平衡,Treap也能快速恢复平衡。 4. **Splay树**:Splay树是由Daniel Sleator和Robert ...
二叉树常用于实现搜索、排序等操作,如二叉搜索树和堆。 无根树与有根树的主要区别在于是否指定了一个特殊的节点作为树的根。无根树没有明确的起点,节点之间的关系相对自由,而在有根树中,根节点的存在为树提供了...
2. **特性**:二叉排序树保证了搜索、插入和删除操作的时间复杂度为O(log n),在平衡的情况下。但在最坏情况下,如果树退化成链表,性能会降为O(n)。 3. **插入操作**:在二叉排序树中插入新节点时,通过比较新节点...
二叉排序树(也称为二叉搜索树)是一种特殊的二叉树,其中每个节点的左子树只包含小于当前节点的值,右子树包含大于当前节点的值。这使得插入、查找和删除操作的效率很高,平均时间复杂度为O(log n)。在实验四中,你...
搜索二叉树,也称为二叉查找树,是一种特殊的二叉树,其每个节点都具有以下特性: 1. 左子树中的所有节点的值都小于当前节点的值。 2. 右子树中的所有节点的值都大于当前节点的值。 3. 每个子树都是一棵搜索二叉树。...
二叉树常用于搜索、排序等操作,如二叉搜索树和堆。 3. **树的类型**:包括但不限于二叉搜索树、完全二叉树、满二叉树、平衡二叉树(如AVL树和红黑树)、B树和B+树等,每种类型的树有其特定的性质和应用场景。 4. ...
linux程序实验报告,数据结构(红黑树、堆、栈、二叉搜索树、队列、链表、图)的c代码实现+源代码+文档说明+实验报告 - 小白不懂运行,下载完可以私聊问,可远程教学 该资源内项目源码是个人的课程设计,代码都测试...
14.4 带有相同关键字元素的二叉搜索树 14.5 索引二叉搜索树 14.6 应用 14.6.1 直方图 14.6.2 箱子装载问题的最优匹配法 14.6.3 交叉分布 第15章 平衡搜索树 15.1 AVL树 15.1.1 定义 15.1.2 AVL树的高度 15.1.3 AVL树...