typedef struct ThreadNode{
ElemType data; //存放数据
struct ThreadNode *lchild,*rchild; //左指针及右指针
int ltag,rtag; //左右线索 ,=0表示指向孩子,=1表示指向线索
}ThreadNode, * ThreadTree;
后序遍历顺序 :左 右 根。
思路:
利用栈,沿着根的左孩子依次入栈
p = p->lchild;
直到左孩子为空时 。读取栈顶元素
if(p == Null)
{
GetTop(S,p);
}
看看元素是否有右孩子,如果有右孩子且没有被访问过的话使指针指向P的右孩子
if(p -> rchild && p->rchild != r) // r为标记
{
p = p ->rchild
}
如果不存在右子树 或者右子树 已经被访问过了 就弹出栈顶元素并对它进行访问
else{
pop(S,p);
visit(p->data);
r = p;
p = NULL;
}
void PostOrder(ThreadTree T)
{
InitStack(S); //栈
ThreadTree p = T;//指针P
r = NULL;//指针标志
while( p || !IsEmpty(S)) //指针非空并且栈不为空
if(p){
push(S,p);
p = p->lchild; // 依次遍历左子树入栈
}else{
GetTop(S,p);
if(p->rchild && p->rchild !=NULL) // 右子树存在未被访问
{
p = p ->rchild; //访问右子树
}else {
pop(S,p);
visit(p->data);
r = p;
p = Null; //
}
}
}
思路:这里的顺序刚好与层次遍历的顺序相反,可以利用层次遍历所得到的结果依次入栈在出栈即可得到
层次遍历算法:
void levelOrder(ThreadTree T)
{
InitQueue(Q);
ThreadNode *p = T;
EnQueue(Q,T); //将根结点入队
while(!IsEmpty(Q))
{
DeQueue(Q,p); //出队
visit(p);
if(p ->lchild != NULL)
{
EnQueue(Q,p->lchild); //左孩子存在左孩子入队
}
if(p ->rchild != NULL)
{
EnQueue(Q,p->rchild);//右孩子存在右孩子入队
}
}
}
更改后:
void levelOrder(ThreadTree T)
{
InitQueue(Q);
InitStack(S)
ThreadNode *p = T;
EnQueue(Q,T); //将根结点入队
while(!IsEmpty(Q))
{
DeQueue(Q,p); //出队
Push(S,p);
visit(p);
if(p ->lchild != NULL)
{
EnQueue(Q,p->lchild); //左孩子存在左孩子入队
}
if(p ->rchild != NULL)
{
EnQueue(Q,p->rchild);//右孩子存在右孩子入队
}
}
while(IsEmpty(S))
{
pop (S,p);
visit(p->data);
}
}
typedef struct BiTNode{
ElemType data; // 数据域
struct BiTNode *lchild,*rchild; //左右孩子指针
}BiTNode,*BiTree;
思路:利用层次遍历一层一层记录,需要考虑的是什么时候让层数加一,做法是设置一个变量用来指向每一层的最右结点,另外设置两个变量,一个变量是每当入队时加一,另一个变量是每当出队时加一,当出队的变量与记录每一层右结点的变量相同时则可以说明这一层已经出队完成,于是让树高加一,并且让变量指向下一层的最右。(这里的最右就是靠入队时+1的变量提供,除了根节点时)
int btdepth(ThreadTree T)
{
if(!T) {
return 0; //树空则返回0
}
int front , rear = -1; // 出队时 front ++ ,入队时 rear ++
int last = 0,level = 0; //last 作用是记录 本层有多少个结点 level记录高度
InitQueue(Q);
EnQueue(Q,T) //根结点入队
rear ++;
while(!IsEmpty(Q))
{
DeQueue(Q,p); //出队
front++;
if(p ->lchild != NULL)
{
EnQueue(Q,p->lchild); //左孩子存在左孩子入队
rear ++;
}
if(p ->rchild != NULL)
{
EnQueue(Q,p->rchild);//右孩子存在右孩子入队
rear ++;
}
if(front == last) //说明一层已经出队完成
{
level ++;
last = rear; // 指向下一层;
}
}
return level;
}
从先序遍历我们可以知道该树的根结点,然后根据这个结点的值在B中寻找到该结点,就可以把B分为左子树及右子树,然后对算法进行递归,就可以得到最后的答案
ThreadTree PreInCreat(ElemType A[],ElemType B[],int l1,int h1,int l2,int h2)
{
// l1,h1分别为先序的第一个和最后一个元素的下标
// l2,h2分别为中序的第一个和最后一个元素的下标;
ThreadNode *root = (ThreadNode *) malloc(sizeof(ThreadNode));
root->data=A[l1];
for(int i = l2;B[i]!=root->data;i++);
llen = i - 12; //左子树长度
rlen = h2 - i; //右子树长度
if(llen)
root->lchild = PreInCreat(A,B,l1+1,l1+len,l2,l2+llen-1);
//由于左子树的长度为llen,所以左子树的最后一个结点先序应该到 l1 + llen ,右子树的最后一个结点先序应该到 l2 - llen -1
else
root->lchild = NULL;
if(rlen)
root->rchild = PreInCreat(A,B,h1-rlen+1,h1,h2-rlen+1,h2);
//同理
else
root->rchild = NULL;
}
完全二叉树的概念 ,结点不能在没有左兄弟的情况下出现。利用层次遍历将结点加入队列,遇到空结点看后面是否有无结点,有结点则不是完全二叉树
bool IsComplete(ThreadTree T)
{
InitQueue(Q);
if(!T) {
return true; //空树为满二叉树
}
EnQueue(Q,T);
while(!IsEmpty(Q))
{
DeQueue(Q,p);
if(p)
{
if(p ->lchild != NULL)
{
EnQueue(Q,p->lchild); //左孩子存在左孩子入队
}
if(p ->rchild != NULL)
{
EnQueue(Q,p->rchild);//右孩子存在右孩子入队
}
}else
{
while(!IsEmpty(Q)) //看是否后面有结点
{
DeQueue(Q,p);
if(p)
return false;
}
}
}
}
利用层次遍历,设置两个标志位当出队时有左右孩子就将两个标志位置为1,在最后判断标志位是否等于1。
int DsonNodes(ThreadTree T)
{
int ltag = 0,rtag=0;
int count = 0;
InitQueue(Q);
EnQueue(T);//根结点入队
while(!IsEmpty(Q))
{
DeQueue(Q,p);
if(p ->lchild != NULL)
{
EnQueue(Q,p->lchild); //左孩子存在左孩子入队
ltag = 1; //说明有左结点
}
if(p ->rchild != NULL)
{
EnQueue(Q,p->rchild);//右孩子存在右孩子入队
rtag = 1;//说明有右结点
}
if(ltag == 1 && ltag == rtag)
{
count ++;
}
ltag = rtag = 0;
}
}
采用递归算法,交换b结点的左孩子的左右子树,右孩子的左右子树,b结点的左右子树
void swap(ThreadTree T)
{
if(T)
{
swap(T->lchild);
swap(T->rchild);
temp = b->lchild;
b->lchild = b->rchild;
b->rchild = temp;
}
}
递归找值
ElemType PreNode(ThreadTree T,int K)
{
if(T == NULL)
{
return '#'; // 空树返回
}
if(i == K)
{
return T->data; //递归出口
}
i ++;
ch = PreNode(T->lchild,K);
if(ch!= '#')
{
return ch;
}
ch = PreNode(T->rchild,K);
return ch;
}
删除结点使用递归算法,唯一要考虑的是删除结点的父结点的指向NULL
利用层次遍历记录父指针
void Search(ThreadTree T,ElemType x)
{
ThreadNode Q[]; //建立存放二叉树,容量足够大
if(T){
if(T->data == x)
{
DeleteXTree(T);
return;
}
}
InitQueque(Q);
EnQueue(Q,T);
while(!IsEmpty(Q))
{
DeQueue(Q,p);
if(p->lchild) //p左结点存在
{
if(p->lchild->data == x) //删除子树,置位空
{
DeleteXTree(p->lchild);
p->lchild = NULL;
}else{
EnQueue(Q,p->lchild);
}
}
if(p->rchild)
{
if(p->rchild->data == x)//同理
{
DeleteXTree(p->rchild);
p->rchild = NULL;
}else{
EnQueue(Q,p->rchild);
}
}
}
}
思路:利用后序遍历非递归算法,先沿着左子树访问,当访问完之后发现并未找到值,开始访问右子树,当也没有找到值时,退栈。当找到值,输出栈里元素
typedef struct {
ThreadTree t;
int tag; //tag 表 O表示对左子树访问,1表示对右子树访问
};stack;
void Search(ThreadTree T,ElemType x)
{
stack s[];
top = 0;
while(T != NULL || top > 0)
{
while(T != NULL && T->data !=x)
{
s[++top] = T;
s[top].tag = 0;
T = T->lchild;
}
if(T->data == x)
{
for(i =1;i < top;i++)
{
printf("%d",s[i].t->data)
return 0;
}
}
while(top!= 0 && s[top].tag == 1)
top--;
if(top!=0)
{
s[top].tag = 1;
T = s[top].t->rchild;
}
}
}