二叉搜索树
二叉搜索树的性质
1.若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
2.若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
3.任意节点的左,右子树也分别为二叉搜索树;
4. 没有键值相等的节点。
代码表示二叉树
使用链表来存储二叉树
public class BinTree
{ // 二叉树类
public bintree left;
public bintree right;
public bintree root;
// 数据域
private Object data;
}
二叉树的函数
创建插入
public void insert(int key)
{
Node p=new Node(); //待插入的节点
p.data=key;
if(root==null)
{
root=p;
}
else
{
Node parent=new Node();
Node current=root;
while(true)
{
parent=current;
if(key>current.data)
{
current=current.right; // 右子树
if(current==null)
{
parent.right=p;
break;
}
}
else //本程序没有做key出现相等情况的处理,暂且假设用户插入的节点值都不同
{
current=current.left; // 左子树
if(current==null)
{
parent.left=p;
return;
}
}
}
}
}
递归的方法 二叉树的插入
有返回的类型,返回的是一个 插入后的树
pubilc BinTree Insert(int key,BinTree BST){
if(BST==null){
//是空树的话创建一个新的树并返回
BST=new BinTree();
BST.data=key;
BST.left=BST.right=null;
}
else{
if(key<BST.data)
BST.left=Insert(key, BST.left);
else if(key>BST.data)
BST.right=Insert(key, BST.right);
//else key相等,就什么也不做
}
return BST;
二叉树的遍历
// 用递归的方法进行先序遍历
public void xinaxuDigui(TreeNode treeNode) {
if (treeNode != null) {
System.out.printf(treeNode.data)
xinaxuDigui(treeNode.left);
xinaxuDigui(treeNode.right);
}
}
// 用递归的方法进行中序遍历
public void zhongxuDigui(TreeNode treeNode) {
if (treeNode!= null) {
zhongxuDigui(treeNode.left);
System.out.printf(treeNode.data)
zhongxuDigui(treeNode.right);
}
}
// 用递归的方法进行后序遍历
public void houxuDigui(TreeNode treeNode) {
if (treeNode != null) {
houxuDigui(treeNode.left);
houxuDigui(treeNode.right);
System.out.printf(treeNode.data)
}
}
非递归的遍历
使用堆栈
// 用非递归的方法进行先序遍历
public void qinaxuFeiDigui(TreeNode treeNode) {
Stack<TreeNode> stack = new Stack<TreeNode>();
while (treeNode != null || !stack.isEmpty()) {
while (treeNode != null) {
System.out.printf(treeNode.data);
stack.push(treeNode);
treeNode = treeNode.left;
}
if(!stack.isEmpty()){
treeNode = stack.pop();
treeNode = treeNode.right;
}
}
}
// 用非递归的方法进行中序遍历
public void zhongxuFeiDigui(TreeNode treeNode) {
Stack<TreeNode> stack = new Stack<TreeNode>();
while (treeNode != null || !stack.isEmpty()) {
while (treeNode != null) {
stack.push(treeNode);
treeNode = treeNode.left;
}
if (!stack.isEmpty()) {
treeNode = stack.pop();
System.out.printf(treeNode.data);
treeNode = treeNode.right;
}
}
}
// 用非递归的方法进行后序遍历
public void houxuFeiDigui(TreeNode treeNode) {
Stack<TreeNode> stack = new Stack<TreeNode>();
while (treeNode != null || !stack.isEmpty()) {
while (treeNode != null) {
stack.push(treeNode);
treeNode = treeNode.left;
}
boolean tag = true;
TreeNode preNode = null; // 前驱节点
while (!stack.isEmpty() && tag == true) {
treeNode = stack.peek();
if (treeNode.right == preNode) { // 之前访问的为空节点或是栈顶节点的右子节点
treeNode = stack.pop();
System.out.printf(treeNode.data);
if (stack.isEmpty()) {
return;
} else {
preNode = treeNode;
}
} else {
treeNode = treeNode.right;
tag = false;
}
}
}
}
非递归的另一种模板遍历
while( 栈非空 || p 非空){
if( p 非空){
}else{
}
}
中序遍历
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> a = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
if(root == null)
return a;
while(!stack.isEmpty() || root != null){
if(root != null){
stack.push(root);
root = root.left;
}
else{
root = stack.pop();
a.add(root.val);
root = root.right;
}
}
return a;
}
}
后序遍历
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root == null)
return res;
Stack<TreeNode> stack = new Stack<>();
TreeNode r = null; //标记结点的右子树是否访问过
while(!stack.isEmpty() || root != null){
if (root != null) { //这里一直while循环到最左边结点
stack.push(root);
root = root.left;
}else{
root = stack.peek();
if(root.right == null || root.right == r){//判断结点右子树状态,是空或者已经访问过,满足就可以访问根结点。
res.add(root.val);
stack.pop();
r = root;
root = null;
}else
root = root.right;
}
}
return res;
}
}
二叉树的查找
在二叉查找树中查找x的过程如下
-
若二叉树是空树,则查找失败。
-
若x等于根结点的数据,则查找成功。
-
若x小于根结点的数据,则递归查找其左子树,否则,递归查找其右子树。
public Bintree Find(int x,BinTree BST){
if(BST==null) return null;
if(x>BST.data) return Find(x,BST.right);
else if(x<BST.data) return Finf(x,BST,left);
else(x==BST.data) return BST;
}
//返回的是找到结点的所在地址
迭代查找
public Bintree Find(int x,BinTree BST){
while(BST!=null){
if(x>BST.data)
BST=BST.right;
else if(x<BST.data)
BST=BST.left;
else
return BST;
}
rerutn null;
}
查找最大最小元素
public Node FindMax(BinTree T){
if(T==null) return null;
else if(T.right==null) return T;
else return FindMax(T.right);
}
public Node FindMin(BinTree T){
if(T!=null){
while(T.left!=null) T=T.left;
return T;
}esle return null;
}
二叉树的删除
考虑三种情况
1.删除的是叶节点
直接删除也叶结点,然后修改其父结点的 指针 为null。
2.删除的是只有一个儿子的节点
将其父结点的指针指向要删除结点的孩子结点
3.删除的是有俩个儿子的节点。
用右子树的最小元素或左子树的最大元素来替换掉这个结点。
用非递归方法
public boolean delete(int key,Bintree root) {
//俩个变量,一个是代表删除的那个结点,一个代表删除结点的父节点
Node current = root;
Node parent = root;
boolean isLeftChild = false;
//判别结点是左儿子还是右儿子
while(current.data != key){
parent = current;
if(current.data > key){
isLeftChild = true;
current = current.leftChild;
}else{
isLeftChild = false;
current = current.rightChild;
}
if(current == null){
return false;
}
return true;
}
这就找到了删除的那个结点 current
//如果当前节点没有子节点
if(current.leftChild == null && current.rightChild == null){
//检查是否为根结点
if(current == root){
root = null;
}else if(isLeftChild){
parent.leftChild = null;
}else{
parent.rightChild = null;
}
return true;
}
return false;
}
//当前节点有一个子节点
if(current.leftChild == null && current.rightChild != null){
if(current == root){
root = current.rightChild;
}else if(isLeftChild){
parent.leftChild = current.rightChild;
}else{
parent.rightChild = current.rightChild;
}
return true;
}else{
//current.leftChild != null && current.rightChild == null
if(current == root){
root = current.leftChild;
}else if(isLeftChild){
parent.leftChild = current.leftChild;
}else{
parent.rightChild = current.leftChild;
}
return true;
}
递归方法
public Bintree Delete(int x, Bintree T){
if(T==null)
System.out.println("未找到元素");
else if(x<T.data)
T.left=Delete(x, T.left);
else if (x>T.data)
T.right=Delete(x,T.right);
else (x==T.data){
if(T.left!=null && T.right!=null){ //俩个孩子结点
T.data=FindMin(T.rihgt).data;
T.right=Delete(T.data, T.right);
}else { //一个孩子结点或者无孩子结点
if(T.left==null)
T=T.right;
else(T.right==null)
T=T.left
}
}
return T;
}