数据结构-树

427 阅读8分钟

前言

今天开始对数据结构-树进行学习。

树结构

逻辑结构中,树结构数组非线性结构。结构中结点是一对多的关系。下图中是一般树示意图:

树结构中的概念

  1. 树的高度:从下至上,0开始。
  2. 树的深度:从上至下,0开始。
  3. 树的层:从上至下,1开始。
  4. 树结点的度:子结点的数量。例如图片中的E结点,有两个子结点,度为2;H结点有1个子结点,度为1;G结点没有子结点,度为0。

高度和深度这两个概念容易混淆。个人理解方式是,在真是世界里,描述一个东西高度都是从下往上测量,比如身高。深度通常是从上往下测量,比如水池深度。这样理解起来比较清晰好记。

树结构分类

树结构可根据树本身的特性进行分类,上图中的树结构,我们通常称为“一般树”。如果树中只有一个结点,我们称之为“只有根结点树”。

二叉树

计算机中的数据结构都有相关的规律性,但一般树中的结点是一对多的关系。这种关系对于开发中意义不是很大,所以进而演化出二叉树的模式。如图:

图中可见二叉树的结点中可以有0~2个子结点。

二叉树分类

通过二叉树的特性,可分为满二叉树和完全二叉树,其实满二叉树是完全二叉树中的一种特殊情况。而完全二叉树是由满二叉树引导出来的。

二叉树的性质

  1. 二叉树的第i层上最多有2^(i-1)个结点。
  2. 深度为k的二叉树最多有2^k -1个结点(k>=1)。
  3. 对于任何一颗二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2 + 1。例如上图中:n0=5(6、7、8、9、10是终端结点),n2=4(1、2、3、4)。
  4. 具有n个结点的完全二叉树深度为log(n)+1
  5. 对具有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;
}