使用java实现链式存储的二叉树
2017-11-18 12:09
387 查看
上一篇文章写了使用java实现顺序存储的二叉树,这次接着使用java实现链式存储的二叉树:
首先创建一个结点类TreeNode<E>:
package com.linkedTree;
public class TreeNode<E> {
private E item;
private TreeNode<E> leftChild;
private TreeNode<E> rightChild;
public TreeNode(E item){
this(item,null,null);
}
public TreeNode(E item, TreeNode<E> l , TreeNode<E> r){
this.item = item;
this.leftChild = l;
this.rightChild = r;
}
public TreeNode<E> getRightChild() {
return rightChild;
}
public void setRightSibling(TreeNode<E> rightChild) {
this.rightChild = rightChild;
}
public TreeNode<E> getLeftChild() {
return leftChild;
}
public void setLeftSibling(TreeNode<E> leftChild) {
this.leftChild = leftChild;
}
public E getItem() {
return item;
}
public void setItem(E item) {
this.item = item;
}
@Override
public int hashCode() {//重写hashCode和equals方法
final int prime = 31;
int result = 1;
result = prime * result + ((item == null) ? 0 : item.hashCode());
result = prime * result + ((leftChild == null) ? 0 : leftChild.hashCode());
result = prime * result + ((rightChild == null) ? 0 : rightChild.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TreeNode<?> other = (TreeNode<?>) obj;
if (item == null) {
if (other.item != null)
return false;
} else if (!item.equals(other.item))
return false;
if (leftChild == null) {
if (other.leftChild != null)
return false;
} else if (!leftChild.equals(other.leftChild))
return false;
if (rightChild == null) {
if (other.rightChild != null)
return false;
} else if (!rightChild.equals(other.rightChild))
return false;
return true;
}
}
然后创建一个接口LTree<E>,规范链式存储二叉树的方法:
package com.linkedTree;
import com.linkedTree.TreeNode;
public interface Ltree<E> {
boolean isEmpty();
TreeNode<E> getRoot();
TreeNode<E> getParent(TreeNode<E> node);
TreeNode<E> getLeftChild(TreeNode<E> node);
TreeNode<E> getRightChild(TreeNode<E> node);
void breadFirstOrder();//广度优先
void preOrder();//先序遍历
void inOrder();//中序遍历
void postOrder();//后序遍历
void clear();//删除整个树
}
接着创建一个类LinkedTree<E>来实现LTree<E>接口:
package com.linkedTree;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;
public class LinkedTree<E> implements Ltree<E> {
private TreeNode<E> root;
public LinkedTree(TreeNode<E> root){
this.root = root;
}
@Override
public boolean isEmpty() {
return root == null;
}
@Override
public TreeNode<E> getRoot() {
return root;
}
@Override
public TreeNode<E> getParent(TreeNode<E> node) {
/**
* 采用后序遍历来寻找其父节点
* 后序遍历:
* 从根结点开始,向左搜索,每搜索到一个结点就将其压入栈中,直到压入栈中的结点不再有左子树。读取栈顶元素,如果结点有右子树不为空且未被访问则入栈当前结点访问其右子树,否则访问当前元素弹栈访问
* */
Stack<TreeNode<E>> nodeStack = new Stack<TreeNode<E>>();
TreeNode<E> pointer = root;
Set<TreeNode<E>> visitedSet = new HashSet<TreeNode<E>>();
while(pointer != null){
while(pointer.getLeftChild()!=null){
nodeStack.push(pointer);
pointer = pointer.getLeftChild();
}
while( pointer != null&&
(pointer.getRightChild()==null||visitedSet.contains(pointer.getRightChild()))){
if(node.equals(pointer))
return nodeStack.pop();
visitedSet.add(pointer);
if(nodeStack.isEmpty())
return null;
pointer = nodeStack.pop();
}
nodeStack.push(pointer);
pointer = pointer.getRightChild();
}
return null;
}
@Override
public TreeNode<E> getLeftChild(TreeNode<E> node) {
return node.getLeftChild();
}
@Override
public TreeNode<E> getRightChild(TreeNode<E> node) {
return node.getRightChild();
}
@Override
public void breadFirstOrder() {
/**
* 广度优先遍历:
* 用队列来实现,对于根节点,进行访问,然后出队列将左孩子放入队列如果不为空,右孩子放入队列如果不为空,
* 然后继续分别访问左孩子,将左孩子的左孩子右孩子放入队列,同理右孩子,以此类推,直到队列为空
* */
String str = "";
Queue<TreeNode<E>> nodeList =new LinkedList<TreeNode<E>>();//LinkedLits实现了Queue而ArrayList没有实现 因此前者可以当队列用 后者不可以
nodeList.add(root);
while(!nodeList.isEmpty()){
TreeNode<E> node = nodeList.poll();
str+=node.getItem()+" ";
if(node.get
c810
LeftChild()!=null){
nodeList.add(node.getLeftChild());
}
if(node.getRightChild()!=null){
nodeList.add(node.getRightChild());
}
}
System.out.println(str);
}
@Override
public void preOrder() {
/**
* 先序遍历:
* 访问一个节点,然后遍历访问左子树,将右子树压入栈中,依次弹栈 直到栈空
* */
Stack<TreeNode<E>> nodeStack = new Stack<TreeNode<E>>();
TreeNode<E> pointer = root;
String str = "";
while(!nodeStack.isEmpty()||pointer!=null){
if(pointer!=null){
str += pointer.getItem()+" ";
TreeNode<E> l = pointer.getLeftChild();
TreeNode<E> r = pointer.getRightChild();
pointer = l;
if(r!=null){
nodeStack.push(r);
}
}
else{
pointer = nodeStack.pop();
}
}
System.out.println(str);
}
@Override
public void inOrder() {
/**
* 中序遍历:
* 从根节点开始,对左子树进行遍历,将遍历到的左子树压入栈中,遍历完后访问弹栈的结点,访问该节点的右子树,同理前面的方法继续遍历右子树的左子树 直到栈空
* */
Stack<TreeNode<E>> nodeStack = new Stack<TreeNode<E>>();
String str = "";
TreeNode<E> pointer = root;
while(!nodeStack.isEmpty()||pointer!=null){
if(pointer!=null){//将左子树一一放入栈
nodeStack.push(pointer);
pointer = pointer.getLeftChild();
}
else{//当前结点没有左子树了
pointer = nodeStack.pop();
str += pointer.getItem()+" ";
pointer = pointer.getRightChild();
}
}
System.out.println(str);
}
@Override
public void postOrder() {
/**
* 后序遍历:
* 从根结点开始,向左搜索,每搜索到一个结点就将其压入栈中,直到压入栈中的结点不再有左子树。读取栈顶元素,如果结点右右子树不为空且未被访问则当前结点入栈,访问其右子树,否则访问当前元素 弹栈
* */
Stack<TreeNode<E>> nodeStack = new Stack<TreeNode<E>>();
TreeNode<E> pointer = root;
Set<TreeNode<E>> visitedSet = new HashSet<TreeNode<E>>();//存放被访问过的元素
String str = "";
while(pointer!=null){
for(;pointer.getLeftChild()!=null;pointer = pointer.getLeftChild()){//最后一个有左子树的结点的左子树没有被压入栈
nodeStack.push(pointer);//将所有左子树结点压入栈中
}
while(pointer!=null && (pointer.getRightChild()==null||visitedSet.contains(pointer.getRightChild()))){//右子树被访问过了或者右子树为空
str += pointer.getItem()+" ";
visitedSet.add(pointer);//把pointer置为被访问了
if(nodeStack.isEmpty())
{
System.out.println(str);
return;
}
pointer = nodeStack.pop();
}
nodeStack.push(pointer);
pointer = pointer.getRightChild();
}
}
@Override
public void clear() {
root = null;//直接root=null就可以 因为剩下的结点会因为不可达而被GC回收
}
}
最后写测试类,来进行测试:
public class Test{
public static void main(String[] args) {
System.out.println("LinkedTree test:");
TreeNode<Integer> node7 = new TreeNode<Integer>(7);
TreeNode<Integer> node8 = new TreeNode<Integer>(8);
TreeNode<Integer> node3 = new TreeNode<Integer>(3,node7,node8);
TreeNode<Integer> node4 = new TreeNode<Integer>(4);
TreeNode<Integer> node5 = new TreeNode<Integer>(5);
TreeNode<Integer> node6 = new TreeNode<Integer>(6);
TreeNode<Integer> node2 = new TreeNode<Integer>(2,node5,node6);
TreeNode<Integer> node1 = new TreeNode<Integer>(1,node3,node4);
TreeNode<Integer> root = new TreeNode<Integer>(0, node1, node2);
LinkedTree<Integer> lt = new LinkedTree<Integer>(root);
lt.breadFirstOrder();//0 1 2 3 4 5 6 7 8
lt.preOrder();//0 1 3 7 8 4 2 5 6
lt.inOrder();//7 3 8 1 4 0 5 2 6
lt.postOrder();//7 8 3 4 1 5 6 2 0
System.out.println(lt.getParent(node7).getItem());//3
lt.clear();
System.out.println(lt.getRoot());//null
}
}简单的链式存储二叉树便实现了。
首先创建一个结点类TreeNode<E>:
package com.linkedTree;
public class TreeNode<E> {
private E item;
private TreeNode<E> leftChild;
private TreeNode<E> rightChild;
public TreeNode(E item){
this(item,null,null);
}
public TreeNode(E item, TreeNode<E> l , TreeNode<E> r){
this.item = item;
this.leftChild = l;
this.rightChild = r;
}
public TreeNode<E> getRightChild() {
return rightChild;
}
public void setRightSibling(TreeNode<E> rightChild) {
this.rightChild = rightChild;
}
public TreeNode<E> getLeftChild() {
return leftChild;
}
public void setLeftSibling(TreeNode<E> leftChild) {
this.leftChild = leftChild;
}
public E getItem() {
return item;
}
public void setItem(E item) {
this.item = item;
}
@Override
public int hashCode() {//重写hashCode和equals方法
final int prime = 31;
int result = 1;
result = prime * result + ((item == null) ? 0 : item.hashCode());
result = prime * result + ((leftChild == null) ? 0 : leftChild.hashCode());
result = prime * result + ((rightChild == null) ? 0 : rightChild.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TreeNode<?> other = (TreeNode<?>) obj;
if (item == null) {
if (other.item != null)
return false;
} else if (!item.equals(other.item))
return false;
if (leftChild == null) {
if (other.leftChild != null)
return false;
} else if (!leftChild.equals(other.leftChild))
return false;
if (rightChild == null) {
if (other.rightChild != null)
return false;
} else if (!rightChild.equals(other.rightChild))
return false;
return true;
}
}
然后创建一个接口LTree<E>,规范链式存储二叉树的方法:
package com.linkedTree;
import com.linkedTree.TreeNode;
public interface Ltree<E> {
boolean isEmpty();
TreeNode<E> getRoot();
TreeNode<E> getParent(TreeNode<E> node);
TreeNode<E> getLeftChild(TreeNode<E> node);
TreeNode<E> getRightChild(TreeNode<E> node);
void breadFirstOrder();//广度优先
void preOrder();//先序遍历
void inOrder();//中序遍历
void postOrder();//后序遍历
void clear();//删除整个树
}
接着创建一个类LinkedTree<E>来实现LTree<E>接口:
package com.linkedTree;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
import java.util.Stack;
public class LinkedTree<E> implements Ltree<E> {
private TreeNode<E> root;
public LinkedTree(TreeNode<E> root){
this.root = root;
}
@Override
public boolean isEmpty() {
return root == null;
}
@Override
public TreeNode<E> getRoot() {
return root;
}
@Override
public TreeNode<E> getParent(TreeNode<E> node) {
/**
* 采用后序遍历来寻找其父节点
* 后序遍历:
* 从根结点开始,向左搜索,每搜索到一个结点就将其压入栈中,直到压入栈中的结点不再有左子树。读取栈顶元素,如果结点有右子树不为空且未被访问则入栈当前结点访问其右子树,否则访问当前元素弹栈访问
* */
Stack<TreeNode<E>> nodeStack = new Stack<TreeNode<E>>();
TreeNode<E> pointer = root;
Set<TreeNode<E>> visitedSet = new HashSet<TreeNode<E>>();
while(pointer != null){
while(pointer.getLeftChild()!=null){
nodeStack.push(pointer);
pointer = pointer.getLeftChild();
}
while( pointer != null&&
(pointer.getRightChild()==null||visitedSet.contains(pointer.getRightChild()))){
if(node.equals(pointer))
return nodeStack.pop();
visitedSet.add(pointer);
if(nodeStack.isEmpty())
return null;
pointer = nodeStack.pop();
}
nodeStack.push(pointer);
pointer = pointer.getRightChild();
}
return null;
}
@Override
public TreeNode<E> getLeftChild(TreeNode<E> node) {
return node.getLeftChild();
}
@Override
public TreeNode<E> getRightChild(TreeNode<E> node) {
return node.getRightChild();
}
@Override
public void breadFirstOrder() {
/**
* 广度优先遍历:
* 用队列来实现,对于根节点,进行访问,然后出队列将左孩子放入队列如果不为空,右孩子放入队列如果不为空,
* 然后继续分别访问左孩子,将左孩子的左孩子右孩子放入队列,同理右孩子,以此类推,直到队列为空
* */
String str = "";
Queue<TreeNode<E>> nodeList =new LinkedList<TreeNode<E>>();//LinkedLits实现了Queue而ArrayList没有实现 因此前者可以当队列用 后者不可以
nodeList.add(root);
while(!nodeList.isEmpty()){
TreeNode<E> node = nodeList.poll();
str+=node.getItem()+" ";
if(node.get
c810
LeftChild()!=null){
nodeList.add(node.getLeftChild());
}
if(node.getRightChild()!=null){
nodeList.add(node.getRightChild());
}
}
System.out.println(str);
}
@Override
public void preOrder() {
/**
* 先序遍历:
* 访问一个节点,然后遍历访问左子树,将右子树压入栈中,依次弹栈 直到栈空
* */
Stack<TreeNode<E>> nodeStack = new Stack<TreeNode<E>>();
TreeNode<E> pointer = root;
String str = "";
while(!nodeStack.isEmpty()||pointer!=null){
if(pointer!=null){
str += pointer.getItem()+" ";
TreeNode<E> l = pointer.getLeftChild();
TreeNode<E> r = pointer.getRightChild();
pointer = l;
if(r!=null){
nodeStack.push(r);
}
}
else{
pointer = nodeStack.pop();
}
}
System.out.println(str);
}
@Override
public void inOrder() {
/**
* 中序遍历:
* 从根节点开始,对左子树进行遍历,将遍历到的左子树压入栈中,遍历完后访问弹栈的结点,访问该节点的右子树,同理前面的方法继续遍历右子树的左子树 直到栈空
* */
Stack<TreeNode<E>> nodeStack = new Stack<TreeNode<E>>();
String str = "";
TreeNode<E> pointer = root;
while(!nodeStack.isEmpty()||pointer!=null){
if(pointer!=null){//将左子树一一放入栈
nodeStack.push(pointer);
pointer = pointer.getLeftChild();
}
else{//当前结点没有左子树了
pointer = nodeStack.pop();
str += pointer.getItem()+" ";
pointer = pointer.getRightChild();
}
}
System.out.println(str);
}
@Override
public void postOrder() {
/**
* 后序遍历:
* 从根结点开始,向左搜索,每搜索到一个结点就将其压入栈中,直到压入栈中的结点不再有左子树。读取栈顶元素,如果结点右右子树不为空且未被访问则当前结点入栈,访问其右子树,否则访问当前元素 弹栈
* */
Stack<TreeNode<E>> nodeStack = new Stack<TreeNode<E>>();
TreeNode<E> pointer = root;
Set<TreeNode<E>> visitedSet = new HashSet<TreeNode<E>>();//存放被访问过的元素
String str = "";
while(pointer!=null){
for(;pointer.getLeftChild()!=null;pointer = pointer.getLeftChild()){//最后一个有左子树的结点的左子树没有被压入栈
nodeStack.push(pointer);//将所有左子树结点压入栈中
}
while(pointer!=null && (pointer.getRightChild()==null||visitedSet.contains(pointer.getRightChild()))){//右子树被访问过了或者右子树为空
str += pointer.getItem()+" ";
visitedSet.add(pointer);//把pointer置为被访问了
if(nodeStack.isEmpty())
{
System.out.println(str);
return;
}
pointer = nodeStack.pop();
}
nodeStack.push(pointer);
pointer = pointer.getRightChild();
}
}
@Override
public void clear() {
root = null;//直接root=null就可以 因为剩下的结点会因为不可达而被GC回收
}
}
最后写测试类,来进行测试:
public class Test{
public static void main(String[] args) {
System.out.println("LinkedTree test:");
TreeNode<Integer> node7 = new TreeNode<Integer>(7);
TreeNode<Integer> node8 = new TreeNode<Integer>(8);
TreeNode<Integer> node3 = new TreeNode<Integer>(3,node7,node8);
TreeNode<Integer> node4 = new TreeNode<Integer>(4);
TreeNode<Integer> node5 = new TreeNode<Integer>(5);
TreeNode<Integer> node6 = new TreeNode<Integer>(6);
TreeNode<Integer> node2 = new TreeNode<Integer>(2,node5,node6);
TreeNode<Integer> node1 = new TreeNode<Integer>(1,node3,node4);
TreeNode<Integer> root = new TreeNode<Integer>(0, node1, node2);
LinkedTree<Integer> lt = new LinkedTree<Integer>(root);
lt.breadFirstOrder();//0 1 2 3 4 5 6 7 8
lt.preOrder();//0 1 3 7 8 4 2 5 6
lt.inOrder();//7 3 8 1 4 0 5 2 6
lt.postOrder();//7 8 3 4 1 5 6 2 0
System.out.println(lt.getParent(node7).getItem());//3
lt.clear();
System.out.println(lt.getRoot());//null
}
}简单的链式存储二叉树便实现了。
相关文章推荐
- 使用java实现顺序存储的二叉树
- java实现二叉树的链式存储
- 二叉树-链式存储-Java实现(未完待续)
- Java实现链式存储的二叉树
- 二叉树的链式存储结构 C++代码实现
- 使用Java实现在SQLserver中实现图片的存储
- 使用Java实现在SQLserver中实现图片的存储
- 使用Java实现在SQLserver中实现图片的存储
- 二叉树链式存储的实现
- 数据结构:二叉树的二叉链表存储--Java实现
- 队列- 链式存储-Java实现
- 数据结构:二叉树的三叉链表存储--Java实现
- Thinking in Java 泛型章节中不用LinkedList来实现自己的内部链式存储机制
- 栈的Java实现(顺序存储实现与链式存储实现)
- 数据结构:线性表的链式存储(单向链表)--Java实现
- 二叉树基本操作实现(二叉树的链式存储)
- java实现树(链式存储)
- 使用Java实现在SQLserver中实现图片的存储
- 使用Java实现在SQLserver中实现图片的存储
- 线性表的链式存储结构之单链表类的实现_Java