1. 二叉树基本概念
-
定义:
n(n≥0)个结点的有限集合,由一个根结点以及两棵互不相交的、分别称为左子树和右子树的二叉树组成 。 -
逻辑结构:
一对二(1:2) -
基本特征:
- 每个结点最多只有两棵子树(不存在度大于2的结点)
- 左子树和右子树次序不能颠倒(有序树)。
-
基本形态:
-
二叉树性质
-
性质1: 在二叉树的第i层上至多有2i-1个结点(i>0)
-
性质2: 深度为k的二叉树至多有2k-1个结点(k>0)
-
性质3: 对于任何一棵二叉树,若度为2的结点数有n2个,则叶子数(n0)必定为n2+1 (即n0=n2+1)
-
满二叉树
一棵深度为k 且有2k -1个结点的二叉树。
特点:每层都“充满”了结点
-
完全二叉树
除最后一层外,每一层上的节点数均达到最大值;在最后一层上只缺少右边的若干结点。理解:k-1层与满二叉树完全相同,第k层结点尽力靠左
-
性质4: 具有n个结点的完全二叉树的深度必为(\log_2 N)+1
-
性质5: 对完全二叉树,若从上至下、从左至右编号,则编号为i 的结点,其左孩子编号必为2i,其右孩子编号必为2i+1;其双亲的编号必为i/2(i=1 时为根,除外)
-
2. 二叉树的表示
-
二叉链表示法
一般从根结点开始存储。相应地,访问树中结点时也只能从根开始。
- 存储结构
-
结点数据类型定义:
typedef struct BiTNode { int data; struct BiTNode *lchild, *rchild; }BiTNode, *BiTree;
-
三叉链表表示法
- 存储结构
-
节点数据类型定义:
//三叉链表 typedef struct TriTNode { int data; //左右孩子指针 struct TriTNode *lchild, *rchild; struct TriTNode *parent; }TriTNode, *TriTree;
3. 二叉树的遍历
-
遍历定义
指按某条搜索路线遍访每个结点且不重复(又称周游)。
-
遍历用途
它是树结构插入、删除、修改、查找和排序运算的前提,是二叉树一切运算的基础和核心。
-
遍历方法
牢记一种约定,对每个结点的查看都是“先左后右” 。
限定先左后右,树的遍历有三种实现方案:
DLR LDR LRD
先 (根)序遍历 中 (根)序遍历 后(根)序遍历- DLR — 先序遍历,即先根再左再右
- LDR — 中序遍历,即先左再根再右
- LRD — 后序遍历,即先左再右再根
注:“先、中、后”的意思是指访问的结点D是先于子树出现还是后于子树出现。
从递归的角度看,这三种算法是完全相同的,或者说这三种遍历算法的访问路径是相同的,只是访问结点的时机不同。
从虚线的出发点到终点的路径上,每个结点经过3次。
- 第1次经过时访问=先序遍历
- 第2次经过时访问=中序遍历
- 第3次经过时访问=后序遍历
4 示例代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
typedef int KEY_VALUE;
#define BSTREE_ENTRY(name, type) \
struct name \
{ \
struct type *left; \
struct type *right; \
}
struct bstree_node
{
KEY_VALUE data;
BSTREE_ENTRY(, bstree_node)
bst;
};
struct bstree
{
struct bstree_node *root;
};
/* -------------------------------------------*/
/**
* @brief bstree_create_node
*
* @param key
*
* @returns
*/
/* -------------------------------------------*/
struct bstree_node *bstree_create_node(KEY_VALUE key)
{
struct bstree_node *node = (struct bstree_node *)malloc(sizeof(struct bstree_node));
if (node == NULL)
{
assert(0);
}
node->data = key;
node->bst.left = node->bst.right = NULL;
return node;
}
/* -------------------------------------------*/
/**
* @brief bstree_insert
*
* @param T
* @param key
*
* @returns
*/
/* -------------------------------------------*/
int bstree_insert(struct bstree *T, int key)
{
assert(T != NULL);
//根节点为空,创建节点
if (T->root == NULL)
{
T->root = bstree_create_node(key);
return 0;
}
//定义一个node游标
struct bstree_node *node = T->root;
//tmp 记录上一个节点
struct bstree_node *tmp = T->root;
while (node != NULL)
{
tmp = node;
if (key < node->data)
{
node = node->bst.left;
}
else
{
node = node->bst.right;
}
}
if (key < tmp->data)
{
tmp->bst.left = bstree_create_node(key);
}
else
{
tmp->bst.right = bstree_create_node(key);
}
return 0;
}
/* -------------------------------------------*/
/**
* @brief bstree_traversal
*
* @param node
*
* @returns
*/
/* -------------------------------------------*/
int bstree_traversal(struct bstree_node *node)
{
if (node == NULL)
return 0;
printf("%4d ", node->data); //前序遍历
bstree_traversal(node->bst.left);
bstree_traversal(node->bst.right);
return 0;
}
/* -------------------------------------------*/
/**
* @brief bstree_free
*
* @param node
*
* @returns
*/
/* -------------------------------------------*/
int bstree_free(struct bstree_node *node)
{
if (node == NULL)
return 0;
bstree_free(node->bst.left);
bstree_free(node->bst.right);
free(node);
return 0;
}
#define ARRAY_LENGTH 10
int main()
{
int keyArray[ARRAY_LENGTH] = {13, 35, 23, 26, 67, 47, 38, 98, 20, 12};
struct bstree T = {0};
int i = 0;
for (i = 0; i < ARRAY_LENGTH; i++)
{
bstree_insert(&T, keyArray[i]);
}
bstree_traversal(T.root);
printf("\n");
bstree_free(T.root);
return 0;
}