to meimei,
二分查找是常见的一种查找方式,即:对有序的序列,每次查找先比较中间位置mid=(left+right)/2是否为所找元素
,是则结束查找,否则分别遍历左右半边序列,直至找到目标。
时间复杂度为O(lgn)。
做过的一个笔试题:
2015去哪儿春季笔试题
一个递增数组如【1,2,3,4,5】可以右移 例如【3,4,5,1,2】
请设计一个函数int indexofArray(int []array, int target),如果target在数字中返回数组下标否则返回-1
思路:
一般思路为顺序找到交界处位置k,需要O(lgn),然后对k,k+1,n,1,…k-1进行二分查找,稍微变换下坐标即可。
我的思路为先用二分查找找到交界处,代码如下:
private static int fun(int[] a,int i,int j) {
if(a==null || a.length==0||i<0||j>=a.length){
return -1;
}
int half = (i+j)/2;
while(i<=j){
half = (i+j)/2;
if(a[half]<a[half+1]){
int m = fun(a,i,half-1);
int n = fun(a,half+1,j);
return m>0?m:n>0?n:-1;
}else{
return half;//返回有序序列的最大值位置
}
}
return -1;
}
再根据返回值,进行下一步的二分查找。
================================================
二叉树有以下分类
完全二叉树、满二叉树、平衡二叉树
(1)完全二叉树——若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排
布,这就是完全二叉树。
(2)满二叉树——除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树。
(3)平衡二叉树——平衡二叉树又被称为AVL树(区别于AVL算法),它是一棵二叉排序树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对
值不超过1,并且左右两个子树都是一棵平衡二叉树。
算法题:
<6.在二叉树中找出和为某一值的所有路径
在二叉树中找出和为某一值的所有路径
栈s为静态的sum值初始为0
如果sum+root.value<target 则加上root.value并且s.push(root); 然后递归到root左子树,右子树 递归后s.pop sum还原
public class Test11 {
public static void main(String[] args) {
TNode t4 = new TNode(4, null, null);
TNode t7 = new TNode(7, null, null);
TNode t5 = new TNode(5, t4, t7);
TNode t12 = new TNode(12, null, null);
TNode t10 = new TNode(10, t5, t12);
//postOrder(t10);
printPath(t10,0,22);
}
static Stack<TNode> s = new Stack<TNode>();
public static void printPath(TNode root, int sum, final int target) {
if( root == null)
return;
if( sum + root. value == target){
visit(s);
visit(root);
} else if( sum + root. value < target){
sum += root. value;
s.push( root);
printPath(root.left, sum, target);
printPath(root.right, sum, target);
s.pop();
sum-= root. value;
} else{
return;
}
}
private static void visit(TNode root) {
System. out.println( root. value);
}
private static void visit(Stack<TNode> s2) {
for (TNode tNode : s2) {
System. out.println( tNode. value);
}
}
}
8.判断整数序列是不是二叉搜索树的后序遍历结果
思路:
空二叉树和只有根节点的二叉树也是一棵二叉查找树,所以不要忽略对空序列以及只有一个元素的序列的处理。
最后一个元素为根节点root
先判断空二叉树和单节点二叉树 if(array==null || array.length<2) return true;
先找到第一个大于root的位置i,判断i右边元素全部大于root
那么二叉排序树和平衡二叉树有何区别?
二叉排序树是已排序好的二叉树,左子树<父<右子树 构建二叉排序树的过程即从待排序元素 一个个插入二叉排序树
查询的平均时间复杂度为O(lgn) 类似于二分查找 而当待排序序列为有序序列时 二叉排序树退化成一个单链
查询的时间复杂度退化为线性的O(n) 查询稳定性不够好,当然,通过随机化建立二叉树可以改善,但不能完全避免。
而且,在进行了多次的操作之后,由于在删除时,我们总是选择将待删除节点的后继代替它本身,这样就会造成总是
右边的节点数目减少,以至于树向左偏沉。这同时也会造成树的平衡性受到破坏,提高它的操作的时间复杂度。
=============================
平衡二叉树应运而生
平衡二叉搜索树(Balanced Binary Tree,即AVL树)具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝
对值不超过1,并且左右两个子树都是一棵平衡二叉树。常用算法有红黑树、AVL、Treap、伸展树等。在平衡二叉搜索树
中,我们可以看到,其高度一般都良好地维持在O(log2n),大大降低了操作的时间复杂度。
在做插入,删除操作时,会通过旋转保证平衡二叉树的平衡性。
=============================
b树和b+树的比较
b树:一棵m阶B树(balanced tree of order m)是一棵平衡的m路搜索树。
B树的查找 在B树中查找给定关键字的方法是,首先把根结点取来,在根结点所包含的关键字K1,…,kj查找给定的关键字(
可用顺序查找或二分查找法,若找到等于给定值的关键字,则查找成功;否则,一定可以确定要查的关键字在
某个Ki或Ki+1之间,于是取Pi所指的结点继续查找,直到找到,或指针Pi为空时查找失败。
![b树](http://h.hiphotos.baidu.com/baike/c0=baike72,5,5,72,24/sign=764d1b48d3a20cf4529df68d17602053/50da81cb39dbb6fd7da979e90a24ab18962b370a.jpg)
b+树
B+ 树是一种树数据结构,通常用于数据库和操作系统的文件系统中。B+ 树的特点是能够保持数据稳定有序,其插入
与修改拥有较稳定的对数时间复杂度。B+ 树元素自底向上插入。
文件较多时,B树比平衡二叉树所用的磁盘IO次数越少,效率越高
下面,咱们来模拟下查找文件29的过程:
1. 根据根结点指针找到文件目录的根磁盘块1,将其中的信息导入内存。【磁盘IO操作 1次】
2. 此时内存中有两个文件名17、35和三个存储其他磁盘页面地址的数据。根据算法我们发现:17<29<35,因此我们找到指针p2。
3. 根据p2指针,我们定位到磁盘块3,并将其中的信息导入内存。【磁盘IO操作 2次】
4. 此时内存中有两个文件名26,30和三个存储其他磁盘页面地址的数据。根据算法我们发现:26<29<30,因此我们找到指针p2。
5.根据p2指针,我们定位到磁盘块8,并将其中的信息导入内存。【磁盘IO操作 3次】
此时内存中有两个文件名28,29。根据算法我们查找到文件名29,并定位了该文件内存的磁盘地址。
B+树比B树更适合实际应用中操作系统的文建索引和数据库索引?
1.B+树的内部节点并没有指向关键字具体信息的指针,内部节点更小,则一个盘块可以容纳的关键字数量也越多,相对来说IO读写次数也就降低了
2.查询效率更加稳定,非终节点并不是最终指向文件内容,而只是叶子节点中关键字的索引,所以查找任何关键字,必须从根到叶子。查询效率稳定
3.B+树在遍历元素时,只需要遍历叶子节点。而且在数据库中基于范围的查询非常频繁,使用b+树索引时,效率较高。如select * from a where id>20;
=============================
mysql的索引
mysql默认存储引擎innodb使用的有b+树索引mysql中还有全文索引,哈希索引等。
说到索引和mysql,必须了解mysql的这些点:
1.聚簇索引和非聚簇索引的区别
2.mysql的主键索引是聚簇索引吗
3.主键和唯一性索引的区别
4.现有联合主键index(a,b,c) 查询中使用where a=1 and b = 1;使用到索引了吗 where b = 1;呢 where b = 1 and c = 2;呢
5.数据库事务的ACID指什么
6.内连接和外连接 union的用法回到正文:可参考该资料:http://blog.phpha.com/archives/1670.html
索引小结:
索引用于提升查询效率 普通索引会经过一次b+tree的查找后,得到在主键索引上的位置,然后再去查主键索引的b+tree 所以需要两次 b+tree查询
而直接查询主键索引效率较高。
但是,mysql innodb的主键索引是基于聚簇索引的,也就是说数据行的存储就存储在b+tree的叶子节点上。如果主键较大,或者是联合主键索引,那么b+tree的每个节点就会较大(包括主键索引的b+tree和普通索引的b+tree) 实际占用空间较大。
因此,精简主键。使用多个字段的联合主键效率较低,而且数据实际占用的空间相当于原有的多倍。因为对于(a,b,c)联合主键,会同时建立索引a 索引ab 索引abc 而前面说过,mysql里的普通索引是利用了b+树,对于每一个索引,都要建立一个相应的b+树。1.当你写了一个sql语句,mysql会先选择能使用到的最佳的索引,在b+树中找到主键索引的位置。2.而mysql是聚簇索引,所有数据行的数据是根据主键的排列而存储的。所以会根据上一步找到的主键索引的位置再去所以上面说的主键索引中查询,最终得到数据。
所以需要两次 b+tree查询
where a=1 and b = 1; 使用到了
where b = 1;没使用到
where b = 1 and c = 2; 使用到了
所以,sql语句的顺序对索引的使用起了关键作用。
mysql查询执行的过程
1.客户端发送一条查询给服务器
2.服务器先检查查询缓存,命中则立刻返回,否则下一步
3.服务器进行sql解析,预处理,再由优化器生成对应的执行计划
4.mysql根据优化器生成的执行计划,调用存储引擎的api来执行查询
5.返回给客户端
最后,了解下字典树以及与二叉排序树的性能比较
![字典树与二叉排序树](https://img-blog.csdn.net/20150520015726013)
![字典树与二叉排序树](https://img-blog.csdn.net/20150520015719161)
![字典树与二叉排序树](https://img-blog.csdn.net/20150520015820208)
所以能得出:要查找的关键字可以分解成字符序列,可根据上面的比较决定是否使用。
=======================分割线
下一期内容前瞻:
平面上N个点,每两个点都确定一条直线,求出斜率最大的那条直线所通过的两个点(斜率不存在的情况不考虑)。时间效率越高越好。