C语言数据结构---二叉树(搜索树)

 可以直接通过代码和代码注释的结合来学习并理解数据结构--队列的基本逻辑,比单纯的看文字理解代码更有乐趣,不过笔者建议在看代码之前可以先去本链接下的视频学习下数据结构---队列会事半功倍哦~ 

注:本视频来源于B站大佬:@动画讲编程的视频

看动画,学习五个经典的树形数据结构,树、二叉树、二叉堆、二叉搜索树、字典树_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV1B5411n7uq/?spm_id_from=333.337.search-card.all.click&vd_source=d16e4170ec5d95766145b717597ec72f

#define  _CRT_SECURE_NO_WARNINGS 

#include <stdio.h>
#include <math.h>
#include <stdlib.h>


/*********************************二叉搜索树************************************************/

//定义二叉搜索树节点结构体
typedef struct TreeNode
{
	int node_val;         //每个树节点上的值
	TreeNode* left_node;  //指向树左侧的节点地址的指针
	TreeNode* right_node; //指向树右侧的节点地址的指针
}TreeNode_t;



//创建一个新节点
TreeNode_t* Creat_Node(int val)
{
	TreeNode_t* node = (TreeNode_t*)malloc(sizeof(TreeNode_t));
	node->node_val = val;
	node->left_node = NULL;          //因为二叉树的性质,刚创建的节点是属于"树梢"
	node->right_node = NULL;         //所以其左右指针不应该指向其他地方,那么置为NULL                                      
	return node;
}


//插入节点到二叉树中
TreeNode_t* Insert_Node(TreeNode_t* root, int val)
{
	TreeNode_t* node = NULL;
	if (root == NULL)                               //二叉树如果不存在
	{
		node=Creat_Node(val);                       //创建一个父节点(树根)
		return node;
	}
	if (val < root->node_val)                       //如果插入的值小于父节点  
	{//那就让要想插入的节点的以目前的父节点的左指针域所指向的地址
		root->left_node= Insert_Node(root->left_node,val);//为这个节点的位置插入,那此时又加入了插入函数以此来形成递归调用
	}//直到让要插入的节点刚好找到一个父节点的指针域指向为NULL的节点,让这个父节点的指针指向该节点即可成功插入 
	else if (val > root->node_val)//插入右边与插入左边同理
	{
		root->right_node = Insert_Node(root->right_node, val);
	}
	else if (val == root->node_val)//如果要插入的值正好等于树中的某个值,那就说明插入的值不符合二叉树的数据结构,那就直接报错
	{//并且不对该值做任何的处理而直接退出函数
		printf("You insert's value equal to tree node value ,insert fail!!!\n");
	}
	return root;
}

//搜索在二叉树中的节点
TreeNode_t* Search_Node(TreeNode_t* root, int val)//与插入节点的方法类似
{
	if (root == NULL || root->node_val == val)//当通过递归调用到节点的地址为NULL时,说明该二叉树没有这个值
	{//或者说二叉树不存在
		return root;//而当出现了要搜索的值正好等于树中的某个值的时候,就说明找到了要搜索的值,那就直接返回
	}
	if (val < root->node_val)                     //要搜索的值在当前节点左边
	{
		return Search_Node(root->left_node, val);
	}
	if (val > root->node_val)					 //要搜索的值在当前节点右边
	{
		return Search_Node(root->right_node, val);
	}
}

//删除一个二叉树节点
TreeNode_t* Delete_Node(TreeNode_t* root,int val)
{	
	TreeNode_t* temp = NULL;
	if (root == NULL)										    //树不存在                    
	{
		return root;//NULL
	}
	if (val < root->node_val)                                   //要删除的节点在左子树
	{
		root->left_node = Delete_Node(root->left_node, val);
	}
	if (val > root->node_val)									//要删除的节点在右子树
	{
		root->right_node = Delete_Node(root->right_node, val);
	}
	else if(val == root->node_val)							    //要删除的节点刚好被找到
	{
		if (root->left_node == NULL && root->right_node == NULL)//就只有一个节点或者在树的子叶节点处
		{
			free(root);                                         //直接删除(释放内存空间)
			return NULL;										//该树就一个节点,所以删除后就应该返回NULL
		}
		else if (root->left_node != NULL && root->right_node == NULL)//该节点只有左子树
		{
			temp = root->left_node;								     //temp指向就会该节点的左子树
			free(root);
			return temp;                                             //返回那个被删除后的节点遗留下的节点的地址,因为递归的调用,这个地址会被被删除的那个节点的父节点的指针所指向,于是这个temp就和整个树就连起来了!!!
		}
		else if (root->left_node == NULL && root->right_node != NULL)//该节点只有右子树
		{
			temp = root->right_node;								//temp指向就会该节点的右子树
			free(root);                                             //返回那个被删除后的节点遗留下的节点的地址,因为递归的调用,这个地址会被被删除的那个节点的父节点的指针所指向,于是这个temp就和整个树就连起来了!!!
			return temp;                 
		}
		/*这部分还需要多理解*/
		else if (root->left_node != NULL && root->right_node != NULL)//该节点有既有左子树又有右子树
		{
			TreeNode_t* Minnode = root->right_node;                 //切换为右子树
			while (Minnode->left_node != NULL)                      //找到右子树最小的节点
			{
				Minnode = Minnode->left_node;					    //这是因为二叉树的数据结构就是左子树永远要小于自己的父节点,而右子树永远要大于自己的父节点
			}														//所以这里一直让Minnode去指向该root的右子树的最左边的左子树
			root->node_val = Minnode->node_val;						//将找到的最小值赋给要想删除的节点
			root->right_node = Delete_Node(root->right_node, Minnode->node_val);//通过递归来删除该树右子树的最小节点,因为该节点已经被用来代替了那个被删除的节点了
		}
	}
	return root;
}

