二叉查找树的循环插入以及使用循环和递归的两种先序遍历方式
这是我第一次写博客,作为一个半路出家的预备程序员,在学习的同时,希望可以记录下来,以便自己以后回顾的时候能有所了解。(希望大家不要吐槽我的排版)。话不多说,上干货。
- 使用一个内部类来当做树的节点
- 循环插入元素
- 先序遍历的递归实现
- 先序遍历的循环实现
成员变量
public class BinTree<T> {
Node<T> root;
内部类
//树中的节点用内部类表示
class Node<E>{
//一个节点中包含指向左右儿子节点的引用和这个节点包含的数据
Node<E> Left;
Node<E> Right;
Node<E> parent;
E data;
public Node<E> getLeft() {
return Left;
}
public void setLeft(Node<E> left) {
Left = left;
}
public Node<E> getRight() {
return Right;
}
public void setRight(Node<E> right) {
Right = right;
}
public E getData() {
return data;
}
public void setData(E data) {
this.data = data;
}
public Node() {
super();
// TODO Auto-generated constructor stub
}
public Node(E e,Node<E> parent) {
this.data= e;
this.parent = parent;
}
插入元素
public void add(T e ){
//先判断这棵树是不是空的
Node<T> t = root;
if(t==null) {
this.root = new Node(e,null);
return;
}
int cmp;
//定义一个父节点
Node<T> parent;
//
do {
parent = t;
Comparable<? super T> k = (Comparable<? super T>) e;
cmp = k.compareTo(t.getData());
if(cmp<0) {
t = t.Left;
}else if(cmp>0) {
t=t.Right;
}
else return;
}while(t!=null);
//子类节点中包含一个对父类节点的引用,可以通过其来访问父类节点
Node<T> w = new Node(e, parent);
if (cmp < 0)
//将子节点赋值给父节点的左儿子节点引用,也就是说父节点的左子节点指向新插入的节点
parent.Left = w;
else
//将子节点赋值给父节点的右儿子节点引用,也就是说父节点的右子节点指向新插入的节点
parent.Right = w;
}
先序遍历的递归实现
递归实现感觉还是比较容易思考的到的,因为看数据结构的视频的时候,老师都是用c语言实现的,不过不会c语言,所以就用java试试看
public void preorder() {
if(this.root==null) {
return ;
}
preorder(this.root);
}
public void preorder(Node<T> node) {
System.out.println(node.data.toString());
if(node.Left!=null) {
preorder(node.Left);
}
if(node.Right!=null) {
preorder(node.Right);
}
}
先序遍历的循环实现
写这个的时候,我是使用了两个集合,一个冲当栈,一个放出栈的元素,其实应该是一个集合或者数组就可以的,但是不想改了,以后有时间再改一下吧。
//使用循环 先序遍历 一个排序二叉树
//先序遍历:先遍历树的根节点,然后遍历树的左子树,最后遍历树的右子树
public void loopPreOrder() {
if(root == null) {
return;
}
//栈
LinkedList<Node<T>> list1 = new LinkedList<>();
//出栈后的元素放在这个集合里 简称 垃圾堆
LinkedList<Node<T>> list2 = new LinkedList<>();
Node<T> t = root;
//定义一个父节点
Node<T> parent;
do {
parent = t;
//如果栈集合中不包含这个父节点,就让它进栈,并打印出来
if(!list1.contains(parent)) {
list1.add(t);
System.out.println(parent.getData().toString());
}
//如果这个节点的左子节点不为空同时垃圾堆集合中不包含这个左子节点(为了防止重复进栈)
// 就把它的左子节点 赋值给t,成为下一个父节点
if(t.Left!=null&&(!list2.contains(t.Left))) {
t = t.Left;
//同上
}else if(t.Right!=null&&(!list2.contains(t.Right))) {
t = t.Right;
//如果这个节点没有左子节点和右子节点,就把这个节点放到垃圾堆中
//同时在栈集合中移除这个节点,同时判断一下这个栈集合中是否为空,如果空
//就说明 遍历结束,跳出循环
}else {
list2.add(list1.getLast());
list1.removeLast();
if(!list1.isEmpty()) {
t = list1.getLast();
}else {
return ;
}
}
}while(list1.size()!=0);
}
插入操作参考了TreeMap集合中的插入的源码,简化了很多,然后循环遍历的时候和插入的操作其实好相像。