二叉排序树 logn
一、二叉排序树介绍
二叉排序树:对于二叉排序树的任何一个非叶子节点,要求左子节点的值比当前节点的值小,右子节点的值比当前节点的值大。
特别说明:如果有相同的值,可以将该节点放在左子节点或右子节点
要求:一个节点的左子树的值一定小于等于该节点,右子树的值一定大于该节点。
是整个树有序。
如何构建?
链表的构建。
单链表分两个部分: value next
双链表
树在存储的时候肯定是链式存储的方式。
构建有序二叉树实现思路
- 如果左子树不为空,那么左子树上的所有值都均小于它的根节点的值
- 如果右子树不为空,那么右子树上的所有值都均大于或等于它的根节点的值
- 左,右子树也为二叉排序树
当前必须有一个节点的类,TreeNode
新建TreeNode节点
public class TreeNode {
private TreeNode leftTreeNode; //左子树
private TreeNode rightTreeNode; //右子树
private Integer value; //值
public TreeNode(Integer value) {
super();
this.value = value;
}
public TreeNode getLeftTreeNode() {
return leftTreeNode;
}
public void setLeftTreeNode(TreeNode leftTreeNode) {
this.leftTreeNode = leftTreeNode;
}
public TreeNode getRightTreeNode() {
return rightTreeNode;
}
public void setRightTreeNode(TreeNode rightTreeNode) {
this.rightTreeNode = rightTreeNode;
}
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
@Override
public String toString() {
return "TreeNode [leftTreeNode=" + leftTreeNode + ", rightTreeNode=" + rightTreeNode + ", value=" + value + "]";
}
}
新建BinaryTree
public class BinaryTree {
//新建二叉树
TreeNode root;
//获取二叉树的数据
public TreeNode getRoot() {
return root;
}
/**
* f(node,value) --> f(node.right,value)
* if(node.value > value) :
* node.getRightTreeNode() == null
*
* f(node,value) --> f(node.left,value)
* if(node.value < value) :
* node.getRightTreeNode() == null
*
* @param value
* @return
*/
public TreeNode insertdigui(TreeNode node, Integer value){
// 新建一个节点
TreeNode newNode = new TreeNode(value);
if(root == null){
return root = newNode;
}
if(newNode.getValue() > node.getValue()){
if(node.getRightTreeNode() == null){
node.setRightTreeNode(newNode);
return root;
}
return insertdigui(node.getRightTreeNode(),value);
}else {
if(node.getLeftTreeNode() == null){
node.setLeftTreeNode(newNode);
return root;
}
return insertdigui(node.getLeftTreeNode(),value);
}
}
/**
* 构建有序二叉树
* @param value
*/
public void insert(Integer value) {
// 新建一个节点
TreeNode newNode = new TreeNode(value);
if (root == null) {
root = newNode;
} else {
// 定义一个指针用来遍历二叉树
TreeNode currentNode = root;
//定义这个指针的目的是:记录currentNode的前一个位置
TreeNode parentNode;
// 有孩子继续循环,一直循环到最后一个节点 和插入的节点比较
// 大的放到右节点,小于放到左节点
while (true) {
//记录currentNode
parentNode = currentNode;
// 往右放
if (newNode.getValue() > currentNode.getValue()) {
currentNode = currentNode.getRightTreeNode();
if (currentNode == null) {
parentNode.setRightTreeNode(newNode);
return;
}
} else {
// 往左放
currentNode = currentNode.getLeftTreeNode();
if (currentNode == null) {
parentNode.setLeftTreeNode(newNode);
return;
}
}
}
}
}
}
测试类
public class Test {
public static void main(String[] args) {
TreeNOde treeNOde5 = new TreeNOde(5);
TreeNOde treeNOde7 = new TreeNOde(7);
TreeNOde treeNOde4 = new TreeNOde(4);
TreeNOde treeNOde2 = new TreeNOde(2);
TreeNOde treeNOde0 = new TreeNOde(0);
TreeNOde treeNOde3 = new TreeNOde(3);
TreeNOde treeNOde1 = new TreeNOde(1);
TreeNOde treeNOde6 = new TreeNOde(6);
//在构建这样树的过程,树的插入位置由人来判断
treeNode5.setRightTreeNode(treeNode7);
treeNode5.setRightTreeNode(treeNode4);
treeNode4.setRightTreeNode(treeNode2);
treeNode2.setRightTreeNode(treeNode0);
treeNode2.setRightTreeNode(treeNode3);
treeNode0.setRightTreeNode(treeNode1);
treeNode7.setRightTreeNode(treeNode6);
}
}
后边再想创建树,不需要再写
public class Test {
public static void main(String[] args) {
// TreeNOde treeNOde7 = new TreeNOde(5);
// TreeNOde treeNOde4 = new TreeNOde(5);
// TreeNOde treeNOde2 = new TreeNOde(5);
// TreeNOde treeNOde0 = new TreeNOde(5);
// TreeNOde treeNOde3 = new TreeNOde(5);
// TreeNOde treeNOde1 = new TreeNOde(5);
// TreeNOde treeNOde6 = new TreeNOde(5);
//
// //在构建这棵树的过程当,树的插入位置是由人来判断的
// treeNode5.setRightTreeNode(treeNode7);
// treeNode5.setRightTreeNode(treeNode4);
// treeNode4.setRightTreeNode(treeNode2);
// treeNode2.setRightTreeNode(treeNode0);
// treeNode2.setRightTreeNode(treeNode3);
// treeNode0.setRightTreeNode(treeNode1);
// treeNode7.setRightTreeNode(treeNode6);
BinaryTree binaryTree = new BinaryTree();
binaryTree.insert(5);
binaryTree.insert(7);
binaryTree.insert(4);
binaryTree.insert(2);
binaryTree.insert(0);
binaryTree.insert(3);
binaryTree.insert(1);
binaryTree.insert(6);
System.out.println();
}
}
}
package 二叉树;
/**
* 有序二叉树的管理类
*/
public class BinaryTree {
// 新建代表整棵树的节点
TreeNode root;
public void insert(Integer value){
// 新建一个节点
TreeNode newNode = new TreeNode(value);
if(root == null){
root = newNode;
}else {//10
//定义一个指针来遍历这棵树
TreeNode currentNode = root;
//定义一个指针指向currentNode的上一个位置,目的是方便数据插入
TreeNode parentNode;
while(true) {
parentNode = currentNode;
if(newNode.getValue() > currentNode.getValue()) {//向右走
currentNode = currentNode.getRightTreeNode();
if(currentNode == null) {
parentNode.setLeftTreeNode(newNode);
return;
}else {
currentNode = currentNode.getLeftTreeNode();
if(currentNode == null) {
parentNode.setLeftTreeNode(newNode);
return;
}
}
}
}
}
}
}
解析代码:
画一下内存图 栈内存 堆内存
test的main方法先入栈,按照我们当前的需求,创建了一个叫binaryTree 地址0x1,有一个insert方法,入栈,要先创建节点,
新建一个NewNode 0x2 ,如果roo==null,指向 0x2
如何让0x7挂到5的哪边,
再来一个4,2 ,0
多了个判断
需要指针,currentNode。
就是尾插法,用一个指针遍历树。
指针往右走,往左走,判断为null的时候就要插入数据,
输出
递归方式
构建有序二叉树
递归:方法调用其本身:循环
递归函数:
递归表达式 f(n) = f(n-1) + f(n-2)
递归出口 f(1) = 1,f(2) = 2;
1 1 2 3 5 8 13 21...
public void digui(int n){
if(n==1){
return 1;
}else if(n==2){
return 2;
}else{
return digui(n-1) + digui(n-2);
}
}
简单回忆一下快速排序:
俩游标移动,
相遇,基准数与相遇的位置的数互换。
重新分成左右两部分,依次进行以上过程。
递归表达式:
递归表达式 f(arr,left,right)
-
-
-
- f(arr,left,i-1)
- f(arr,i+1,right)
-
-
递归出口 left >= right{
怎么用递归的方式实现一棵树?
递归表达式 function(node)
递归出口 left >= right
之后默写一下快速排序代码 。
有这样一棵树,怎么实现1的插入?
根据递归表达式,判断,要么往左走要么往右走 。
递归表达式: function(node,value) ---> f(node.right,value) root代表整个树
function(node,value) ---> f(node.left,value)
代码实现:
//当前要对比的子树节点
public TreeNode insetDigui(TreeNode node, Integer value) {
// 新建一个节点
TreeNode newNode = new TreeNode(value);
if (root == null) {
return root = newNode;
}
//核心代码
if (newNode.getValue() > node.getValue()) {
if (node.getRightTreeNode() == null) {
node.setRightTreeNode(newNode);
return root;
}
return insetDigui(node.getRightTreeNode(), value);
} else {
if (node.getLeftTreeNode() == null) {
node.setLeftTreeNode(newNode);
return root;
}
return insetDigui(node.getLeftTreeNode(), value);
}
}
node最开始指向的节点是5
与node.getValue比较,走else,然后指向4
node不断的指向代表的节点。
继续insert方法,node指向2,还是2大,往左走else,走之前做一个判断,node节点往左边走有没有树,是null的话就不需要走了,往左边一塞就可以。
同理右边也是如此。
递归出口:node.getRightNode() == null
node.getLeftNode() == null