前言
今天开始对数据结构-树进行学习。
树结构
逻辑结构中,树结构数组非线性结构。结构中结点是一对多的关系。下图中是一般树示意图:
树结构中的概念
- 树的高度:从下至上,0开始。
- 树的深度:从上至下,0开始。
- 树的层:从上至下,1开始。
- 树结点的度:子结点的数量。例如图片中的E结点,有两个子结点,度为2;H结点有1个子结点,度为1;G结点没有子结点,度为0。
高度和深度这两个概念容易混淆。个人理解方式是,在真是世界里,描述一个东西高度都是从下往上测量,比如身高。深度通常是从上往下测量,比如水池深度。这样理解起来比较清晰好记。
树结构分类
树结构可根据树本身的特性进行分类,上图中的树结构,我们通常称为“一般树”。如果树中只有一个结点,我们称之为“只有根结点树”。
二叉树
计算机中的数据结构都有相关的规律性,但一般树中的结点是一对多的关系。这种关系对于开发中意义不是很大,所以进而演化出二叉树的模式。如图:
二叉树分类
通过二叉树的特性,可分为满二叉树和完全二叉树,其实满二叉树是完全二叉树中的一种特殊情况。而完全二叉树是由满二叉树引导出来的。
二叉树的性质
- 二叉树的第i层上最多有2^(i-1)个结点。
- 深度为k的二叉树最多有2^k -1个结点(k>=1)。
- 对于任何一颗二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2 + 1。例如上图中:n0=5(6、7、8、9、10是终端结点),n2=4(1、2、3、4)。
- 具有n个结点的完全二叉树深度为log(n)+1
- 对具有n个结点的完全二叉树,如果按照从上之下和从左至右的顺序对二叉树的所有结点从1开始编号,则对任意序号i的结点有:
- i>1,i的双亲结点序号为i/2
- i=1,i为根结点,无双亲结点
- 2i<n,i结点的左孩子为2i
- 2i>n,i结点无左孩子
- 2i+1<=n,i结点的右孩子为2i+1
- 2i+1>n,i结点无右孩子
二叉树的遍历方式
二叉树的遍历方式有:层序遍历,前序遍历,中序遍历和后续遍历。
- 层序遍历:比较直观的遍历方式,按照层级,逐层遍历元素。
- 前序遍历:“根-左-右”的方式
- 中序遍历:“左-根-右”的方式
- 后续遍历:“左-右-根”的方式
二叉树存储方式
顺序存储
使用数组来存储二叉树中结点
代码
#include <stdio.h>
#include <string.h>
#include "math.h"
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100
#define MAX_TREE_SIZE MAXSIZE
typedef int Status;
typedef int ElemType;
typedef ElemType SqBiTree[MAX_TREE_SIZE];
typedef struct {
int level;//层
int order;//层中的序号
}Postion;
//初始化树
Status initBiTree(SqBiTree T) {
memset(T, 0, sizeof(int) * MAX_TREE_SIZE);
return OK;
}
//创建树
Status createBiTree(SqBiTree T) {
int i = 0;
while (i < 10) {
T[i] = i+1;
i++;
}
return OK;
}
//清空树
#define clearBiTree initBitree
//是否为空树
Status biTreeEmpty(SqBiTree T) {
if (T[0] == 0) {
return TRUE;
} else {
return FALSE;
}
}
//树深度
int biTreeDepth(SqBiTree T) {
int i;
for (i = MAX_TREE_SIZE - 1; i >= 0; i++) {
if (T[i] != 0) {
break;
}
}
int j = -1;
do {
j++;
} while (powl(2, j) <= i);
return j;
}
//找到指定节点
ElemType nodeValue(SqBiTree T, Postion pos) {
//树的数据结构是从0开始,外界传进来的参数层数和本层序列号都是从1开始的
//层:2的(pos.level-1)次幂
//序列号:pos.order - 2
//序列号减2原因:根是从0开始,到指定层后也是要从0开始。外界传进来的值都是从1开始,所以需要-2.
//例如找第10个的结点,对应的数组下标是9,应该在4层3的位置。2^(4-1) + 3 - 2 = 9
return T[(ElemType)powl(2, pos.level - 1) + pos.order - 2];
}
//根节点
Status root(SqBiTree T, ElemType *e) {
if (biTreeEmpty(T)) {
return ERROR;
} else {
*e = T[0];
return OK;
}
}
//插入
Status assign(SqBiTree T, Postion pos, ElemType value) {
int i = powl(2, pos.level-1) + pos.order - 2;
//没有父节点
if (value != 0 && T[(i+1)/2-1] == 0) {
return ERROR;
}
//有子节点
if (value == 0 && (T[i*2+1] != 0 || (T[i*2+2] != 0))) {
return ERROR;
}
T[i] = value;
return OK;
}
//父节点
ElemType parent(SqBiTree T, ElemType value) {
//空树
if (T[0] == 0) {
return 0;
}
for (int i = 1; i < MAX_TREE_SIZE; i++) {
if (T[i] == value) {
return T[(i+1)/2-1];
}
}
return 0;
}
//左孩子节点
ElemType leftChild(SqBiTree T, ElemType value) {
if (T[0] == 0) {
return 0;
}
for (int i = 1; i < MAX_TREE_SIZE-1; i++) {
if (T[i] == value) {
return T[i*2+1];
}
}
return 0;
}
//有孩子节点
ElemType rightChild(SqBiTree T, ElemType value) {
if (T[0]== 0) {
return 0;
}
for (int i = 1; i < MAX_TREE_SIZE-1; i++) {
if (T[i] == value) {
return T[i*2+2];
}
}
return 0;
}
//兄弟左节点
ElemType leftSibling(SqBiTree T, ElemType value) {
if (T[0] == 0) {
return ERROR;
}
for (int i = 1; i < MAX_TREE_SIZE - 1; i++) {
if (T[i] == value && i % 2 == 0) {
return T[i-1];
}
}
return 0;
}
//兄弟右节点
ElemType rightSibling(SqBiTree T, ElemType value) {
if (T[0] == 0) {
return ERROR;
}
for (int i = 1; i < MAX_TREE_SIZE - 1; i++) {
if (T[i]==0 && i%2==1) {
return T[i+1];
}
}
return 0;
}
//层遍历
void levelOrderTraverse(SqBiTree T) {
int i = MAXSIZE - 1;
while (T[i] == 0) {
i--;
}
for (int j = 0; j <= i; j++) {
if (T[j] != 0) {
printf("%d ", T[j]);
}
}
printf("\n");
}
//前序遍历
void preTraverse(SqBiTree T, int e) {
printf("%d ", T[e]);
if (T[2 * e + 1] != 0) {
preTraverse(T, 2*e+1);
}
if (T[2*e+2] != 0) {
preTraverse(T, 2*e+2);
}
}
void preOrderTraverse(SqBiTree T) {
if (!biTreeEmpty(T)) {
preTraverse(T, 0);
}
printf("\n");
}
//中序遍历
void inTraverse(SqBiTree T, int e) {
if (T[2*e+1] != 0) {
inTraverse(T, 2*e+1);
}
printf("%d ", T[e]);
if (T[2*e+2] != 0) {
inTraverse(T, 2*e+2);
}
}
void inOrderTraverse(SqBiTree T) {
if (!biTreeEmpty(T)) {
inTraverse(T, 0);
}
printf("\n");
}
//后续遍历
void postTraverse(SqBiTree T, int e) {
if (T[2*e+1] != 0) {
postTraverse(T, 2*e+1);
}
if (T[2*e+2] != 0) {
postTraverse(T, 2*e+2);
}
printf("%d ", T[e]);
}
void postOrderTraverse(SqBiTree T) {
if (!biTreeEmpty(T)) {
postTraverse(T, 0);
}
printf("\n");
}
运行
int main(int argc, const char * argv[]) {
// insert code here...
printf("Hello, 二叉树顺序存储!\n");
Status iStatus;
Postion p;
ElemType e;
SqBiTree T;
initBiTree(T);
createBiTree(T);
printf("简历二叉树后是否为空:%d(1:是,0:否)\n", biTreeEmpty(T));
printf("树深度:%d\n", biTreeDepth(T));
p.level = 3;
p.order = 2;
e=nodeValue(T, p);
printf("第%d层第%d个结点的值:%d\n", p.level, p.order, e);
iStatus = root(T, &e);
if (iStatus) {
printf("二叉树的根为:%d\n",e);
}else
{
printf("树为空,无根!\n");
}
//向树中3层第2个结点位置上结点赋值99
e = 99;
assign(T, p, e);
//获取树中3层第2个结点位置结点的值是多少:
e=nodeValue(T,p);
printf("第%d层第%d个结点的值: %d\n",p.level,p.order,e);
//找到e这个结点的双亲;
printf("结点%d的双亲为%d_",e,parent(T, e));
//找到e这个结点的左右孩子;
printf("左右孩子分别为:%d,%d\n",leftChild(T, e),rightChild(T, e));
//找到e这个结点的左右兄弟;
printf("结点%d的左右兄弟:%d,%d\n",e,leftSibling(T, e),rightSibling(T, e));
assign(T, p, 5);
printf("二叉树T层序遍历:");
levelOrderTraverse(T);
printf("二叉树T先序遍历:");
preOrderTraverse(T);
printf("二叉树T中序遍历:");
inOrderTraverse(T);
printf("二叉树T后序遍历:");
postOrderTraverse(T);
return 0;
}
链式存储
#include <stdio.h>
#include "string.h"
#include "stdlib.h"
#include "math.h"
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100
typedef int Status;
int indexs = 1;
typedef char String[24];
String str;
Status strAssign(String T, char *chars) {
if (strlen(chars) > MAXSIZE) {
return ERROR;
} else {
T[0] = strlen(chars);
for (int i = 1; i <= T[0]; i++) {
T[i] = *(chars+i-1);
}
return OK;
}
}
typedef char ElemType;
ElemType Nil = ' ';
typedef struct BiTNode{
ElemType data;
struct BiTNode *lchild, *rchild;
}BiTnode, *BiTree;
Status initBiTree(BiTree *T) {
*T=NULL;
return OK;
}
void DestoryBiTree(BiTree *T) {
if (*T) {
if ((*T)->lchild) {
DestoryBiTree(&(*T)->lchild);
}
if ((*T)->rchild) {
DestoryBiTree(&(*T)->rchild);
}
free(*T);
*T=NULL;
}
}
#define ClearBiTree DestoryBiTree
void createBiTree(BiTree *T) {
ElemType ch;
ch = str[indexs++];
if (ch == '#') {
*T = NULL;
} else {
*T = (BiTree)malloc(sizeof(BiTnode));
if (!*T) {
exit(OVERFLOW);
}
(*T)->data = ch;
createBiTree(&(*T)->lchild);
createBiTree(&(*T)->rchild);
}
}
Status biTreeEmpty(BiTree T) {
if (T) {
return FALSE;
} else {
return TRUE;
}
}
int biTreeDepth(BiTree T) {
int i,j;
if (!T) {
return 0;
}
if (T->lchild) {
i=biTreeDepth(T->lchild);
} else {
i=0;
}
if (T->lchild) {
j=biTreeDepth(T->rchild);
} else {
j=0;
}
return i>j?i+1:j+1;
}
ElemType root(BiTree T) {
if (biTreeEmpty(T)) {
return Nil;
}
return T->data;
}
ElemType value(BiTree p) {
return p->data;
}
void assign(BiTree p, ElemType value) {
p->data = value;
}
void preOrderTraverse(BiTree T) {
if (T==NULL) {
return;
}
printf("%c", T->data);
preOrderTraverse(T->lchild);
preOrderTraverse(T->rchild);
}
void inOrderTraverse(BiTree T) {
if (T==NULL) {
return;
}
inOrderTraverse(T->lchild);
printf("%c", T->data);
inOrderTraverse(T->rchild);
}
void postOrderTraverse(BiTree T) {
if (T==NULL) {
return;
}
postOrderTraverse(T->lchild);
postOrderTraverse(T->rchild);
printf("%c", T->data);
}
运行
int main(int argc, const char * argv[]) {
// insert code here...
printf("Hello, 二叉树链式存储!\n");
BiTree T;
ElemType e1;
initBiTree(&T);
strAssign(str,"ABDH#K###E##CFI###G#J##");
createBiTree(&T);
printf("二叉树是否为空%d(1:是 0:否),树的深度=%d\n",biTreeEmpty(T),biTreeDepth(T));
e1=root(T);
printf("二叉树的根为: %c\n",e1);
printf("\n前序遍历二叉树:");
preOrderTraverse(T);
printf("\n中序遍历二叉树:");
inOrderTraverse(T);
printf("\n后序遍历二叉树:");
postOrderTraverse(T);
printf("\n");
return 0;
}