二叉树

来源:互联网 发布:sql server卸载干净 编辑:程序博客网 时间:2024/06/06 20:42

include

include

include

define SIZE 15

define INF 127

typedef struct BiTNode
{
int data;
struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;

typedef struct
{
BiTree data[SIZE];
int fron, rear;
}Queue;

void CreatBiTree(BiTree &T);//输入建立树
void CreatBiTree(BiTree &T, FILE *fp);//文件中读取树 失败
void CreatArrayTree(int n, int i, int tree[], BiTree &T);//数组中读取树
//数组中一共有几个元素(n) 当前数组元素位置i(i必须从1开始!!因为之后有对i的乘法) 数组 树

void DispTree(BiTree ); //树广义表表示法输出

void PreOrderTraverse(BiTree T);// 先序遍历
void PreStack(BiTree);//前序遍历的非递归表示

void InderOrderTraverse(BiTree T);// 中序遍历
void InderStack(BiTree T); //树的非递归中序遍历

void PostOrderTraverse(BiTree T);// 后序遍历
void PostStack(BiTree);//树的非递归后序遍历

void TranLevel(BiTree); //按层序遍历

void Visit(BiTree T); //访问该节点的数据

void Relese(BiTree);//将树清空

int getDepth(BiTree); //得到树的深度

void Level(BiTree T, BiTree p, int &h, int nowh);//求指定结点(自定义的新的节点只是和树中的某结点的值是一样的)的层数
//(从根开始计数) 规定该结点的值
//树 指定结点 要返回的结点的层数 当前层次
int Level(BiTree T, BiTNode *N);//求某结点(该结点是树中的结点)的层数 (从该结点向上开始数)

void Path(BiTree T, BiTree p);//求出任一结点的路径(缺陷 在左子树部分的路径无法输出根节点 右子树可以)

void CountLeaf(BiTree T, int &num);//计算树的叶子数并输出 法一
int CountLeaf(BiTree T);//计算树的叶子数并输出 法二

BiTree disLink(BiTree T, int x);//以树中值为X的节点为新的根节点将原树进行拆分

void CountChild(BiTree T, int &counts); //计算树的单孩子结点个数

void prePaint(BiTree T, int level);//树的图形化打印
void Paint(BiTree T);

//定义了全局变量 避免需要进行参数的传递 而直接可以对该变量的值进行反复修改
char buffer[SIZE][SIZE*SIZE];//规定了最大层数
int now=0;
int hight;

int main ()
{
int length, counts=0;
int n=SIZE, i=1;
BiTree T=NULL;
BiTree p;
int trees[20]={1,2,3,0,4,0,5,0,0,6,7,0,0,0,0};//0代表该位置的结点的值是空

//CreatBiTree(T);//输入读取CreatArrayTree(n, i, trees, T);//数组中读取printf("\n树广义表表示法输出\n");DispTree(T);printf("\n\n该树的叶子是:");//两种方法CountLeaf(T, counts);printf("\n树的叶子个数是:%d\n", counts);printf("树的叶子个数是:%d\n", CountLeaf(T));counts=0;printf("\n该树的单孩子结点是:\n");CountChild(T, counts);printf("\n树的单孩子结点个数是:%d\n", counts);length=getDepth(T);printf("\n树的深度是%d", length-1); //深度是先进行到叶子然后在逐层返回并递增 但最后多加了1printf("\n\n树的非递归前序遍历\n");PreStack(T);printf("\n树的递归前序遍历\n");PreOrderTraverse(T);printf("\n\n树的非递归中序遍历\n");InderStack(T);printf("\n树的中序遍历\n");InderOrderTraverse(T);printf("\n\n树的递归后序遍历\n");PostOrderTraverse(T);printf("\n树的非递归后序遍历\n");PostStack(T);printf("\n\n树的层序遍历\n");TranLevel(T);p=(BiTree)malloc(sizeof(BiTNode));   //指定了一个固定值的结点 而后在树中查找该结点的p->data=2;int h=-1, nowh=0;Level(T, p, h, nowh);     //指定结点  要返回的结点的层数  当前层次//int locate=Level(T, p);     p是树中的结点printf("\n\n值为%d的结点在树中的高度为%d\n", p->data, h+1);//h返回是深度(从根开始)Path(T, p);//找值为p的结点的路径printf("\n指定原树中某值的结点为新的根节点\n新树的递归后序遍历\n");PostOrderTraverse(disLink(T, p->data));printf("\n树的图形化输出\n");Paint(T);

}

void CreatBiTree(BiTree &T)//树的建立 法一:输入
{
int num;
scanf(“%d”, &num);
if(num==0)
{
T=NULL;
return;
}
else
{
T=(BiTree)malloc(sizeof(BiTNode));
T->data=num;
CreatBiTree(T->lchild);
CreatBiTree(T->rchild);
}
}

void CreatBiTree(BiTree &T, FILE *fp)//树的建立 法二:从文件中读取(失败)
{
int num;
fscanf(fp, “%d”, &num);
if(!feof(fp) && num!=0)
{printf(“(%d)”, num);
T=(BiTree)malloc(sizeof(BiTNode));
T->data=num;
CreatBiTree(T->lchild, fp);
CreatBiTree(T->rchild, fp);
}
else
{
printf(“return”);
return;
}

}

void CreatArrayTree(int n, int i, int tree[], BiTree &T)//树的建立 法三:从数组中读取(n的值不变)
{
if(i>n)
{
T=NULL; //终止对该链表的引用(也可以不加return)
return; //但是必须有 T=NULL !!!!!!!!!!!!
}
else
{
T=(BiTree)malloc(sizeof(BiTNode));
T->data=tree[i-1];
CreatArrayTree(n, 2*i, tree, T->lchild);//所以i必须从1开始 之后应用对i的乘法
CreatArrayTree(n, 2*i+1, tree, T->rchild);
}
}

void DispTree(BiTree T) //树广义表表示法输出
{
if(T) //先进行T是否为空的判断否则仍要继续执行在后两行中 将判断空的T的左右孩子是否为空
{
Visit(T); //打印根结点
if(T->lchild || T->rchild)//该结点不是叶子的话
{
printf(“(“); //因为不是叶子 所以一定有子树 所以左括号
DispTree(T->lchild); //进行该结点所有左子树的遍历
if(T->rchild) //逐层返回 从最内层开始
printf(“,”); //有右子树的进行逗号的打印
DispTree(T->rchild);
printf(“)”); //直到进行到右子树也遍历结束 则打印右括号
}
}
}

void CountLeaf(BiTree T, int &counts)//计算树的叶子数并输出 法一
{ //counts也可以定义全局变量 这样就不用进行参数的传递 而直接对main中的值进行修改
if(T) //一定要进行T是否为空的判断
{
if((!T->lchild && !T->rchild)||(T->lchild->data==0 && T->rchild->data==0))
{ //与我建立树的特殊型有关(我将二叉树补全 空位的元素是0)
//比如:0 00 前面是跟后面是两个叶子 但起的作用是空
//所以要进行||之后的判断 否则只进行前面的就可以
if(T->data!=0) //0 00 的情况
{
counts++;
printf(“%d\t”, T->data);
}
}
CountLeaf(T->lchild, counts);//一定要放在if(T)里面 否则直接进行
CountLeaf(T->rchild, counts);
}
return; //不加return也可以
}

int CountLeaf(BiTree T) //树的叶子数 法二
//从根开始遍历直到找到第一个叶子 才开始计数
{
int num1, num2; //不能给初值 否则递归时每次都进行初始化 将左右子树分开看
if(T)
{
if((!T->lchild && !T->rchild)||(T->lchild->data==0 && T->rchild->data==0))
{
if(T->data!=0)
{
return 1;
}
else
return 0;
}
num1=CountLeaf(T->lchild);
num2=CountLeaf(T->rchild);
}
return (num1+num2); //4 5 6 则一次进行两个叶子的求和(1+1)
}

void CountChild(BiTree T, int &counts) //树的单孩子结点个数并打印
{
if(T && (T->lchild||T->rchild))//不可以用 T->rchild->data!=0 || T->lchild->data!=0 当T为空时无法进行
//也不可以用(T && T->data!=0)????????????
//按照我建立的原则 难道不应该是只要该结点值不是零就一定会有两个孩子么
{
if((T->lchild->data==0 && T->rchild->data!=0) || (T->rchild->data==0 && T->lchild->data!=0))
{
counts++;
printf(“%d\t”, T->data);
}
CountChild(T->lchild, counts);
CountChild(T->rchild, counts);
}
return;
}

int getDepth(BiTree T) //树的深度 从叶子开始数
{
int left=0, right=0, length=0;
if(T)
{
left=getDepth(T->lchild);
right=getDepth(T->rchild);
}
length=(left>right?left:right);
return length+1;
}

int Level(BiTree T, BiTNode *N)//求某结点的层数 从该结点向上开始数
{
int i, j;
if(T == NULL)
{
return 0;
}
if(T == N)
{
return 1;
}
i = Level(T->lchild, N);
j = Level(T->rchild, N);
if(i != 0)
{
return (i + 1);
}
else if(j != 0)
{
return (j + 1);
}
else
{
return 0;
}
}

void PreStack(BiTree T)//非递归前序遍历
{
BiTree Tstack[20], p;
int top=1;
if(T)
{
top++;
Tstack[top]=T;//根节点入栈
while(top>1) //栈不为空则循环
{
p=Tstack[top];
top–;
if(p->data!=0)
printf(“%d\t”, p->data);
if(p->rchild)//右孩子入栈
{
top++;
Tstack[top]=p->rchild;
}
if(p->lchild) //左孩子入栈
{
top++;
Tstack[top]=p->lchild;
}
}
}
}

void PreOrderTraverse(BiTree T) //递归前序遍历
{
if(T)
{
Visit(T);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}

void InderOrderTraverse(BiTree T)//递归中序遍历
{
if(T)
{
InderOrderTraverse(T->lchild);
Visit(T);
InderOrderTraverse(T->rchild);
}
}

void InderStack(BiTree T)//非递归中序遍历
{
BiTree S[SIZE], p;
int top=-1;
p=T;
while(p || top>-1)
{
while(p)
{
top++;
S[top]=p;
p=p->lchild;
}
if(top>-1)
{
p=S[top];
if(p->data!=0)
printf(“%d\t”, p->data);
top–;
p=p->rchild;
}
}

}

void PostOrderTraverse(BiTree T) //递归后序遍历
{
if(T)
{
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
Visit(T);
}
}

void PostStack(BiTree T) /*树的非递归后序遍历:用一个栈保存返回的结点 先扫描根节点的所有左结点并入栈
出栈一个结点 然后扫描该节点的右结点并入栈 再扫描该右结点的所有左结点并入栈
当一个节点的左右子树均访问过后在访问该结点 不断进行直到栈空为止
难点:判断一个结点的右结点已经访问过 因此用p保存刚访问过的结点(初值为NULL)
若是t->right==p成立(在后序遍历中,t的右结点一定刚好在t之前访问)说明t的左右子树均已访问
*/
{
BiTree Tstack[20];
BiTree p;
int flag, top=-1;
do
{
while(T)
{
top++;
Tstack[top]=T;
T=T->lchild; //所有左孩子入栈
}
p=NULL; //p指向当前结点的前一个已访问过的结点
flag=1; //设置T的访问标记为已访问过
while(top!=-1 && flag)
{
T=Tstack[top];
if(T->rchild==p)//一开始时因为T走到了头 所以T为叶子节点 此时T->rchild=NULL 所以输出
//后来p就为T的左孩子
//只要是叶子就可以打印
{
if(T->data!=0)
printf(“%d\t”, T->data);
top–;
p=T;
}
else //用于将右孩子读入栈中
{
T=T->rchild;
flag=0; //此时下一次最近的while的条件就不满足了
}
}
} while(top!=-1);
}

void Level(BiTree T, BiTree p, int &h, int nowh)//找某结点在树中的高度 从根开始的
/*设h返回p所指结点的高度 其初值为-1 找到指定结点时返回其层次 否则返回-1
nowh作为一个中间变量在计算搜索层次时使用 其初值为1
*/
{
if(T==NULL) //为空 返回-1作为标志
h=-1;
else if(T->data==p->data) //找到结点
h=nowh;
else
{
Level(T->lchild, p, h, nowh+1); //在左子树中查找
if(h==-1)
Level(T->rchild, p, h, nowh+1); //在右子树中进行查找
}
}

BiTree disLink(BiTree T, int x)//以树中值为X的节点为新的根节点将原树进行拆分
{
BiTree p, finds;
if(T)
{
if(T->data==x)
{
p=T;
T=NULL;
return p;
}
else
{
finds=disLink(T->lchild, x);
if(!finds)
finds=disLink(T->rchild, x);
return finds;
}
}
else
return NULL;
}

void prePaint(BiTree T, int level)//树的图形化打印
{
if(!T)
{
now+=(int)pow(2, getDepth(T)-level-1);
return;
}
prePaint(T->lchild, level+1);
if(T->data==0)
now++;
else
buffer[level][now++]=T->data;
prePaint(T->rchild, level+1);
}
void Paint(BiTree T) //只能打印有最大层数限制的二叉树 但是不一定是完全二叉树
{
if (T == NULL)
return;
for (int i = 0; i<6; i++)
{
for (int j = 0; j<128; j++)
{
buffer[i][j] = INF;
}
}
hight = getDepth(T);
if (hight> 6)
{
printf(“树超过6层,无法打印”);
return;
}
prePaint(T, 0);
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 128; j++){
if (buffer[i][j] == INF)
printf(” “);
else
printf(“%d”, (int)buffer[i][j]);
}
printf(“\n”);
}
}

