Java实现二叉搜索树
2022-11-22 17:06 杭伟 阅读(95) 评论(0) 编辑 收藏 举报将链表进行改造,即可构造一棵二叉树。
本文用java实现一颗二叉搜索树,实现二叉树的新增,删除,查找等功能。并测试新增和查找的时间复杂度。
节点类与链表节点相似,将链表的前后节点定义逻辑改为左右(孩子)节点:
/** * 二叉搜索树节点 */ public class Node { private int data;//数据域 private Node left;//左节点(左孩子) private Node right;//右节点(右孩子) public int getData() { return data; } public void setData(int data) { this.data = data; } public Node getLeft() { return left; } public void setLeft(Node left) { this.left = left; } public Node getRight() { return right; } public void setRight(Node right) { this.right = right; } //构造函数 public Node(int data, Node left, Node right){ this.data = data; this.left = left; this.right = right; } public Node(int data){ this(data,null,null); } public Node(){ this(0,null,null); } }
二叉搜索树的实现:
1 /** 2 * 二叉搜索树 3 * Author:hangwei 4 * Date:2022/11 5 */ 6 public class SearchTree { 7 private Node root; 8 public Node getRoot() { 9 return root; 10 } 11 public void setRoot(Node root) { 12 this.root = root; 13 } 14 15 //查找树中是否存在某个值 16 public Node search(Node root,int val){ 17 int nums = 0; 18 while (root != null && root.getData() != val){ 19 if(val < root.getData())//位于左子树 20 root = root.getLeft();//缩小范围 21 else 22 root = root.getRight(); 23 nums++; 24 } 25 System.out.println("本次查找执行了:"+nums+"次"); 26 return root; 27 } 28 29 int addCount = 0; 30 //给树新增节点 31 public void Add(Node root,int val){ 32 if(val == 30) 33 addCount++; 34 if(root == null) { 35 setRoot(new Node(val)); 36 } 37 else { 38 if(val < root.getData()){ 39 if(root.getLeft() == null)//左子树为空新增 40 root.setLeft(new Node(val)); 41 else 42 Add(root.getLeft(),val);//缩小子树范围并递归 43 } 44 else { 45 if(root.getRight() == null)//右子树为空新增 46 root.setRight(new Node(val)); 47 else 48 Add(root.getRight(), val); 49 } 50 //验证插入的时间复杂度 51 if(root.getRight()!=null && root.getRight().getData() == 30) 52 System.out.println("本次新增节点30执行了:"+addCount+" 次"); 53 } 54 55 } 56 public Node delete(Node root,int val){ 57 if(root == null) 58 return root; 59 if(root.getData() == val){//找到节点 60 if(root.getLeft() == null && root.getRight() ==null){//1,左右子节点为空则直接返回空 61 return null; 62 } else if (root.getLeft() == null) {//2,左孩子节点为空则返回右孩子节点 63 return root.getRight(); 64 } else if (root.getRight() == null) {//3,右孩子节点为空则返回左孩子节点 65 return root.getLeft(); 66 } 67 else {//4,左右孩子节点都不为空 68 Node cur = root.getRight(); 69 while (cur.getLeft() !=null)//如果右节点有孩子节点且左孩子不为空 70 cur = cur.getLeft();//找到右节点的最小左孩子 71 cur.setLeft(root.getLeft());//因为被删除目标节点的右子树始终比左子树大,所以找到右子树的最小左孩子,并设置最小左孩子的左子树为目标节点的左子树 72 return root.getRight(); 73 } 74 } 75 else if(val < root.getData())//处理左子树 76 root.setLeft(delete(root.getLeft(),val)); 77 else//处理右子树 78 root.setRight(delete(root.getRight(),val)); 79 return root; 80 } 81 }
测试类:
import java.util.*; public class Main { public static void main(String[] args) { /** * 假设有一颗二叉搜索树,总结点树是n,高度是h,根节点的高度是1,假设也是满二叉树, * 则n与h的关系:n=2^h - 1;(极端情况n=h暂不考虑退化到链表的情况) * 即:h=log2^(n+1) */ //二叉搜索树测试 SearchTree st = new SearchTree(); //插入节点&验证插入的时间复杂度 st.Add(null,25); st.Add(st.getRoot(),18); st.Add(st.getRoot(),16); st.Add(st.getRoot(),19); st.Add(st.getRoot(),29); st.Add(st.getRoot(),27); st.Add(st.getRoot(),30); //输出树 System.out.println(Arrays.toString(levelOrder(st.getRoot()))); //查找 System.out.println(st.search(st.getRoot(),27).getData()); System.out.println(st.search(st.getRoot(),30).getData()); System.out.println(st.search(st.getRoot(),31)); //验证查找的时间复杂度 //删除节点 st.delete(st.getRoot(),30); //再次输出树 System.out.println(Arrays.toString(levelOrder(st.getRoot()))); //删除节点 st.delete(st.getRoot(),18); //再次输出树 System.out.println(Arrays.toString(levelOrder(st.getRoot()))); } /** * 层序遍历 * @param root * @return */ public static int[] levelOrder(Node root) { if(root == null){ return new int[0]; } Queue<Node> queue = new LinkedList<Node>(); queue.add(root); ArrayList<Integer> arr = new ArrayList<>(); while( !queue.isEmpty() ){ Node temp = queue.poll(); arr.add(temp.getData()); if(temp.getLeft() != null){ queue.add(temp.getLeft()); } if(temp.getRight() != null){ queue.add(temp.getRight()); } } int[] res = new int[arr.size()]; for(int i = 0;i < arr.size();i++){ res[i] = arr.get(i); } return res; } }
执行结果:
*重点:
1,双向链表即可改造成二叉树;
2,二叉搜索树定义:左子树小于根节点,右子树大于根节点,左子树和右子树的子树一样符合这个定义;
3,新增,查找,删除方法中无处不在的递归思路;
4,层序遍历和时间复杂度验证。
作者:hangwei
出处:http://www.cnblogs.com/hangwei/
关于作者:专注于开源平台,分布式系统的架构设计与开发、数据库性能调优等工作。如有问题或建议,请多多赐教!
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
如果您觉得文章对您有帮助,可以点击文章右下角“推荐”一下。您的鼓励是作者坚持原创和持续写作的最大动力!