c语言k=log10(i) 1,二叉搜索树(1)图形分析和C语言实现

本文介绍了树的基本概念和术语,包括二叉树的定义和性质,如二叉树的层节点数、高度等。详细讲解了完全二叉树、满二叉树和二叉搜索树的特性。此外,还提供了二叉搜索树的C语言实现,包括节点定义、遍历、查找、最大值和最小值操作。
摘要由CSDN通过智能技术生成

e24887063f0a19858928d15bbc0f735a.png

更多: 数据结构和算法系列目录

(01). 二叉树的图形分析与C语言实现(一)

(02). 二进制搜索树的C ++实现(2)

(03). 二进制搜索树的Java实现(3)

1. 树的定义

树是一种数据结构,它是由n(n> = 1)个有限节点组成的一组层次关系.

3b2450103267330d9f770219da6bf8a4.png

它被称为“树”,因为它看起来像一棵倒立的树,也就是说,它的根朝上,而叶子朝下. 具有以下特点:

(01)每个节点有零个或多个子节点;

(02)没有父节点的节点称为根节点;

(03)每个非根节点只有一个父节点;

(04)除了根节点之外,每个子节点都可以分为多个不相交的子树.

2. 树木的基本术语

如果节点具有子树,则该节点称为子树根的“父级”,而子树的根就是该节点的“子级”. 具有相同父代的节点是彼此的“兄弟”. 节点的所有子树中的任何节点都是该节点的后代. 从根节点到节点的路径上的所有节点都是该节点的祖先.

节点的度数: 节点拥有的子树的数量.

离开: 零度的节点.

分支节点: 度数不为零的节点.

树的程度: 树中节点的最大程度.

级别: 根节点的级别为1,其余节点的级别等于该节点的父节点的级别加1.

树的高度: 树中节点的最大级别.

无序树: 如果树中节点的子树之间的顺序不重要,则可以交换位置.

有序树: 如果树中节点的子树之间的顺序很重要,则不能交换位置.

森林: 由0棵或更多棵不连贯的树木组成. 在森林中添加根,森林变成一棵树. 删除根,树变成森林.

1. 二叉树的定义

二叉树是每个节点最多具有两个子树的树结构. 它具有五种基本形式: 二叉树可以是一个空集;二叉树可以是一个空集. 根可以有一个空的左或右子树;或左右子树都为空.

6cf3bac143466f2fceede04019a2ac32.png

2. 二叉树的性质

二叉树具有以下属性: TODO(上标和下标)

属性1: 二叉树的第i层上的节点数最多为2 {i-1}(i≥1).

属性2: 深度为k的二叉树最多具有2 {k} -1个节点(k≥1).

属性3: 具有n个节点的二叉树的高度至少为log2(n + 1).

属性4: 在任何二叉树中,如果终端节点数为n0,度数为2的节点数为n2,则n0 = n2 + 1.

2.1属性1: 二叉树的第i层上的节点数最多为2 {i-1}(i≥1)

证明: 以下使用“数学归纳法”进行证明.

(01)当i = 1时,第i层中的节点数为2 {i-1} = 2 {0} = 1. 因为级别1上只有一个根节点,所以命题是正确的.

(02)假设当i> 1时,第i层中的节点数为2 {i-1}. 这是从(01)推断出来的!

基于此假设,可以推断出“第(i + 1)层中的节点数为2 {i}”.

由于二叉树的每个节点最多具有两个子节点,因此“第(i + 1)层上的节点数”最多是“第i层上的节点数的两倍”. 也就是说,第(i + 1)层上的最大节点数= 2×2 {i-1} = 2 {i}.

因此假设成立二叉排序树 c,原始命题得到证明!

2.2属性2: 深度为k的二叉树最多具有2 {k} -1个节点(k≥1)

证明: 在具有相同深度的二叉树中,当每层包含最大数量的节点时,树中的节点数量最大. 根据“属性1”,深度为k的二叉树的节点数最多为:

