数据结构--二叉树实例分析

时间:2021-07-30 17:30:46
<pre name="code" class="cpp">#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include <stdlib.h>
#include <stdio.h>
/*自己来看看一个完整性的二叉树的例子,加深理解*/
#define MAX 100

typedef struct BNode/*二叉树的节点结构*/
{
    int data;
    struct BNode *l_child;
    struct BNode* r_child;
} BNode;
int e,z,i,j,k;//这是一些常用的变量。
BNode *t,*q,*p;
typedef struct//栈的顺序存储结构
{
    BNode *a[MAX];
    int top;
}sqstack;
typedef struct//循环队列存储结构,用于二叉树的按层次访问
{
    BNode *a[MAX];
    int front;
    int rear;
}squeue;
//这个用于创建一个节点,本来想传递一个参数x作为节点的值,发现这样不好,值是输入的,当作函数参数传递后递归不会用了
BNode *Creat_One()//所以通过scanf从缓冲区扫描比较好
{
    BNode *p;
    int x;
    scanf("%d",&x);
    if((p=(BNode*)malloc(sizeof(BNode)))==NULL)//用指针p申请一块内存,因为在堆空间,返回堆空间的地址不会出错
    {
        printf("创建头节点失败.\n");
        return NULL;
    }
    else
    {
        p->data=x;
        p->l_child=NULL;
        p->r_child=NULL;
    }
    return p;//p所指向的空间是动态申请来的,可以返回。

}
void push(sqstack *s,BNode *x)//这是入栈函数,进一个就指针位置就+1
{
    if(s->top==MAX)
    {
        printf("栈满了.\n");
    }
    else
    {
        s->top++;
        s->a[s->top]=x;//把x存入
    }
}
BNode * pop(sqstack *s)//出栈函数,每次取出一个栈位置指针减去一
{
    BNode *x;
    if(s->top==0)
    {
        printf("栈是空的.\n");
    }
    else
    {
        x=s->a[s->top];
        s->top--;
    }
    return x;//返回取出的栈的元素
}
/*队列处理函数*///这里是循环队列。省去判断是否假满
void enqueue(squeue *Q,BNode *x)//把x放在队列里面
{
    if((Q->rear+1)%MAX==Q->front)//采用取余数省去了判断队列是否假满,空去了一个存储单元
    {
        printf("队列满了");
    }
    else
    {

        Q->a[Q->rear]=x; Q->rear=(Q->rear+1)%MAX;
    }
}
BNode *delqueue(squeue*Q)
{ BNode *x;
    if(Q->rear==Q->front)
    {
        printf("队列是空的.\n");

    }
    else
    {
        x=Q->a[Q->front];
        Q->front=(Q->front+1)%MAX;//防止越界处理 return x;
    }
}/*模仿先序递归遍历法建立二叉树*/
BNode *Creat_Bt1()//对比Creat_One函数进行的递归
{ //缺点,递归不断的调用自身,不知道什么什么时候结束,对于每次调用都要对最后的节点复制0程序才知道结束
    //输入的数据是2^0+2^1+...2^n个,需要输入0来告诉程序结束的个数是2^(n+1)个
    BNode *t; printf("\ndata=");
    scanf("%d",&e); if(e==0) t=NULL;
    else { t=(BNode*)malloc(sizeof(BNode));
        t->data=e; t->l_child=Creat_Bt1();/*获得新的指针值*/
        t->r_child=Creat_Bt1(); } return t;}/*非递归*///这是根据二叉树的性质来写的,关键是对性质的理解
/*对于具有N个节点的完全二叉树,如果按照从上到下和从左到有的顺序,
对二叉树的所有节点从1开始按顺序编号 对于任意的序号i的节点有 1.如果i>1,
则序号i的结点的双亲节点的序号是/2 i=1就是根结点无双亲节点 2.如果2i<=n则序号i的结点的左孩子节点的序号是2i,
如果2*i大于n节点无左孩子 3.如果2*i+1<=n序号为i的节点的右孩子的序号2*i+1,否则i的结点无右孩子*/
BNode *Creat_Bt0()
{ BNode *t,*p,*v[20];
    printf("\n i data=?");
    scanf("%d %d",&i,&e);
    while(i!=0&&e!=0)
    {
        p=(BNode*)malloc(sizeof(BNode));
        p->data=e; p->r_child=NULL;
        p->l_child=NULL; v[i]=p;
        if(i==1)
        {
            t=p;
        }
        else { j=i/2; if(i%2==0)
            {
                v[j]->l_child=p;
            } else { v[j]->r_child=p; }
        }
        printf("\n i data=?");
        scanf("%d %d",&i,&e);
    } return t;}
/*先根序遍历*/
void preorder(BNode *p)
{ if(p)
    { printf("%3d",p->data);
        preorder(p->l_child);
        preorder(p->r_child);
    }
}
/*中根序遍历,递归*/
void inorder(BNode*p)
{ if(p)
    { inorder(p->l_child);
        printf("%3d",p->data);
        inorder(p->r_child);
    }}
/* 非递归中根遍历*/
void inorder_2(BNode *t)
{ sqstack s; BNode *p;
    s.top=0; push(&s,t);
    while(s.top!=0)
    { while(s.a[s.top]!=NULL)
        {
            p=s.a[s.top];
            push(&s,p->l_child);
        } p=pop(&s); if(s.top!=0)
        { p=pop(&s);
            printf("%3d",p->data);
            push(&s,p->r_child);
        }
    }
}
void level(BNode *t)
{ squeue q; BNode *p;
    q.front=0; q.rear=0;
    enqueue(&q,t);
    while(q.rear!=q.front)
    { p=delqueue(&q);
        printf("%3d",p->data);
        if(p->l_child)enqueue(&q,p->l_child);
        if(p->r_child)enqueue(&q,p->r_child);
    }
    printf("\n");}
int e,z,i,j,k;BNode *t,*q,*p;
void main()
{
    do {
        printf("\n\n");
        printf("\n\n 0.建立二叉树方法0");
        printf("\n\n 1.建立二叉树方法1");
        printf("\n\n 2.中序递归二叉树");
        printf("\n\n 3.中序非递归二叉树");
        printf("\n\n 4.按层遍历二叉树");
        printf("\n\n 5.结束");
        printf("请输入选择:\n");
        scanf("%d",&k);
        switch(k)
        {   case 0:
            {
                printf("输入负数结束\n");
                t=Creat_Bt0(); preorder(t);
                break;
            }
            case 1:
            {
                printf("依次输入数据,空孩子也要输入0");
                t=Creat_Bt1(); preorder(t); break;
            }
            case 2:
            { printf("中序递归遍历:\n");
                inorder(t);
                break;
            }
            case 3:
            {
                printf("中序非递归遍历:\n");
                inorder_2(t);
                break;
            }
            case 4:
            { printf("按层次遍历:\n");
                level(t); break; }
            case 5:
                exit(0);
            }
    }
    while(k>=0&&k<=5); printf("再见\n");
}