数据结构基础加强之二叉树
二叉树的按层遍历
对于二叉树遍历的方式有中序遍历、先序遍历、后序遍历等。但有时需要打印行信息时需要使用按层遍历。
对于
按层按层遍历需要打印出结果:
1
2 3
4 5 6 7
建立二叉树节点类:
public class TreeNode {
private int val;
public TreeNode left = null;
public TreeNode right = null;
public int getVal() {
return val;
}
public void setVal(int val) {
this.val = val;
}
public TreeNode(int val){
this.val = val;
}
}
对于按层遍历二叉树只需要使用一个队列queue以及2个变量:last指向当前层的最右节点、nlast指向下一层的最右节点。
依次将节点加入队列,每次弹出一个节点打印,并将弹出节点的左右子节点加入队列,并让nlast依次指向当前加入队列的节点。当弹出队列的节点和last指向的节点相同时换行,并让last指向nlast。
代码如下:
import java.util.LinkedList;
import java.util.Queue;
public class PrintTreeByLine {
public static void main(String[] args){
//构造二叉树
TreeNode root = new TreeNode(1);
TreeNode left = root.left = new TreeNode(2);
TreeNode right = root.right = new TreeNode(3);
left.left = new TreeNode(4);
left.right = new TreeNode(5);
right.left = new TreeNode(6);
right.right = new TreeNode(7);
print(root);
}
//使用队列进项二叉树的按层遍历
public static void print(TreeNode root){
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.add(root);
TreeNode last = root; //当前行的最右节点
TreeNode nlast = null; //下一行的最右节点
while (!queue.isEmpty()) {
TreeNode pollNode = queue.poll();
System.out.print(pollNode.getVal() + " ");
// root = pollNode;
if (pollNode.left != null) {
queue.add(pollNode.left);
nlast = pollNode.left;
}
if (pollNode.right != null) {
queue.add(pollNode.right);
nlast = pollNode.right;
}
if (last == pollNode) {
last = nlast;
System.out.println();
}
}
}
}
二叉树的序列化与反序列化
对于程序建立的二叉树都是保存在内存中,当机器关闭时将不再存在。因此需要将树永久保存的时候,需要存储于文件中,即树的序列化。使用树时,需要读取文件还原树,即树的反序列化。
序列化:将树以文件的方式存储。
反序列化:读取文件还原二叉树。
二叉树的序列化
对于二叉树的序列化采取先序遍历的方式。用!来分割节点,防止序列化的时候出现歧义。当节点存在是在文件中写入节点值val!,当节点不存在是写入#!。因为是先序遍历。所以可以使用递归的方式执行。
代码如下:
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
public class TreeToFile {
public static void main(String[] args) throws Exception {
//构造二叉树
TreeNode root = new TreeNode(1);
TreeNode left = root.left = new TreeNode(2);
TreeNode right = root.right = new TreeNode(3);
left.left = new TreeNode(4);
left.right = new TreeNode(5);
right.left = new TreeNode(6);
right.right = new TreeNode(7);
File file = new File("src/tree.txt");
BufferedWriter bw = new BufferedWriter(new FileWriter(file));
saveToFile(root,bw);
bw.close();
}
//二叉树按先序遍历存储到文件
private static void saveToFile(TreeNode root, BufferedWriter bw) throws Exception {
if (root == null) {
bw.write("#!");
}else{
bw.write(root.getVal()+"!");
saveToFile(root.left, bw);
saveToFile(root.right, bw);
}
}
}
二叉树的反序列化
将先序遍历序列化的树还原。因为节点是用!分割,读取文件等到String s,用!来分割s得到String数组,遍历数组将数组一次加入队列。采用先序遍历的方式存储,可以采用递归的方式执行,每一次都弹出队列第一个元素,判断是否为数字,是数字则将元素转为int设置为当前节点的值,用递归的方式依次得出node.left与node.right。
代码如下:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.LinkedList;
import java.util.Queue;
public class FileToTree {
public static void main(String[] args) throws Exception {
File file = new File("src/tree.txt");
BufferedReader br = new BufferedReader(new FileReader(file));
String s = null;
StringBuffer sb = new StringBuffer();
while ((s = br.readLine()) != null) {
sb.append(s);
}
br.close();
String[] tree = sb.toString().split("!");
Queue<String> queue = new LinkedList<String>();
for (String s1 : tree) {
queue.add(s1);
}
TreeNode root = buildTree(queue);
PrintTreeByLine.print(root);
}
// 二叉树的反序列化
private static TreeNode buildTree(Queue<String> queue) {
String s = queue.poll();
TreeNode root = null;
// 判断读取的字符是不是数字 是返回true 否则返回false
if (!s.equals("#")) {
root = new TreeNode(Integer.parseInt(s));
root.left = buildTree(queue);
root.right = buildTree(queue);
}
return root;
}
}
具体代码可以参考:https://github.com/Li-JY/algorithm-and-datastructure/tree/master/src/tree