二叉搜索树
1、 题目要求
① 实现一个二叉搜索树, 提供添加、删除、查找、遍历功能,实现Insert(),delete(),visit(),search()方法
② 利用接口实现通用Insert(),delete(),visit(),search()
③ 处理异常
④ 实现树数据的数据库存储(自选数据库)
2、 环境准备
语言:java version ’1.8.0_221’
平台:IntelliJ IDEA 2019.2.4 x64
数据库:MySQL
数据库可视化软件:Navicat
3、 题目解析
建立一个二叉搜索树,用以实现对树结点的增添,删除,查找,遍历等功能。
增添的前提查找,先查找到该放置的位置,然后把新结点加进去,再对已有结点进行重排列(父结点和左右子树的操作)
删除与增添类似,先找到删除的结点,然后删除,再对已有结点进行一系列操作。
遍历,分为前序,中序,后序遍历三种。
利用接口实现通用Insert(),delete(),visit(),search()。
把JAVA与数据库连接到一起,实现数据库的一系列操作。
4、 算法描述
① 二叉搜索树需满足以下四个条件:
若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
任意节点的左、右子树也分别为二叉搜索树;
没有键值相等的节点。
② 二叉搜索树性质
按中序遍历二叉搜索树,所得到的中序遍历序列是一个递增有序序列。
二叉搜索树就是具备上述四种性质的二叉树。
③ 增删改查操作
二叉搜索树的插入
在二叉搜索树中插入新结点,要保证插入后的二叉树仍符合二叉搜索树的定义。插入过程如下:
若二叉搜索树为空,则待插入结点S作为根结点插入到空树中;
当非空时,将待插结点关键字S->key和树根关键字t->key进行比较,若s->key = t->key,则无须插入,若s->key< t->key,则插入到根的左子树中,若s->key> t->key,则插入到根的右子树中。而子树中的插入过程和在树中的插入过程相同,如此进行下去,直到把结点s作为一个新的树叶插入到二叉搜索树中,或者直到发现树已有相同关键字的结点为止。
插入完成。
二叉排序树的查找
假定二叉排序树的根结点指针为 root ,给定的关键字值为 K ,则查找算法可描述为:
置初值: q = root ;
如果 K = q -> key ,则查找成功,算法结束;
否则,如果 K < q -> key ,而且 q 的左子树非空,则将 q 的左子树根送 q ,转上步骤;否则,查找失败,结束算法;
否则,如果 K > q -> key ,而且 q 的右子树非空,则将 q 的右子树根送 q ,转第二步;否则,查找失败,算法结束。
二叉排序树的删除
假设被删结点是p,其双亲是f,不失一般性,设p是f的左孩子,下面分三种情况讨论:
⑴ 若结点p是叶子结点,则只需修改其双亲结点f的指针即可。
⑵ 若结点p只有左子树PL或者只有右子树PR,则只要使PL或PR 成为其双亲结点的左子树即可。
⑶ 若结点p的左、右子树均非空,先找到p的中序后继(或前驱)节点s(注意s是p的右子树中的key最小的结点,它的左子树为空),然后步骤如下:
找到 *p 的节点的直接中序后继节点(即其右子树中key值最小的节点 ),并删除此直接中序后继节点。
将此后继节点的 key、value 值赋给待删除节点的 key,value值。
5、 源代码
① 节点类
package com.company;
public class Node {
int key;
int value;
Node leftChild;
Node rightChild;
public Node(int key, int value) {
this.key = key;
this.value = value;
this.leftChild = null;
this.rightChild = null;
}
public Node(int key, int value, Node leftChild, Node rightChild) {
super();
this.key = key;
this.value = value;
this.leftChild = leftChild;
this.rightChild = rightChild;
}
public Node() {}
@Override
public String toString() {
return "Node [key=" + this.key + ", value=" + this.value + ", leftChild=" + this.leftChild + ", rightChild=" + this.rightChild + "]";
}
public int getKey() {
return this.key;
}
public void setKey(int key) {
this.key = key;
}
public int getValue() {
return this.value;
}
public void setValue(int value) {
this.value = value;
}
public Node getLeftChild() {
return this.leftChild;
}
public void setLeftChild(Node leftChild) {
this.leftChild = leftChild;
}
public Node getRightChild() {
return this.rightChild;
}
public void setRightChild(Node rightChild) {
this.rightChild = rightChild;
}
}
② 二叉搜索树接口方法
package com.company;
public interface interfaceBinaryTree {
Node visit(int key);// Find the specified node
boolean update(int key, int value);
void insert(int key, int value); // Insertion node
boolean delete(int key); //Delete the specified node
Node getDirectPostNode(Node delNode); // Get the direct successor node of the node to be deleted
void preOrder(Node rootNode);
void inOrder(Node rootNode);
void postOrder(Node rootNode);
}
public class BinaryTree implements interfaceBinaryTree {
……
}
③ 数据库设计及存储实现
本题选用MySQL数据库,并使用了Navicat可视化软件。数据库设计如下图所示
JDBC实现代码如下(在编写数据库操作中运用到处理异常操作,确保成功连接数据库,并对数据库进行相关操作)
package com.company;
import java.sql.*;
public class MySQL {
public void CreateDatabase() {
Connection connection = null;
Statement statement = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/binarytree", "root", "***你的数据库密码***");
statement = connection.createStatement();
String sql = "CREATE TABLE `binarytree`.`binarytree` (\n" +
" `key` varchar(255) CHARACTER SET utf8 NOT NULL,\n" +
" `value` varchar(255) CHARACTER SET utf8 NULL,\n" +
" PRIMARY KEY (`key`)\n" +
");";
statement.executeUpdate(sql);
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
try {
if(statement!=null) {
statement.close();
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(connection!=null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
public void add(int key,int value) {
Connection connection = null;
Statement statement = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/binarytree", "root", "***你的数据库密码***");
statement = connection.createStatement();
String sql = "INSERT INTO binarytree VALUES('"+key+"','"+value+"')";
statement.executeUpdate(sql);
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
try {
if(statement!=null) {
statement.close();
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(connection!=null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
public void delete(int key) {
Connection connection = null;
Statement statement = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/binarytree", "root", "***你的数据库密码***");
statement = connection.createStatement();
String sql = "delete from binarytree where binarytree.`key`= '"+key+"';";
statement.executeUpdate(sql);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
if(statement!=null) {
statement.close();
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(connection!=null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
public void update(int key,int value ) {
Connection connection = null;
Statement statement = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/binarytree", "root", "***你的数据库密码***");
statement = connection.createStatement();
String sql = "update binarytree set binarytree.`value`='"+value+"' where binarytree.`key`='"+key+"';";
statement.executeUpdate(sql);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
if(statement!=null) {
statement.close();
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(connection!=null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
public void select() {
Connection connection = null;
Statement statement = null;
ResultSet rs = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/binarytree", "root", "***你的数据库密码***");
statement = connection.createStatement();
//查find one node
/*String sql = "select * from binarytree where key ='3' ;";
rs = statement.executeQuery(sql);
System.out.println(rs.next());
System.out.print("key = "+rs.getInt("key")+" , ");
System.out.print("value = "+rs.getString("value"));*/
String sql = "select * from binarytree;";
rs = statement.executeQuery(sql);
while(rs.next()){
System.out.print("key = "+rs.getInt("key")+" , ");
System.out.print("value = "+rs.getString("value"));
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
if(rs!=null)rs.close();
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(statement!=null)statement.close();
} catch (SQLException e) {
e.printStackTrace();
}finally{
try {
if(connection!=null)connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
}
④ 二叉搜索树具体实现
package com.company;
public class BinaryTree implements interfaceBinaryTree {
private Node root;
private MySQL sql=new MySQL();
BinaryTree(){
sql.CreateDatabase();
};
public Node getRoot() {
return this.root;
}
public void setRoot(Node root) {
this.root = root;
}
@Override
public Node visit(int key) {
// TODO Auto-generated method stub
Node currentNode = this.root;
while ((currentNode != null) && (currentNode.key != key)) {
if (key < currentNode.key) {
currentNode = currentNode.leftChild;
} else if (key > currentNode.key) {
currentNode = currentNode.rightChild;
}
}
return currentNode;
}
@Override
public void insert(int key, int value) {
// TODO Auto-generated method stub
sql.add(key,value);
if (this.root == null) {
this.root = new Node(key, value);
return;
}
Node currentNode = this.root;
Node parentNode = this.root;
boolean isLeftChild = true;
while (currentNode != null) {
parentNode = currentNode;
if (key < currentNode.key) {
currentNode = currentNode.leftChild;
isLeftChild = true;
} else if (key > currentNode.key) {
currentNode = currentNode.rightChild;
isLeftChild = false;
} else {
break;
}
}
if (parentNode != currentNode) {
Node newNode = new Node(key, value);
if (isLeftChild) {
parentNode.leftChild = newNode;
} else {
parentNode.rightChild = newNode;
}
} else {
currentNode.setValue(value);
}
}
@Override
public boolean delete(int key) {
// TODO Auto-generated method stub
sql.delete(key);
Node currentNode = this.root;
Node parentNode = this.root;
boolean isLeftChild = true;
while ((currentNode != null) && (currentNode.key != key)) {
parentNode = currentNode;
if (key < currentNode.key) {
currentNode = currentNode.leftChild;
isLeftChild = true;
} else {
currentNode = currentNode.rightChild;
isLeftChild = false;
}
}
if (currentNode == null) return false;
if ((currentNode.leftChild == null) && (currentNode.rightChild == null)) {
if (currentNode == this.root) {
this.root = null;
} else if (isLeftChild) {
parentNode.leftChild = null;
} else {
parentNode.rightChild = null;
}
} else if ((currentNode.rightChild == null) && (currentNode.leftChild != null)) {
if (currentNode == this.root) {
this.root = currentNode.leftChild;
} else if (isLeftChild) {
parentNode.leftChild = currentNode.leftChild;
} else {
parentNode.rightChild = currentNode.leftChild;
}
} else if ((currentNode.leftChild == null) && (currentNode.rightChild != null)) {
if (currentNode == this.root) {
this.root = currentNode.rightChild;
} else if (isLeftChild) {
parentNode.leftChild = currentNode.rightChild;
} else {
parentNode.rightChild = currentNode.rightChild;
}
}
else {
Node directPostNode = this.getDirectPostNode(currentNode);
currentNode.key = directPostNode.key;
currentNode.value = directPostNode.value;
}
return true;
}
@Override
public Node getDirectPostNode(Node delNode) {
// TODO Auto-generated method stub
Node parentNode = delNode;
Node direcrPostNode = delNode;
Node currentNode = delNode.rightChild;
while (currentNode != null) {
parentNode = direcrPostNode;
direcrPostNode = currentNode;
currentNode = currentNode.leftChild;
}
if (direcrPostNode != delNode.rightChild) {
parentNode.leftChild = direcrPostNode.rightChild;
direcrPostNode.rightChild = null;
}
return direcrPostNode;
}
@Override
public void preOrder(Node rootNode) {
// TODO Auto-generated method stub
if (rootNode != null) {
System.out.println(rootNode.key + " " + rootNode.value);
this.preOrder(rootNode.leftChild);
this.preOrder(rootNode.rightChild);
}
}
@Override
public void inOrder(Node rootNode) {
// TODO Auto-generated method stub
if (rootNode != null) {
this.inOrder(rootNode.leftChild);
System.out.println(rootNode.key + " " + rootNode.value);
this.inOrder(rootNode.rightChild);
}
}
@Override
public void postOrder(Node rootNode) {
// TODO Auto-generated method stub
if (rootNode != null) {
this.postOrder(rootNode.leftChild);
this.postOrder(rootNode.rightChild);
System.out.println(rootNode.key + " " + rootNode.value);
}
}
@Override
public boolean update(int key, int value) {
// TODO Auto-generated method stub
sql.update(key,value);
Node node = this.visit(key);
node.setValue(value);
return true;
}
}
⑤ 测试
package com.company;
public class Main{
public static void main(String[] args) {
// TODO Auto-generated method stub
BinaryTree tree = new BinaryTree();
tree.insert(6, 6);
tree.insert(3, 3);
tree.insert(14, 14);
tree.insert(16, 16);
tree.insert(10, 10);
tree.insert(9, 9);
tree.insert(13, 13);
tree.insert(11, 11);
tree.insert(12, 12);
System.out.println("Results of inOrder traversal before deleting.The result is an increasing ordered sequence.
");
tree.inOrder(tree.getRoot());
tree.update(12, 200);
System.out.println("Update the value of node key = 12");
tree.inOrder(tree.getRoot());
System.out.println("Results after deleting node 10");
tree.delete(10);
tree.inOrder(tree.getRoot());
System.out.println("The results of preorder traversal are as follows");
tree.preOrder(tree.getRoot());
}
}
6、 程序结果
运行程序后数据库中结果显示如下