二叉树实例

来源:互联网 发布:php oa 开源 编辑:程序博客网 时间:2024/05/29 16:21

二叉树:

二叉树性质:    1.第i层的节点总数最多有2i-1个结点    2.深度额我k的二叉树最多有2k-1个结点,最少有k个结点    3.二叉树,如果其叶结点为n0,而度为2的结点总数为n2,则n0=n2+1    4.有n个结点的完全二叉树的深度k为:k=[log2n]+1    5.有n个结点的完全二叉树各结点如果用顺序表存储,对任意结点i,有如下关系:        如果 i != 1,则其父节点的编号为i/2        如果 2*i <= n,则其左子树根节点的编号为2*i;若 2*i>n,则无左子树        如果 2*i+1 <= n,则右子树根节点的编号为2*i+1;若 2*i+1>n,则无右子树

二叉树的存储:

    1.顺序存储结构:若是完全二叉树,则某个结点的父节点=(该节点的位置/2),其子节点为(该节点的位置*2)和(该节点的位置*2+1),从1开始计算;                    若不是完全二叉树,可以在没有结点数据的位置置为空,模拟成完全二叉树(然后同上);

这里写图片描述

            如图二叉树,如果使用顺序存储结则数据结构定义为如下sqTree数组:                #definde MAXSIZE 100                typedef int DATA;                typedef DATA SeqBinTree[MAXSIZE];                SeqBinTree sqTree;       //顺序存储结构            对于上面的完全二叉树,最终使用顺序存储结构后,得到的效果为如下图:

这里写图片描述

            通过图中规律可发现:                1.求某个结点的子结点,只需把该结点在数组中的位置(非下标,而是下标+1)乘2,则子节点为所得的位置的结点以及其下一个结点;                2.求某个结点的父结点,只需把该结点在数组中的位置除以2,说的的商即为父结点位置;                3.对于非完全二叉树,可以模拟为完全二叉树使用,即把没有结点的位置“空出来”,表示没有结点,如图,假设I节点不存在,则9的位置即为空            顺序存储结构问题:占用内存连续且必须提前分配足够的内存,不能扩容,不够灵活,所以一般使用链式存储结构存储树;

这里写图片描述

    2.二叉链式存储结构:数据结构定义包括一个数据,一个指向左子树的指针,一个指向右子树的指针(没有则赋值为空);        对于链式存储结构,可以使用树的基本原理,即树相当于多个子树嵌套,树中包含多个子树,而子树也是一个树结构,所以算法中经常涉及到递归调用,递归查询;        其中left指针存放左子树的根节点的地址,right指针存放右子树的根节点的地址;    2.三叉链式存储结构:数据结构定义包括一个数据,一个指向左子树的指针,一个指向右子树的指针以及一个指向父结点的指针

二叉树的遍历:

    1.先序遍历(DLR): 顺序:根-左-右    2.中序遍历(LDR): 顺序:左-根-右    3.后序遍历(LRD)" 顺序:左-右-跟    4.按层遍历

BinTree.h

    #include <stdio.h>    #define QUEUE_MAXSIZE 50    typedef char DATA;          //定义树结点的元素类型    typedef struct ChainTree{   //定义二叉树结点类型        DATA data;              //结点数据        struct ChainTree *left; //左子树结点指针        struct ChainTree *right;//右子树结点指针    }ChainBinTree;    /*初始化二叉树根节点*/    ChainBinTree *binTreeInit(ChainBinTree *node);    /*添加数据到二叉树*/    int binTreeAddNode(ChainBinTree *bt, ChainBinTree *node, int n);    /*返回左子节点和右子节点*/    ChainBinTree *binTreeLeft(ChainBinTree *bt);    ChainBinTree *binTreeRight(ChainBinTree *bt);    /*判断二叉树是否为空*/    int binTreeIsEmpty(ChainBinTree *bt);    /*求二叉树深度*/    int binTreeDepth(ChainBinTree *bt);    /*寻找值为data的结点*/    ChainBinTree *binTreeFind(ChainBinTree *bt, DATA data);    /*清空树*/    void binTreeClear(ChainBinTree *bt);    /********************************树的遍历***************************/    /*遍历树要进行的操作*/    void oper(ChainBinTree *p);    /*先序遍历*/    void binTree_DLR(ChainBinTree *bt, void (*oper) (ChainBinTree *p));    /*中序遍历*/    void binTree_LDR(ChainBinTree *bt, void (*oper) (ChainBinTree *p));    /*后序遍历*/    void binTree_LRD(ChainBinTree *bt, void (*oper) (ChainBinTree *p));    /*按层遍历*/    void binTree_Level(ChainBinTree *bt, void (*oper) (ChainBinTree *p));

