#include <iostream> #include <windows.h>
using namespace std; #pragma warning(disable:4996)
//可不能夠利用c++的泛化編程的思想去改邊它
typedef int Tree_type; //樹中的存儲結構的類型(先去掉---用泛化的思想) //注意枚舉和結構體同樣的命名和定以方式
typedef enum PoitnterTag { link, Thread } PointerTag; //注意----當二叉樹遇到中序遍歷時就自動排好序了 //template<class Tree_type>
typedef struct Tree { Tree_type data; //要存儲的結構
Tree *Left; //左孩子
Tree *Right; //右孩子
PointerTag LTag; //左標誌位
PointerTag RTag; //右標誌位
} Tree, *PTree; //template <class Tree_type> //標誌位的定義應該在樹造成以後去定義---根據是否有左右結點指針去爲其賦值
PTree pre = NULL; //在此定義一個全局變量去保留上一個的結點
bool Threading(PTree &T) { if (T) //仍是利用中序遍歷去查看是否須要用到標誌位
{ Threading(T->Left); if (!T->Left) //是否T沒有左孩子
{ T->Left = pre; //若是它沒有左孩子則讓它的左指針指向它的上一個結點
T->LTag = Thread; //並把它的左標誌位賦值爲1
} if (!pre->Right) { pre->Right = T; //若是上一個結點沒有右孩子則讓它的右指針指向它的下一個結點即T
pre->RTag = Thread; //而且把它的右標誌位賦值爲1
} pre = T; //改變上一個結點的值
Threading(T->Right); } //寫到這裏可能會有個疑問--pre一開始還只是個空將T->Left指向空--不是錯了嗎? //所以在這以前咱們還須要對pre進行賦值。。。。。。。。。。。。。。 //而在這裏應該把這個pre定義爲誰呢?仔細一想就會發現這個pre必須指向一個其餘的不屬於原來這個樹的結點不然就會對其餘的結點的線索化形成影響
return true; } //所以在這裏必須從新定義一個結點
bool Init_pre(PTree &P, PTree &T) { if (T) //T必須存在才行
{ P = new Tree; P->Left = T; //讓它指向頭結點
P->LTag = link; //link表示這個指針有指向
P->RTag = link; //有指向的標誌位
P->Right = NULL; //而且將它的值賦值位空 //在這裏pre的初始化就完成了--是否是很簡單 //以後就能夠直接調用Threading了
pre = P; Threading(T); //在這裏有一點要注意當pre的值不斷的改變而且到達最後一個結點時要手動對它進行線索化
pre->Right = P; pre->RTag = Thread; P->Right = pre; //構成一個相互的指向
} return true; } template<class Tree_type>
bool Insert_Tree(PTree &T, Tree_type &elem) { if (T == NULL) //若是樹爲空就要從新構造
{ PTree temp = new Tree; temp->data = elem; temp->LTag = link; //在這裏先假設他們都有結點鏈接--若是沒有到時候在改變它的值
temp->RTag = link; //初始化=====
temp->Left = NULL; temp->Right = NULL; T = temp; } else if (elem < T->data) { Insert_Tree(T->Left, elem); //若是elem要小於某個節點的值則讓它插入到該節點的左邊
} else if (elem > T->data) { Insert_Tree(T->Right, elem); //若是elem要大於某個節點的值則讓它插入到該節點的右邊
} //如此的重複的進行知道T爲空
return true; } //樹的遍歷---遞歸的形式 /* bool Traverse_Tree(PTree& T) { if(T)//若是T不指向空則則繼續遞歸 { Traverse_Tree(T->Left); cout << T->data << " "; Traverse_Tree(T->Right);//在這裏有個巧妙的地方--當從這個點向右遍歷時右爲空所以又會回到上一個結點 } return true; } */
//樹的遍歷---非遞歸實現中序遍歷
bool Traverse_Tree(PTree &T) { PTree temp = T->Left; //T爲Root
while(temp!=T){ while (temp->LTag == link) //與當初的一直往下走同樣,一直走到它的最左邊,不一樣的時此時的咱們已經能夠回到上一個結點了
{ temp = temp->Left; } cout << temp->data << " "; //循環出來後temp就是最左邊的一個結點了--此時應該往上走了 //temp->RTag的意思是隻有當其不能在繼續往下走時要利用它的標誌位的特色
while (temp->RTag == Thread && temp->Right != T)//可能在這一部有所疑問--temp->Right!=T的意思是當結點爲最後的一個結點時咱們不能再繼續往下執行了
{ temp = temp->Right; cout << temp->data << " "; } //當循環不知足條件的時候會跳出循環,爲了讓程序繼續走完---應該手動的使它跳到下一個結點上去
temp = temp->Right; //此時T在最左邊的結點上//發現好像剩下的左右結點指針都沒什麼用且到達最右端時無發再回到上一個結點了 //那麼可不能夠用那兩個沒用的結點指針使他們指向上一個結點--變廢爲寶呢?--線索二叉樹的來源
} cout << endl; return true; } int main() { PTree space = NULL; PTree Root = NULL; Tree_type data; do { cout << "請輸入要進入樹的數據:"; cin >> data; if (data == 0) break; Insert_Tree(space, data); } while (1); Init_pre(Root, space); Traverse_Tree(Root); system("pause"); return 0; } java下面展現的是java版本的可供java學習者參考
思想是同樣的所以不寫註釋了 package com.acm; import java.util.Scanner; class Solution { private class node { private int val; private node left; private node right; private int Ltag; private int Rtag; public node(int val) { this.val=val; Ltag=Rtag=0; } public boolean addNode(int data) { if(data>this.val) { if(this.right==null) this.right=new node(data); else { this.right.addNode(data); } } else if(data<this.val) { if(this.left==null) this.left=new node(data); else { this.left.addNode(data); } } return true; } public boolean showNode() { if(this.left!=null) this.left.showNode(); System.out.print(this.val); if(this.right!=null) this.right.showNode(); return true; } public boolean ThreadTravel() { if(this.left!=null) this.left.ThreadTravel(); if(this.left==null) { this.left=pre; this.Ltag=1; } if(pre.right==null) { pre.right=this; pre.Rtag=1; } pre=this; if(this.right!=null) this.right.ThreadTravel(); return true; } } private node root; private node pre; private node head; public boolean add(int data) { if(root==null) { root=new node(data); root.left=null; root.right=null; } else { root.addNode(data); } return true; } public boolean show() { if(root!=null) { root.showNode(); } return true; } public boolean showThreading() { if(root!=null) root.ThreadTravel(); return true; } public boolean Threading() { if(root!=null) { head=new node(0); head.left=root; pre=head; root.ThreadTravel(); pre.right=head; head.right=pre; pre.Rtag=1; } return true; } public boolean TravelNode() { if(root==null)return true; node temp=root; while(temp!=head) { while(temp.Ltag==0)temp=temp.left; System.out.print(temp.val); while(temp.Rtag==1&&temp.right!=head) { temp=temp.right; System.out.print(temp.val); } temp=temp.right; } return true; } } public class Main { public static void main(String[] args) { Solution space=new Solution(); int val=0; Scanner iner=new Scanner(System.in); do { System.out.println("請輸入要進入樹的節點:"); val=iner.nextInt(); }while(val!=666&&space.add(val)); System.out.println("輸入結束!"); space.Threading(); //space.show(); //此時會進入死循環
space.TravelNode(); iner.close(); } }