#include<iostream>
#define maxsize 100
void visit(BTtree T)
{
printf("%d",T->data);
}
typedef struct BTNode
{
int data; //为简单起见,不妨假设树节点的元素为int型
struct BTNode *lchild;
struct BTNode *rchild;
}BTNode,*BTtree;
递归遍历
先序遍历
//递归先序遍历
void PreOrder(BTtree T)
{
if(T!=NULL)
{
visit(T);
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
中序遍历
//递归中序遍历
void InOrder(BTtree T)
{
if(T!=NULL)
{
InOrder(T->lchild);
visit(T);
InOrder(T->rchild);
}
}
后序遍历
//递归后序遍历
void PostOrder(BTtree T)
{
if(T!=NULL)
{
PostOrder(T->lchild);
PostOrder(T->rchild);
visit(T);
}
}
非递归遍历
先序遍历
//先序非递归
//1.根节点入栈
//2.栈不空,出栈。栈空,结束。
//3.判断出栈结点是否有孩子,右孩子先入栈,左孩子后入栈。跳到第2步。
void PreOrder2(BTtree bt)
{
if(bt!=NULL)
{
BTtree Stack[maxsize];
int top=-1;
BTtree p;
Stack[++top]=bt;
while(top!=-1)
{
p=Stack[top--];//出栈,P为栈顶结点
visit(p);
if(p->rchild!=NULL)
Stack[++top]=p->rchild;
if(p->lchild!=NULL)
Stack[++top]=p->lchild;
}
}
}
中序遍历
//中序非递归
//1.沿着根的左孩子,依次入栈,直到左孩子为空
//2.出栈,访问栈顶元素,其右孩子为空则重复执行2,若右孩子存在,转向1.
void InOrder2(BTtree T)
{
if(T!=NULL)
{
BTtree Stack[maxsize];
int top=-1;
BTtree p=T;//工作结点
while(top!=-1||p!=NULL)//栈不空或p不空时循环
{
if(p!=NULL)
{
Stack[++top]=p;
p=p->lchild;
}
else
{ //出栈,访问栈顶结点,并转向右子树
p=Stack[top--];
visit(p);
p=p->rchild; //p指向右孩子,继续循环
}
}
}
}
后序遍历
后续遍历,先将左子树入栈,直到左子树为空,转向右子树,右子树不为空,则以右子树为根又找左子树,否则出栈。当右子树被访问过时也出栈。实际上一个元素会处在栈顶两次,一次是它的右孩子被访问前,一次是右孩子出栈后又回到他这里。所以一个元素如果第二次弹出来,那就将他打印。为了方便,我们可以所有的栈顶结点都先出栈弹出一次,再入栈,再判断它的右孩子。没有右孩子的结点也会被弹出一次,然后马上弹出第二次,并打印。
typedef struct node
{
int key;
struct node *left,*right;
int flag; //标记是否访问过。初始设0
}*Tree,tree;
void PostOrder(Tree root)
{
Tree p=root;
Tree stack[maxsize];
int top=-1;
while(p!=NULL)
{
stack[++top]=p; //沿着根的左孩子,依次入栈
p=p->left;
}
while(top!=-1)
{
p=stack[top--];
if(p->flag==1)//第二次出栈的结点直接打印
{
printf("%d\n",p->key);
}
else
{
p->flag=1;
stack[++top]=p;
p=p->right;//转向右子树
while(p!=NULL)
{
stack[++top]=p;
p=p->left; //找右子树中的左子树
}
}
}
}
还有一种思路就是,因为后序遍历是左右根,那么可以求其逆序,先用类似于先序遍历的思路求根右左,然后依次保存在另一个栈,出栈顺序就是后序遍历的顺序了,即左右根。
//后序遍历非递归
//逆后续遍历等于先序遍历过程中交换左右子树遍历顺序得到的结果,即根右左。
//最后在从后往前地输出逆后续的结果就是后续遍历序列。用两个栈。一个栈前序遍历,一个栈存逆后续序列。
void PostOrder2(BTtree T)
{
if(T!=NULL)
{
BTtree Stack1[maxsize];
int top1=-1;
BTtree Stack2[maxsize];
int top2=-1;
BTtree p;
Stack1[++top1]=T; //根节点入栈
while(top1!=-1)
{
p=Stack1[top1--];//出栈
Stack2[++top2]=p;//出栈结点入栈到stack2
if(p->lchild!=NULL) //先入左后右,因为先遍历右再遍历左(根右左)
Stack1[++top1]=p->lchild;
if(p->rchild!=NULL)
Stack1[++top1]=p->rchild;
}
while(top2!=-1)
{
//出栈序列即为后序遍历序列
p=Stack2[top2--];
visit(p);
}
}
}
层次遍历
//层次遍历
//借助队列来实现
//首先,根节点入队;然后出队,访问出队结点;如果它有左子树,则左子树根节点入队;如果它有右子树,则右子树根结点入队;然后出队,对出队结点访问;循环直到队列为空。
void LevelOrder(BTtree T)
{
int front,rear;
BTtree queue[maxsize];
front=rear=0;
BTtree q;
if(T!=NULL)
{
queue[rear++]=T;//根结点入队
while(front!=rear)//队列不为空
{
q=queue[front++];//出队
visit(q);
if(q->lchild!=NULL)
{
queue[rear++]=q->lchild;//左孩子入队
}
if(q->rchild!=NULL)
{
queue[rear++]=q->rchild;//右孩子入队
}
}
}
}
线索二叉树
//中序线索二叉树中序线索化
//设一个pre,p指针,pre为p的遍历前驱结点,p的左线索如果在,则指向pre,pre的右线索在,则指向p。
void InThread(BTtree p,BTtree pre)
{
if(p!=NULL)
{
InThread(p->lchild,pre);//左子树线索化
if(p->lchild==NULL)
{
p->lchild=pre;
p->ltag=1;
}
if(pre!=NULL&&pre->rchild==NULL)
{
pre->rchild=p;
pre->rtag=1;
}
pre=p;
p=p->rchild;
InThread(p,pre);//右子树线索化
}
}
void createInThread(BTtree root)
{
BTtree pre=NULL;
if(root!=NULL)
{
InThread(root,pre);
pre->rchild=NULL;
pre->rtag=1;
}
}
二叉排序树
递归查找
//二叉排序树的递归查找
BTtree Search(BTtree bt,int key)
{
if(bt==NULL)
{
return NULL;
}
else
{
if(bt->data==key)
return bt;
else if(key<bt->data) //小于根节点关键字就到左子树中去找
return Search(bt->lchild,key);
else
return Search(bt->rchild,key);
}
}
非递归查找
//二叉排序树的非递归查找
BTtree Search2(BTtree T,int key)
{
while(T!=NULL&&key!=T->data)
{
if(key<T->data)T=T->lchild;
else
T=T->rchild;
}
return T;
}
插入
//二叉排序树的插入
int Insert(BTtree &T,int k)
{
if(T==NULL) //原树为空,新插入的记录为根结点
{
T=(BTNode*)malloc(sizeof(BTNode));
T->data=k;
T->lchild=T->rchild=NULL;
return 1;
}
else if(k==T->data)
return 0;
else if(k<T->data)
return Insert(T->lchild,k);
else
return Insert(T->rchild,k);
}
构造
//二叉树的构造
void Creat(BTtree &T,int str[],int n)
{
T=NULL;
int i=0;
while(i<n)
{
Insert(T,str[i]);
i++;
}
}