/*====知识总结=*/
//1线索二叉树就是比一般的二叉树多了个线索,即指向结点前驱和后继的指针
//2线索二叉树基本结构分为LTag,lchild,data,RTag,rchild.即左标志,左指针,结点数据,右指针,右标志。
//3标志位的取值决定指针的指向(为线索,指向结点前驱或后继;或位正常指针,指向左右孩子结点),这个程 序的设定就是LTag1,指向左子树(右同)。LTag0,指向结点的前驱或后继。
package 线索二叉树;
//线索二叉树的声明。
class ThreadNode{
int value; //结点都值。
int left_Thread; //结点的左标志。
int right_Thread; //右标志
ThreadNode left_Node; //左结点
ThreadNode right_Node; //右结点
//树结点的构造方法。
public ThreadNode(int value){
this.value=value;
this.left_Thread = 0;
this.right_Thread = 0;
this.left_Node = null;
this.right_Node = null;
}
}
//线索二叉树的类声明。
class Threaded_Binary_Tree{
public ThreadNode rootNode; //线索二叉树的根节点;
//无传入参数的构造函数。
public Threaded_Binary_Tree(){
rootNode = null;
}
//构造函数,用来建立线索二叉树,传入参数为一个数组。
public Threaded_Binary_Tree(int data[]){
for(int i = 0;i<data.length;i++){
Add_Node_To_Tree(data[i]);
}
}
//将指定的值加入线索二叉树适当的结点。
void Add_Node_To_Tree(int value){
ThreadNode newnode = new ThreadNode(value); //创建一个新结点,用于添加到二叉树。
ThreadNode current; //声明当前结点。
ThreadNode parent; //声明一个父亲结点。
ThreadNode previous = new ThreadNode(value); //创建一个结点,用来指示上个结点。
int pos;
//设定线索二叉树的开头结点。
if(rootNode==null){
rootNode = newnode; //将newnode的引用赋给rootNode;
//rootNode.left_Node = rootNode;
//rootNode.right_Node = null;
//rootNode.left_Thread = 0;
rootNode.right_Thread = 1;
//rootNode = new ThreadNode(value);
return; //结束该方法,不执行这条语句后面的语句。。
}
//设定开头结点所指的结点。
current = rootNode.right_Node; //将根结点的左子结点的引用赋给current
if(current==null){
rootNode.right_Node = newnode;
//newnode.left_Node = rootNode;
//newnode.right_Node = rootNode;
return;
}
//依照一下规则,建立线索二叉树。
parent = rootNode; //父结点指向根结点。即每次从根结点开始建立线索二叉树。
pos = 0;
while(current!=null){ //current不是空值开始循环。
if(current.value>value){ //current结点的值大于当前的值,建立左子树。执行大括号里面的语句。
if(pos!=-1){
pos=-1;
previous = parent; //令previous指向parent
}
parent=current; //令parent指向current
if(current.left_Thread==1) //current的左标志为1;即left_Node为正常指针,即current结点有左子结点。
current = current.left_Node; //将current。left_Node的引用赋给current,即将current的左子结点设置为当前结点。
else //当前结点没有左子结点,即当前结点为叶子结点。
current = null; //令current为0;结束本次循环,执行循环体下面的语句。
}
else{ //current结点的值小于当前的值,右左子树。执行大括号里面的语句。
if(pos!=1){
pos=1;
previous = parent; //令previous指向parent
}
parent = current; //令parent指向current
if(current.right_Thread==1) //current的左标志为1;即left_Node为正常指针,即current结点有左子结点。
current = current.right_Node; //将current。left_Node的引用赋给current,即将current的左子结点设置为当前结点。
else
current = null; //令current为0;结束本次循环。
}
}
//将结点加入二叉树。
if(parent.value>value){ //实际上是current结点,两个是结点是一致的。parent=current;
//parent结点的值大于当前的值,建立左子树。
parent.left_Thread=1; //令left_Thread为1,即其存在左子结点
parent.left_Node=newnode; //将新结点加入二叉树中。
newnode.left_Node=previous; //左指针指向指向前驱结点。
newnode.right_Node=parent; //指向后继结点。
}
else{ //parent结点的值大于当前的值,建立右子树
parent.right_Thread=1;
parent.right_Node = newnode;
newnode.left_Node = parent;
newnode.right_Node = previous;
}
return; //结束该方法,执行其他语句。
}
//线索二叉树中序遍历。
void print(){
ThreadNode tempNode; //声明一个临时结点tempNode;
tempNode = rootNode; //将rootNode的引用赋给tempNode
//循环判断,中序遍历。
do{
if(tempNode.right_Thread==0){ //没有右子结点。即当前结点为叶子结点,
tempNode=tempNode.right_Node; //指向后继结点。
}
else{ //有右子结点。
tempNode = tempNode.right_Node; //将tempNode。right_Node的引用赋给tempNode,即将tempNode的右子结点设置为当前结点,即线索树真正的结点。
while(tempNode.left_Thread!=0){ //有左子结点。
tempNode = tempNode.left_Node; //将tempNode。right_Node的引用赋给tempNode,即将tempNode的左子结点设置为当前结点。
}
}
if(tempNode!=rootNode) //如果临时结点不等于开头节点。输出临时结点的值
System.out.println("["+tempNode.value+"]");
}while(tempNode!=rootNode); //条件成立循环,(最后一个结点的后继会指向rootNode结点。)
}
}
public class demoThreadTree {
public static void main(String[] args) {
System.out.println("线索二叉树经建立后,以中序追踪能有排序的效果");
System.out.println("除了第一个数字作为线索二叉树的开头节点外");
int [] data1 = {0,10,20,30,100,399,453,43,237,373,655};
Threaded_Binary_Tree tree1 = new Threaded_Binary_Tree(data1);
System.out.println("=====================================");
System.out.println("范例1");
System.out.println("数字由小到大的排列顺序结果为: ");
tree1.print();
int[]data2 = {0,101,118,87,12,765,65};
Threaded_Binary_Tree tree2 = new Threaded_Binary_Tree(data2);
System.out.println("=====================================");
System.out.println("范例2");
System.out.println("数字由小到大的排列顺序结果为: ");
tree2.print();
}
}
/程序总结=/
1.这个程序比较复杂,废了很大的功夫,才读懂整个程序,有很多地方设置的比较复杂,很冗余,完全可以删除一些语句,简化程序。
2.例如那个建立线索二叉树,用了一个循环既然只是为了遍历叶子结点,后面还用了一个循环来添加新结点,这个完全可以合并的。自己能力有限只能看看了。
3.自己通过这个程序,学会了如何debug。下次遇到复杂的程序,自己先仔细读懂,慢一点没关系不着急,如果读不懂,不知道程序如何运行的,就运用debug。
4.这个程序超出自己的知识高度,理解思想和读懂程序就好。
5.eclipse debug视频连接: https://www.bilibili.com/video/av31632777?from=search&seid=2095717832218173241