上一篇:iOS标准库中常用数据结构和算法之排序

?二叉排序树

功能:二叉排序树的标准实现是一颗平衡二叉树。二叉排序树主要用来解决高效插入和高效检索以及进行排序的问题。系统分别提供了二叉排序树节点的查找、添加、删除、遍历4个功能。

iOS中实现的二叉排序树并不是一颗平衡二叉树,因此进行检索时其时间复杂度可能不是O(logN)。这里极度鄙视一下!但是其它UNIX系统中的实现则是正确的。

对于二叉排序树节点的数据结构,系统给出了一个模板:

typedef   struct node {char         *key;          //第一个数据成员必须是指针类型!struct node  *llink;   //左子树 struct node *rlink;   //又子树
} node_t;
复制代码

要实现用二叉排序树时需要我们自己来定义节点的数据结构,因为下列函数中所有关于节点的参数都是void*类型的。所以其内部实现不关心结构体是如何的,但是一定要满足上面的模板的格式。

头文件:#include <search.h>

平台: BSD Unix。

1.查找和添加

函数签名

 //查找节点,如果找不到则返回NULL。void *tfind(const void *key, void *const *rootp, int (*compar) (const void *key1, const void *key2));
//查找节点,如果找不到则添加到树中去。void *tsearch(const void *key, void **rootp, int (*compar) (const void *key1, const void *key2));
复制代码

参数

key:[in] 要查找或者插入的内容

rootp:[in/out] 二叉树根节点指针的指针,这里作为输出的原因是因为要构造出一颗平衡二叉树,所以树根节点可能会变化。如果要建立的是第一个节点则可以传一个空指针的指针作为输入输出。

compar:[in] 节点函数比较器,这个比较器的格式如下:

/*
@key1: 函数传递进来的关键字。
@key2: 树中节点中的关键字,注意的是这个参数并不是树的节点指针而是节点中的key数据成员。
@return: 如果比较结果相等则返回0, 如果key1在key2前返回小于0,如果key1在key2后面则返回大于0
*/int compar(const void *key1, const void *key2);
复制代码

return:[out] 对于tfind来说如果在树中查找到对应的节点则返回节点指针,如果没有找到则返回NULL。对于tsearch来说如果在树中查找到对应的节点则返回节点指针,如果没有找到则会将创建一个新的节点并将要查找的key作为新插入节点的key属性,同时把新创建的节点返回。

描述

这两个函数分别负责查找和插入操作。树节点的内存分配和构建由系统来完成。

2.删除

函数签名


void * tdelete(const void *restrict key, void **restrict rootp, int (*compar) (const void *key1, const void *key2));复制代码

参数: key:[in] 要删除的节点key属性。 rootp:[in/out] 树的根节点,随着节点的删除为了保证平衡性会调节树的根节点,因此这里需要传递指针的指针值。 compar:[in] 节点函数比较器。 return:[out] 返回删除的节点的父节点指针,如果删除的是根节点则返回根节点本身,如果要删除的key并不在树中则返回NULL。

描述 系统内部负责节点内存的创建和销毁,因此当某个树节点被删除后这个树节点内存会被销毁而不能再访问了,否则会出现crash。

3.遍历

函数签名


void twalk(const void *root, void (*action) (const void *node, VISIT order, int level));复制代码

参数

root:[in] 树的根节点指针,注意这里不是指针的指针。因为遍历不会调整树的根节点。

action:[in] 遍历一棵树有前序遍历、中序遍历和后序遍历三种遍历方式,因为系统不知道你要怎么处理遍历的节点,因此通过提供一个回调函数来实现节点的遍历。这个回调函数的格式如下:

@node: 要遍历的节点。
@order:要遍历的顺序,这个VISIT是一个枚举类型。
@level: 当前遍历的节点所处的树的层级,层级以0开始,对应树根节点的层级。
void action(const void *node, VISIT order, int level);
复制代码

描述

可以看出上面要实现遍历时必须提供一个回调的action函数,在action函数中通过对VISIT类型的参数order进行判断可以实现各种遍历。VISIT的定义如下:

typedef  enum {preorder,postorder,endorder,leaf
} VISIT;
复制代码

当order的值是preorder或者leaf时系统将执行的是前序遍历,当order的值是postorder或者leaf时系统将执行的是中序遍历,当order的值是endorder或者leaf时系统将执行的是后序遍历,当order的值是leaf系统将执行的叶子遍历。下面的代码将演示对遍历的处理。

