- 最近学习的有点累。导致二叉树学习的有点模糊
- 我们之前学过数组 和链表 数组插入比较慢 链表查询比较慢。这时候我们就需要使用树这种结构。都比较快
- 树的基本概念
- 根:树最上面的节点称为根节点,一棵树只有一个根节点
- 父节点:每一个节点都有一条边向上连接到另一个节点,这个节点就是称为下面这个节点的父节点
- 子节点:每一个节点都有条向下连接的节点,下面的这个节点就是该节点的子节点
- 叶子节点:没有子节点的节点也叫叶子节点.
- 子树:每一个节点都可以作为一个子树的根。他和他的所有子节点组合在一起就是个子树
- 查找节点:从根节点开始查找,如果查找的节点值比当前节点的值小,则继续查找左子树,否则查找右子树
- 遍历树:遍历树是根据一个特定的顺序访问树的每一个节点,根据顺序的不同分为前序,中序,后序遍历三种。
前序遍历。
- (1)访问根节点
- (2)前序遍历左子树
- (3)前序遍历右子树
中序遍历。
- (1)中序遍历左子树
- (2)访问根节点
- (3)中序遍历右子树
后序遍历。
- (1)后序遍历左子树
- (2)后序遍历右子树
- (3)访问根节点
上代码:
/**
* 二叉树的节点类
* @author Administrator
*
*/
public class Node {
public int iData;
public String sData;
public Node leftChild;
public Node rightChild;
public Node(int iData,String sData) {
this.iData = iData;
this.sData =sData;
}
public Node() {
// TODO Auto-generated constructor stub
}
public void dispalyNode(){
System.out.print("{"+ iData +"}");
}
}
二叉树的具体实现
package com.chapter5_1;
public class Tree {
//根节点
public Node root;
/**
* 二叉树的插入 s
*/
public void insert(int d,String s){
//新节点
Node newNode = new Node(d,s);
//引用当前的节点
Node current = root;
//引用父节点
Node parent;
if(current == null){
root = newNode;
return ;//如果root节点为空的话,直接点添加都结束了
}
while(true){
//先将当前的节点付给一个parent. 这个节点一直在变动
parent = current;
if(d < current.iData){
//当前的节点变成刚才的左节点
current = current.leftChild;
if(current == null){
parent.leftChild =newNode;
return;
}
}else{//d >
// 变成刚才的又节点
current = current.rightChild;
if(current == null){
parent.rightChild= newNode;
return;
}
}
}
}
/**
* 查找二叉树
* @param value
* @return
*/
public Node find(int value){
Node current = root;
while(current.iData !=value){
//如果这个值比当前的节点值小,那么找左子节点
if(current.iData > value){
current = current.leftChild;
}else{
current = current.rightChild;
}
if(current == null){
return null;
}
}
return current;
}
public void traverse(int traverseType){
switch (traverseType) {
case 1://
//前序遍历
System.out.println("前序遍历");
frontOrder(root);
break;
case 2:
System.out.println("中序遍历");
inOrder(root);
break;
case 3:
System.out.println("后序遍历");
postOrder(root);
break;
default:
break;
}
System.out.println("--------------------------------");
}
/**
* 前序遍历
* @param localNode
*/
public void frontOrder(Node localNode){
if(localNode != null){
//访问根节点
System.out.println(localNode.iData +","+localNode.sData);
//前序遍历左子树
frontOrder(localNode.leftChild);
//前序遍历右子树
frontOrder(localNode.rightChild);
}
}
/**
* 中序遍历 -
* 1.中序遍历左子树
* 2.访问根节点
* 3.中序遍历右子树(从小到大)
* @param localNode
*/
public void inOrder(Node localNode){
if(localNode != null){
//中序遍历左子树
inOrder(localNode.leftChild);
//访问根节点
System.out.println(localNode.iData +","+localNode.sData);
//中序遍历右子树
inOrder(localNode.rightChild);
}
}
/**
* 后序遍历。。先遍历左子树-右子树-访问根节点
* @param localNode
*/
public void postOrder(Node localNode){
if(localNode != null){
//后序遍历左子树
postOrder(localNode.leftChild);
//后序遍历右子树
postOrder(localNode.rightChild);
//访问根节点
System.out.println(localNode.iData +","+localNode.sData);
}
}
/**
* 删除一个节点
* 有3种情况
* 1.该节点是叶子节点
* 2.该节点只有 一个节点
* 3.该节点有俩个节点。需要找到右边节点的最小节点。(中序遍历后继。。找到)
* @param value
* @return
*/
public boolean delete(int value){
//引用当前节点
Node current = root;
//引用父节点
Node parent = root;
//判断是否为左子节点
boolean isLeftChild =true;
while(current.iData != value){
//先赋值
parent = current;
//如果这个值比当前的节点值小,那么找左子节点
if(current.iData > value){
current = current.leftChild;
isLeftChild =true;
}else{
current = current.rightChild;
isLeftChild =false;
}
if(current == null){
return false;
}
}
//删除叶子节点,也就是该节点没有子节点
if(current.leftChild == null && current.rightChild == null){
if(current == root){//删除的是根。并且根么有子子节点
root = null;
}else if(isLeftChild){//删除的叶子节点是父节点的左子节点
parent.leftChild = null;
}else{
parent.rightChild = null;
}
}else if(current.rightChild == null){//只有一个节点 意思就是左子节点有数据
if(current == root){//如果是根的话。就是根节点=当前的左子节点
root = current.leftChild;
}else if(isLeftChild){
parent.leftChild = current.leftChild;
}else{
parent.rightChild = current.leftChild;
}
}else if(current.leftChild == null){//只有一个节点 意思就是右子节点有数据
if(current == root) root = current.rightChild;
//这里看起来比较绕。。所以删除的时候可以自己画一个图。自己想
else if(isLeftChild){
parent.leftChild = current.rightChild;
}else{
parent.rightChild = current.rightChild;
}
}else{//有俩个节点。。。。
Node successor = getSuccessor(current);
if(current ==root){
root = successor;
}else if(isLeftChild){
parent.leftChild = successor;
}else{
parent.rightChild = successor;
}
successor.leftChild =current.leftChild;
}
return true;
}
public Node getSuccessor(Node delNode){
Node successor = delNode;
Node successorParent = delNode;
Node current =delNode.rightChild;
while(current != null){
successorParent =successor;
successor =current;//先右边然后然后一直找左子节点
current = current.leftChild;//一直往左子节点找
}
if(successor != delNode.rightChild){//这里没有看懂。
successorParent.leftChild = successor.rightChild;
successor.rightChild = delNode.rightChild;
}
return successor;
}
}
测试代码:
package com.chapter5_1;
public class Test {
public static void main(String[] args) {
Tree t = new Tree();
t.insert(10,"thinkpad");
t.insert(20,"mac");
t.insert(15,"del");
t.insert(3,"leishen");
t.insert(40,"zhangsan");
t.insert(16,"liao");
t.insert(4,"luyao");
// System.out.println(t.root.rightChild.iData);
// System.out.println(t.root.rightChild.leftChild.iData);
// System.out.println(t.root.leftChild.iData);
// Node node = t.find(15);
System.out.println(node.iData +", " + node.sData);
// node = t.find(3);
System.out.println(node.iData +", " + node.sData);
t.delete(3);
// t.traverse(1);
t.traverse(2);
// t.traverse(3);
t.delete(16);
// t.traverse(1);
t.traverse(2);
}
}
至于测试结果我就不贴了。很多。在删除二叉树有俩个节点的时。我没有弄明白。我先贴代码。最近比较累。