二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。链式结构又分为二叉链和三叉链,当前学习二叉链。
普通二叉树的增删查改没有意义。如果是为了存储数据,线性表更简单,二叉树更复杂,并且插入删除也不好定义。有意义的是通过二叉树引出搜索树,搜索树又有AVL树和红黑树。再搜索树中查找一个节点最多找高度次。
深度优先:前中后序遍历 一般借助递归
广度优先:层序遍历 一般借助队列
typedef char BTDataType;
typedef struct BinaryTreeNode
{
BTDataType data;
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
}BTNode;
// 二叉树前序遍历 递归
void PrevOrder(BTNode* root)
{
if(root == NULL)
{
printf("NULL ");
return;
}
// 根 左 右子树 递归 递归过程图在下方
printf("%c ",root->data);
PrevOrder(root->left);
PrevOrder(root->right);
}
// 二叉树中序遍历
void InOrder(BTNode* root)
{
if(root == NULL)
{
printf("NULL ");
return;
}
// 左 根 右子树 递归 递归过程图在下方
InOrder(root->left);
printf("%c ",root->data);
InOrder(root->right);
}
// 二叉树后序遍历
void PostOrder(BTNode* root)
{
if(root == NULL)
{
printf("NULL ");
return;
}
// 左 右 根 递归 递归过程图在下方
PostOrder(root->left);
PostOrder(root->right);
printf("%c ",root->data);
}
// 求节点的个数
int TreeSize(BTNode* root)
{
// root不是NULL,则个数为左节点个数+右节点个数+1(加的1就是对本节点个数加上去)
return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}
// 求叶子结点的个数
// 1.NULL return 0 2.叶子 return 1 3.非空且不是叶子 reutrn 左子树叶子节点个数+右子树叶子节点个数
int TreeLeefSize(BTNode* root)
{
if(root == NULL)
return 0;
if(root->left == NULL && root->right == NULL)
return 1;
return TreeLeefSize(root->left) + root->left(root->right);
}
// 求第K层节点的个数 设K=3 化解为左子树的第K-1(2)层和右子树的第k -1(2)层
int TreeKLeefSize(BTNode* root, int k)
{
if(root == NULL)
return 0;
if(k == 1)
return 1;
return TreeKLeefSize(root->left, k-1) + TreeKLeefSize(root->right, k-1);
}
// 查找树里面值为X的那个节点 1.root == NULL return NULL
// 2.root 不是要找的 先找左树 左树如果没有再找右树 3.左右都没有则当前树没找到 return null
BTNode* TreeFind(BTNode* root, BTDataType x)
{
if(root == NULL)
return NULL;
// 我就是x则返回
if(root->data == x)
{
return root;
}
// 不是x先在左边找再在右边找
BTNode* lret = TreeFind(root->left, x); // 找到了返回root 没找到返回NULL
if(lret)
return lret;
BTNode* rret = TreeFind(root->right, x); // 找到了返回root 没找到返回NULL
if(rret)
return rret;
// 左右都没找到
return NULL;
}
// 二叉树销毁 形参的改变不会影响实参,因此需要二级指针
void BinaryTreeDestory(BTNode** pproot)
{
// if(*pproot == NULL)
// return;
// BinaryTreeDestory(&(*pproot)->left); //先将二级指针转换为一级再取地址变为2级传参
// BinaryTreeDestory(&(*pproot)->right);
// free(*pproot);
// *pproot== NULL;
}
// 一级指针的做法 存在野指针,需要将野指针置空 保持接口一致性
void BinaryTreeDestory(BTNode* root)
{
if(root == NULL)
return;
BinaryTreeDestory(root->left); //先将二级指针转换为一级再取地址变为2级传参
BinaryTreeDestory(root->right);
free(root);
}
// 创建节点
BTNode* CreateTreeNode (BTDataType x)
{
BTNode* n1 = (BTNode*)malloc(sizeof(BTNode));
n1->data = x;
n1->left = NULL;
n1->right = NULL:
return node;
}
int main()
{
// 手动连接上图中的树
BTNode* A = CreateTreeNode('A');
BTNode* B = CreateTreeNode('B');
BTNode* C = CreateTreeNode('C');
BTNode* D = CreateTreeNode('D');
BTNode* E = CreateTreeNode('E');
BTNode* F = CreateTreeNode('F');
A->left = B;
A->right = C;
B->left = D;
C->left = E;
c->right = F;
// 二级做法BinaryTreeDestory(&A);
// 一级做法
BinaryTreeDestory(A);
A = NULL;
}
下图为PrevOrder的递归过程图。函数调用该板块完成后会返回到使用该板块的语句。前中后序的本质是一样的,就是打印的时机不同。
- 求节点的个数(前序) 1+左树节点个数+右树节点个数
- 求树的高度(后序) max(左树的高度,右树的高度)+1
深度优先:前中后序遍历 一般借助递归
广度优先:层序遍历 一般借助队列