void action(const void *node, VISIT order, int level)
{if (order == preorder || order == leaf){//前序遍历}if (order == postorder || order == leaf){//中序遍历}if (order == endorder || order == leaf){//后序遍历}if (order == leaf){//只遍历叶子}
}
复制代码

示例代码

//定义一个树节点类型,节点必须按这个格式定义
typedef struct _node
{char *key;    //树节点的内容。struct _node *left;struct _node *right;
}node_t;//树排序比较器函数
int bintreecompar(const char *key1, const char *key2)
{return strcmp(key1, key2);
}//树遍历函数,这里进行前序遍历,按树节点升序输出。
void action(node_t *node, VISIT order, int level)
{if (order == preorder || order == leaf){printf("node's key = %s\n", node->key);}
}void main()
{node_t *root = NULL;   //定义树的根节点,最开始时根节点为空。//添加//看这里对root参数传递的规则,因为每次插入都有可能会改变根节点的值。node_t *p1 = tsearch("Bob", &root, bintreecompar);   //返回节点对象,我们不需要负责节点对象的销毁,而是通过调用tdelete函数来销毁。NSAssert(strcmp(p1->key, "Bob")==0, @"oops!");node_t *p2 = tsearch("Alice", &root, bintreecompar);node_t *p3 = tsearch("Max", &root, bintreecompar);node_t *p4 = tsearch("Lucy", &root, bintreecompar);//查找node_t *p = tfind("Lily", &root, bintreecompar);NSAssert(p == NULL, @"oops!");p =  tfind("Lucy", &root, bintreecompar);NSAssert(p != NULL, @"oops!");//删除p = tdelete("Jone", &root, bintreecompar);NSAssert(p == NULL, @"oops!");p = tdelete("Lucy", &root, bintreecompar);NSAssert(p != NULL, @"oops!");//遍历树twalk(root, action);
}复制代码

iOS标准库中常用数据结构和算法之二叉排序树相关推荐

  1. iOS标准库中常用数据结构和算法之内存池

    上一篇:iOS标准库中常用数据结构和算法之位串 ⛲️内存池 内存池提供了内存的复用和持久的存储功能.设想一个场景,当你分配了一块大内存并且填写了内容,但是你又不是经常去访问这块内存.这样的内存利用率将 ...

  2. keilcjson内存分配失败_iOS标准库中常用数据结构和算法之内存池

    黑客技术点击右侧关注,了解黑客的世界! Java开发进阶点击右侧关注,掌握进阶之路! Linux编程点击右侧关注,免费入门到精通! 作者丨欧阳大哥2013https://www.jianshu.com ...

  3. C++知识点26——使用C++标准库(常用的泛型算法1)

    C++中实现了很多的泛型算法,大约100多个,使用前要添加#include<algorithm> 下面介绍的基本可以满足绝大部分需求,其他的用到再查 一.计数算法 1.count temp ...

  4. C++知识点27——使用C++标准库(常用的泛型算法2)

    接上一篇博客https://blog.csdn.net/Master_Cui/article/details/108404257 八.删除元素 template <class ForwardIt ...

  5. ollections 库中常用的 4 个数据结构

    collections 库是标准库的一部分,里面有很多数据结构,在列表.字典.元组的基础上做了很多修改和提升. 今天就来说说最有用的几个. 1.deque 它实现了两端都可以操作的队列,相当于双端队列 ...

  6. 聊聊C++11标准库中堆(heap)算法的源码

    STL中支持堆操作,对外暴露了std::make_heap,std::push_heap,std::pop_heap,std::sort_heap,std::is_heap,std::is_heap_ ...

  7. php spl函数,PHP SPL标准库中的常用函数介绍

    这篇文章主要介绍了PHP SPL标准库中的常用函数介绍,本文着重讲解了spl_autoload_extensions().spl_autoload_register().spl_autoload()三 ...

  8. 面试常考的常用数据结构与算法

    面试常考的常用数据结构与算法 数据结构与算法,这个部分的内容其实是十分的庞大,要想都覆盖到不太容易.在校学习阶段我们可能需要对每种结构,每种算法都学习,但是找工作笔试或者面试的时候,要在很短的时间内考 ...

  9. C++标准库中的随机数生成

    C++标准库中的随机数生成 一.伪随机与真随机 数字计算机的结果可以说是固定的.必然的.都是根据现有数据的状态得出接下来的状态.除非硬件损坏,计算机不会产生真正的随机和无法预料的事.在生活中随手抛一个 ...

最新文章

  1. 你了解 Java 的 jstat 命令吗?
  2. python400集视频教程 百度云-Python自动化测试视频教程【百度云盘下载】
  3. love2d教程3--输入和音乐
  4. Same Sum Blocks
  5. 配置 CentOS 7 的网络,及重命名网卡名
  6. php querystring使用,node.js中的querystring.parse方法使用说明_node.js
  7. 开放、普惠、高性能-SLS时序存储助力打造企业级全方位监控方案
  8. 【Kubernetes】mac 安装minikube
  9. c#图片色阶调整、亮度调整
  10. [转]SQL Server 安全性概論與無法刪除資料庫使用者的解決辦法
  11. 并联串联混合的电压和电流_如何从本质上判断电压表测量谁的电压?
  12. matlab节约里程法_节约里程法matlab.doc
  13. 平衡小车simulink仿真_到底该用哪款神器来仿真我的机器人?
  14. 打开计算机显示远程控制,win7系统远程协助怎么打开?开启远程协助功能教程...
  15. 悲伤是一种毒,会上瘾
  16. 小程序登录、微信网页授权(Java版)
  17. 对话论答创始人王枫:“TAD”战法布局AI教育 让每个孩子都能享受优质教育
  18. python meizitu
  19. 高德地图轨迹回放、点的弹跳效果、浏览器环境监测、设置地图的主题样式、GPS坐标转为高德坐标、地图加载提示、地图DOM事件、修改图层等API接口
  20. AndroidStudio制作个人资料界面模块以及SQLite数据库的使用

热门文章

  1. 漂流瓶 php,PHP实现的迷你漂流瓶
  2. npm更换成淘宝镜像源以及cnpm
  3. java计算两个日期相差月数
  4. 找回消失的ubuntu启动选项
  5. C++目录遍历:使用第三方库boost.filesystem等
  6. mysql数据库优化课程---13、mysql基础操作
  7. java:我们对Iterator理解错了
  8. C#核编之系统数据类型和相应的C#关键字
  9. Spring 常用注入注解(annotation)和其对应xml标签
  10. FTP服务器配置与管理(4) 服务器端的常用配置及FTP命令