数据结构(java)——二叉树的构造(增删查遍历)

本文介绍了如何在Java中自定义二叉树的数据结构,包括节点类的定义,二叉树类的创建,以及增、删、查、遍历等基本操作。文章详细讲解了前序、中序、后序和层序四种遍历方法,并提到了删除节点的实现,虽然删除原理未展开,但提供了相关代码参考链接。

二叉树:

        在java的api当中,有一些数据结构已经封装好了,比如链表linkedlist,栈stack,队列queue和优先队列PriorityQueue等等。

        但是二叉树(BinaryTree)在api中没有显式的定义,需要我们自己定义那我们来看一下二叉树的定义和基本操作。

节点类:

public class Node {
	//long数据项
	public long data;
	//String数据项
	public String sData;
	//左孩子节点
	public Node leftChild;
	//右子节点
	public Node rightChild;
	//是否被访问
	public boolean wasVisited;
		
	//构造方法
	public Node(long data, String sData) {
		this.data = data;
		this.sData = sData;
	}
}

二叉树类:需要一个根节点

//二叉树
public class BinaryTree {
	
	//根节点
	public Node root;
	
	
	//……这里还有很多操作,在下面
}

下面介绍一点基本的建立操作:

1、增加数据:根据任何左孩子都要比跟节点小,右孩子比跟大的特点,我们写出如下代码:

        //插入一个节点
	public void insert(long data , String sData) {
		
		//封装节点
		Node newNode = new Node(data , sData);
		
		//两个引用
		//当前节点
		Node current = root;
		//父节点
		Node parent;
		
		//第一次插入直接赋值
		if(current == null) {
			root = newNode;
			return;
		}
		
		//循环左走右走
		while (true) {
			//父节点指向当前节点
			parent = current;
			//比较大小左右走
			if (current.data > data) {
				current = current.leftChild;
				if(current == null) {
					parent.leftChild = newNode;
					return;
				}
			}
			else {
				current = current.rightChild;
				if(current == null) {
					parent.rightChild = newNode;
					return;
				}
			}
		}
	}

2、查找节点:

        //查找节点
	public Node find(long data) {
		//引用当前节点
		Node current = root;
		
		while(current.data != data) {
			//进行比较和当前节点大小
			if (current.data > data) {
				current = current.leftChild;				
			} else {
				current = current.rightChild;
			}
			
			//查不到
			if(current == null) {
				return null;
			}
		}
		return current;
	}

3、遍历:4种

(1)前序遍历:先访问跟节点,再访问根节点的左子树(左子树也同样前序遍历,先左子树的跟,再左子树的左子树,以此类推),最后访问右子树(同理)。

        /*前序遍历
	 * 1.访问根节点
	 * 2.递归前序遍历左子树
	 * 3.递归前序遍历右子树
	 */
	public void frontOrder(Node localNode) {
		if(localNode != null) {
			System.out.print(localNode.data + "," + localNode.sData + " ; ");
			frontOrder(localNode.leftChild);
			frontOrder(localNode.rightChild);
		}
	}

(2)中序遍历(可按升序输出):

        /*
	 * 中序遍历
	 * 1.递归中序遍历左子树
	 * 2.访问根节点
	 * 3.递归中序遍历右子树
	 */
	public void inOrder(Node localNode) {
		if (localNode != null) {
			inOrder(localNode.leftChild);
			System.out.print(localNode.data + "," + localNode.sData + " ; ");
			inOrder(localNode.rightChild);
		}
	}

(3)后序遍历:

        /*
	 * 后序遍历
	 * 1.递归后序遍历左子树
	 * 2.递归后序遍历右子树
	 * 3.访问根节点
	 */
	public void afterOrder(Node localNode) {
		if (localNode != null) {
			afterOrder(localNode.leftChild);
			afterOrder(localNode.rightChild);
			System.out.print(localNode.data + "," + localNode.sData + " ; ");
		}
	}

(4)层序遍历:利用到了队列的特点

        //层序遍历
	public void LevelOrder(Node root) {
		Queue<Node> queue = new LinkedList<Node>();
		
		Node now = root;
		queue.add(root);
		
		while (!queue.isEmpty()) {
			now = queue.poll();
			if (now != null) {
				System.out.print(now.data + "," + now.sData + " ; ");
			}
			if (now.leftChild != null) {
				queue.add(now.leftChild);
			}
			if (now.rightChild != null) {
				queue.add(now.rightChild);
			}
		}
	}

前三种遍历方式我们用到了递归的思想,这样容易理解,代码也简单。如果不用递归也可以实现,具体参照https://blog.csdn.net/likunkun__/article/details/80183599

4、删除节点(原理另开一章讲,这里先贴代码):

        //先寻找中序后继节点,再进行删除
        //寻找中序后继节点
        public Node getHouJiNode(Node delNode) {
		//定义中序后继节点
		Node houji = delNode;
		//定义中序后继的父节点
		Node houjiparent = delNode;
		//当前节点
		Node current = delNode.rightChild;
		
		while(current != null) {
			houjiparent = houji;
			houji = current;
			current = current.leftChild;//往左边找
		}
		
		//把删除节点替换成终须后继节点
		//1.如果删除节点的右节点不是后继节点(正常右左左……找到的)
		if(houji != delNode.rightChild) {
			//中序后继的父节点的左子节点指向中序后继节点的右子节点(中序后继节点没有左子节点)
			houjiparent.leftChild = houji.rightChild;
			//后继的右边接上删除的右边,左边接上删除的左边
			houji.rightChild = delNode.rightChild;
			houji.leftChild = delNode.leftChild;
		}
		//2.删除节点的右节点就是中序后继节点,右边不用动,吧左边接上就可以
		else {
			houji.leftChild = delNode.leftChild;
		}
		
		return houji;
		
	}
	
	
	//删除节点delete
	public boolean delete(long data) {
		//引用当前节点
		Node current = root;
		
		//引用当前节点的父节点
		Node parent = root;
		
		//是左子节点还是右节点
		boolean isLeftChild = true;
		
		
		//循环找到要删的节点
		while (current.data != data) {
			
			parent = current;
			
			if (current.data > data) {
				current = current.leftChild;
				isLeftChild = true;
			} else {
				current = current.rightChild;
				isLeftChild = false;
			}
			
			//没有
			if(current == null) {
				return false;
			}		
		}
		//循环结束,current指向要删除节点,parent指向父节点
		
		
		
		//进行删除current节点
		
		//1.如果是叶子节点(没有子节点)
		if (current.leftChild == null &¤t.rightChild ==null) {
			if (current == root) {
				root = null;
			}
			//如果是左边的节点
			else if (isLeftChild) {
				parent.leftChild = null;
			}
			//如果是右边的节点
			else {
				parent.rightChild = null;
			}
		}
		
		//2.删除带有一个子节点的节点
		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;
			}
		}
		
		//3.删除有2个子节点的节点,需要寻找中续后继节点来替换删除节点
		else {
			Node houji = getHouJiNode(current);
			if (current == root) {
				root = houji;
			}
			else if (isLeftChild) {
				parent.leftChild = houji;
			}
			else {
				parent.rightChild = houji;
			}
		}
		
		return true;
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值