二叉查找树的C语言实现(一)
什么是二叉查找树?
二叉查找树(Binary Search Tree),也称有序二叉树(ordered binary tree),排序二叉树(sorted binary tree),是指一棵空树或者具有下列性质的二叉树:
- 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 任意节点的左、右子树也分别为二叉查找树;
- 没有键值相等的节点(no duplicate nodes)。
struct bnode_info {
struct bnode_info *parent;
struct bnode_info *lchild;
struct bnode_info *rchild;
};
怎么没有数据域呢?模仿内核链表,我们把这个节点嵌入到大的结构体里。
static inline void bnode_init(struct bnode_info *bnode)
{
bnode->parent = NULL;
bnode->lchild = NULL;
bnode->rchild = NULL;
}
节点的初始化函数,为下文做准备。
struct data_info {
int data;
struct bnode_info bnode;
};
这个是测试用的,可以看到,把节点嵌入了进去。
static int bnode_cmp(struct bnode_info *a, struct bnode_info *b)
{
struct data_info *pa = list_entry(a, struct data_info, bnode);
struct data_info *pb = list_entry(b, struct data_info, bnode);
return pa->data - pb->data;
}
这是比较函数,关于list_entry宏,前面的博文已经说了,这里不赘述。
struct btree_info {
struct bnode_info *root; //指向树根
int (*key_cmp)(struct bnode_info *a,
struct bnode_info *b);
void (*push)(struct bnode_info *bnode,
struct btree_info *info);
int (*del)(struct bnode_info *bnode, struct btree_info *info);
struct bnode_info *(*find)(struct bnode_info *bnode,
struct btree_info *info);
void (*pre_order)(struct btree_info *info,
void (*todo)(struct bnode_info *bnode));
void (*in_order)(struct btree_info *info,
void (*todo)(struct bnode_info *bnode));
void (*post_order)(struct btree_info *info,
void (*todo)(struct bnode_info *bnode));
//非递归遍历
void (*pre_order_norecur)(struct btree_info *info,
void (*todo)(struct bnode_info *bnode));
void (*in_order_norecur)(struct btree_info *info,
void (*todo)(struct bnode_info *bnode));
void (*post_order_norecur)(struct btree_info *info,
void (*todo)(struct bnode_info *bnode));
void (*level_order)(struct btree_info *info,
void (*todo)(struct bnode_info *bnode));
size_t (*get_depth)(const struct btree_info *info);
int (*is_empty)(const struct btree_info *info);
};
这里定义了很多方法,我们先不管,只要知道里面有个指针,指向树根就可以了。
static int btree_is_empty(const struct btree_info *btree)
{
return btree->root == NULL;
}
如果树为空,那就是连树根都没有了。
static void btree_push2(struct bnode_info *bnode,
struct btree_info *info)
{
assert(bnode != NULL && info != NULL); bnode_init(bnode); //[1].空树
if (btree_is_empty(info))
{
info->root = bnode;
return;
} //[2].非空树
struct bnode_info *cur = info->root;
struct bnode_info *parent = NULL;
int flag = 0; while (cur != NULL)
{
parent = cur;
if (info->key_cmp(bnode, cur) >= 0)
{
//右
cur = cur->rchild;
flag = 1;
}
else
{
//左
cur = cur->lchild;
flag = 0;
}
} if(flag==0)
parent->lchild=bnode;
else
parent->rchild=bnode; bnode->parent = parent; }
为了验证对错,我们要写个遍历树的方法。看看先序遍历-递归版本,(先树根,然后左子树,最后右子树)
static void __pre_order(struct bnode_info *bnode,
void (*todo)(struct bnode_info *bnode))
{
if (bnode != NULL) {
todo(bnode);
__pre_order(bnode->lchild, todo);
__pre_order(bnode->rchild, todo);
}
} static void btree_pre_order(struct btree_info *info,
void (*todo)(struct bnode_info *bnode))
{
__pre_order(info->root, todo);
}
void print_node(struct bnode_info *node)
{
struct data_info *pa = list_entry(node, struct data_info, bnode); printf("%d ", pa->data);
}
这个是打印用的,到时候传给todo。
int main()
{ struct data_info s[]={
{50},{24},{80},{16},{26},{5}
};
struct btree_info *btree = (struct btree_info *)
malloc(sizeof(struct btree_info));
assert(btree != NULL); btree_init(btree, bnode_cmp); int i;
for (i = 0; i < sizeof s/ sizeof *s; ++i) {
btree->push(&s[i].bnode, btree);
} //遍历
printf("--pre_order--\n");
btree->pre_order(btree, print_node);
printf("\n");
--pre_order--
50 24 16 5 26 80
接着说插入,前面是非递归方法。这次我们用递归。思路很简单,把要插入的节点,和树根比,如果树根为空,那么这个节点就成为树根;如果比树根小,就和树根的左孩子比(左孩子可以看成是新的树根);如果比树根大,就和树根的右孩子比。这里需要注意的是,假设比树根小,那么就和树根的左孩子比,假设传进来的参数是新节点和左孩子,我们发现左孩子为NULL,怎么办呢?当然应该把新节点的地址写入这里,为了改写NULL,我们就应该知道这个域的地址,这里就引入了二级指针。也就是说,我们的函数设计的时候,参数是新节点的地址,和树根的二级指针。
static void __push(struct bnode_info *bnode, struct bnode_info **pnode,
int (*cmp)(struct bnode_info *a, struct bnode_info *b))
{
if (*pnode == NULL)
{
bnode_init(bnode);
*pnode = bnode;
}
else
{
if (cmp(bnode, *pnode) > 0)
__push(bnode, &(*pnode)->rchild,cmp); else
__push(bnode, &(*pnode)->lchild,cmp);
}
} void btree_push_recursion(struct bnode_info *bnode, struct btree_info *info)
{
assert(bnode != NULL && info != NULL);
__push(bnode, &info->root,info->key_cmp);//第二个参数是二级指针
}
总结一下,这篇文章我们说了什么?1.节点的插入(递归和非递归)2.先序遍历(递归版本)
二叉查找树的C语言实现(一)的更多相关文章
- 二叉查找树的C语言实现(二)
接着上次的话题.这次我们要讨论,二叉查找树的中序遍历和后序遍历(递归和非递归),另外还有先序遍历(非递归) 1.中序遍历(递归) static void __in_order(struct bnode ...
- 二叉查找树(二叉排序树)(C语言)
#include<stdio.h> #include "fatal.h" struct TreeNode; typedef struct TreeNode *Posit ...
- 二叉查找树(一)之 图文解析 和 C语言的实现
概要 本章先对二叉树的相关理论知识进行介绍,然后给出C语言的详细实现.关于二叉树的学习,需要说明的是:它并不难,不仅不难,而且它非常简单.初次接触树的时候,我也觉得它似乎很难:而之所产生这种感觉主要是 ...
- AVL树(一)之 图文解析 和 C语言的实现
概要 本章介绍AVL树.和前面介绍"二叉查找树"的流程一样,本章先对AVL树的理论知识进行简单介绍,然后给出C语言的实现.本篇实现的二叉查找树是C语言版的,后面章节再分别给出C++ ...
- 二叉查找树C语言实现
二叉查找树C语言实现 1. 二叉查找树的定义: 左子树不为空的时候,左子树的结点值小于根节点,右子树不为空时,右子树的结点值大于根节点,左右子树分别为二叉查找树 2. 二叉查找树的 ...
- 数据结构学习:二叉查找树的概念和C语言实现
什么是二叉查找树? 二叉查找树又叫二叉排序树,缩写为BST,全称Binary Sort Tree或者Binary Search Tree. 以下定义来自百度百科: 二叉排序树或者是一棵空树,或者是具有 ...
- 数据结构:二叉查找树(C语言实现)
数据结构:二叉查找树(C语言实现) ►写在前面 关于二叉树的基础知识,请看我的一篇博客:二叉树的链式存储 说明: 二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: 1.若其左子树不空,则左子树上 ...
- 深入浅出数据结构C语言版(12)——平衡二叉查找树之AVL树
在上一篇博文中我们提到了,如果对普通二叉查找树进行随机的插入.删除,很可能导致树的严重不平衡 所以这一次,我们就来介绍一种最老的.可以实现左右子树"平衡效果"的树(或者说算法),即 ...
- 二叉查找树(查找、插入、删除)——C语言
二叉查找树 二叉查找树(BST:Binary Search Tree)是一种特殊的二叉树,它改善了二叉树节点查找的效率.二叉查找树有以下性质: (1)若左子树不空,则左子树上所有节点的值均小于它的根节 ...
随机推荐
- Spring Boot 学习系列(02)—使用热部署,提升开发效
此文已由作者易国强授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 开发调试很简单 热部署的使用非常简单,但能极大的提高我们的开发效率,像传统的web应用,我们修改后需要重新编 ...
- Liunx在开机后,自动启动openldap、radius、memcached等程序的shell脚本
以下是脚本命令: #!/bin/bash #说明:此文件需放在/etc/rc.d/init.d/目录下,然后编辑文件/etc/rc.d/rc.local,在里面添加bash /etc/init.d/A ...
- [SinGuaRiTy] 2017-07-24 NOIP2015 模拟赛
[SinGuLaRiTy-1030] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 对于所有题目: Time Limit: 1s | Mem ...
- [SinGuLaRiTy] 数论题目复习
[SinGuLaRiTy-1020] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. [CQBZOJ 1464] Hankson 题目描述 H ...
- 解决“System.Data.OracleClient 需要 Oracle 客户端软件 version 8.1.7 或更高版本”的问题
以server2008为例: 首先确保使用sqlplus能访问数据库. 1.管理工具->计算机管理->本地用户和组->组->administrators属性,添加,高级,立即查 ...
- 配置vuex并使用
配置vuex并使用 安装vuex: npm install --save-dev vuex 在src目录下创建store文件夹 store文件夹下文件 index.js,state.js,getter ...
- 快速找出故障机器(single number)
简单起见,假设每个机器存储一个标号为ID的记录(ID是小于十亿的整数),假设每份数据都保存两个备份,这样就有两个机器储存了同样的数据. 1.在某个时间,如果得到一个数据文件ID的列表,是否能够快速地找 ...
- HashMap 1.8的源码分析一
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, ...
- 读经典——《CLR via C#》(Jeffrey Richter著) 笔记_命名空间和程序集的关系
命名空间和程序集不一定相关 1. 同一个命名空间中的各个类型可能是在不同的程序集中实现的.(System.IO.FileStream在MSCorLib.dll程序集中,而System.IO.FileS ...
- Quartz中Cron详解
Quartz中的cron跟Linux系统的cron定义不太一样(Linux从分开始) 特殊字符: * 用来表示包含一个范围内的任意值. 例如, 分钟位置的“*” 表示 “每分钟”. ? 当不特定指代 ...