树与二叉树
非线性结构:一对多关系。
概念
- 度数: 节点的孩子数量,书的度数=节点中最大度数;
- 层次: 节点在树的第几层(根节点层数=1);
- 高度/深度: 最大层数;
- 路径长度=从root到该节点的路径边数;
- 森林= n棵互不相交的树(森林+root=一棵树);
二叉树
定义: 所有节点只有最多两个孩子的树。
性质:
1. 严格区分左右孩子(即使只有1个孩子);
2. 第i层上的 节点最多为 2^(i-1)个;(根节点层数=1)
3. 深度为n的二叉树的最多节点数=2^n - 1 个节点;(每个非叶子节点都有2个孩子,即满二叉树)
4. 叶子树 = 度数为2的节点数+1;
5. 完全二叉树:
① 度数小于2的节点在最下面2层;
② 最下面一层叶子集中在最左边。
二叉树的储存
也是代码实现创建二叉树的原理
完全二叉树编号方式从上到下,从左到右编号,root=1;
假设节点数为 n, 某节点编号 i
- 当i>1, 不是根节点,该节点有父节点。 该节点的编号是i/2;
- 当 2*i<=n时, 有左孩子。编号为2*i; 否则,无孩子,该节点为叶子;
- 当 2*i+1 <=n, 有右孩子。编号为2*i+1; 否则,无孩子,为叶子;
二叉树的实现,一般采用链式
//bitree.h 完全二叉树
#ifndef _BI_TREE_H
#define _BI_TREE_H
#include <string.h>
#include <strings.h>
typedef int data_t;
typedef int bool;
typedef struct node_t{
data_t data;
struct node_t *lchild, *rchild;
}bitree_t;
//i是二叉树的起始编号,n是要创建的二叉树节点数
bitree_t* bitree_create(int i, int n);
//遍历二叉树的三种方法
void bitree_DLR(bitree_t *);
void bitree_LDR(bitree_t *);
void bitree_LRD(bitree_t *);
//使用队列方式 逐层遍历
void bitree_queueShow(bitree_t*);
//删除
bool bitree_destroy(bitree_t*);
#endif
//bitree.c
#include <stdio.h>
#include <stdlib.h>
#include "bitree.h"
#include "linkqueue.h" //用于使用队列方式遍历二叉树
bitree_t* bitree_create(int i, int n)
{
bitree_t* root = (bitree_t*) malloc (sizeof(bitree_t) );
if(NULL == root)
{
printf("Err: Create: malloc for root failed.\n");
return NULL;
}
bzero(root, sizeof(bitree_t));
root->data = i;
if( 2*i <= n) //2*i<n---有左孩子,其编号就是2×i
{
root->lchild = bitree_create(2*i, n);
}else{ //否则没有左孩子,本身就是叶子节点
root->lchild = NULL;
}
if(2*i + 1 <=n) //2*i+1 <=n ---有右孩子,编号就是2*i+1
{
root->rchild = bitree_create(2*i + 1, n);
}else{
root->rchild = NULL;
}
return root;
}
//遍历二叉树的三种方法
//先序遍历-递归调用
void bitree_DLR(bitree_t *root)
{
//当访问的二叉树为空时,结束操作
if(NULL == root)
{
return;
}
//先访问当前root节点
printf("%d,", root->data);
//再访问lchild
bitree_DLR(root->lchild);
//最后访问rchild
bitree_DLR(root->rchild);
}
//中序遍历
void bitree_LDR(bitree_t *root)
{
if(NULL == root)
{
return;
}
//lchild
bitree_DLR(root->lchild);
//root
printf("%d,", root->data);
//rchild
bitree_LDR(root->rchild);
}
void bitree_LRD(bitree_t *root)
{
if(NULL == root)
{
return;
}
//lchild
bitree_LDR(root->lchild);
//rchild
bitree_LDR(root->rchild);
//root
printf("%d,", root->data);
}
//使用队列方式 按照编号 逐层遍历
//这里需要先创建好队列数据结构,才能使用
void bitree_queueShow(bitree_t*root)
{
linkqueue_t* p = linkqueue_create();
if(NULL == p)
{
printf("Err: Queueshow(): malloc for temp linkqueue_t* failed.\n");
return;
}
if(NULL == root)
{
printf("Warning: Tree is empty.\n");
return;
}
linkqueue_en(p, root); //将root装入队列
//当队列不为空时,输出队头保存的节点
//并将该节点的孩子插入队尾
//最后将队头节点弹出
while(linkqueue_isEmpty(p) != TRUE)
{
linkqueue_en(root->lchild);
linkqueue_en(root->rchild);
printf("%d,", *(linkqueue_pop(p)) );
}
}