二叉排序树(Binary Sort Tree) 又称为二叉查找树(Binary Search Tree) - (代码、分析)

目录:

    • 代码:
    • 分析:

代码:

BSTree.h

#ifndef _BSTREE_H_
#define _BSTREE_H_typedef void BSTree;//定义二叉树类型
typedef void BSKey;//定义节点的键值类型(用于节点排序)typedef struct _tag_BSTreeNode BSTreeNode;//定义二叉树节点类型
struct _tag_BSTreeNode
{BSKey* key;//键值BSTreeNode* left;//左子节点BSTreeNode* right;//右子节点
};typedef void (BSTree_Printf)(BSTreeNode*);//定义参数为一个节点指针并且无返回值的函数类型
typedef int (BSTree_Compare)(BSKey*, BSKey*);//定义参数为两个键值指针并且无返回值的函数类型BSTree* BSTree_Create();//声明创建树函数void BSTree_Destroy(BSTree* tree);//声明销毁树函数void BSTree_Clear(BSTree* tree);//声明清空树函数int BSTree_Insert(BSTree* tree, BSTreeNode* node, BSTree_Compare* compare);//声明插入节点函数BSTreeNode* BSTree_Delete(BSTree* tree, BSKey* key, BSTree_Compare* compare);//声明删除节点函数BSTreeNode* BSTree_Get(BSTree* tree, BSKey* key, BSTree_Compare* compare);//声明获取节点函数BSTreeNode* BSTree_Root(BSTree* tree);//声明获取根节点函数int BSTree_Height(BSTree* tree);//声明获取树高度函数int BSTree_Count(BSTree* tree);//声明获取节点数量函数int BSTree_Degree(BSTree* tree);//声明获取树度数函数void BSTree_Display(BSTree* tree, BSTree_Printf* pFunc, int gap, char div);//定义统一用函数处理节点函数#endif

BSTree.c

