【数据结构】——6.1 二叉树
树(Tree):树是一种非线性的数据结构,它是由n个有限结点组成一个具有层次关系的集合。
树有一个特殊的结点,称为根结点,根节点没有前驱结点
除根节点外,其余结点被分成M(M>0)个互不相交的集合,其中每一个集合又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继,因此,树是递归定义的。
树形结构子树不能有交集,否则就不是树,而是另一种数据结构 图
节点的度:一个节点含有的子树个数
叶子节点(终端节点):度为0的节点就是叶子节点
分支节点(非终端节点):度不为0的节点
双亲结点(父节点):若一个结点含有一个子节点,则该节点为子节点的父节点
兄弟节点:具有相同父节点的节点,兄弟节点都是亲兄弟
堂兄弟节点:双亲在同一层的节点叫做堂兄弟节点
祖先:从根节点到该节点经过的所有节点
子孙:以某节点为根的子树中的任意节点都叫该节点的子孙
节点的层次:从根处开始,根为第1层,子节点为第2层,以此类推
树的度:树中的最大的节点的度就是树的度
树的高度(深度):树中节点的最大层次
森林:不相交的树的集合叫森林
树结构的存储结构就比较复杂,若使用指针指向每个节点的子节点,则每个节点的子节点数量不同,定义固定数量的指针就会出现浪费或溢出的情况,所以我们介绍最常用的树的存储方法

树结构声明
struct Tree
{
DataType* data;
struct Tree* child_1;
struct Tree* child_2;
... //此处又该定义几个孩子指针呢
};
以上的存储方式显然是不好的,即便是定义成指针数组,也可能会出现大量的浪费或者溢出现象。
每一个节点都有一个指向自己的左孩子的指针,和一个指向右兄弟的指针。节点可以通过左孩子指针找到自己的左孩子,,再利用孩子的右兄弟指针找到自己的所有孩子。结构图如下

兄弟表示法的声明
struct Tree
{
DataType* data; //数据域
struct Tree* _firstChild; //第一个孩子的指针
struct Tree* _nextBrother; //下一个兄弟的指针
};
使用线性的存储结构存储每个节点,并将它们的父节点下标也进行存储,通过子节点找父节点的方式遍历树

此方式使用-1下标来表示根节点
二叉树:每个节点最多只有2个子节点的树

二叉树的顺序结构一般只适用于完全二叉树,堆的实现就是顺序结构,非完全二叉树中空缺的位置会浪费大量空间


二叉链表的结构体声明:
typedef int BTDataType;
typedef struct BTree
{
struct BTree* left;
struct BTree* right;
BTDataType data;
} BTNode;
三叉链表的结构体声明:
typedef int BTDataType;
typedef struct BTree
{
struct BTree* left;
struct BTree* right;
struct BTree* parent;
BTDataType data;
} BTNode;
满二叉树:二叉树的每一层都到达最大节点数,那么二叉树就是慢二叉树

完全二叉树:对于深度为k的二叉树而言,前k-1层满节点数,,第k层节点可以不满,但是节点必须是与满二叉树中的编号对应的,完全二叉树是一个很高效的数据结构

满二叉树一定是完全二叉树,但是完全二叉树不一定是满二叉树
typedef char BTDataType;
typedef struct BTreeNode
{
BTDataType data;
struct BTreeNode* left;
struct BTreeNode* right;
}BTNode;
#来表示NULLs为字符串,pi为当前下标的指针,由于每次调用函数下标都要加一,必须使用传址调用,所以使用下标的指针BTNode* BinaryTreeCreate(BTDataType* s, int* pi)
{
if (s[*pi] == '#')
{
(*pi)++;
return NULL;
}
//创建节点并赋值
BTNode* node = (BTNode*)malloc(sizeof(BTNode));
if (node == NULL)
{
perror("malloc fail");
exit(-1);
}
node->data = s[*pi];
(*pi)++;
//创建左子树和右子树
node->left = BinaryTreeCreate(s, pi);
node->right = BinaryTreeCreate(s, pi);
}
void PreOrder(BTNode* root)
{
if (root == NULL)
{
return;
}
printf("%c ", root->data);
PreOrder(root->left);
PreOrder(root->right);
}
void PreOrder(BTNode* root)
{
if (root == NULL)
{
return;
}
PreOrder(root->left);
printf("%c ", root->data);
PreOrder(root->right);
}
void PreOrder(BTNode* root)
{
if (root == NULL)
{
return;
}
PreOrder(root->left);
PreOrder(root->right);
printf("%c ", root->data);
}
//队列接口
void QueueInit(Queue** ppq); //初始化
void QueuePush(Queue** ppq, QDataType x); //入队列
void QueuePop(Queue** ppq); //出队列
QDataType QueueFront(Queue* pq); //获取队头元素
_Bool QueueEmpty(Queue* pq); //判空
void QueueDestroy(Queue** ppq) //销毁队列
void LevelOrder(BTNode* root)
{
Queue pq = NULL;
QueueInit(&pq);
//若根节点存在,则入队列
if (root != NULL)
{
QueuePush(&pq, root);
}
//若队列不为空
while (!QueueEmpty(pq))
{
//该节点出队列,并打印其值
BTNode* node = QueueFront(pq);
QueuePop(&pq);
printf("%c ", node->data);
//该节点的子节点入队列
if (node->left != NULL)
{
QueuePush(&pq, node->left);
}
if (node->right != NULL)
{
QueuePush(&pq, node->right);
}
}
printf("\n");
QueueDestroy(&pq);
}
int BTreeSize(BTNode* root)
{
return root == NULL ? 0
: BTreeSize(root->left) + BTreeSize(root->right) + 1;
}
int BTreeLeafSize(BTNode* root)
{
if (root == NULL)
{
return 0;
}
if (root->left == NULL && root->right == NULL)
{
return 1;
}
return BTreeSize(root->left) + BTreeSize(root->right);
}
int BTreeKLevel(BTNode* root, int k)
{
if (root == NULL)
{
return 0;
}
if (k == 1)
{
return 1;
}
return BTreeKLevel(root->left, k - 1) + BTreeKLevel(root->right, k - 1);
}
int BTreeHeight(BTNode* root)
{
if (root == NULL)
{
return 0;
}
int left = BTreeHeight(root->left);
int right = BTreeHeight(root->right);
return (left > right ? left : right) + 1;
}
BTNode* BTreeFind(BTNode* root, BTDataType x)
{
if (root == NULL)
{
return NULL;
}
//如果值为当前节点,则返回当前节点
if (root->data == x)
{
return root;
}
//若值为左孩子,则返回左孩子
BTNode* left = BTreeFind(root->left, x);
if (left != NULL)
{
return left;
}
//若值为右孩子,则返回右孩子
BTNode* right = BTreeFind(root->right, x);
if(right != NULL)
{
return right;
}
//若都不是,则没找到,返回NULL
return NULL;
}
销毁二叉树使用后序遍历,先销毁左右子树,再销毁当前节点,先销毁当前节点会丢失子树的地址
void BinaryTreeDestory(BTNode* root)
{
if (root == NULL)
{
return;
}
BinaryTreeDestory(root->left);
BinaryTreeDestory(root->right);
free(root);
}
代码保存在gitee中:点击完整代码参考