BinTree.c

    #include "BinTree.h"    /*初始化二叉树根节点*/    ChainBinTree *binTreeInit(ChainBinTree *node){        if(node != NULL)            return node;        else            return NULL;    }    /*添加数据到二叉树 bt为要添加的位置的父节点 node为添加的节点 n=1表示左子树 n=2表示右子树*/    int binTreeAddNode(ChainBinTree *bt, ChainBinTree *node, int n){        if(bt == NULL){            printf("父节点不存在!\n");            return 0;        }        switch(n){            //添加到左子树            case 1:                if(bt->left){                    printf("左子树不为空, 不能添加!\n");                    return 0;                }else{                    bt->left = node;                }                break;            case 2:                if(bt->right){                    printf("右子树不为空, 不能添加!\n");                    return 0;                }else{                    bt->right = node;                }                break;            default:                printf("参数错误");                return 0;        }        return 1;    }    /*返回左子节点和右子节点*/    ChainBinTree *binTreeLeft(ChainBinTree *bt){        if(bt)            return bt->left;        else            return NULL;    }    ChainBinTree *binTreeRight(ChainBinTree *bt){        if(bt)            return bt->right;        else            return NULL;    }    /*判断二叉树是否为空*/    int binTreeIsEmpty(ChainBinTree *bt){        if(bt)            return 0;        else            return 1;    }    /*求二叉树深度*/    int binTreeDepth(ChainBinTree *bt){        int dep1,dep2;        if(bt == NULL){            return 0; //空树        }else{            //递归调用 递归子树直到最后的叶子结点没有子节点,返回0            dep1 = binTreeDepth(bt->left);            dep2 = binTreeDepth(bt->right);            //返回子树中深度更深的子树的深度            if(dep1 > dep2){                return dep1 + 1;            }else{                return dep2 + 1;            }        }    }    /*寻找值为data的结点*/    ChainBinTree *binTreeFind(ChainBinTree *bt, DATA data){        ChainBinTree *p;        if(bt == NULL)            return NULL;        else{            if(bt->data == data){                return bt;            }else{                //递归调用                if(p = binTreeFind(bt->left, data))                    return p;                else if(p = binTreeFind(bt->right, data))                    return p;                else                    return NULL;            }        }    }    /*清空树*/    void binTreeClear(ChainBinTree *bt){        if(bt){            binTreeClear(bt->left);            binTreeClear(bt->right);            free(bt);        }        return;    }    /********************************树的遍历***************************/    /*遍历树要进行的操作*/    void oper(ChainBinTree *p){        printf("%c \t", p->data);        return;    }    /*先序遍历*/    void binTree_DLR(ChainBinTree *bt, void (*oper)(ChainBinTree *p)){        if(bt){            oper(bt);            binTree_DLR(bt->left, oper);            binTree_DLR(bt->right, oper);        }        return;    }    /*中序遍历*/    void binTree_LDR(ChainBinTree *bt, void (*oper) (ChainBinTree *p)){        if(bt){            binTree_LDR(bt->left, oper);            oper(bt);            binTree_LDR(bt->right, oper);        }        return;    }    /*后序遍历*/    void binTree_LRD(ChainBinTree *bt, void (*oper) (ChainBinTree *p)){        if(bt){            binTree_LRD(bt->left, oper);            binTree_LRD(bt->right, oper);            oper(bt);        }        return;    }    /*按层遍历*/    void binTree_Level(ChainBinTree *bt, void (*oper) (ChainBinTree *p)){        ChainBinTree *p;        ChainBinTree *q[QUEUE_MAXSIZE];         //定义一个顺序队列,先进先出        int head = 0, tail = 0;                 //队首队尾序号        if(bt){                                 //如果队首指针不为空            tail = (tail + 1) % QUEUE_MAXSIZE;  //计算循环队列队尾序号            q[tail] = bt;                       //把二叉树根指针进队        }        //本质上:每次tail进行两次改变(只有当是完全二叉树,其他情况则有不同),然后head进行一次改变,实现按层把树的元素放到队列中去        //即每次把head指向的结点的两个子节点存放到队列,并且把该结点进行操作(执行oper方法);        //当tail不再增加,也就是说再也没有哪个未读取得结点还拥有子节点了,则剩下的就是把队列中剩余未操作的结点进行操作,直到队列为空,即head==tail,退出循环        while(head != tail){                    //队列不为空, 进行循环            head = (head + 1) % QUEUE_MAXSIZE;  //计算循环队列的队首序号            p = q[head];                        //获取队列元素            oper(p);                           //处理队首元素            if(p->left != NULL){                //若结点存在左子树, 则左子树指针进队                tail = (tail + 1) % QUEUE_MAXSIZE;                q[tail] = p->left;            }            if(p->right != NULL){                //若结点存在右子树, 则右子树指针进队                tail = (tail + 1) % QUEUE_MAXSIZE;                q[tail] = p->right;            }        }        return;    }

