最近终于静下心来,自己实现了个二叉排序树,还是很有成就感的。
package tree; public class TreeNode<T> { //结点存放的数据 public T data; //当前结点的父结点 public TreeNode<T> parent; //当前结点的左孩子 public TreeNode<T> leftChild; //当前结点的右孩子 public TreeNode<T> rightChild; public TreeNode(T data,TreeNode<T> parent) { this.data = data; this.leftChild = null; this.rightChild = null; this.parent = parent; } } package tree; /** * 二叉排序树或者是一棵空树, 或者是一棵具有如下性质的二叉树 * (1)、若左子树不空,则左子树上所有结点的值均小于它的根结点的值; * (2)、若右子树不空,则右子树上所有结点的值均大于它的根结点的值; * (3)、左、右子树也分别为二叉排序树; */ //二叉排序树的结构通常不是一次生成的,而是在查找过程中动态构建的; public class BinarySortTree<T extends Comparable<T>> { //根结点指针 public TreeNode<T> rootNode = null; //二叉树的结点个数 public int nodeCount = 0; //获取targetData在二叉排序树中对应的结点指针 public TreeNode<T> find(T targetData) { TreeNode<T> curNode = this.rootNode; while (curNode != null) { T curNodeData = curNode.data; if(curNodeData.compareTo(targetData) == 0) { return curNode; } else if(curNodeData.compareTo(targetData) > 0) { curNode = curNode.leftChild; } else { curNode = curNode.rightChild; } } return null; } public TreeNode<T> add(T targetData) { TreeNode<T> targetNode= find(targetData); //已经存在,不用再插入新结点 if(targetNode != null) { return targetNode; } //没有根结点,需要创建一个根结点,存放数据targetData if(this.rootNode == null) { this.rootNode = new TreeNode<T>(targetData, null); this.nodeCount = 1; return this.rootNode; } //已经存在根节点的情况,但是没有对应targetData的结点 TreeNode<T> insertPos = findInsertPos(targetData); TreeNode<T> tempNode = new TreeNode<T>(targetData, insertPos); this.nodeCount++; if(targetData.compareTo(insertPos.data) > 0 ) { insertPos.rightChild = tempNode; } else { insertPos.leftChild = tempNode; } return tempNode; } public void delete(T targetData) { TreeNode<T> tagNode = find(targetData); //不存在,直接返回 if( tagNode == null) { return; } //要删除的结点是叶子结点 if(tagNode.leftChild == null && tagNode.rightChild == null) { deleteWhenLeaf(tagNode); } //要删除的结点只有左子树,或只有右子树 else if(tagNode.leftChild == null || tagNode.rightChild == null) { deleteWhenSingleChild(tagNode); } else { deleteWhenTwoChild(tagNode); } } //删去叶子结点不破坏整棵树的结构,只需修改其父结点的孩子指针 private void deleteWhenLeaf(TreeNode<T> tagNode) { this.nodeCount--; TreeNode<T> parent = tagNode.parent; //要删除的是根结点 if(parent == null) { this.rootNode = null; } else { if(parent.leftChild == tagNode) { parent.leftChild = null; } else { parent.rightChild = null; } } } //若p结点只有左子树PL或右子树PR,此时只要令PL或PR直接成为其双亲结点f的左子树(当*p是左子树) //或右子树(当*p是右子树)即可 private void deleteWhenSingleChild(TreeNode<T> tagNode) { this.nodeCount--; //当前结点的父亲 TreeNode<T> parent = tagNode.parent; //当前结点的左孩子 TreeNode<T> left = tagNode.leftChild; //当前结点的右孩子 TreeNode<T> right = tagNode.rightChild; if(left != null) { left.parent = parent; } else { right.parent = parent; } //要删除的是根结点 if(parent == null) { if(left != null) { this.rootNode = left; } else { this.rootNode = right; } } else//删除的结点不是根结点 { if(left != null) { parent.leftChild = left; } else { parent.rightChild = right; } } } //tagNode结点的后继结点肯定无左子树;前驱结点肯定没有右子树; //由于tagNode既有左孩子,又有右孩子,所以前驱和后继都不可能是null //假如tagNode的前驱是before,则用before代替tagNode位置; //before的左子树代替before的位置 private void deleteWhenTwoChild(TreeNode<T> tagetNode) { this.nodeCount--; //tagetNode的前驱结点是before TreeNode<T> before = searchPredecessor(tagetNode); //1.before的左子树取代结点before的位置 if(before.parent.leftChild == before) { before.parent.leftChild = before.leftChild; } else { before.parent.rightChild = before.leftChild; } if(before.leftChild != null) { before.leftChild.parent = before.parent; } //2.before取代tagetNode的位置 before.parent = tagetNode.parent; before.leftChild = tagetNode.leftChild; before.rightChild = tagetNode.rightChild; //3.改变tagetNode的父结点的孩子指针 if(tagetNode.parent == null) { this.rootNode = before; } else { if(tagetNode.parent.leftChild == tagetNode) { tagetNode.parent.leftChild = before; } else { tagetNode.parent.rightChild = before; } } } //获取targetData在二叉排序中插入位置 //如果targetData在二叉树中已经存在,则不需要再插入,返回null public TreeNode<T> findInsertPos(T targetData) { //将要插入的位置 TreeNode<T> willInsert = null; TreeNode<T> curNode = this.rootNode; while (curNode != null) { T curNodeData = curNode.data; //结点已经存在,插入位置设为null if(curNodeData.compareTo(targetData) == 0) { willInsert = null; break; } else if(curNodeData.compareTo(targetData) >0) { willInsert = curNode; curNode = curNode.leftChild; } else { willInsert = curNode; curNode = curNode.rightChild; } } return willInsert; } //二叉排序树的中序遍历,查找tagetNode结点的后继结点 //如果没有后继结点,则返回null; public TreeNode<T> searchSuccessor(TreeNode<T> tagetNode) { if(tagetNode == null) { return null; } //从右子树中寻找后继结点 if(tagetNode.rightChild != null) { return searchMinValueNode(tagetNode.rightChild); } //从父节点向上寻找后继 else { //根结点没有右子树,就没有后继结点 if(tagetNode.parent == null) { return null; } else { TreeNode<T> temp = tagetNode; while (temp.parent != null) { if(temp.parent.leftChild == temp) { break; } temp = temp.parent; } return temp.parent; } } } //查找某个结点的前驱,如果没有前驱结点,则返回null public TreeNode<T> searchPredecessor(TreeNode<T> tagetNode) { if(tagetNode == null) { return null; } if(tagetNode.leftChild != null) { return searchMaxValueNode(tagetNode.leftChild); } else { //根结点没有左子树,就没有前驱结点 if(tagetNode.parent == null) { return null; } else { TreeNode<T> temp = tagetNode; while (temp.parent != null) { if(temp.parent.rightChild == temp) { break; } temp = temp.parent; } return temp.parent; } } } //查找以root为根结点的二叉排序树中,最小的数据值对应的结点 public TreeNode<T> searchMinValueNode(TreeNode<T> root) { if(root == null) { return null; } TreeNode<T> resultNode = root; while (resultNode.leftChild != null) { resultNode = resultNode.leftChild; } return resultNode; } //查找以root为根结点的二叉排序树中,最大的数据值对应的结点 public TreeNode<T> searchMaxValueNode(TreeNode<T> root) { if(root == null) { return null; } TreeNode<T> resultNode = root; while (resultNode.rightChild != null) { resultNode = resultNode.rightChild; } return resultNode; } public void inorderTraversal(TreeNode<T> node) { if(node == null) { return; } inorderTraversal(node.leftChild); System.out.println(node.data); inorderTraversal(node.rightChild); } }
相关推荐
在Java中实现二叉排序树,我们通常会定义一个`Node`类来表示树的节点,它包含键、值以及左右子节点的引用。例如: ```java class Node { int key; Object value; Node left, right; public Node(int item) { ...
在Java中实现二叉排序树,我们需要定义一个Node类来表示树的节点,包含键值、左子节点和右子节点。然后创建一个BST类,包含插入、查找和删除等基本操作。以下是一个简单的Java实现: ```java public class Node { ...
`BiSortTreeGui.java` 文件很可能是实现了二叉排序树并结合Java Swing库创建了一个图形用户界面(GUI)的应用程序。Swing是Java的一个图形库,用于构建桌面应用程序,提供了丰富的组件和事件处理机制。 首先,我们...
以上就是关于Java实现二叉排序树的基本介绍,具体实现可以参考提供的`BinarySortTree.java`文件。在实际应用中,二叉排序树常用于构建索引结构、数据库系统等场景,其高效的查询能力使其成为数据存储和检索的重要...
在iOS编程中,实现二叉排序树的增删改查操作是数据结构和算法的重要应用。CodeBlocks是一款跨平台的C++集成开发环境,虽然通常用于Windows,但它同样支持创建和调试Objective-C代码,这是iOS开发的主要语言。 ### ...
在压缩包文件“二叉排序树的相关操作”中,可能包含了实现这些功能的源代码,如C、C++或Java等编程语言的实现。通过阅读和分析这些代码,我们可以更深入地理解二叉排序树的内部机制,掌握数据结构和算法在实际编程中...
数据结构是计算机科学中的核心课程,它探讨了如何有效地存储和检索数据,以优化...这个实验报告提供了一个实用的框架,可以帮助其他学生理解和实现二叉排序树的各种操作,进一步巩固他们在数据结构课程中的学习成果。
2. **顺序表存储结构**:对于较小的数据集,可以考虑使用数组来实现二叉排序树,这样可以直接通过索引访问元素,但插入和删除操作可能需要更多的移动操作。 3. **插入操作**:在二叉排序树中插入一个新节点,需要...
在Java中实现二叉排序树,首先需要定义一个表示节点的类,通常包含三个属性:键值、左子节点和右子节点。下面是一个简单的`Node`类的示例: ```java public class Node { int key; Node left; Node right; ...
在这个任务中,学生需要设计一个程序来实现二叉排序树的基本操作,同时提升自身的编程能力和问题解决能力。 **一、二叉排序树**是一种特殊的二叉树,它的每个节点都大于其左子树中的所有节点,小于其右子树中的所有...
在C++中实现二叉排序树查找算法,通常涉及以下几个关键步骤: 1. **定义节点结构体**: 首先,我们需要定义一个表示二叉树节点的结构体,包含一个整数值和两个指向子节点的指针。 ```cpp struct TreeNode { int ...
在Java中,我们可以利用面向对象编程的概念来实现二叉排序树。以下是关于这个主题的详细知识点: 1. **二叉树基础**: - 二叉树是每个节点最多有两个子节点的树结构,分别称为左子节点和右子节点。 - 节点通常...
这段代码主要实现了递归判断二叉树是否为二叉排序树的功能。核心逻辑在于递归地检查每个节点的左子树中的最大值是否小于当前节点的值,并且右子树中的最小值是否大于当前节点的值。同时,还需要递归地确保左右子树也...
平衡二叉排序树(Balanced Binary ...在“算法8.10平衡二叉排序树”这个压缩包文件中,可能包含了有关平衡二叉排序树实现的详细代码和示例,你可以通过阅读和理解这些代码来深入学习和掌握平衡二叉排序树的算法实现。
在Java中,二叉排序树的节点通常定义为一个类,包含键值、左子节点和右子节点的引用。插入和删除操作可以通过实例化这个类并调用相应的方法实现。例如: ```java class Node { int key; Node left, right; ...
这个实验的目的是让学生理解和掌握二叉排序树的基本操作,并通过编写源码来实现这些功能。 首先,我们要理解二叉排序树的核心操作: 1. **插入操作**:在二叉排序树中插入一个新节点,需要根据新节点的值与当前...
自然语言理解 关于词频统计的代码 利用treemap来完成
3. **递归与迭代**:Java中实现二叉排序树的操作,可以使用递归或迭代方法,递归通常更直观,而迭代更适合大型树以避免栈溢出。 在实际项目中,除了二叉排序树,可能还需要结合其他数据结构如链表、堆、哈希表等,...
10. **参考文献**:报告中引用的参考资料可能来自教科书、论文或其他可靠来源,提供了设计和实现二叉排序树算法的理论基础和技术支持。 11. **源程序清单**:附录中的源程序清单是实现上述功能的代码,通常包括C、...