二叉树实例
来源:互联网 发布: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
阅读全文
0 0
- 线索二叉树实例
- 平衡二叉树 实例
- 构建二叉树实例
- 二叉树遍历实例
- 二叉树实例
- 线索二叉树实例
- (2011.08.13)二叉树实例
- C#二叉树简易实例
- 数据结构--二叉树实例分析
- 二叉树 C 实例代码
- C#二叉树简易实例
- 二叉树遍历实例 - Java
- 二叉树的实例化
- 测试二叉搜索树的实例
- 二叉树建立及遍历 实例
- 平衡二叉树实现的实例
- 递归遍历二叉树代码实例
- 循环遍历二叉树代码实例
- i = i++; in JAVA
- FreeSWITCH加载非默认模块
- hdu1404 博弈
- k近邻理论与实践
- UE4学习笔记22th:配置游戏模式
- 二叉树实例
- 优美的链式前向星
- 数据结构 图的遍历 C语言版
- ImageJ 综述
- HTTP 协议入门
- hql/sql语句查询英文字符时是不区分大小写的
- Android应用组件之加载器(Loader)
- 数据结构 图的建立 C语言版
- 素数距离问题