笔记——二叉树
1、 二叉树的定义及特点
定义
定义:二叉树是树中节点数小于等于2的树
特点
1)在 k 层(即深度)中节点数<= 2 ^(k-1)
2)若最大层数为 k ,则树的总节点数<= 2^k-1(若为满二叉树则等于)
3)若叶节点个数:n0,度为2的节点数:n2,则 n2=n0-1
2、满二叉树与完全二叉树
满二叉树:除叶节点外,其余节点度数均为2
性质:若最大层数为 k ,则树的总节点数:2^k-1
完全二叉树:若树深度为K,则除第K层外其余层节点度数均=2,== 且第K层节点都集中在左边,依次排列==
3、二叉树存储结构(主要讲链式)
选择存储
用一组连续的存储单元存放二叉树中的结点。用编号的方法从树根起,自上层至下层,每层自左至右地给所有结点编号。
若为满二叉树或完全二叉树,则为最优选
链式存储
链表中每个结点由三个域组成,分别为:数据域和左右指针域。
定义节点
typedef struct node {
int data;
node *l;
node *r;
} Tree;
创建树
void Create(node *&root) {
int x;
scanf("%d", &x);
if (x == -1)
root = NULL;
else {
root = (node *)malloc(sizeof(node));//分配空间
root->data = x;//数据域赋值
count++;//计算总节点数
//递归调用,给左右孩子节点赋值
Create(root->l);
Create(root->r);
}
}
链式存储与顺序存储的优缺点
顺序存储
优点:存储密度大=1,存储空间利用概率高。
缺点:
(1)在顺序表中做插入、删除操作时,平均移动表中的一半元素,因此对n较大的顺序表效率低。
(2)需要预先分配足够大的存储空间,估计过大,可能会导致顺序表后部大量闲置;预先分配过小,又会造成溢出
链式存储
优点:插入、删除运算方便。
缺点:链表不是一种随机存储结构,不能随机存取元素。
适用情况
主要操作是查找,则采用顺序表;
主要操作是插入、删除操作,则采用链表。
4、树三种遍历方法
先序
void Preorder(Tree *root)
{
if(NULL == root){
return;
}
printf("%c ", root->data);//输出当前节点的数据
//利用递归操作,先遍历完左子树,再遍历右子树
Preorder_Tree(root->l);
Preorder_Tree(root->r);
}
中序
void Mediate(Tree *root)
{
if(NULL == root){
return;
}
//先遍历左子树
Mediate_Tree(root->l);
printf("%c ", root->data);
//再遍历右子树
Mediate_Tree(root->r);
}
后序
void Post(Tree *root)
{
if(NULL == root){
return;
}
//先遍历左子树,再遍历右子树
Post_Tree(root->l);
Post_Tree(root->r);
printf("%c ", root->data);
}
无视笔记,笔记不对
5、完整代码(增删查)
#include <stdio.h>
#include <stdlib.h>
//结点
typedef struct TreeNode {
int value;
struct TreeNode *left;
struct TreeNode *right;
} TreeNode;
//创建树
TreeNode *createNode(int value) {
TreeNode *newNode = (TreeNode *)malloc(sizeof(TreeNode));
if (!newNode) {
printf("内存分配失败\n");
exit(0);
}
newNode->value = value;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
//增
TreeNode *insertNode(TreeNode *root, int value) {
if (root == NULL) {
return createNode(value);
}
if (value < root->value) {
root->left = insertNode(root->left, value);
} else if (value > root->value) {
root->right = insertNode(root->right, value);
}
return root;
}
//查
TreeNode *findNode(TreeNode *root, int value) {
if (root == NULL || root->value == value) {
return root;
}
if (value < root->value) {
return findNode(root->left, value);
} else {
return findNode(root->right, value);
}
}
//遍历
void inorderTraversal(TreeNode *root) {
if (root == NULL) {
return;
}
inorderTraversal(root->left);
printf("%d ", root->value);
inorderTraversal(root->right);
}
//删
TreeNode *deleteNode(TreeNode *root, int value) {
if (root == NULL) {
return root;
}
if (value < root->value) {
root->left = deleteNode(root->left, value);
} else if (value > root->value) {
root->right = deleteNode(root->right, value);
} else {
if (root->left == NULL) {
TreeNode *temp = root->right;
free(root);
root = temp;
} else if (root->right == NULL) {
TreeNode *temp = root->left;
free(root);
root = temp;
} else {
root->right = deleteNode(root->right, root->value);
}
}
return root;
}
//----
int minValue(TreeNode *root) {
int minValue = root->value;
while (root->left != NULL) {
minValue = root->left->value;
root = root->left;
}
return minValue;
}
int main() {
TreeNode *root = NULL;
root = insertNode(root, 50);
insertNode(root, 30);
insertNode(root, 70);
insertNode(root, 20);
insertNode(root, 40);
insertNode(root, 60);
insertNode(root, 80);
printf("中序遍历:");
inorderTraversal(root);
printf("\n查找元素 :40\n");
TreeNode *node = findNode(root, 40);
if (node != NULL) {
printf("找到%d\n", node->value);
} else {
printf("未找到\n");
}
printf("\n删除元素:20\n剩余元素排序:");
root = deleteNode(root, 20);
inorderTraversal(root);
return 0;
}