//遍历并打印二叉树中的各个节点的值
void Ergodic_Tree(TreeNode_t* root)
{
	if (root != NULL)
	{
		 printf("root value=%d\n", root->node_val);//打印节点的值
		 Ergodic_Tree(root->left_node);            //递归打印左子树的值 
		 Ergodic_Tree(root->right_node);           //递归打印右子树的值
	}
}


//示例
int main(void)
{
	//创建一个"树根"
	TreeNode_t* root=NULL;
	//创建并插入二叉树节点
	printf("Ceart and insert tree node:\n");
	root = Insert_Node(root, 10);
	root = Insert_Node(root, 20);
	root = Insert_Node(root, 40);
	root = Insert_Node(root, 30);
	root = Insert_Node(root, 100);
	root = Insert_Node(root, 30);
	root = Insert_Node(root, 60);
	//遍历二叉树
	printf("Ergodic tree:\n");
	Ergodic_Tree(root);
	//删除一个节点
	printf("Delect a tree node:\n");
	root = Delete_Node(root,100);
	//遍历二叉树
	printf("Ergodic tree:\n");
	Ergodic_Tree(root);
	//搜索一个节点
	printf("Search a tree node:\n");
	root=Search_Node(root,60);
	if (root != NULL)
	{
		printf("Search Success!!!,value=%d\n",root->node_val);//搜索到了
	}
	else
	{
		printf("Search Fail!!!,not exist value!!\n");        //没有搜索到
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
平衡二叉树是一种特殊的二叉树,它的左右子的高度差不超过1。AVL是一种自平衡的二叉搜索,它的高度始终保持在O(log n)。 下面是C语言实现平衡二叉树(AVL)的代码: ``` #include <stdio.h> #include <stdlib.h> /* 定义平衡二叉树节点结构体 */ struct AVLNode { int data; // 存储的数据 int height; // 节点高度 struct AVLNode *leftChild; // 左子 struct AVLNode *rightChild; // 右子 }; /* 获取节点高度 */ int getHeight(struct AVLNode *node) { if (node == NULL) { return -1; } else { return node->height; } } /* 获取节点平衡因子 */ int getBalanceFactor(struct AVLNode *node) { if (node == NULL) { return 0; } else { return getHeight(node->leftChild) - getHeight(node->rightChild); } } /* 更新节点高度 */ void updateHeight(struct AVLNode *node) { node->height = 1 + (getHeight(node->leftChild) > getHeight(node->rightChild) ? getHeight(node->leftChild) : getHeight(node->rightChild)); } /* 右旋操作 */ struct AVLNode *rotateRight(struct AVLNode *node) { struct AVLNode *newRoot = node->leftChild; node->leftChild = newRoot->rightChild; newRoot->rightChild = node; updateHeight(node); updateHeight(newRoot); return newRoot; } /* 左旋操作 */ struct AVLNode *rotateLeft(struct AVLNode *node) { struct AVLNode *newRoot = node->rightChild; node->rightChild = newRoot->leftChild; newRoot->leftChild = node; updateHeight(node); updateHeight(newRoot); return newRoot; } /* 插入操作 */ struct AVLNode *insert(struct AVLNode *root, int data) { if (root == NULL) { root = (struct AVLNode *) malloc(sizeof(struct AVLNode)); root->data = data; root->height = 0; root->leftChild = NULL; root->rightChild = NULL; } else if (data < root->data) { root->leftChild = insert(root->leftChild, data); if (getHeight(root->leftChild) - getHeight(root->rightChild) == 2) { if (data < root->leftChild->data) { root = rotateRight(root); } else { root->leftChild = rotateLeft(root->leftChild); root = rotateRight(root); } } } else if (data > root->data) { root->rightChild = insert(root->rightChild, data); if (getHeight(root->rightChild) - getHeight(root->leftChild) == 2) { if (data > root->rightChild->data) { root = rotateLeft(root); } else { root->rightChild = rotateRight(root->rightChild); root = rotateLeft(root); } } } updateHeight(root); return root; } /* 中序遍历 */ void inOrderTraversal(struct AVLNode *root) { if (root != NULL) { inOrderTraversal(root->leftChild); printf("%d ", root->data); inOrderTraversal(root->rightChild); } } int main() { struct AVLNode *root = NULL; int data[] = {5, 2, 8, 1, 3, 6, 9}; int len = sizeof(data) / sizeof(data[0]); int i; for (i = 0; i < len; i++) { root = insert(root, data[i]); } inOrderTraversal(root); return 0; } ``` 以上代码实现了平衡二叉树的插入和中序遍历操作。在插入操作中,根据插入节点的值和当前节点的值的大小关系,不断递归向左或向右子进行插入操作,并在递归返回时更新节点高度和进行平衡操作。在平衡操作中,根据节点的平衡因子进行旋转操作,使重新平衡。在中序遍历操作中,按照左子、根节点、右子的顺序遍历中的节点,输出节点的值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值