树、二叉树

本文详细介绍了树的概念,包括树的定义、特征、度数、节点分类,以及二叉树、满二叉树、完全二叉树的特性和性质。重点讲解了最优二叉树(哈夫曼树)和带权路径长度的概念,以及节点编号规则和二叉树的三种遍历方式(前序、中序、后序)。同时给出了C语言代码示例实现树的创建、遍历和释放操作。

概念

树(Tree)是n(n>=0)个节点的有限集合 T,它满足两个条件:
1)有且仅有一个特定的称为根(Root)的节点;
2)其余的节点可以分为m(m≥0)个互不相交的有限集合 T1、T2、……、Tm,
其中每一个集合又是一棵树,并称为其根的子树(Subtree)。
在这里插入图片描述

特征

一对多,每个节点最多有一个前驱,但可以有多个后继(根节点无前驱,叶节点无后继)。

名词解释

度数:

一个节点的子树的个数(一个节点的子树的个数称为该节点的度数)。

树 的度数:

树中节点的最大度数。

叶节点 或 终端节点:

度数为零的节点 。

分支节点 = 根节点 + 内部节点

度数不为零的节点。

内部节点:

除根节点以外的分支节点 (B,C,D,E,H)。

节点层次:

根节点的层次为1,根节点子树的根为第2层,以此类推。

树的深度或高度:

树中所有节点层次的最大值。
在这里插入图片描述

二叉树

二叉树(Binary Tree)是 n(n≥0)个节点的有限集合,它或者是空集(n=0),
或者是由一个根节点以及两棵互不相交的、分别称为左子树和右子树的二叉树组成。
二叉树严格区分左孩子和右孩子,即使只有一个子节点也要区分左右。
在这里插入图片描述

满二叉树

深度为k(k>=1)时节点为2^k - 1。
在这里插入图片描述

完全二叉树

只有最下面两层有 度数小于2 的节点,且最下面一层的叶节点集中在最左边的若干位置上。
在这里插入图片描述

性质

1、二叉树第 k(k>=1)层上 最多有 2^(k-1) 个节点;
2、深度为 k(k>=1)的二叉树 最多有 2^k-1 个节点;
3、在任意一棵二叉树中,树叶的数目比度数为2的节点的数目多一。
总节点数 n = n0 + n1 + n2
总节点数 n = 子节点总数 + 1
子节点总数 = n1 + 2n2
∴ n0 = n2 + 1

最优二叉树(赫夫曼树)

给定 N 个权值作为 N 个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。
哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

路径、路径长度

在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第 L 层结点的路径长度为 L-1。

结点的权、带权路径长度

若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。

树的带权路径长度(WPL)

树的带权路径长度规定为所有叶子结点的带权路径长度之和,
记为WPL(Weighted Path Length of Tree)。
e.g.
在这里插入图片描述

而,WPLmin = 71 + 22 + 5*2 = 21.

节点编号

完全二叉树节点的编号方法:从上到下,从左到右,根节点为1号节点。
根节点:编号 1
根节点左子节点编号: 2
根节点右子节点编号: 3

……
第 i 个节点
左子节点编号: 2 * i
右子节点编号: 2 * i + 1

有无父子节点的判定

设完全二叉树的节点数为 n,某节点编号为 i:
当 i >1(不是根节点)时,有父节点,其父节点编号为 i / 2;
当 2i <= n 时,有左孩子,其编号为 2i (否则没有左孩子,本身是叶节点);
当 2i+1 <=n 时,有右孩子,其编号为 2i+1 (否则没有右孩子)。

二叉树的顺序存储结构

存储

有 n 个节点的完全二叉树可以用有 n+1 个元素的数组进行顺序存储,节点号和数组下标一一对应,
下标为零的元素不用。
利用以上特性,可以从下标获得节点的逻辑关系。
不完全二叉树通过添加虚节点构成完全二叉树,采用数组存储会浪费一些存储空间。
在这里插入图片描述

