参考王道和严蔚敏数据结构与算法
- 王道和严蔚敏老师的书都是C友好,对于java有些地方是有坑的,特别是在递归的地方,java由于没有指针和引用和c有些坑需要填。
- 所有代码思路均参考这两本书,对于代码的解释亦在两本书中。
1. 定义
直接上代码,至于性质与概念请参考书籍或者百度定义等等。
1.1树的定义
public class ThreadTree {
char data;
ThreadTree lChild, rChild;
int lTag, rTag;
ThreadTree(){}
ThreadTree(char data){
this.data = data;
}
}
1.2 递归算法
这边有个坑要填就是pre 需要设置成全局的,否则会失败
static ThreadTree pre = new ThreadTree(); //辅助节点,java如果直接用严老师的会有点坑
/**
* 核心算法
*
* @param p 传入一个根节点
*/
public static void inThread(ThreadTree p){
if (p != null){
inThread(p.lChild);// 先递归左子树
if (p.lChild == null){
p.lChild = pre; // 把左子树空指针指向前驱
p.lTag = 1;
}
if (pre != null && pre.rChild == null){ //前驱没有左子树, 则将前驱的值为线索
pre.rChild = p;
pre.rTag = 1;
}
pre = p; // 指定前驱的值
inThread(p.rChild); // 递归右子树
}
}
1.3 构建代码
/**
* 把二叉树线索化
* @param root
*/
public static void createInThread(ThreadTree root){
if (root != null){
inThread(root);
pre.rChild = null; // 最后一个节点
pre.rTag = 1;
}
}
1.4查找算法
/**
* 找到最左下的节点
* 或者说是找到中序遍历最前面的节点
* @param root
* @return
*/
public static ThreadTree firstNode(ThreadTree root){
ThreadTree temp = root;
while (temp.lTag == 0){
temp = temp.lChild; //找到最左下的节点
}
return temp;
}
/**
* 返回一个节点的后序节点
* @param cur
* @return
*/
public static ThreadTree nextNode(ThreadTree cur){
if (cur.rTag == 0) return firstNode(cur.rChild);//说明给的节点不太对.
else return cur.rChild; //直接返回后继节点
}
public static void inOrder(ThreadTree root){
System.out.println("-----------------中序遍历开始了--------------------");
for (ThreadTree cur = firstNode(root); cur != null; cur = nextNode(cur)){
visit(cur);
}
System.out.println();
System.out.println("-----------------中序遍历结束了--------------------");
}
2.完整代码
使用的构建数据:
程序结构:
采用的是按层建立的方式,建立二叉树
主程序
package tree.thread;
import input.MyScanner;
import java.io.FileNotFoundException;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
/**
* @author jiayuan
* @date 2020/8/7 20:57
*/
public class ThreadTree {
char data;
ThreadTree lChild, rChild;
int lTag, rTag;
ThreadTree(){}
ThreadTree(char data){
this.data = data;
}
static ThreadTree pre = new ThreadTree(); //辅助节点,java如果直接用严老师的会有点坑
/**
* 核心算法
*
* @param p 传入一个根节点
*/
public static void inThread(ThreadTree p){
if (p != null){
inThread(p.lChild);// 先递归左子树
if (p.lChild == null){
p.lChild = pre; // 把左子树空指针指向前驱
p.lTag = 1;
}
if (pre != null && pre.rChild == null){ //前驱没有左子树, 则将前驱的值为线索
pre.rChild = p;
pre.rTag = 1;
}
pre = p; // 指定前驱的值
inThread(p.rChild); // 递归右子树
}
}
/**
* 把二叉树线索化
* @param root
*/
public static void createInThread(ThreadTree root){
if (root != null){
inThread(root);
pre.rChild = null; // 最后一个节点
pre.rTag = 1;
}
}
/**
* 用于构造二叉树的
* 通过层次遍历构造
* @return
* @throws FileNotFoundException
*/
public static ThreadTree buildTree() throws FileNotFoundException {
Scanner sc = MyScanner.getMySc("C:\\Users\\jiayuan\\Desktop\\DataStruct\\src\\tree\\data\\threadTree");// 改成自己的文件路径即可
int n = Integer.valueOf(sc.nextLine());
char[] chars = sc.nextLine().toCharArray();
ThreadTree root = new ThreadTree(chars[0]);
int k = 1;
Queue<ThreadTree> queue = new LinkedList<>();
queue.add(root);
while (k < n && queue.size()!=0){
int len = queue.size();
for (int i = 0; i < len; i++) {
ThreadTree temp = queue.poll();
char left = chars[k++];
if (left != '#'){
temp.lChild = new ThreadTree(left);
queue.add(temp.lChild);
}
if (k >= n-1){
break;
}
char right = chars[k++];
if (right != '#'){
temp.rChild = new ThreadTree(right);
queue.add(temp.rChild);
}
}
}
return root;
}
/**
* 按层打印二叉树
* @param root
*/
public static void printTree(ThreadTree root){
Queue<ThreadTree> queue = new LinkedList<>();
queue.add(root);
int cen = 0;
while (!queue.isEmpty()){
int len = queue.size();
System.out.println("现在是第"+(++cen)+"层");
for (int i = 0; i < len; i++) {
ThreadTree poll = queue.poll();
char temp = poll.data;
System.out.printf(temp + " ");
if (poll.lChild != null){
queue.add(poll.lChild);
}
if (poll.rChild!=null){
queue.add(poll.rChild);
}
}
System.out.println();
}
}
/**
* 找到最左下的节点
* 或者说是找到中序遍历最前面的节点
* @param root
* @return
*/
public static ThreadTree firstNode(ThreadTree root){
ThreadTree temp = root;
while (temp.lTag == 0){
temp = temp.lChild; //找到最左下的节点
}
return temp;
}
/**
* 返回一个节点的后序节点
* @param cur
* @return
*/
public static ThreadTree nextNode(ThreadTree cur){
if (cur.rTag == 0) return firstNode(cur.rChild);//说明给的节点不太对.
else return cur.rChild; //直接返回后继节点
}
public static void inOrder(ThreadTree root){
System.out.println("-----------------中序遍历开始了--------------------");
for (ThreadTree cur = firstNode(root); cur != null; cur = nextNode(cur)){
visit(cur);
}
System.out.println();
System.out.println("-----------------中序遍历结束了--------------------");
}
/**
* 遍历算法
* @param node
*/
public static void visit(ThreadTree node){
System.out.print(node.data+" ");
}
}
测试代码:
package input;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Scanner;
/**
* @author jiayuan
* @date 2020/7/25 20:26
*/
public class MyScanner {
public static Scanner getMySc(String path) throws FileNotFoundException {
System.setIn(new FileInputStream(new File(path)));
Scanner sc = new Scanner(System.in);
return sc;
}
}
package tree.thread;
import java.io.FileNotFoundException;
/**
* @author jiayuan
* @date 2020/8/7 21:12
*/
public class TestThreadTree {
public static void main(String[] args) throws FileNotFoundException {
ThreadTree threadTree = new ThreadTree();
threadTree = ThreadTree.buildTree();
ThreadTree.printTree(threadTree);
System.out.println();
ThreadTree.createInThread(threadTree);//先线索化
ThreadTree.inOrder(threadTree);
}
}