您的位置:首页 > 其它

二叉搜索树实现与深度优先遍历和广度优先遍历

2017-08-16 21:18 453 查看
public class BinarySearchTree<T> {
private TreeNode root;
/**
* 插入数据
* @param key
* @param value
*/
public void insert(int key,T value){
if(root == null){
root = new TreeNode(key,value);
}else{
insert(root,key,value);
}

}

/**
* 递归找到插入的节点并插入
* @param node
* @param key
* @param value
*/
private void insert(TreeNode node,int key,T value){
//如果值比传进来的节点小就向下执行
if(key < node.key){
//如果传进来的节点的左节点没有了,说明是最小的节点了,在最小的节点下添加一个更小的节点
if(node.leftChild == null){
TreeNode treeNode = new TreeNode(key,value);
node.leftChild = treeNode;
}else{
//左节点不为空就继续递归
insert(node.leftChild, key, value);
}
}else{
//同上
if(node.rightChild == null){
TreeNode treeNode = new TreeNode(key,value);
node.rightChild = treeNode;
}else{
insert(node.rightChild, key, value);
}
}
}
/**
* 获最小的一个节点
* @param node
* @return
*/
private TreeNode min(TreeNode node){
if(node == null){
return null;
}else if(node.leftChild == null){
return node;
}
return min(node.leftChild);
}
/**
* 获取最大的一个节点
* @param node
* @return
*/
private TreeNode max(TreeNode node){
if(node == null){
return null;
}else if(node.rightChild == null){
return node;
}
return max(node.rightChild);
}
/**
* 移除节点
* @param key
*/
public void remove(int key){
remove(root, key);
}
/**
* 移除
* @param node
* @param key
*/
private void remove(TreeNode node,int key){
if(node == null ){
return ;
}
//如果键比当前的节点的值小就递归查询做节点
if(key < node.key){
remove(node.leftChild, key);
//如果键比当前节点的值大就递归查询右节点
}else if(key > node.key){
remove(node.rightChild, key);
//*找到了要删除的节点,如果左节点和右节点都不为空,就执行替换操作
}else if(node.leftChild != null && node.rightChild != null){
//找到右节点中最小的那个节点,因为最小的节点是个单节点,所有很好操作
TreeNode min = min(node.rightChild);
//替换搜索到的需要移除的节点为右节点中最小的节点
node.key = min.key;
node.data = min.data;
//然后递归从右节点中删除找到的最小的节点
remove(node.rightChild,min.key);
}else{
//删除单节点或者只有一个孩子节点的情况,如果当前结点的左节点为空就将右节点赋值为当前节点
node = node.leftChild == null ? node.rightChild:node.leftChild;
}
}
/**
* 先序遍历,递归
*/
public void firstOrder(TreeNode node){
if(node == null){
return ;
}
show(node);
firstOrder(node.leftChild);
firstOrder(node.rightChild);
}
/**
* 中序遍历
* @param node
*/
public void middleOrder(TreeNode node){
if(node == null){
return ;
}
middleOrder(node.leftChild);
show(node);
middleOrder(node.rightChild);
}
/**
* 后序遍历
* @param node
*/
public void lastOrder(TreeNode node){
if(node == null){
return ;
}
lastOrder(node.leftChild);
lastOrder(node.rightChild);
show(node);
}
/**
* 先序遍历,非递归
* @param node
*/
public void firstOrderStack(TreeNode node){
if(node == null){
throw new RuntimeException("没有节点啊");
}
//通过栈来记忆行走的路径
Stack<TreeNode> stack = new Stack<>();
//将最开的节点压进栈
stack.push(node);
//循环获取节点信息,直到节点为空或者栈为空
while(node != null && !stack.isEmpty()){
//先访问节点
show(node);
//如果当前节点的右节点不为空,就将右节点压进栈
if(node.rightChild != null){
stack.push(node.rightChild);
}
//如果左节点不为空,就将左节点压进栈
if(node.leftChild != null){
stack.push(node.leftChild);
}
//出栈,将节点替换为最后进栈的节点,作为基础的节点进行循环
node = stack.pop();
}
}
/**
* 先序遍历,非递归2,一路向左
* @param node
*/
public void firstOrderStack2(TreeNode node){
if(node == null){
throw new RuntimeException("没有节点啊");
}
Stack<TreeNode> stack = new Stack<>();
//
while(node != null || !stack.isEmpty()){
//先依次访问左节点,并把左节点压进栈
while(node != null){
show(node);
stack.push(node);
node = node.leftChild;
}
//然后转向获得栈顶(最后访问的)的右节点
node = stack.pop().rightChild;
}

}
/**
* 中序遍历,非递归
* @param node
*/
public void middleOrderStack(TreeNode node){
if(node == null){
throw new RuntimeException("没有节点啊");
}

Stack<TreeNode> stack = new Stack<>();
//如果节点不为空个或者栈不为空就循环
while(node != null || !stack.isEmpty()){
//一路向左,先把所有左节点放入栈中,直到没有左节点了
while(node != null){
stack.push(node);
node = node.leftChild;
}
//取得栈顶节点,并访问,然后转向获得他的右节点
node =stack.pop();
show(node);
node = node.rightChild;

}
}
/**
* 后序遍历,非递归
* @param node
*/
public void lastOrderStack(TreeNode node){
if(node == null){
throw new RuntimeException("没有节点啊");
}
//保存最后访问的节点
TreeNode last = null;
Stack<TreeNode> stack = new Stack<>();
while(node != null ){
//先往最左遍历,直到为空
while(node != null){
stack.push(node);
node = node.leftChild;
}
//取出为空前的那一个节点
node = stack.pop();
//然后进行循环遍历,第一个是判断是否为叶子节点,如果是叶子节点就直接访问。如果节点的右节点等于最后访问的节点,就代表已经访问过了
while(node.rightChild == null || node.rightChild == last){
//访问节点
show(node);
//最开始将叶子节点设置为最后的节点,然后第二次判断会递归的将叶子节点上一个节点置为最后的节点
last = node;
if(stack.isEmpty()){
return;
}
//弹出当前节点的上一个节点
node = stack.pop();
}
//放进当前节点,说明当前节点有右节点,记忆当前节点
stack.push(node);
//让节点等于当前节点的右节点,转向右节点,因为上面已经通过判断了,到这里就是最左支的节点,然后该节点有右边的节点
node = node.rightChild;
}
}
/**
* 广度优先遍历
* @param node
*/
public void OrderQueue(TreeNode node){
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(node);
//如果队列不为空,就循环遍历
while(!queue.isEmpty()){
//出队
node = queue.poll();
//访问节点
show(node);
//如果当前节点的左节点不为空,就将左节点入队
if(node.leftChild != null){
queue.offer(node.leftChild);
}
//如果当前节点的右节点不为空,就将右节点入队
if(node.rightChild != null){
queue.offer(node.rightChild);
}
}
}
public void show(TreeNode node){
System.err.println("key:"+node.key+",vlaue:"+node.data);
}
/**
* 树节点
* @author yuli
*
*/
private  class TreeNode{
int key;
T data;
TreeNode leftChild;
TreeNode rightChild;
TreeNode(int key,T data){
this.key = key;
this.data = data;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: