「数据结构」二叉树的构建(C语言)

文章目录

  • 前言
  • 一、二叉树的基本概念与性质
    • 基础概念
    • 特殊的二叉树
    • 性质
  • 二、二叉树存储结构与实现
    • 1. 顺序存储结构
    • 2.链表存储结构
      • 3.代码实现部分:
      • 二叉树的层序遍历
      • 判断是否为完全二叉树
      • 具体函数实现


前言

二叉树是孩子节点数最多只有两个的树,在许多算法中都能看到它,例如:二叉平衡树,AVL树,红黑树等,为了掌握这些算法,必须对二叉树有基本的了解。所以,本文将介绍普通二叉树的构建。


一、二叉树的基本概念与性质

基础概念

在数据结构中, 二叉树是树节点数最多为两个的树结构。而且,二叉树的子节点分为左子树右子树,其次序不能随意颠倒。

「数据结构」二叉树的构建(C语言)_第1张图片

特殊的二叉树

    1. 满二叉树: 如果一个二叉树每一层的结点数都达到最大值,则这棵树就是满二叉树。例如,一颗深度为k,且节点数为2k-1,则它就是满二叉树。
    1. 完全二叉树: 深度为k,有 n 个节点的二叉树,当且仅当其每一个节点都与深度为 k 的满二叉树中编号从 1 至 n 的节点 一 一对应时,称之为完全二叉树。

「数据结构」二叉树的构建(C语言)_第2张图片

性质

  • 二叉树在第 i 层上至多有 2i-1 个结点 ( i ≥ \geq 1 )
  • 对于深度为 k 的二叉树结点最多为 ( 2k-1
  • 对于任意一颗二叉树,如果其度为0的结点数 n 0 n_0 n0度为 2 的节点数 n 2 n_2 n2 ,则 n 0 = n 2 + 1 \bold{n_0 = n_2 + 1} n0=n2+1
  • 具有 n 个节点的完全二叉树的深度为 l o g 2 n + 1 log_2n + 1 log2n+1
  • 对于具有 n 个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的结点有:
    1. 若 i > 0, i 位置节点的双亲序号:( i - 1 )/ 2i = 0, i 为根结点编号,无双亲节点
    2. 若 2i + 1 < n,左孩子序号:2i + 12i + 1 ≥ \geq n 否则无左孩子
    3. 若 2i + 2 < n, 右孩子序号:2i+22i+2 ≥ \geq n 否则无右孩子

二、二叉树存储结构与实现

二叉树的实现能够通过 顺序存储结构链表存储结构 实现。

1. 顺序存储结构

根据二叉树的性质,二叉树的孩子结点分别存储在 2i + 1 与 2i + 2 的空间,但我们不难得知,这种存储方式只适用于完全二叉树,对于普通二叉树,将造成大量的空间浪费。在极端环境下,一个深度为 k 且只有 k 个结点的单支树(树中不存在度为 2 的结点)却需要长度为2k-1的一维数组。
「数据结构」二叉树的构建(C语言)_第3张图片

2.链表存储结构

通过二叉树的定义可知,二叉树的结点由一个数据元素和分别指向其左、右子树的两个分支组成。所以,表示二叉树的域至少要有3个,有时为了方便找到双亲结点还会新增一个指向其双亲结点的指针域,而它们分别被称为二叉链表三叉链表
「数据结构」二叉树的构建(C语言)_第4张图片


3.代码实现部分:

二叉树的二叉链结构声明与函数声明:

//头文件
#include 
#include 
#include 
#include 

// ---- 二叉树的二叉链存储表示
typedef char BTDataType;
typedef struct BinaryTreeNode {
    BTDataType _data;				//当前节点值域
    struct BinaryTreeNode *_left;	//左孩子
    struct BinaryTreeNode *_right;	//右孩子
} BTNode;
// ------

// ---- 二叉树的三叉链存储表示
//本文不写三叉链的实现
struct BinaryTreeNode
{
 struct BinTreeNode* _pParent; // 指向当前节点的双亲
 struct BinTreeNode* _pLeft; // 指向当前节点左孩子
 struct BinTreeNode* _pRight; // 指向当前节点右孩子
 BTDataType _data; // 当前节点值域
};
// -------

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode *BinaryTreeCreate(BTDataType *a, int n, int *pi);
// 二叉树销毁
void BinaryTreeDestory(BTNode **root);
// 二叉树节点个数
int BinaryTreeSize(BTNode *root);
// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode *root);
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode *root, int k);
// 二叉树查找值为x的节点
BTNode *BinaryTreeFind(BTNode *root, BTDataType x);
// 二叉树前序遍历
void BinaryTreePrevOrder(BTNode *root);
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode *root);
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode *root);
// 层序遍历
void BinaryTreeLevelOrder(BTNode *root);
// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode *root);

二叉树的层序遍历

二叉树的层序遍历就是从左到右依序遍历树,需要一个队列来实现,因为队列的先进先出符合层序遍历的遍历条件,词穷图见 ⇓ \Downarrow
「数据结构」二叉树的构建(C语言)_第5张图片