遍历

前序:根 ----> 左 -----> 右
中序:左 ----> 根 -----> 右
后序:左 ----> 右 -----> 根
e.g.
在这里插入图片描述

前序:
A —> B —> C —> D —> E —> F —> G —> H —> K
中序:
B —> D —> C —> A —> E —> H —> G —> K —> F
后序:
D —> C —> B —> H —> K —> G —> F —> E —> A
e.g.
已知遍历结果如下,试画出对应的二叉树:
前序: A B C E H F I J D G K
中序: A H E C I F J B D K G
在这里插入图片描述

二叉树的链式存储

层次遍历(队列思想)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

bitree.h
#ifndef _BITREE_H_
#define _BITREE_H_

typedef char datatype_tree; 
typedef struct tree_node_t
	{
		datatype_tree data;					// 数据域
		struct tree_node_t *lchild;			// 左子left 
		struct tree_node_t *rchild;			// 右子right 
	}bitree_node_t, *bitree_list_t;

// 创建
bitree_list_t CreateBitree(int n,int i);
// 前序
void PreOrder(bitree_list_t r);
// 中序
void InOrder(bitree_list_t r);
// 后序
void PostOrder(bitree_list_t r);
// 释放
void Delete(bitree_list_t r);
#endif
makefile
CC=gcc
OBJS=main.o create.o pre_in_post_order.o delete.o
CFLAGS=-c -Wall -g -o

bitree:$(OBJS)
	$(CC) $^ -o $@
%.o:%.c
	$(CC) $(CFLAGS) $@ $<

.PHONY:clean
clean:
	rm *.o seqlist -f
main.c
#include <stdio.h>
#include "bitree.h"

int main(int argc, char const *argv[])
{
    printf("Please input 'n' for the number of bitree nodes: ");
    int n;
    scanf("%d", &n);
    bitree_list_t root = CreateBitree(n, 1);

    PreOrder(root);
    putchar(10);
    InOrder(root);
    putchar(10);
    PostOrder(root);
    putchar(10);

    Delete(root);

    return 0;
}
*.c
/***********************************************************/
// create.c
#include <stdio.h>
#include <stdlib.h>
#include "bitree.h"

// 创建
bitree_list_t CreateBitree(int n, int i){

    bitree_list_t current_root = (bitree_list_t)malloc(sizeof(bitree_node_t));
    if (current_root == NULL){
        perror("Failed to create a root.");
        return NULL;
    }

    current_root->data = i + 64;

    if (2*i <= n)
        current_root->lchild = CreateBitree(n, 2*i);
    else 
        current_root->lchild = NULL;

    if (2*i+1 <= n)
        current_root->rchild = CreateBitree(n, 2*i+1);
    else 
        current_root->rchild = NULL;

    return current_root;
}


/***********************************************************/
// delete.c
#include <stdio.h>
#include <stdlib.h>
#include "bitree.h"

// 释放
void Delete(bitree_list_t r){

    if (r == NULL)
        return;
    
    Delete(r->lchild);
    Delete(r->rchild);
    free(r);
    r = NULL;
}


/***********************************************************/
// pre_in_post_order.c
#include <stdio.h>
#include "bitree.h"

// 前序
void PreOrder(bitree_list_t r){

    if (r == NULL)
        return;
    printf("%c ", r->data);
    PreOrder(r->lchild);
    PreOrder(r->rchild);

}

// 中序
void InOrder(bitree_list_t r){

    if (r == NULL)
        return;
    
    InOrder(r->lchild);
    printf("%c ", r->data);
    InOrder(r->rchild);

}

// 后序
void PostOrder(bitree_list_t r){

    if (r == NULL)
        return;
    
    PostOrder(r->lchild);
    PostOrder(r->rchild);
    printf("%c ", r->data);

}


/***********************************************************/
实现效果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值