一、概述
二叉树是一种非常重要的数据结构,它由节点组成,每个节点都包含三个部分:一个存储数据的元素(如整数、浮点数、字符、字符串等),一个指向左子节点的指针,以及一个指向右子节点的指针。二叉树的特点是每个节点最多有两个子节点,通常称为左子节点和右子节点。
二、常见类型
- 普通二叉树:没有额外约束的二叉树。
- 二叉搜索树(BST):二叉搜索树(也称为二叉排序树、有序二叉树)是一种特殊的二叉树,它满足这样的性质:左子树的所有节点的值都小于根节点的值;右子树的所有节点的值都大于根节点的值;适用于快速查找、插入和删除操作。
- 满二叉树:一个二叉树,如果每一个层的节点数都达到最大值,则这个二叉树就是满二叉树。也就是说,除了叶子节点外,每个节点都有两个子节点。
- 完全二叉树(Complete Binary Tree):每一层都被完全填充,除了最后一层,且最后一层的节点集中在左侧。
- 平衡二叉树:
- AVL 树:任意节点的两个子树的高度差至多为 1。
- 红黑树:通过颜色标记节点,并保持特定的平衡规则,以保证操作在对数时间内完成。
三、基本操作
1、遍历:前序遍历、中序遍历、后序遍历和层次遍历。
- 前序遍历(Pre-order):访问根节点,遍历左子树,遍历右子树,图1的遍历顺序为:ABDHKECFIGJ。
- 中序遍历(In-order):遍历左子树,访问根节点,遍历右子树,图1的遍历顺序为:HKDBEAIFCGJ 。
- 后序遍历(Post-order):遍历左子树,遍历右子树,访问根节点,图1的遍历顺序为:KHDEBIFJGCA。
- 层序遍历(Level-order):逐层访问节点,通常使用队列实现,图1的遍历顺序为:ABCDEFGHIJK。
2、插入:在二叉搜索树中,插入新的节点以保持树的排序属性。
3、删除:从二叉搜索树中删除节点,并重新组织树以维持其排序属性。
4、查找:在二叉树中查找具有特定值的节点。
#include <stdlib.h>
#include <stdio.h>
typedef int TElemType;
/* 二叉树的二叉链表结点结构定义 */
/* 结点结构 */
typedef struct Node_t
{
/* 结点数据 */
TElemType data;
/* 左右孩子指针 */
struct Node_t*lchild, *rchild;
} Node;
/* 二叉树的前序遍历递归算法 */
void PreOrderTraverse(Node *T)
{
if (T == NULL)
return;
/* 显示结点数据,可以更改为其他对结点操作 */
printf("%d ", T->data);
/* 再先序遍历左子树 */
PreOrderTraverse(T->lchild);
/* 最后先序遍历右子树 */
PreOrderTraverse(T->rchild);
}
/* 二叉树的中序遍历递归算法 */
void InOrderTraverse(Node *T)
{
if (T == NULL)
return;
/* 中序遍历左子树 */
InOrderTraverse(T->lchild);
/* 显示结点数据,可以更改为其他对结点操作 */
printf("%d ", T->data);
/* 最后中序遍历右子树 */
InOrderTraverse(T->rchild);
}
/* 二叉树的后序遍历递归算法 */
void PostOrderTraverse(Node *T)
{
if (T == NULL)
return;
/* 先后序遍历左子树 */
PostOrderTraverse(T->lchild);
/* 再后序遍历右子树 */
PostOrderTraverse(T->rchild);
/* 显示结点数据,可以更改为其他对结点操作 */
printf("%d ", T->data);
}
// 查找节点
Node* search(Node* root, int key)
{
if (root == NULL || root->data == key)
{
return root;
}
if (key < root->data)
{
return search(root->lchild, key);
}
else
{
return search(root->rchild, key);
}
}
// 查找最小节点(用于删除有两个子节点的节点时替换)
Node* minValueNode(Node* node)
{
Node* current = node;
while (current->lchild != NULL)
{
current = current->lchild;
}
return current;
}
// 删除节点
Node* deleteNode(Node* root, int key)
{
if (root == NULL) return root;
if (key < root->data)
{
root->lchild = deleteNode(root->lchild, key);
}
else if (key > root->data)
{
root->rchild = deleteNode(root->rchild, key);
}
else
{
// 节点有两个子节点
if (root->lchild != NULL && root->rchild != NULL)
{
Node* temp = minValueNode(root->rchild);
root->data = temp->data;
root->rchild = deleteNode(root->rchild, temp->data);
}
// 节点有一个子节点或没有子节点
else
{
Node* temp = root->lchild ? root->lchild : root->rchild;
free(root);
return temp;
}
}
return root;
}
/* 插入节点到二叉搜索树 */
Node *insert(Node *node, TElemType value)
{
if(node == NULL)
{
node = (Node *)malloc(sizeof(Node));
node->data = value;
node->lchild = NULL;
node->rchild = NULL;
return node;
}
if(value < node->data)
node->lchild = insert(node->lchild, value);
else
node->rchild = insert(node->rchild, value);
return node;
}
int main(int argc, char *argv[])
{
Node *root = NULL;
root = insert(root, 50);
insert(root, 30);
insert(root, 20);
insert(root, 40);
insert(root, 70);
insert(root, 60);
insert(root, 80);
//前序遍历
printf("front:");
PreOrderTraverse(root);
printf("\n");
//中序遍历
printf("mid:");
InOrderTraverse(root);
printf("\n");
//后序遍历
printf("back:");
PostOrderTraverse(root);
printf("\n");
//查找
const Node *node = search(root, 80);
if(node != NULL)
{
printf("search:%d\n", node->data);
}
//删除
deleteNode(root, 20);
deleteNode(root, 70);
//中序遍历
printf("mid:");
InOrderTraverse(root);
printf("\n");
return 0;
}
qq群交流:698593923
觉得有帮助的话,打赏一下呗。。