按层遍历过程
按层遍历过程。。。

main.c

    #include <stdio.h>    #include "BinTree.h"    ChainBinTree *initRoot(){        ChainBinTree *node;        if(node = (ChainBinTree *)malloc(sizeof(ChainBinTree))){            printf("\n输入根数据结点");            scanf("%s", &node->data);            node->left = NULL;            node->right = NULL;            return binTreeInit(node);        }        return NULL;    }    void addNode(ChainBinTree *bt){        ChainBinTree *node, *parent;//存放新增的结点和要挂接的父节点        DATA data;        char select;        if(node = (ChainBinTree *)malloc(sizeof(ChainBinTree))){//分配内存            printf("\n输入二叉树结点数据:");            fflush(stdin);            scanf("%s", &node->data);            node->left = NULL;            node->right = NULL;            printf("输入父结点数据:");            fflush(stdin);            scanf("%s",&data);            parent = binTreeFind(bt, data);//查找结点            if(!parent){                printf("未找到结点\n");                free(node);                return;            }            printf("1.添加到左子树\n2.添加到右子树");            do{                select = getch();                select -= '0';                if(select == 1 || select == 2){                    binTreeAddNode(parent, node, select);//添加结点到二叉树                }            }while(select != 1 && select != 2);            return;        }    }    int main()    {        ChainBinTree *root = NULL;          //root为指向二叉树根节点的指针        char select;        void (*oper1)();                    //指向函数的指针        oper1 = oper;                       //指向具体操作的函数        do{            printf("\n1.设置二叉树根元素 2.添加二叉树结点  3.先序  4.中序  5.后序  6.按层  7.二叉树深度  0.退出");            select = getch();            switch(select){                case '1':                    root = initRoot();                    break;                case '2':                    addNode(root);                    break;                case '3':                    binTree_DLR(root, oper1);                    printf("\n");                    break;                case '4':                    binTree_LDR(root, oper1);                    printf("\n");                    break;                case '5':                    binTree_LRD(root, oper1);                    printf("\n");                    break;                case '6':                    binTree_Level(root, oper1);                    printf("\n");                    break;                case '7':                    printf("%d", binTreeDepth(root));                    break;            }        }while(select != '0');        binTreeClear(root);        root = NULL;        return 0;    }

个人博客 欢迎来访: http://ay2626.me

原创粉丝点击