Loading

二叉树的实现:BSTree

一、树和二叉树

1-1 树的定义

翻译过来就是:树是由结点构成的,结点可以有也可以没有。若有结点,则肯定只有一个根结点。树是一种递归结构,俗称 “套娃”

1-2 二叉树的定义

翻译过来就是:二叉树是树的一个子集,每一个结点 至多 只能有两个结点(左结点和右结点)

二、二叉树的特性

2-1 二叉树的存储

二叉树的存储结构可以采用 顺序存储链式存储 两种方式。下面示例采用链式存储结构实现

示例中,小小改动,其中名称和结点数据域变化

typedef struct BSTreeNode
{
	int    key;                 // 关键字(键值)
	struct BSTreeNode *left;    // 左孩子
	struct BSTreeNode *right;   // 右孩子
	struct BSTreeNode *parent;  // 父结点
}Node, *BSTree;

2-2 二叉树的遍历

遍历二叉树(traversing binary tree)是指按某条搜索路径巡访树中每一个结点,使得每一个结点均被访问一次,而且仅被访问一次。

“遍历” 是二叉树各种操作的基础,假设访问结点的具体操作不仅仅局限于输出结点数据域的值,而把 “访问” 延申到对结点的判别、计数等其他操作,可以解决一些关于而二叉树的其他实际问题。

根据访问限定先左后右,有3种访问情况,分别称之为 先(根)序遍历、中(根)序遍历和后(根)序遍历

注意:以集合的方式区分左子树和右子树,不能单纯的以左结点、右结点进行遍历

1️⃣ 先序遍历

若二叉树为空,则空操作;否则
1)访问根结点
2)先序遍历左子树
3)先序遍历右子树

2️⃣ 中序遍历

若二叉树为空,则空操作;否则
1)中序遍历左子树
2)访问根结点
3)中序遍历右子树

3️⃣ 后序遍历

若二叉树为空,则空操作;否则
1)后序遍历左子树
2)后序遍历右子树
3)访问根结点

示例图:

三、二叉树的实现

二叉树项目的主要功能有:

1)创建结点、插入结点、删除结点

2)查找数据域值最大的结点、查找数据域值最小的结点、查找指定数据域值的结点

3)先序遍历、中序遍历、后序遍历

4)查找指定数据域值的结点的前驱结点、查找指定数据域值的结点的后继结点

5)初始化二叉树、销毁二叉树

3-1 源码链接

由于源码篇幅过长,故不放在本页面,需要请访问博主的GitHub链接

  • 遍历
/* 前序遍历 */
static void bstree_preorder(BSTree tree)
{
	if (tree != NULL)
	{
		printf("%d ", tree->key);
		bstree_preorder(tree->left);
		bstree_preorder(tree->right);
	}
}


/* 中序遍历 */
static void bstree_midorder(BSTree tree)
{
	if (tree != NULL)
	{ 
		bstree_midorder(tree->left);
		printf("%d ", tree->key);
		bstree_midorder(tree->right);
	}
}


/* 后序遍历 */
static void bstree_postorder(BSTree tree)
{
	if (tree != NULL)
	{
		bstree_postorder(tree->left);
		bstree_postorder(tree->right);
		printf("%d ", tree->key);
	}
}
  • 查找结点
/* 查找key值最大的结点 */
static Node* bstree_node_maximum_find(BSTree tree)
{
	if (NULL == tree)
	{
		return NULL;
	}
	while (tree->right != NULL)
	{
		tree = tree->right;
	}
	return tree;
}

/* 查找key值最小的结点 */
static Node* bstree_node_minimum_find(BSTree tree)
{
	if (NULL == tree)
	{
		return NULL;
	}
	while (tree->left != NULL)
	{
		tree = tree->left;
	}
	return tree;
}

/* 递归查找法 通过指定key值搜索结点 */
static Node* bstree_node_search_with_key(BSTree tree, int key)
{
	if (NULL == tree || tree->key == key)
	{
		return tree;
	}
	if (key < tree->key)
	{
		return bstree_node_search_with_key(tree->left, key);
	}
	else
	{
		return bstree_node_search_with_key(tree->right, key);
	}
}
  • 前驱结点和后继结点

注意:中序遍历--左子树-> 根 -> 右子树

前驱结点的定义:对二叉树进行 中序遍历 排序后,指定结点的前一个结点称之为前驱结点

后继结点的定义:对二叉树进行 中序遍历 排序后,指定结点的后一个结点称之为后继结点

/* 查找结点node的后继结点,即查找"二叉树中数据值大于该结点的最小结点" */
static Node* bstree_successor(Node *node)
{
	// 若该结点存在右孩子,则查找以右孩子为根结点二叉树的最小结点
	if (node->right != NULL)
	{
		return bstree_node_minimum_find(node->right);
	}
	// 若该结点没有右孩子。则该结点有两种可能:
	// 01) 该结点是一个左孩子,则该结点的后继结点就是它的父结点
	// 02) 该结点是一个右孩子,则查找该结点的最低父结点,且该父结点拥有左孩子,满足条件的最低父结点就是结点node的后继结点
	Node *p = node->parent;
	while (p != NULL && node == p->right)
	{
		node = p;
		p = p->parent;
	}
	return p;
}

/* 查找结点node的前驱结点,即查找"二叉树中数据值小于该结点的最大结点" */
static Node* bstree_predecessor(Node *node)
{
	// 若该结点存在左孩子,则查找以左孩子为根结点二叉树的最大结点
	if (node->left != NULL)
	{
		return bstree_node_maximum_find(node->left);
	}
	// 若该结点没有左孩子。则该结点有两种可能:
	// 01) 该结点是一个左孩子,则查找该结点的最低父结点,且该父结点拥有右孩子,满足条件的最低父结点就是结点的前驱结点
	// 02) 该结点是一个右孩子,则该结点的前驱结点就是它的父结点
	Node *p = node->parent;
	while (p != NULL && node == p->left)
	{
		node = p;
		p = p->parent;
	}
	return p;
}

3-2 编译运行

四、参考来源

数据结构第二版:C语言版--【严蔚敏】 第五章 树和二叉树

posted @ 2023-01-28 14:31  eiSouthBoy  阅读(48)  评论(0)    收藏  举报