树二叉树森林

Posted sanweizuiji

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树二叉树森林相关的知识,希望对你有一定的参考价值。

1 树的基本概念

树的度和m叉树

结点数 = 总度数 + 1 结点数=总度数+1 结点数=总度数+1

结点的度指的是结点有几个孩子(分支)

度为m的树

第i层至多有 m i − 1 m^i-1 mi1个结点(i≥1)

高度为h的m叉树

至多有个结点 1 − m h 1 − m \\frac1-m^h1-m 1m1mh

具有n个结点的m叉树的最小高度为

l o g m ( n ( m − 1 ) + 1 ) log_m(n(m-1)+1) logm(n(m1)+1)

2 二叉树

基本概念与性质

叶子结点比二分支结点多一个

设非空二叉树中度为0、1和2的结点个数分别为n0、n1和n2,则n0= n2 + 1

满二叉树

完全二叉树

二叉排序树

一棵二叉树或者是空二叉树,或者是具有如下性质的二叉树

左子树上所有结点的关键字均小于根结点的关键字

右子树上所有结点的关键字均大于根结点的关键字

左子树和右子树又各是一棵二叉排序树

平衡二叉树

树上任一结点的左子树和右子树的深度之差不超过1

二叉树的实现

顺序存储结构

链式存储结构

3 遍历二叉树及其应用(任何一棵二叉树的叶子结点在前序、中序和后序遍历序列中的相对次序都不发生改变)

先序遍历二叉树

#include <stdio.h>
#include <malloc.h>

// 自定义树的节点
typedef int treeElementDataType;
struct myBinaryTreeNode 
    treeElementDataType data;
    struct myBinaryTreeNode *leftChild;
    struct myBinaryTreeNode *rightChild;
;
typedef struct myBinaryTreeNode BinaryTreeNode;

void printTreeNode(BinaryTreeNode *node) 
    printf("%d", node->data);


// 先序遍历(先根遍历)
void preOrder(BinaryTreeNode *node) 
    if (node != NULL) 
        printTreeNode(node);
        preOrder(node->leftChild);
        preOrder(node->rightChild);
    

中序遍历二叉树

// 中序遍历
void inOrder(BinaryTreeNode *node) 
    if (node != NULL) 
        inOrder(node->leftChild);
        printTreeNode(node);
        inOrder(node->rightChild);
    

后序遍历二叉树

// 后序遍历
void postOrder(BinaryTreeNode *node) 
    if (node != NULL) 
        postOrder(node->leftChild);
        postOrder(node->rightChild);
        printTreeNode(node);
    


// 求树的深度
int treeDepth(BinaryTreeNode *node) 
    if (node == NULL) 
        return 0;
     else 
        int leftDepth = treeDepth(node->leftChild);
        int rightDepth = treeDepth(node->rightChild);
        return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
    

层次遍历二叉树

// ----------------------------------------------- 此块为队列的基本操作,需将队列元素的数据类型改为树的结点的指针
// 这里灵活定义队列元素的数据类型,因为后续可能将树的结点的指针作为数据类型
// typedef int queueElementDataType;
typedef BinaryTreeNode *queueElementDataType;

// 自定义队列元素结构体
struct myQueueElement 
    queueElementDataType data;
    struct myQueueElement *next;
;
typedef struct myQueueElement QueueElement;
// 自定义队列结构体
struct myQueue 
    QueueElement *front, *rear;
;
typedef struct myQueue Queue;

Queue *initQueue() 
    QueueElement *queueElement = (QueueElement *) malloc(sizeof(QueueElement));
    Queue *queue = (Queue *) malloc(sizeof(Queue));
    // 初始化时 front rear 都指向头结点
    queue->front = queue->rear = queueElement;
    queue->front->next = NULL;
    return queue;


// 返回入队后的队列
Queue *enQueue(Queue *queue, queueElementDataType x) 
    QueueElement *s = (QueueElement *) malloc(sizeof(QueueElement));
    s->data = x;
    s->next = NULL;
    // 将新节点入队
    queue->rear->next = s;
    // 将尾指针后移
    queue->rear = s;
    return queue;


// 返回出队后的队列
Queue *deQueue(Queue *queue) 
    if (queue->front == queue->rear) 
        printf("队列为空\\n");
     else 
        // temp 为队头结点
        QueueElement *temp = queue->front->next;
        queue->front->next = temp->next;
        // 如果此时出队的结点刚好是最后一个结点
        if (temp == queue->rear) 
            // 那么在修改头结点的指向后,还要将尾指针指向头结点
            queue->rear = queue->front;
        
        free(temp);
    
    return queue;


queueElementDataType getFirstElementData(Queue *queue) 
    return queue->front->next->data;


void printQueue(Queue *queue) 
    printf("----- 当前队列 -----\\n");
    printf("从上至下代表从队头到队尾\\n");
    // temp 为队头元素
    QueueElement *temp = queue->front->next;
    while (temp != NULL) 
        // 这里需要根据 queueElementDataType 的类型来决定如何打印
        printf("%d\\n", temp->data);
        temp = temp->next;
    


// ----------------------------------------------- 此块为队列的基本操作,需将队列元素的数据类型改为树的结点的指针

// 使用队列按层次遍历(BFS)
void levelOrder(BinaryTreeNode *root) 
    // 新建队列用来存储二叉树结点的数据
    Queue *queue;
    queue = initQueue();
    BinaryTreeNode *temp;
    // 树根入队
    queue = enQueue(queue, root);
    while (queue->front != queue->rear) 
        // 先保存即将出队的队头元素
        temp = getFirstElementData(queue);
        // 再进行出队操作
        queue = deQueue(queue);
        printTreeNode(temp);
        // 如果左孩子不为空,则将左孩子的数据入队
        if (temp->leftChild != NULL) 
            queue = enQueue(queue, temp->leftChild);
        
        // 如果右孩子不为空,则将右孩子的数据入队
        if (temp->rightChild != NULL) 
            queue = enQueue(queue, temp->rightChild);
        
    

4 线索树

线索二叉树知道了“前驱”和“后继”信息,就可以把二叉树看作一个链表结构,从而可以像遍历链表那样来遍历二叉树,进而提高效率。

如果ltag=0,表示指向节点的左孩子。如果ltag=1,则表示lchild为线索,指向节点的直接前驱

如果rtag=0,表示指向节点的右孩子。如果rtag=1,则表示rchild为线索,指向节点的直接后继

例 在线索化树中,每个结点必须设置一个标志来说明它的左、右链指向的是树结构信息还是线索化信息,若0标识树结构信息,1标识线索,对应叶结点的左右链域,应标识为(11)

叶节点没有必要标注左右子节点了,所以直接标记为线索,然后根据有无前后继再决定是否将线索指为空

例 线索二叉树的左线索指向其(遍历序列中的前驱),右线索指向(其遍历序列中的后继)

5 二叉树与森林

6 二叉排序树和平衡二叉树

6.1 最小不平衡树的右孩子的右子树上插入元素

6.2 最小不平衡树的右孩子的左子树上插入元素

右旋+左旋 结点66

6.3 最小不平衡树的左孩子的左子树上插入元素

6.4 最小不平衡树的左孩子的右子树上插入元素

左旋+右旋 结点60

7 哈夫曼树

例 一棵有n个叶子结点的哈夫曼树共有(2n-1)个结点

以上是关于树二叉树森林的主要内容,如果未能解决你的问题,请参考以下文章

如何用word画一幅二叉树图啊?

树二叉树森林之间的转换

数据结构-树树二叉树森林的转换

树和二叉树

小白科普丨何为树二叉树和森林?

树二叉树森林的转换