//二叉树的层序遍历
void BinaryTreeLevelOrder(BTNode *root)
{
    if(!root)
        return;
    
    Que que;		//队列的声明与初始化
    QueueInit(&que);
    QueuePush(&que, root);	

    while(!QueueEmpty(&que))
    {
        int sz = QueueSize(&que);		//记录当前队列数据量
        while(sz--)
        {
            BTNode* node = QueueFront(&que);
            printf("%c ", node->_data);
            
            // 依次入队列左右结点,注意判断是否为空
            if(node->_left)
                QueuePush(&que, node->_left);
            if(node->_right)
                QueuePush(&que, node->_right);
			
            QueuePop(&que);
        }
    }
    QueueDestroy(&que);
}

判断是否为完全二叉树

该函数和层序遍历相似,通过队列模拟层序遍历,直到遇到一个NULL指针,然后继续循环出队列,如果遇到非空结点则说明不是完全二叉树。

int BinaryTreeComplete(BTNode *root)
{
    Que que;
    QueueInit(&que);
    QueuePush(&que, root);

    while(!QueueEmpty(&que))		//层序遍历
    {
        if(!QueueFront(&que))
            break;
        
        BTNode* node = QueueFront(&que);
        QueuePush(&que, node->_left);
        QueuePush(&que, root->_right);

        QueuePop(&que);
    }

    while(!QueueEmpty(&que))		//判断是否有非空结点
    {
        if(QueueFront(&que))
            return 0;

        QueuePop(&que);
    }
    
    QueueDestroy(&que);
    return 1;
}

具体函数实现

#include "BTNode.h"
#include "queue.h"

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode *BinaryTreeCreate(BTDataType *a, int n, int *pi) {
    if (a[*pi] == '#' || *pi == n) {
        (*pi)++
        return NULL;
    }

    BTNode *node = (BTNode *)malloc(sizeof(BTNode));
    node->_data = a[(*pi)++];

    node->_left = BinaryTreeCreate(a, n, pi);	//建造左右孩子并返回
    node->_right = BinaryTreeCreate(a, n, pi);	

    return node;
}

//二叉树的销毁
void BinaryTreeDestory(BTNode **root) {
    if (*root == NULL)
        return;
        
	//通过后序方式销毁
    BinaryTreeDestory(&((*root)->_left));
    BinaryTreeDestory(&((*root)->_right));
    free(*root);
}

int BinaryTreeSize(BTNode *root) {
    if (!root)
        return 0;

    return BinaryTreeSize(root->_left) + 
    	BinaryTreeSize(root->_right) + 1;
}

int BinaryTreeLeafSize(BTNode *root) {
    if (!root)
        return 0;
    if (!root->_left && !root->_right) 
        return 1;

    int left = BinaryTreeLeafSize(root->_left);
    int right = BinaryTreeLeafSize(root->_right);

    return left + right;
}

//寻找值为x的结点
BTNode *BinaryTreeFind(BTNode *root, BTDataType x) {
    if (!root)
        return NULL;
    if (root->_data == x)
        return root;

    BTNode *left = BinaryTreeFind(root->_left, x);
    BTNode *right = BinaryTreeFind(root->_right, x);
	
	//	如果left 和 right指针不为空,则说明找到了目标
    if (left)
        return left;
    if (right)
        return right;

    return NULL;
}

//第k层结点个数
int BinaryTreeLevelKSize(BTNode *root, int k) {
    if (!root)
        return 0;
    if (k == 1)			//k == 1 
        return 1;

    return BinaryTreeLevelKSize(root->_left, k - 1) +
           BinaryTreeLevelKSize(root->_right, k - 1);
}

//前序遍历
void BinaryTreePrevOrder(BTNode *root) {
    if (!root) {
        return;
    }

    printf("%c->", root->_data);
    BinaryTreePrevOrder(root->_left);
    BinaryTreePrevOrder(root->_right);
}

//中序遍历
void BinaryTreeInOrder(BTNode *root) {
    if (!root)
    {
        return;
    }
    
    BinaryTreeInOrder(root->_left);
    printf("%c->", root->_data);
    BinaryTreeInOrder(root->_right);
}

// 后序遍历
void BinaryTreePostOrder(BTNode *root)
{
    if(!root)
    {
        return;
    }

    BinaryTreePostOrder(root->_left);
    BinaryTreePostOrder(root->_right);
    printf("%c->", root->_data);
}

//二叉树的层序遍历
void BinaryTreeLevelOrder(BTNode *root)
{
    if(!root)
        return;
    
    Que que;
    QueueInit(&que);
    QueuePush(&que, root);

    while(!QueueEmpty(&que))
    {
        int sz = QueueSize(&que);
        while(sz--)
        {
            BTNode* node = QueueFront(&que);
            printf("%c ", node->_data);

            if(node->_left)
                QueuePush(&que, node->_left);
            if(node->_right)
                QueuePush(&que, node->_right);

            QueuePop(&que);
        }
    }
    QueueDestroy(&que);
}

int BinaryTreeComplete(BTNode *root)
{
    Que que;
    QueueInit(&que);
    QueuePush(&que, root);

    while(!QueueEmpty(&que))	//层序遍历
    {
        if(!QueueFront(&que))
            break;
        
        BTNode* node = QueueFront(&que);
        QueuePush(&que, node->_left);
        QueuePush(&que, root->_right);
        QueuePop(&que);
    }

    while(!QueueEmpty(&que))
    {
        if(QueueFront(&que)	//遇到非空结点证明不是完全二叉树
            return 0;

        QueuePop(&que);
    }

    return 1;
}

你可能感兴趣的:(数据结构,c语言,开发语言)