二叉树构建、新增、删除和遍历总结
来源:互联网 发布:淘宝账户暂时被冻结 编辑:程序博客网 时间:2024/06/06 15:38
源码:
------------------------------------------------------------------------------------
Node.java:
packagecn.com.tree;
/**
* 二叉树节点
*@author daniel zhou
*
*/
publicclass Node {
// 数据项
publiclong data;
// 数据项
publicStringsData;
// 左子节点
publicNodeleftChild;
// 右子节点
publicNoderightChild;
/**
* 构造方法
*@param data
*@param sData
*/
publicNode(longdata, String sData){
this.data= data;
this.sData= sData;
}
}
--------------------------------------------------------------------------------
Tree.java:
packagecn.com.tree;
/**
* 二叉树类
*@author daniel zhou
*
*/
publicclass Tree {
// 根节点
publicNoderoot;
/**
* 原理:在一颗二叉树上插入节点,插入是建立在小于父节点,
* 则插入到父节点左边,如果大于父节点,则插入到父节点右边。
* 在插入树节点,需要判断树根是否为空,如果不为空,则需要
* 当前节点指向树根和父节点指向当前节点。直到当前节点等于null,
* 那么可以在父节点左边或者右边插入新节点,并且返回树根跳出循环。
* 如果树根为空,直接把树根指向新创建的节点,实现过程如下所示:
*
* 插入节点
*@param value
*/
publicvoid insert(longvalue, String sValue){
// 封装节点
Node newNode =new Node(value, sValue);
// 引用当前节点
Node current =root;
// 引用父节点
Node parent;
// 如果root为空,也就是第一次插入的时候
if(root==null){
root= newNode;
return;
}else{
while(true){
// 父节点指向当前节点
parent = current;
// 如果当前指向的节点数据比插入的要大,则向左走
if(current.data> value){
current = current.leftChild;
if(current == null){
parent.leftChild= newNode;
return;
}
}else{
current = current.rightChild;
if(current == null){
parent.rightChild= newNode;
return;
}
}
}
}
}
/**
* 查找节点
*@param value
*@return
*/
publicNode find(longvalue){
// 引用当前节点
Node current =root;
// 循环,只要查找值不等于当前节点的数据项
while(current.data!= value){
// 进行比较,比较查找值和当前节点的大小
if(current.data> value){
current = current.leftChild;
}else{
current = current.rightChild;
}
// 如果查找不到
if(current == null){
returnnull;
}
}
returncurrent;
}
二叉树删除节点原理图:
由于过程比较复杂,这里用图来表示
/**
* 删除节点:
* 工作原理:
从二叉查找树上删除节点的操作复杂程度取决于删除哪个节点。如果删除没有子节点的节点就非常简单,
如果节点只有一个子节点,不管是左子节点还是右子节点,就变得稍微有点复杂,如果节点包含两个子节点就最复杂。
如果待删除节点是叶子节点,那么只需要将从父节点指向它的链接指向null。
如果待删除节点只包含一个子节点,那么原本指向它的节点就得使其指向它的子节点。
如果待删除节点包含两个子节点,那么我们可以采用两种方式:
一种是查找待删除节点左子树上的最大值,
一种是查找待删除节点右节点上的最小值。
我们采取后者,找到最小值后,将临时节点上的值复制到待删除节点,然后再删除临时节点。
*@param value
*/
publicboolean delete(longvalue){
// 引用当前节点,从父节点开始
Node current =root;
// 引用当前节点父节点
Node parent =root;
// 是否为左节点
booleanisLeftChild =true;
while(current.data!= value){
parent = current;
// 进行比较
if(current.data> value){
// 向左走
current = current.leftChild;
isLeftChild =true;
}else{
// 向左走
current = current.rightChild;
isLeftChild =false;
}
// 如果查找不到
if(current == null){
returnfalse;
}
}
// 找到对应的节点
if(current.leftChild==null && current.rightChild==null){
// 1,该节点没有子节点,直接删除叶子节点
// 如果是根节点
if(current == root){
root=null;
}elseif(isLeftChild){
// 如果该节点是其父节点的左子节点,将其父节点的左子节点置为null
parent.leftChild=null;
}else{
// 如果该节点是其父节点的右子节点,将其父节点的右子节点置为null
parent.rightChild=null;
}
}elseif(current.rightChild==null){
// 2,该节点没有右子节点,直接将该节点的左子节点挂在其父节点的左/右节点上
if(current == root){
root= current.leftChild;
}elseif(isLeftChild){
// 如果该节点是其父节点的左子节点,将该节点的左子节点挂在其父节点的左子节点上
parent.leftChild= current.leftChild;
}else{
// 如果该节点是其父节点的右子节点,将该节点的左子节点挂在其父节点的右子节点上
parent.rightChild= current.leftChild;
}
}elseif(current.leftChild==null){
// 3,该节点没有左子节点,直接将该节点的右子节点挂在其父节点的左/右节点上
if(current == root){
root= current.rightChild;
}elseif(isLeftChild){
// 如果该节点是其父节点的左子节点,将该节点的左子节点挂在其父节点的左子节点上
parent.leftChild= current.rightChild;
}else{
// 如果该节点是其父节点的右子节点,将该节点的右子节点挂在其父节点的右子节点上
parent.rightChild= current.rightChild;
}
}else{
// 4,该节点有左右子节点
// 获取替代被删除节点的节点(即:找到该节点的中序后继节点,并将该节点替代被删除节点)
Node successor = getSuccessor(current);
if(current == root){
root = successor;
}elseif(isLeftChild){
// 如果该节点是其父节点的左子节点
parent.leftChild= successor;
}else{
// 如果该节点是其父节点的右子节点
parent.rightChild= successor;
}
// 固定替代节点的位置(固定其在被删除节点的位置,右边位置已经固定,现在固定左边)
successor.leftChild= current.leftChild;
}
returntrue;
}
/** 返回替代被删除节点的节点对象
* 工作原理:
* 被删除的有两个孩子节点,这种情况最复杂,因为要考虑到删除之后顺序不能乱。
* 所以这种类型的节点要删除,如果直接删,真个树的大小顺序就乱了,所以需要考虑,
* 在树中找到一个合适的节点来把这个节点给替换掉,用这种方法来保持整个数的稳定。
* 所以又一个问题又来了了,该找哪个节点来替换它?结论是,需要在树中找出所有比
* 被删除节点的值大的所有数,并在这些数中找出一个最小的数来。听起来很拗,如果
* 把它用图形来描述的话,就是,从被删除的节点出发经过它的右节点,然后右节点最
* 左边的叶子节点就是我们要找的,它有一个专业名词叫中序后继节点。下面专门来写一个方法来找它:
*/
publicNode 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;
}
// 如果替代节点为该节点的右节点,直接返回
returnsuccessor;
}
//*************N--root, L--left, R--right****************//
/** 遍历顺序:
- 前序遍历:NLR
1.访问根节点
2.前序遍历左子树
3.前序遍历右子树
中序遍历: LNR
1.中序遍历左子树
2.访问根节点
3.中序遍历右子树
后序遍历: LRN
1.后序遍历左子树
2.后序遍历右子树
3.访问根节点
*/
1前序遍历
遍历的顺序为:ABDGHCEIF
/**
* 基本思想:
1.访问根节点
2.前序遍历左子树
3.前序遍历右子树
* 顺序:NLR
* 前序遍历(递归遍历)
*@param localNode
*/
publicvoid frontOrder(Node localNode){
if(localNode != null){
// 访问根节点
System.out.println(localNode.data+", " + localNode.sData);
// 前序遍历左子树
frontOrder(localNode.leftChild);
// 前序遍历右子树
frontOrder(localNode.rightChild);
}
}
/**
* 前序非递归遍历:
对于任一结点p:
a. 访问结点p,并将结点p入栈;
b. 判断结点p的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,
并将栈顶结点的右孩子置为当前的结点p,循环置a;若不为空,则将p的左孩子置为当前结点p;
c. 直到p为空,并且栈为空,则遍历结束。
*@param localNode
*/
publicvoid frontOrder2(Node localNode){
}
2中序遍历
遍历的顺序为:GDHBAEICF
/**
* 基本思想:
1.中序遍历左子树
2.访问根节点
3.中序遍历右子树
* 中序遍历
* 顺序:LNR
*@param localNode
*/
publicvoid inOrder(Node localNode){
if(localNode != null){
// 中序遍历左子树
inOrder(localNode.leftChild);
// 访问根节点
System.out.println(localNode.data+", "+localNode.sData);
// 中序遍历右子树
inOrder(localNode.rightChild);
}
}
3后序遍历
遍历的顺序为:GHDBIEFCA
/**
* 基本思想:
1.后序遍历左子树
2.后序遍历右子树
3.访问根节点
* 后序遍历
* 顺序:LRN
*@param localNode
*/
publicvoid afterOrder(Node localNode){
if(localNode != null){
// 后序遍历左子树
afterOrder(localNode.leftChild);
// 后序遍历右子树
afterOrder(localNode.rightChild);
// 访问根节点
System.out.println(localNode.data+", "+localNode.sData);
}
}
4层序遍历
规则是若树为空,则空操作返回,否则从树的第一层,也就是根结点开始访问,从上而下逐层遍历,在同一层中,按从左到右的顺序对结点逐个访问。
遍历的顺序为:ABCDEFGHI
}
--------------------------------------------------------------------------------
阅读全文
0 0
- 二叉树构建、新增、删除和遍历总结
- BinaryTree的构建和遍历,以及搜索删除(非完全二叉树,非平衡二叉树)
- 二叉树的构建和遍历
- 二叉树的构建和前中后序遍历
- 二叉树的构建和遍历
- 二叉树遍历&构建
- 二叉搜索树的构建,遍历,查找,删除
- 中序遍历和先序遍历构建二叉树
- 二叉树的创建和遍历、删除
- 二叉树构建与遍历
- 层次遍历构建二叉树
- 构建二叉树及遍历
- 二叉树遍历总结和重构
- 二叉树的java构建和三种遍历方式
- java实现二叉树的构建和遍历
- C++类实现二叉树的构建和遍历
- 根据中序和前序遍历构建二叉树
- 中序遍历和先序遍历/后序遍历构建二叉树
- jsp的URL重写实现会话跟踪技术
- BlueCoat ProxySG配置FTP代理
- Android图表库HelloChart绘制多折线图
- ORACLE 数据库的备份
- 如何编辑pdf文件
- 二叉树构建、新增、删除和遍历总结
- mysql主从
- Linux 学习(四)
- 巴哥语录
- linux c 一站式学习 形参与实参
- js回调函数 同步 异步
- c++中的字符串分割
- 1、用C语言实现字符数组1拷贝到字符数组2,替代strcpy函数
- Delphi APP 里面使用 HTML5 来做帮助文档,移植WebBroker进Android APP