void Relese(BiTree T) //通过后序遍历 先释放根节点的左右子树所占空间 然后释放根节点所占空间
{
if(T)
{
Relese(T->lchild); //从右结点走到头的叶子开始释放
Relese(T->rchild);
free(T);
}
}

void Path(BiTree T, BiTree p)
{
BiTree stacks[SIZE], s;
int tag[SIZE];
int top=-1, i;
s=T;
printf(“路径:”);
do
{
while(s)
{
top++;
stacks[top]=s;//将S的所有左子树和左子树的左子树均存进stacks
tag[top]=0; //tag中每个元素的值均置零
s=s->lchild; //走到左子树的终点
}
if(top>-1)
{
if(tag[top]==1)
{
if(stacks[top]->data==p->data)//找到所求结点
{
for(i=1; i<=top; i++)
printf(“%d\t”, stacks[i]->data);
printf(“\n”);
break;
}
top–;
}
else
{
s=stacks[top];
if(top>0)
{
s=s->rchild;//从下向上找
tag[top]=1;
}
}
}
}while(s!=NULL || top!=-1);
}

void TranLevel(BiTree T) /*按层次遍历: 采用队列 先将根节点入队 然后退队 输出该结点 若它有左子树
便将左子树的根节点入队列 若它有右子树 便将右子树的根节点入队列
而出入队列的顺序始终为(假设都存在的情况下)
树: 1
2 3
4 5 6
则1入队出队并打印 输出左孩子2并入队 输出左孩子3并入队 此时队列顺序为:2 3
2出队 并打印2的左孩子和右孩子 输出之后2的左右孩子入队 此时队列顺序为 3 4 5
3出队并打印的3左孩子 打印之后左孩子入队 此时队列顺序为 4 5 6
*/
{
Queue q;
q.fron=q.rear=0; //将循环队列置空
if(T)
{
printf(“%d\t”, T->data);
}
q.data[q.rear]=T; //T结点入队 并将队尾指针后移
q.rear=(q.rear+1)%SIZE;

while(q.fron<q.rear)  //判断队列不为空{    T=q.data[q.fron];  //队头元素出队列 并移动队头指针    q.fron=(q.fron+1)%SIZE;    if(T->lchild)    {        if(T->lchild->data!=0)            printf("%d\t", T->lchild->data); //输出左孩子并令左孩子入队        q.data[q.rear]=T->lchild;        //一定要先输出在入队 否则队列的指针已经移动了        q.rear=(q.rear+1)%SIZE;    }    if(T->rchild)    {        if(T->rchild->data!=0)            printf("%d\t", T->rchild->data);      //输出右孩子并令右孩子入队        q.data[q.rear]=T->rchild;        q.rear=(q.rear+1)%SIZE;         //一定要先输出在入队 否则队列的指针已经移动了    }}

}

void Visit(BiTree T) //访问树的各个节点 在递归中被调用
{
if(T)
{
if(T->data==0)
return;
else
printf(“%d\t”, T->data);
}
else
return;
}

原创粉丝点击