03330ec49a5eaab0f324fa33d918e755.png

20 + 21 +…+ 2k-1 = 2k-1

因此,最初的命题得到了证明!

2.3属性3: 具有n个节点的二叉树的高度至少为log2(n + 1)

证明: 根据“属性2”,高度为h的二叉树最多具有2 {h} –1个节点. 相反,包含n个节点的二叉树的高度至少为log2(n + 1).

2.4属性4: 在任何二叉树中,如果终端节点的数量为n0,度数为2的节点的数量为n2,则n0 = n2 + 1

证明: 由于二叉树中所有节点的度不大于2,所以节点总数(表示为n)=“ 0度节点数(n0)” +“ 1度节点数(n1) “ +” 2度节点(n2)“. 这样就得到了等式1.

(等式1)n = n0 + n1 + n2

另一方面,0度节点没有子节点,1度节点有一个孩子,而2度节点有两个孩子,因此二叉树中的子节点总数为: n1 + 2n2. 此外,只有根不是任何节点的子代. 因此,二叉树中的节点总数可以表示为公式2.

(等式2)n = n1 + 2n2 + 1

根据(等式1)和(等式2)计算: n0 = n2 + 1. 原来的命题被证明了!

3. 完整的二叉树,完整的二叉树和二叉搜索树

3.1完整的二叉树

定义: 高度为h且由2 {h} –1个节点组成的二叉树称为完整二叉树.

5d6d36fbea67c9e611fbdcf9c84eca67.png

3.2完整的二叉树

定义: 在二叉树中,只有最下面两层的节点的度数可以小于2,最下面一层的叶节点集中在左侧的几个位置. 这样的二叉树称为完整二叉树.

特征: 叶节点只能出现在最下层和下一个较低层中,最低的叶节点集中在树的左侧. 显然,完整的二叉树必须是完整的二叉树,完整的二叉树可能不是完整的二叉树.

bf52bb89a0d2502a9f015b33b206c902.png

3.3二进制搜索树

定义: 二进制搜索树,也称为二进制搜索树. 令x为二叉查找树中的一个节点二叉排序树 c,该x节点包含密钥key,并且节点x的密钥值记录为key [x]. 如果y是x的左子树中的节点,则key [y] <= key [x];如果y是x的右子树中的一个节点,则key [y]> = key [x].

cbd747fede48d12fc441845cfcd9d0f7.png

在二进制搜索树中:

(01)如果任何节点的左子树都不为空,则左子树上所有节点的值都小于其根节点的值;

(02)任何节点的右子树都不为空,则右子树上所有节点的值大于其根节点的值;

(03)任何节点的左和右子树也是二叉搜索树.

(04)没有重复的节点.

在实际应用中,经常使用二进制搜索树. 接下来,以C语言实现二进制搜索树.

1. 节点定义

1.1节点定义

48304ba5e6f9fe08f3fa1abda7d326ab.png

typedef int Type;

typedef struct BSTreeNode{

Type key; // 关键字(键值)

struct BSTreeNode *left; // 左孩子

struct BSTreeNode *right; // 右孩子

struct BSTreeNode *parent; // 父结点

}Node, *BSTree;

48304ba5e6f9fe08f3fa1abda7d326ab.png

二进制搜索树的节点中包含的基本信息:

(01)键-这是用于对二叉搜索树的节点进行排序的键.

(02)left-指向当前节点的左子节点.

(03)right-指向当前节点的右子节点.

(04)parent-指向当前节点的父节点.

1.2创建节点

创建节点的代码

48304ba5e6f9fe08f3fa1abda7d326ab.png

static Node* create_bstree_node(Type key, Node *parent, Node *left, Node* right)

{

Node* p;

if ((p = (Node *)malloc(sizeof(Node))) == NULL)

return NULL;

p->key = key;

p->left = left;

p->right = right;

p->parent = parent;

return p;

}

5dd8b20670a5aa703bdabacfc98bb9cc.png

48304ba5e6f9fe08f3fa1abda7d326ab.png

