树的基本概念
树的存储结构
双亲表示法
假设以一组连续空间存储树的结点,同时在每一个结点中,设置一个指示器指示器双亲结点在数组的位置
//结点
struct Node{
Element data;
int parent; //双亲位置
};
//树结构
struct Tree{
Node node[MAX_TREE_SIZE];
int r, n; //根的位置和结点
};
找双亲的效率高,但找孩子的效率低。
当然如果需要,我们可以继续扩展数据结构,给其增加一个长子域…..
数据结构的设计是非常灵活的,一个数据结构是否合理主要取决于时间和空间复杂度是否适合当前场景
孩子表示法
由于每个结点可能有多个子树,所以可以使用多重链表,即每一个结点有多个指针域,其中每个指针指向一颗子树的根结点。
方案一:
按照树中最大度来分配指针域的个数
例如:一个数最多有3个子树,其他的数都不够或者等于3个子树时,就设置指针域为3
如果每个树之间的子树数量差距过大,那么这个方法效率就很低。空间浪费很大。
方案二:
为了使得空间利用更加合理,我们专门设置一个空间来存储该节点孩子的个数。
方案三:
把一个树的子树用一个链表串起来。
//孩子结点
struct CTNode{
int child;
struct CTNode * next;
};
// 表头结构
struct CTBox{
Element data;
CTNode * firstChild;//链表头,即长子.
};
struct CTree{
CTBox nodes[MAX_TREE_SIZE];
int r , n;//根的位置和结点数。
};
这个方法想知道双亲的话需要遍历,效率低
孩子双亲表示法
按照上述方案三,为表头CTBox增加一个双亲位置的索引即可。
孩子兄弟表示法
任意一棵树,它的结点的第一个孩子如果存在就唯一的,它的右兄弟如果存在就是唯一的。所以,我们设置两个指针,分别指向该结点的第一个孩子和此结点的右兄弟。
struct CSNode {
Element data;
struct CSNode * firstChild, * rightsib;
};
其实这个表示法最大的好处就是能把一颗任意的树转变成一颗二叉树
二叉树
二叉树的定义
一个树的集和中任意一颗子树都最多只有两个子树(左子树和右子树),子树非左即右。和有最多有两个子树的树不同。二叉树规定了孩子是左还是右,而普通的树对孩子是没有顺序要求的(也就是说,二叉树只有一个左子树和只有一个右子树这是两个不同的二叉树,但是如果是普通的树那就是一样的树了。)
二叉树的性质
$$ 性质1:在二叉树的第i层至多有2^{ i-1 } 个结点(i\ge 1) $$
$$ 性质2:深度为k的二叉树至多有2^{k}-1个结点(k\ge 1) $$
$$ 性质3:对于任意一颗二叉树T,如果其终端节点数为n_{0},度为2的结点数为n_{2},则 n_{0} = n_{2}+1 $$
$$ 性质4:具有n个结点的完全二叉树的深度为\left \lfloor long_{2}n \right \rfloor +1 $$
$$ \displaylines{性质5:如果对一颗有n个结点的完全二叉树(其深度为\left \lfloor log_{2} \right \rfloor )+1的结点按层序编号(从第1层到第\left \lfloor log_{2} \right \rfloor 层,从左到右),对于任意结点i(1\le i \le n)有: \\ \begin{cases}1. 如果i = 1,则结点i是二叉树的根,无双亲;如果i > 1,则其双亲是结点\left \lfloor i/2 \right \rfloor \\ 2.如果2i > n,则结点i无左孩子(结点i为叶子结点);否则其做孩子就是结点2i \\ 3.如果2i+1 > n。则结点i无右孩子;否则其右孩子是结点2i+1 \end{cases}} $$
二叉树的建立
树本身就是递归定义,所以建树的过程也是递归建立
#include <stdio.h>
#include <stdlib.h>
typedef struct BinNode{
char data;
struct BinNode * lchild, * rchild;
}BinNode, * BinTree;
void CreatBinTree(BinTree * T){
char ch;
scanf("%d",&ch);
if(ch == '#')
*T = NULL;
else{
*T = (BinTree)malloc(sizeof(BinNode));
if(! *T)
printf("ERROR!");
(*T)->data = ch;
CreatBinTree(& (*T)->lchild);
CreatBinTree(& (*T)->rchild);
}
}
int main(){
BinTree * T;
printf("Ceeeeeeeeb!");
CreatBinTree(T);
return 0;
}
这样写虽然可以输入,但因为没有提示,也没有遍历。所以,测试的时候一定要注意根左右的顺序。
Code
#include<stdio.h>
#include<iostream>
using namespace std;
struct btnode{
char data;
struct btnode *lchild,*rchild;
};
extern int level=0;
extern int count=0;
int depth(btnode* );
void create(btnode* &T)
{
char c;
scanf("%c",&c);
if(c=='/') //若为'/',则该结点为空
return;
T=new btnode;
T->data=c;
T->lchild=NULL;
T->rchild=NULL;
create(T->lchild);
create(T->rchild);
}
void prior_order1(btnode* T)//递归先序遍历二叉树
{
if(T)
{
cout<<T->data<<" ";
prior_order1(T->lchild);
prior_order1(T->rchild);
}
}
void mid_order(btnode* T)//递归中序遍历二叉树
{
if(T)
{
mid_order(T->lchild);
cout<<T->data<<" ";
mid_order(T->rchild);
}
}
void behind_bt(btnode*T)//后续遍历二叉树
{
if(T)
{
behind_bt(T->lchild);
behind_bt(T->rchild);
cout<<T->data<<" ";
}
}
void prior_order(btnode* T)//先序输出二叉树 ,并且同时输出每个节点对应的位数
{
int count=1;
if(T==NULL)
return;
printf("(%c,%d) ",T->data,count++);
if(T->lchild)
printf("(%c,%d) ",T->lchild->data,count);
if(T->rchild)
printf("(%c,%d) ",T->rchild->data,count);
}
void numbers_of_node(btnode* T,int &count)//计算二叉树中结点个数,赋值给count
{
if(T)
{
++count;
numbers_of_node(T->lchild,count);
numbers_of_node(T->rchild,count);
}
}
int depth(btnode* T)//求二叉树的深度,规定根节点所在层次为0层
{
int leftlen,rightlen;
if(T==NULL)
return 0;
else
{
leftlen=depth(T->lchild)+1;
rightlen=depth(T->rchild)+1;
}
if(leftlen>rightlen)
return leftlen;
return rightlen;
}
void leaf(btnode* T,int &count)//求叶子节点个数
{
if(T)
{
if(T->lchild==NULL&&T->rchild==NULL)
count=count+1;
leaf(T->lchild,count);
leaf(T->rchild,count);
}
}
int main()
{
btnode *T=new btnode;
T=NULL;
int num1,node;
num1=node=0;
create(T);
leaf(T,num1);//num1保存叶子结点个数
numbers_of_node(T,node);//node保存结点个数
cout<<"先序序列输出结果为";
prior_order1(T); cout<<'\n';
cout<<"中序序列输出结果为";
mid_order(T); cout<<'\n';
cout<<"后序序列输出结果为";
behind_bt(T); cout<<'\n';
cout<<"叶子结点个数为"<<num1<<endl;
cout<<"二叉树结点个数为"<< node<<endl;
cout<<"二叉树深度为"<<depth(T);
return 0;
}
二叉树的遍历
递归遍历
由于树是递归定义,所以其遍历也是可以递归表达的。
void PreOrderTraverse(BinTree T){
if(T == NULL)
return ;
printf("%c", T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
非递归遍历
但是如果树的数据量非常大的话,那么递归定义的遍历函数很可能会使你的程序宕机,所以我们通过栈来手动模拟遍历。
中序遍历
https://blog.csdn.net/happyja...
- 遇到一个结点,就把它压栈,并去遍历它的左子树;
- 当左子树遍历结束后,从栈顶弹出这个结点并访问它;
- 然后按其右指针再去中序遍历该结点的右子树。
void midOrder(BiTree pRoot)
{
if (pRoot == NULL)
return;
BiTree p = pRoot;
stack<BiTree>s;
while (p != NULL || !s.empty())
{
while (p!=NULL)
{
s.push(p);
p = p->lchild;
}
if (!s.empty())
{
p = s.top();
cout << p->data << " "; //第二次遇见的时候输出
s.pop();
p = p->rchild;
}
}
}
后序遍历
https://blog.csdn.net/happyja...
第一种思路:对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问, 因此其右孩子还为被访问。所以接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。这样就 保证了正确的访问顺序。可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是 否是第一次出现在栈顶
//思路1:
typedef struct Node
{
BiTree btnode;
bool isfirst;
}Node,*node;
void postOrder(BiTree pRoot)
{
if (pRoot == NULL)
return;
stack<node>s;
BiTree p = pRoot;
node tmp;
while (p!=NULL || !s.empty())
{
while (p != NULL) //沿左子树一直往下搜索,直至出现没有左子树的结点
{
node btn = (node)malloc(sizeof(Node));
btn->btnode = p;
btn->isfirst = true;
s.push(btn);
p = p->lchild;
}
if (!s.empty())
{
tmp = s.top();
s.pop();
if (tmp->isfirst == true) //第一次出现在栈顶
{
tmp->isfirst = false;
s.push(tmp);
p = tmp->btnode->rchild;
}
else //第二次出现在栈顶
{
cout << tmp->btnode->data<<" ";
p = NULL;
}
}
}
}
//思路2:
void postorder(BiTree pRoot)
{
if (pRoot == NULL)
return;
stack<BiTree>s;
BiTree cur = pRoot, pre = NULL;
s.push(pRoot);
while (!s.empty())
{
cur = s.top();
if ((cur->lchild == NULL&&cur->rchild == NULL) ||
((pre == cur->lchild || pre == cur->rchild) && pre != NULL))
{
cout << cur->data << " ";
s.pop();
pre = cur;
}
else
{
if (cur->rchild != NULL)
s.push(cur->rchild);
if (cur->lchild != NULL)
s.push(cur->lchild);
}
}
}
C语言code
//这里是使用C语言,首先自己先手动写了栈。如果是C++可以使用STL中的stack
#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR -1
typedef char TElemType;
typedef int Status;
typedef struct BiTNode
{
TElemType data;
struct BiTNode *lchild,*rchild;
} BiTNode,*BiTree;
typedef BiTNode * StackElemType;
typedef struct LinkNode //栈的节点
{
StackElemType data ;
LinkNode * next ;
} LinkNode,*LiStack;
typedef BiTNode * QueueElemType ; //定义队列包含的数据类型
typedef struct QNode //定义队列节点
{
QueueElemType data ;
struct QNode * next ;
} QNode,*QueuePtr;
typedef struct
{
QueuePtr fronts;
QueuePtr rears;
} LinkQueue;
Status creatBiTree(BiTree &T);
void Visit(char ch,int level);
void PreOrderTraverse(BiTree T,int level);
void InOrderTraverse(BiTree T,int level);
void PostOrderTraverse(BiTree T,int level);
Status InitStack(LiStack &S);
void Push(LiStack &S, StackElemType data);
void Pop(LiStack & S, StackElemType &data);
int StackEmpty(LiStack &S);
int GetTop(LiStack &S, StackElemType & data);
Status InitQueue(LinkQueue &Q);
Status EnQueue(LinkQueue &Q, QueueElemType data);
Status DeQueue(LinkQueue &Q, QueueElemType & data);
int QueueEmpty(LinkQueue Q);
void PreOrderTraverse_Nonrecursion(BiTree T);
void InOrderTraverse_Nonrecursion(BiTree T);
void PostOrderTraverse_Nonrecursion(BiTree T);
/*********************************************************************/
/*****************************栈的方法********************************/
//栈的函数定义
Status InitStack(LiStack &S)
{
S = (LinkNode *)malloc(sizeof(LinkNode)) ;
if(NULL == S)
{
printf("内存不足,不能分配栈!\n") ;
exit(0) ;
}
S->next = NULL ;
}
void Push(LiStack &S, StackElemType data)
{
LiStack q ;
q = (LinkNode *)malloc(sizeof(LinkNode)) ;
if(NULL == q)
{
printf("内存不足,不能分配栈!\n") ;
exit(0) ;
}
/*
插入顺序相当于头插法.
*/
q->data = data ;
q->next = S->next ;
S->next = q ;
}
void Pop(LiStack & S, StackElemType &data)
{
LiStack q;
if(NULL == S->next)
{
printf("栈为空,无返回值!\n") ;
}
q = S->next ;
data = q->data ;
S->next = q->next ;
free(q) ;
}
int StackEmpty(LiStack &S)
{
if(NULL == S->next)
{
return(1) ;
}
return(0) ;
}
int GetTop(LiStack &S, StackElemType & data)
{
if(NULL != S->next)
{
data = S->next->data ;
return(1) ;
}
else
{
//data = NULL ;
return(0) ;
}
}
/*********************************************************************/
/*****************************队列的方法******************************/
//队列函数的定义
Status InitQueue(LinkQueue &Q)
{
Q.fronts = Q.rears = (QNode *)malloc(sizeof(QNode)) ;
if(NULL == Q.fronts)
{
printf("内存不足!\n") ;
return ERROR;
}
Q.fronts->next = NULL;
}
Status EnQueue(LinkQueue &Q, QueueElemType data)
{
QueuePtr q ;
q = (QNode*)malloc(sizeof(QNode));
if(NULL == q)
{
printf("内存不足!\n") ;
return ERROR;
}
//构造q
q->data = data ;
q->next = NULL;
q->next = Q.rears->next ;
Q.rears = q ;
return OK;
}
Status DeQueue(LinkQueue &Q, QueueElemType & data)
{
QueuePtr p ;
if(Q.fronts == Q.rears)
{
printf("队列为空!\n") ;
return ERROR ;
}
p = Q.fronts->next ;
data = p->data ;
Q.fronts->next = p->next ;
if(Q.rears == p)
Q.rears = Q.fronts ;
free(p);
return OK;
}
int QueueEmpty(LinkQueue Q)
{
if(Q.fronts == Q.rears)
return(1) ;
else
return(0) ;
}
/*********************************************************************/
/*
先序创建二叉树
*/
Status creatBiTree(BiTree &T)
{
char ch;
scanf("%c",&ch);
if('@' == ch)
{
T = NULL;
}
else
{
//申请失败
if(!(T = (BiTNode*)malloc(sizeof(BiTNode))))
return ERROR;
T->data = ch;
creatBiTree(T->lchild);
creatBiTree(T->rchild);
}
return OK;
}
void VisitF(char ch)
{
printf("%c ",ch);
}
void Visit(char ch,int level)
{
printf("%c 位于第 %d 层 \n",ch,level);
}
/*
先序遍历二叉树
*/
void PreOrderTraverse(BiTree T,int level)
{
if( T )
{
VisitF(T->data);
PreOrderTraverse(T->lchild,++level);
PreOrderTraverse(T->rchild,++level);
}
}
void PreOrderTraverse_Nonrecursion(BiTree T)
{
LiStack S ;
BiTree p ;
S = NULL ;
p = T ;
InitStack(S) ;
if(NULL == p)
{
printf("树为空!\n") ;
return ;
}
while(p || !StackEmpty(S))
{
if(p)
{
Push(S, p) ;
VisitF(p->data);
p = p->lchild ;
}
else
{
Pop(S, p) ;
p = p->rchild ;
}
}
free(S) ;
}
/*
中序遍历二叉树
*/
void InOrderTraverse(BiTree T)
{
if( T )
{
InOrderTraverse(T->lchild);
VisitF(T->data);
InOrderTraverse(T->rchild);
}
}
void InOrderTraverse_Nonrecursion(BiTree T)
{
LiStack S ;
BiTree p ;
S = NULL ;
p = T ;
InitStack(S) ;
if(NULL == p)
{
printf("树为空!\n") ;
return ;
}
while(p || !StackEmpty(S))
{
if(p)
{
Push(S, p) ;
p = p->lchild ;
}
else
{
Pop(S, p) ;
VisitF(p->data);
p = p->rchild ;
}
}
free(S) ;
}
/*
后续遍历二叉树
*/
void PostOrderTraverse(BiTree T)
{
if( T )
{
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
VisitF(T->data);
}
}
void PostOrderTraverse_Nonrecursion(BiTree T)
{
LiStack S ;
BiTree cur, pre ;
S = NULL ;
InitStack(S) ;
if(NULL == T)
{
printf("树为空!\n") ;
return ;
}
pre = NULL ;
cur = NULL ;
Push(S,T) ;
while(!StackEmpty(S))
{
cur = NULL ;
GetTop(S,cur) ;
if((cur->lchild == NULL && cur->rchild == NULL) || (pre != NULL && (pre == cur->lchild ||pre == cur->rchild)))
{
VisitF(cur->data);
pre = cur ;
Pop(S,cur) ;
}
else
{
if(cur->rchild != NULL)
{
Push(S,cur->rchild) ;
}
if(cur->lchild != NULL)
{
Push(S,cur->lchild) ;
}
}
}
free(S) ;
}
int main()
{
int level = 1;
BiTree T = NULL;
creatBiTree(T);
printf("先序遍历二叉树,每个结点在第几行\n");
PreOrderTraverse(T,level);
printf("\n\n");
printf("先序遍历二叉树,非递归算法\n");
PreOrderTraverse_Nonrecursion(T);
printf("\n\n\n");
/***************************************************/
printf("中序遍历二叉树\n");
InOrderTraverse(T);
printf("\n\n");
printf("中序遍历二叉树,非递归算法\n");
InOrderTraverse_Nonrecursion(T);
printf("\n\n\n");
/***************************************************/
printf("后序遍历二叉树\n");
PostOrderTraverse(T);
printf("\n\n");
printf("后序遍历二叉树,非递归算法\n");
PostOrderTraverse_Nonrecursion(T);
printf("\n\n\n");
return 0;
}
C++Code
#include<iostream>
#include<stdlib.h>
#include<stack>
using namespace std;
#define len 15 //定义一个长度
typedef int ElemType;
typedef struct BiTNode
{
ElemType data;
struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;
typedef struct Node
{
BiTree btnode;
bool isfirst;
}Node,*node;
//向下遍历,找到节点s应该插入的位置,节点有重复时,忽略这个节点
void SearchTreeNode(BiTree &root, BiTree &s) //注意:使用引用传递
{
if (root == NULL)
return;
if (s->data > root->data)
{
if (root->rchild == NULL)
{
root->rchild = s;
return;
}
SearchTreeNode(root->rchild, s);//s值大于根节点值,未到达叶子节点,继续向右孩子遍历
}
else if (s->data < root->data)
{
if (root->lchild == NULL)
{
root->lchild = s;
return;
}
SearchTreeNode(root->lchild, s);//s值小于根节点值,未到达叶子节点,继续向左孩子遍历
}
}
//插入一个节点,树为空,插入节点即为根节点,否则找合适的位置插入
void InsertNode(BiTree &tree, BiTree &s) //注意:使用引用传递
{
if (tree == NULL)
tree = s;
else
SearchTreeNode(tree, s);
}
//二叉排序树创建,每次增加一个结点,插到现有的二叉树上去
void CreateOrderBinaryTree(BiTree &tree, int *a)
{
for (int i = 0; i < len; i++)
{
BiTree s = (BiTree)malloc(sizeof(BiTNode));
s->data = a[i];
s->lchild = NULL;
s->rchild = NULL;
InsertNode(tree, s);
}
}
//前序遍历
void ProOrderTraverse(BiTree tree)
{
if (tree == NULL)
return;
cout << tree->data << " ";
ProOrderTraverse(tree->lchild);
ProOrderTraverse(tree->rchild);
}
//非递归前序遍历
void ProOrder(BiTree pRoot)
{
if (pRoot == NULL)
return;
BiTree p = pRoot;
stack<BiTree>s;
while (p != NULL || !s.empty())
{
while (p != NULL)
{
s.push(p);
cout << p->data << " "; //第一次遇见的时候输出
p = p->lchild;
}
if (!s.empty())
{
p = s.top();
s.pop();
p = p->rchild;
}
}
}
//中序遍历
void midOrderTraverse(BiTree tree)
{
if (tree == NULL)
return;
midOrderTraverse(tree->lchild);
cout << tree->data << " ";
midOrderTraverse(tree->rchild);
}
//非递归中序遍历
void midOrder(BiTree pRoot)
{
if (pRoot == NULL)
return;
BiTree p = pRoot;
stack<BiTree>s;
while (p != NULL || !s.empty())
{
while (p!=NULL)
{
s.push(p);
p = p->lchild;
}
if (!s.empty())
{
p = s.top();
cout << p->data << " "; //第二次遇见的时候输出
s.pop();
p = p->rchild;
}
}
}
//后序遍历
void postOrderTraverse(BiTree pRoot)
{
if (pRoot == NULL)
return;
postOrderTraverse(pRoot->lchild);
postOrderTraverse(pRoot->rchild);
cout << pRoot->data<<" ";
}
//非递归实现后续遍历
void postOrder(BiTree pRoot)
{
if (pRoot == NULL)
return;
stack<node>s;
BiTree p = pRoot;
node tmp;
while (p!=NULL || !s.empty())
{
while (p != NULL) //沿左子树一直往下搜索,直至出现没有左子树的结点
{
node btn = (node)malloc(sizeof(Node));
btn->btnode = p;
btn->isfirst = true;
s.push(btn);
p = p->lchild;
}
if (!s.empty())
{
tmp = s.top();
s.pop();
if (tmp->isfirst == true) //第一次出现在栈顶
{
tmp->isfirst = false;
s.push(tmp);
p = tmp->btnode->rchild;
}
else //第二次出现在栈顶
{
cout << tmp->btnode->data<<" ";
p = NULL;
}
}
}
}
//非递归实现后续遍历
void postorder(BiTree pRoot)
{
if (pRoot == NULL)
return;
stack<BiTree>s;
BiTree cur = pRoot, pre = NULL;
s.push(pRoot);
while (!s.empty())
{
cur = s.top();
if ((cur->lchild == NULL&&cur->rchild == NULL) ||
((pre == cur->lchild || pre == cur->rchild) && pre != NULL))
{
cout << cur->data << " ";
s.pop();
pre = cur;
}
else
{
if (cur->rchild != NULL)
s.push(cur->rchild);
if (cur->lchild != NULL)
s.push(cur->lchild);
}
}
}
int main()
{
int a[len] = { 62, 88, 58, 47, 35, 73, 51, 99, 37, 93, 23, 27, 45, 21, 12 };
BiTree tree = NULL;
//创建一个二叉树,并中序遍历
CreateOrderBinaryTree(tree, a);
cout << "前序遍历" << endl;
ProOrderTraverse(tree);
cout << endl;
ProOrder(tree);
cout << endl<<endl;
cout << "中序遍历" << endl;
midOrderTraverse(tree);
cout << endl;
midOrder(tree);
cout << endl<<endl;
cout << "后序遍历" << endl;
postOrderTraverse(tree);
cout << endl;
postOrder(tree);
cout << endl;
postorder(tree);
cout << endl<<endl;
return 0;
}
线索二叉树
线索二叉树实际上是为了将普通二叉树中众多的空节点利用起来而进行的操作的结果。同时可以使得我们二叉树更加灵活。
其原理是与选择的遍历方式密不可分的。具体是在结点中增加新的线索位置,而线索位存放指向前驱和后继的指针,而前驱和后继的选择就与遍历方式相关。
typedef enum {Link, Thread} PointerTag;
//Link == 0 :表示指向左右孩子的指针
//Thread == 1 : 表示指向前驱和后继的线索
typedef struct BinThrNode {
Element data;
struct BinThrNode * lchild, * rchild;
PointerTag LTag, RTag;
};
线索化的过程就是在遍历过程中修改空指针的过程。
//中序遍历线索化
BinThrTree pre;// 全局变量,始终指向刚刚访问过的结点
void InThreading(BinThrTree p){
if(p){
InThreading(p->lchild);//递归左子树线索化
if(!p->lchild){//没有左孩子
p->LTag = Thread;// 前驱线索
p->lchild = pre;//左孩子指针指向前驱
}
if(!pre->rchild){
pre->RTag = Thread;
pre->rchild = p;//前驱右孩子指针指向后继
}
pre = p;
InThreading(p->rchild);//递归右孩子线索化
}
}
//其实只是将打印的操作换成了对应的线索化的操作而已。
if(!p->lchild) 表示如果某结点的左指针域为空,因为前驱结点刚刚已经访问过,赋值给pre,所以可以将pre赋值给p->lchild, 并修改p->LTag = Thread ( 也就是定义为1 )以完成前驱结点的线索化。
后继此时并没有被访问到,因此只能对它的前驱结点pre的右指针rchild做判断, if(!pre->rchild) 表示为空,则p就是pre的后继,于是 pre->rchild = p,并设置pre->RTag = Thread;,完成后续的线索化。
线索化之后的遍历就好像双向链表一样。
//线索二叉树中序遍历伪代码
Status InOrderTraverse_Thr(BinTree T){
BinThrTree p;
p = T->lchild;
while(p != T){
while(p->LTag == Link)
p = p->lchild;
printf("%c",p->data);
while(p->RTag == Thread && p->rchild != T){
p = p->rchild;
printf("%c",p->data);
}
p = p->rchild;
}
return OK;
}
森林
二叉树和森林的转换
https://www.cnblogs.com/wangw...
树转换为二叉树
(1)加线。在所有兄弟结点之间加一条连线。
(2)去线。树中的每个结点,只保留它与第一个孩子结点的连线,删除它与其它孩子结点之间的连线。
(3)层次调整。以树的根节点为轴心,将整棵树顺时针旋转一定角度,使之结构层次分明。(注意第一个孩子是结点的左孩子,兄弟转换过来的孩子是结点的右孩子)
森林转换为二叉树
(1)把每棵树转换为二叉树。
(2)第一棵二叉树不动,从第二棵二叉树开始,依次把后一棵二叉树的根结点作为前一棵二叉树的根结点的右孩子,用线连接起来。
二叉树转换为树
是树转换为二叉树的逆过程。
(1)加线。若某结点X的左孩子结点存在,则将这个左孩子的右孩子结点、右孩子的右孩子结点、右孩子的右孩子的右孩子结点…,都作为结点X的孩子。将结点X与这些右孩子结点用线连接起来。
(2)去线。删除原二叉树中所有结点与其右孩子结点的连线。
(3)层次调整。
二叉树转换为森林
假如一棵二叉树的根节点有右孩子,则这棵二叉树能够转换为森林,否则将转换为一棵树。
(1)从根节点开始,若右孩子存在,则把与右孩子结点的连线删除。再查看分离后的二叉树,若其根节点的右孩子存在,则连线删除…。直到所有这些根节点与右孩子的连线都删除为止。
(2)将每棵分离后的二叉树转换为树。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。