#include <stdio.h>
#include <malloc.h>
#include "BSTree.h"typedef struct _tag_BSTree TBSTree;//定义实际使用二叉树类型
struct _tag_BSTree
{int count;//数量BSTreeNode* root;//根节点
};
//用递归调用函数处理节点函数
static void recursive_display(BSTreeNode* node, BSTree_Printf* pFunc, int format, int gap, char div) // O(n)
{int i = 0;if( (node != NULL) && (pFunc != NULL) ){for(i=0; i<format; i++){printf("%c", div);}pFunc(node);printf("\n");if( (node->left != NULL) || (node->right != NULL) ){recursive_display(node->left, pFunc, format + gap, gap, div);recursive_display(node->right, pFunc, format + gap, gap, div);}}else{for(i=0; i<format; i++){printf("%c", div);}printf("\n");}
}static int recursive_count(BSTreeNode* root) //递归计算节点数量函数(没使用到)
{int ret = 0;if( root != NULL ){ret = recursive_count(root->left) + 1 + recursive_count(root->right);}return ret;
}static int recursive_height(BSTreeNode* root) // 递归计算高度函数
{int ret = 0;if( root != NULL ){int lh = recursive_height(root->left);int rh = recursive_height(root->right);ret = ((lh > rh) ? lh : rh) + 1;}return ret;
}static int recursive_degree(BSTreeNode* root) //递归计算度数函数
{int ret = 0;if( root != NULL ){if( root->left != NULL ){ret++;}if( root->right != NULL ){ret++;}if( ret == 1 ){int ld = recursive_degree(root->left);int rd = recursive_degree(root->right);if( ret < ld ){ret = ld;}if( ret < rd ){ret = rd;}}}return ret;
}static int recursive_insert(BSTreeNode* root, BSTreeNode* node, BSTree_Compare* compare)
{int ret = 1;int r = compare(node->key, root->key);//1参数小于2参数返回负数,大于返回正数,等于返回0if( r == 0 )//如果两个键相等插入结果等于0返回到调用函数,表示插入失败{ret = 0;}else if( r < 0 )//如果插入节点的键小于当前比较的节点的键,表示应该是往当前比较的节点的左子节点走{if( root->left != NULL )//如果当前比较的节点的左子节点不为空{//将其左子节点作为下一个与插入节点比较的节点再调用函数进栈,是否插入成功结果返回这里ret = recursive_insert(root->left, node, compare);}else{//否则直接将插入节点作为当前比较节点的左子节点root->left = node;}}else if( r > 0 )//如果插入节点的键小于当前比较根节点的键,表示应该是往当前比较根节点的右子节点走{if( root->right != NULL )//如果当前比较的节点的右子节点不为空{//将其右子节点作为下一个与插入节点比较的节点再调用函数进栈,是否插入成功结果返回这里ret = recursive_insert(root->right, node, compare);}else{//否则直接将插入节点作为当前比较节点的右子节点root->right = node;}}return ret;//将结果返回
}static BSTreeNode* recursive_get(BSTreeNode* root, BSKey* key, BSTree_Compare* compare)//递归查找节点函数
{BSTreeNode* ret = NULL;if( root != NULL ){int r = compare(key, root->key);if( r == 0 ){ret = root;}else if( r < 0 ){ret = recursive_get(root->left, key, compare);}else if( r > 0 ){ret = recursive_get(root->right, key, compare);}}return ret;
}static BSTreeNode* delete_node(BSTreeNode** pRoot)//进行删除节点函数
{BSTreeNode* ret = *pRoot;//取得要删除节点地址if( (*pRoot)->right == NULL )//如果删除节点的右子节点等于空{*pRoot = (*pRoot)->left;//将删除节点的左子节点赋到本来指向删除节点的指针}else if( (*pRoot)->left == NULL )//如果删除节点的左子节点等于空{*pRoot = (*pRoot)->right;//将删除节点的右子节点赋到本来指向删除节点的指针}else//否则表示左右子节点都不为空{BSTreeNode* g = *pRoot;//取得要删除节点地址BSTreeNode* c = (*pRoot)->left;//取得要删除节点的左子节点地址//从删除节点左子节点开始找出一个键与删除节点键最接近的节点,作为删除节点的那个位置//因为从删除节点的左子节点开始,所以它的右子节点一直沿伸的节点的键是最接近删除节点的//c用于指向作为替换到删除节点位置的节点 g是c的父节点while( c->right != NULL )//从删除节点的左子节点往右查找,找到右节点为空的节点{g = c;//更新位置c = c->right;//更新下一个检测的位置}if( g != *pRoot )//g不等于删除节点,表示找到合适的节点{//因为c要替换到删除节点的位置,这时c节点只有左子节点(有指向或NULL)需要处理连接的,//因为c的右子节点确保为NULL了,经过上面的查找,再将c父节点的本来指向c节点的右子节点//指向c的左子节点,而且c的左子节点键肯定大于c的父节点所以是c的父节点的右子节点//相当替换了c节点原来的位置g->right = c->left;}else//否则表示删除节点的左子节点就是合适替换到删除节点位置的节点{//直接将删除节点的左子节点等于c的左子节点,这里就只有c左子节点有指向的g->left = c->left;}c->left = (*pRoot)->left;//将删除节点本来的左子节点部分赋给c节点左子节点c->right = (*pRoot)->right;//将删除节点本来的右子节部分赋给c节点的右子节点*pRoot = c;//把c节点更新到原来删除节点的指针位置}return ret;//返回删除节点
}static BSTreeNode* recursive_delete(BSTreeNode** pRoot, BSKey* key, BSTree_Compare* compare)
{BSTreeNode* ret = NULL;if( (pRoot != NULL) && (*pRoot != NULL) )//比较节点指针地址与指向不为空{  //将当前节点与key值进行比较等于0表示找到了,小于表示应该往当前节点左子节点查找,大于往右子节点查找int r = compare(key, (*pRoot)->key);if( r == 0 )//找到后调用删除节点函数进行删除{//注意:pRoot不是当前节点地址,是指向要删除节点的节点指针的地址(也就是树的根节点指针地址或是上一个节点的左子节点指针或右子节点指针地址)ret = delete_node(pRoot);//将节点指针地址作为参数进行删除操作}else if( r < 0 ){//将当前节点的左子节点指针地址调用函数继续查找ret = recursive_delete(&((*pRoot)->left), key, compare);}else if( r > 0 ){//将当前节点的右子节点指针地址调用函数继续查找ret = recursive_delete(&((*pRoot)->right), key, compare);}}return ret;
}BSTree* BSTree_Create() // 定义创建树函数
{TBSTree* ret = (TBSTree*)malloc(sizeof(TBSTree));if( ret != NULL ){ret->count = 0;ret->root = NULL;}return ret;
}void BSTree_Destroy(BSTree* tree) // 定义销毁树函数
{free(tree);
}void BSTree_Clear(BSTree* tree) // 定义清空树函数
{TBSTree* btree = (TBSTree*)tree;if( btree != NULL ){btree->count = 0;btree->root = NULL;}
}int BSTree_Insert(BSTree* tree, BSTreeNode* node, BSTree_Compare* compare) //定义插入节点函数
{TBSTree* btree = (TBSTree*)tree;//取得树int ret = (btree != NULL) && (node != NULL) && (compare != NULL);//判断参数不为空if( ret ){node->left = NULL;//将插入节点左子节点设空node->right = NULL;//将插入节点右子节点设空if( btree->root == NULL )//如果根节点等于空表示是第一个节点{btree->root = node;}else{//调用递归检测插入位置ret = recursive_insert(btree->root, node, compare);}if( ret )//如果插入成功{btree->count++;//节点数量增加}}return ret;
}BSTreeNode* BSTree_Delete(BSTree* tree, BSKey* key, BSTree_Compare* compare)//定义删除节点函数
{TBSTree* btree = (TBSTree*)tree;//取得树BSTreeNode* ret = NULL; if( (btree != NULL) && (key != NULL) && (compare != NULL) )//判断参数不为空{ret = recursive_delete(&btree->root, key, compare);if( ret != NULL ){btree->count--;}}return ret;
}BSTreeNode* BSTree_Get(BSTree* tree, BSKey* key, BSTree_Compare* compare)//定义获取节点函数
{TBSTree* btree = (TBSTree*)tree;//取得树BSTreeNode* ret = NULL; if( (btree != NULL) && (key != NULL) && (compare != NULL) )//判断参数不为空{ret = recursive_get(btree->root, key, compare);//调用递归查找 }return ret;//返回获取节点
}BSTreeNode* BSTree_Root(BSTree* tree) // 定义获取根节点函数
{TBSTree* btree = (TBSTree*)tree;BSTreeNode* ret = NULL;if( btree != NULL ){ret = btree->root;}return ret;
}int BSTree_Height(BSTree* tree) // 定义获取树高度函数
{TBSTree* btree = (TBSTree*)tree;int ret = 0;if( btree != NULL ){ret = recursive_height(btree->root);//调用递归计算高度函数}return ret;
}int BSTree_Count(BSTree* tree) // 定义获取节点数量函数
{TBSTree* btree = (TBSTree*)tree;int ret = 0;if( btree != NULL ){ret = btree->count;}return ret;
}int BSTree_Degree(BSTree* tree) // 定义获取树度数函数
{TBSTree* btree = (TBSTree*)tree;int ret = 0;if( btree != NULL ){ret = recursive_degree(btree->root);//调用递归计算度数函数}return ret;
}void BSTree_Display(BSTree* tree, BSTree_Printf* pFunc, int gap, char div) //定义用统一函数处理节点函数
{TBSTree* btree = (TBSTree*)tree;if( btree != NULL ){recursive_display(btree->root, pFunc, 0, gap, div);}
}

main.c

#include <stdio.h>
#include <stdlib.h>
#include "BSTree.h"struct Node
{BSTreeNode header;char v;
};void printf_data(BSTreeNode* node)
{if( node != NULL ){printf("%c", ((struct Node*)node)->v);}
}int compare_key(BSKey* k1, BSKey* k2)
{return (int)k1 - (int)k2;
}int main(int argc, char *argv[])
{BSTree* tree = BSTree_Create();struct Node n1 = {{(BSKey*)1, NULL, NULL}, 'A'};struct Node n2 = {{(BSKey*)2, NULL, NULL}, 'B'};struct Node n3 = {{(BSKey*)3, NULL, NULL}, 'C'};struct Node n4 = {{(BSKey*)4, NULL, NULL}, 'D'};struct Node n5 = {{(BSKey*)5, NULL, NULL}, 'E'};struct Node n6 = {{(BSKey*)6, NULL, NULL}, 'F'};BSTree_Insert(tree, (BSTreeNode*)&n4, compare_key);BSTree_Insert(tree, (BSTreeNode*)&n1, compare_key);BSTree_Insert(tree, (BSTreeNode*)&n3, compare_key);BSTree_Insert(tree, (BSTreeNode*)&n6, compare_key);BSTree_Insert(tree, (BSTreeNode*)&n2, compare_key);BSTree_Insert(tree, (BSTreeNode*)&n5, compare_key);printf("Height: %d\n", BSTree_Height(tree));printf("Degree: %d\n", BSTree_Degree(tree));printf("Count: %d\n", BSTree_Count(tree));printf("Search Key 5: %c\n", ((struct Node*)BSTree_Get(tree, (BSKey*)5, compare_key))->v);printf("Full Tree: \n");BSTree_Display(tree, printf_data, 4, '-');BSTree_Delete(tree, (BSKey*)4, compare_key);printf("After Delete Key 4: \n");printf("Height: %d\n", BSTree_Height(tree));printf("Degree: %d\n", BSTree_Degree(tree));printf("Count: %d\n", BSTree_Count(tree));printf("Full Tree: \n");BSTree_Display(tree, printf_data, 4, '-');BSTree_Clear(tree);printf("After Clear: \n");printf("Height: %d\n", BSTree_Height(tree));printf("Degree: %d\n", BSTree_Degree(tree));printf("Count: %d\n", BSTree_Count(tree));BSTree_Display(tree, printf_data, 4, '-');BSTree_Destroy(tree);getchar();return 0;
}

分析:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/379133.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot tomcat默认线程数_记一次JAVA线程池的错误用法

最近项目一个项目要结项了&#xff0c;但客户要求 TPS 能达到上千&#xff0c;而用我写的代码再怎么弄成只能达到 30 的 TPS&#xff0c;然后我又将代码中能缓存的都缓存了&#xff0c;能拆分的也都拆分了&#xff0c;拆分时用的线程池来实现的&#xff1b;其实现的代码主要为…

引以为鉴-ARM开发板连线注意事项

前些日子把实验室的三台机子放到一个工位上&#xff0c;非常拥挤&#xff0c;做实验也很不方便。因此&#xff0c;想把ARM开发板的环境重新搭建到自己的电脑上。说完就做&#xff0c;上午就开始忙活起来。把开发板上的USB线、串口线、JTAT接口、还有电源线一一插好。接着就开始…

CString 类型和引用

怎么理解CString & 类型&#xff1f;在函数参数表中&#xff0c;列了一项是此类型&#xff0c;据说是引用。可以给个具体方法&#xff0c;示例么&#xff1f; 由于子程序调用是栈传递参数&#xff0c;因此对参数的修改不会改变调用者传入的参数的值。如果要改变调用者的参数…

Java IdentityHashMap putAll()方法与示例

IdentityHashMap类putAll()方法 (IdentityHashMap Class putAll() method) putAll() method is available in java.util package. putAll()方法在java.util包中可用。 putAll() method is used to copy all of the entry (key-value pairs) that exists from the given map (m)…

Python---实验八

1&#xff0c;现在有一份‘邀请函.txt’的空白文件&#xff0c;请在同级目录下编写一段代码&#xff0c;写入内容‘诚挚邀请您来参加本次宴会’。 with open(fG:\study\Python\邀请函.txt,modew,encodingutf-8) as y:y.write(诚挚邀请您来参加本次宴会)效果图如下&#xff1a;…

哈希表 - (代码、分析 )

目录&#xff1a;代码&#xff1a;分析&#xff1a;代码&#xff1a; BSTree.h BSTree.c 二叉排序树(Binary Sort Tree) 又称为二叉查找树(Binary Search Tree) Hash.h #ifndef _HASH_H_ #define _HASH_H_typedef void Hash;//定义哈希表类型 typedef void HashKey;//定义哈…

scala spark 数据对比_IT大牛耗时三个月总结出大数据领域学习路线,网友评论:炸锅了...

大数据不是某个专业或一门编程语言&#xff0c;实际上它是一系列技术的组合运用。有人通过下方的等式给出了大数据的定义。大数据 编程技巧 数据结构和算法 分析能力 数据库技能 数学 机器学习 NLP OS 密码学 并行编程虽然这个等式看起来很长&#xff0c;需要学习的东…

Java IdentityHashMap equals()方法与示例

IdentityHashMap类equals()方法 (IdentityHashMap Class equals() method) equals() method is available in java.util package. equals()方法在java.util包中可用。 equals() method is used to check whether this IdentityHashMap object and the given object (ob) are eq…

jQuery中关于Ajax的详解

本文介绍如何使用jquery实现Ajax功能. 用于发送Ajax请求的相关函数如load, get, getJSON和post这些渐变Ajax方法, 对于核心的ajax 方法没有过多介绍, 主要是通过配置复杂的参数实现完全控制Ajax请求。 Ajax让用户页面丰富起来, 增强用户体验. Ajax是所有Web开发的必修课. 虽然A…

Python---实验九作业

1&#xff0c;使用tkinter实现计算器程序。实现效果如下&#xff1a; from tkinter import * from tkinter.ttk import *def frame(master):"""将共同的属性作为默认值, 以简化Frame创建过程"""w Frame(master)w.pack(sideTOP, expandYES, fill…

分析FLV文件分析和解析器的开源代码

分析一下GitHub上一份FLV文件分析和解析器的开源代码 GitHub源码地址&#xff1a;功能强大的 FLV 文件分析和解析器 &#xff1a;可以将flv文件的视频tag中的h264类型数据和音频tag中的aac类型数据导出 &#xff08;只限h264和aac&#xff09; (这个代码不太适合用于大文件的分…

用pv操作描述如下前驱图_LinkedList实现分析(二)——常用操作

上一篇文章LinkedList实现分析(一)——LinkedList初探与对象创建介绍了LinkedList中的一些重要属性和构造方法&#xff0c;下面我们将详细介绍一下LinkedList提高的常用方法的实现原理元素添加###add(E e)方法往LinkedList添加元素&#xff0c;LinkedList提供了多重方式&#x…

C++多重继承与虚基类及与.NET的比较

多重继承前面我们介绍的派生类只有一个基类&#xff0c;称为单基派生或单一继承。在实际运用中&#xff0c;我们经常需要派生类同时具有多个基类&#xff0c;这种方法称为多基派生或多重继承。2.1 多重继承的声明&#xff1a;在 C 中&#xff0c;声明具有两个以上基类的派生类与…

Javascript的IE和Firefox兼容性汇编

window.event现有问题&#xff1a;使用 window.event 无法在 FF 上运行解决方法&#xff1a;FF 的 event 只能在事件发生的现场使用&#xff0c;此问题暂无法解决。可以这样变通&#xff1a;原代码(可在IE中运行)&#xff1a;<input type"button" name"someB…

Java Double类compareTo()方法与示例

双类compareTo()方法 (Double class compareTo() method) compareTo() method is available in java.lang package. compareTo()方法在java.lang包中可用。 compareTo() method is used to check equality or inequality for this Double-object against the given Double-obje…

平院实训门禁系统导入

这是我的配置&#xff08;如果是Win10最好每一步都管理员身份运行&#xff09; win7 SQLServer2008 VS2012 切记&#xff1a;注意&#xff1a;当你SQLserver创建数据库和VS连接数据库的时候得用同一种方式&#xff0c;要么都用window&#xff08;主机名&#xff09;&#xff0…

ffmpeg 解码音频(aac、mp3)输出pcm文件

ffmpeg 解码音频&#xff08;aac、mp3&#xff09;输出pcm文件 播放pcm可以参考&#xff1a; ffplay -ar 48000 -ac 2 -f f32le out.pcm main.c #include <stdio.h> #include <stdlib.h> #include <string.h>#include <libavutil/frame.h> #include …

Jquery getJSON()

getJSON与aspx 准备工作 Customer类 public class Customer{public int Unid { get; set; }public string CustomerName { get; set; }public string Memo { get; set; }public string Other { get; set; }}&#xff08;一&#xff09;ashx Customer customer new Customer { …

北京中信银行总行地址_中信银行拉萨分行举行“存款保险标识”启用和存款保险条例宣传活动...

11月NOV中信银行拉萨分行举行“存款保险标识”启用和《存款保险条例》宣传活动揭牌启用仪式111月Jul根据人民银行和总行关于“存款保险标识”启用工作相关要求&#xff0c;分行行领导高度重视“存款保险标识”启用和《存款保险条例》宣传活动工作&#xff0c;按照统一工作部署、…

Java ClassLoader getPackage()方法与示例

ClassLoader类的getPackage()方法 (ClassLoader Class getPackage() method) getPackage() method is available in java.lang package. getPackage()方法在java.lang包中可用。 getPackage() method is used to return the package that has been defined in ClassLoader or t…