2个遍历

在这里,我们解释三种方法: 前遍历,中阶遍历和后遍历.

2.1遍历

如果二叉树不为空,请执行以下操作:

(01)访问根节点;

(02)首先遍历左侧子树;

(03)首先遍历右侧子树.

预订遍历代码

48304ba5e6f9fe08f3fa1abda7d326ab.png

void preorder_bstree(BSTree tree)

{

if(tree != NULL)

{

printf("%d ", tree->key);

preorder_bstree(tree->left);

preorder_bstree(tree->right);

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

2.2有序遍历

如果二叉树不为空,请执行以下操作:

(01)左子树的有序遍历;

(02)访问根节点;

(03)以中间顺序遍历右侧子树.

序列遍历代码

48304ba5e6f9fe08f3fa1abda7d326ab.png

void inorder_bstree(BSTree tree)

{

if(tree != NULL)

{

inorder_bstree(tree->left);

printf("%d ", tree->key);

inorder_bstree(tree->right);

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

2.3后遍历

如果二叉树不为空,请执行以下操作:

(01)依次遍历左侧子树;

(02)依次遍历右侧子树;

(03)访问根节点.

后遍历代码

48304ba5e6f9fe08f3fa1abda7d326ab.png

void postorder_bstree(BSTree tree)

{

if(tree != NULL)

{

postorder_bstree(tree->left);

postorder_bstree(tree->right);

printf("%d ", tree->key);

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

通过示例介绍以下遍历方法.

072271348d6dcfc30674b5b16b14d23f.png

对于上面的二叉树,

(01)遍历结果: 3 1 2 5 4 6

(02)有序遍历结果: 1 2 3 4 5 6

(03)后遍历结果: 2 1 4 6 5 3

3. 查找

递归版本的代码

48304ba5e6f9fe08f3fa1abda7d326ab.png

Node* bstree_search(BSTree x, Type key)

{

if (x==NULL || x->key==key)

return x;

if (key < x->key)

return bstree_search(x->left, key);

else

return bstree_search(x->right, key);

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

890_140225135434_1.jpg

该代码的非递归版本

48304ba5e6f9fe08f3fa1abda7d326ab.png

Node* iterative_bstree_search(BSTree x, Type key)

{

while ((x!=NULL) && (x->key!=key))

{

if (key < x->key)

x = x->left;

else

x = x->right;

}

return x;

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

4. 最大值和最小值

找到最大值的代码

48304ba5e6f9fe08f3fa1abda7d326ab.png

Node* bstree_maximum(BSTree tree)

{

if (tree == NULL)

return NULL;

while(tree->right != NULL)

tree = tree->right;

return tree;

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

找到最小值的代码

48304ba5e6f9fe08f3fa1abda7d326ab.png

Node* bstree_minimum(BSTree tree)

{

if (tree == NULL)

return NULL;

while(tree->left != NULL)

tree = tree->left;

return tree;

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

5. 前辈和后继者

节点的前身: 它是该节点左子树中最大的节点.

节点的后代: 是节点右子树中的最小节点.

查找前任节点的代码

48304ba5e6f9fe08f3fa1abda7d326ab.png

Node* bstree_predecessor(Node *x)

{

// 如果x存在左孩子,则"x的前驱结点"为 "以其左孩子为根的子树的最大结点"。

if (x->left != NULL)

return bstree_maximum(x->left);

// 如果x没有左孩子。则x有以下两种可能:

// (01) x是"一个右孩子",则"x的前驱结点"为 "它的父结点"。

// (01) x是"一个左孩子",则查找"x的最低的父结点,并且该父结点要具有右孩子",找到的这个"最低的父结点"就是"x的前驱结点"。

Node* y = x->parent;

while ((y!=NULL) && (x==y->left))

{

x = y;

y = y->parent;

}

return y;

}

本文来自电脑杂谈,转载请注明本文网址:

http://www.pc-fly.com/a/jisuanjixue/article-240760-1.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值