对二叉查找树进行中序遍历,就可以输出一个从小到大的有序数据队列。
查找操作 -- 利用了“二分查找”,所消耗的时间复杂度为 O(logn)。
首先判断根结点是否等于要查找的数据,如果是就返回。
如果根结点大于要查找的数据,就在左子树中递归执行查找动作,直到叶子结点。
如果根结点小于要查找的数据,就在右子树中递归执行查找动作,直到叶子结点。
插入操作
插入操作很简单。从根结点开始,如果要插入的数据比根结点的数据大,且根结点的右子结点不为空,则在根结点的右子树中继续尝试执行插入操作。直到找到为空的子结点执行插入动作。
二叉查找树插入数据的时间复杂度是 O(logn)。这里的时间复杂度更多是消耗在了遍历数据去找到查找位置上,真正执行插入动作的时间复杂度仍然是 O(1)。
删除操作
情况一,如果要删除的结点是某个叶子结点,则直接删除,将其父结点指针指向 null 即可。
情况二,如果要删除的结点只有一个子结点,只需要将其父结点指向的子结点的指针换成其子结点的指针即可。
情况三,如果要删除的结点有两个子结点,则有两种可行的操作方式:
第一种,找到这个结点的左子树中最大的结点,替换要删除的结点。
第二种,找到这个结点的右子树中最小的结点,替换要删除的结点。
树的案例 字典树 -- Dictionary Tree
第一,根结点不包含字符;
第二,除根结点外每一个结点都只包含一个字符;
第三,从根结点到某一叶子结点,路径上经过的字符连接起来,即为集合中的某个字符串。
哈希表 哈希表 -- Hash Table, 也叫作散列表。 哈希表是一种特殊的数据结构,它与数组、链表以及树等我们之前学过的数据结构相比,有很明显的区别。
线性表中的栈和队列对增删有严格要求,它们会更关注数据的顺序。
数组和字符串需要保持数据类型的统一,并且在基于索引的查找上会更有优势。
树的优势则体现在数据的层次结构上。
哈希表优势体现在,无论有多少数据,查找、插入、删除只需要接近常量的时间,即 O(1)的时间级。
核心思想实现 “地址 = f (关键字)” 的映射关系,快速完成基于数据的数值的查找。
哈希函数的设计 直接定制法哈希函数为关键字到地址的线性函数。如,H (key) = a*key + b。这里,a 和 b 是设置好的常数。
数字分析法假设关键字集合中的每个关键字 key 都是由 s 位数字组成(k1,k2,…,Ks),并从中提取分布均匀的若干位组成哈希地址。
平方取中法如果关键字的每一位都有某些数字重复出现,并且频率很高,我们就可以先求关键字的平方值,通过平方扩大差异,然后取中间几位作为最终存储地址。
折叠法如果关键字的位数很多,可以将关键字分割为几个等长的部分,取它们的叠加和的值(舍去进位)作为哈希地址。
除留余数法预先设置一个数 p,然后对关键字进行取余运算。即地址为 key mod p。
解决哈希冲突 开放定址法常用的探测方法是线性探测法。比如有一组关键字 {34,35,36,45},采用的哈希函数为 key mod 11。当插入 34,35,36 时可以直接插入,地址分别为 1、2、3。而当插入 45 时,哈希地址为 45 mod 11 = 1。然而,地址 1 已经被占用,因此沿着地址 1 依次往下探测,直到探测到地址 4,发现为空,则将 45 插入其中。
链地址法将哈希地址相同的记录存储在一张线性链表中。如果出现冲突,就在对应的位置上加上链表的数据结构。
哈希表的基本操作 哈希表中的增加和删除数据操作,不涉及增删后对数据的挪移问题
如果是采用数组实现就需要考虑数据的挪移问题
哈希表查找的细节过程是:对于给定的 key,通过哈希函数计算哈希地址 H (key)。
如果哈希地址对应的值为空,则查找不成功。
反之,则查找成功。
哈希表的案例 实时返回用户的字符串搜索结果