数据结构

1、二叉查找树
(1)左子树上所有节点的值均小于或等于它的根结点的值。
(2)右子树上所有节点的值均大于或等于它的根结点的值
2、红黑树
R-B Tree,全称是Red-Black Tree,它一种特殊的二叉查找树。红黑树的每个节点上都有存储位表示节点的颜色,可以是红或黑。
红黑树的特性:
(1)每个节点或者是黑色,或者是红色。
(2)根节点是黑色。
(3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
(4)如果一个节点是红色的,则它的子节点必须是黑色的。
(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
3、红黑树的基本操作是添加、删除。在对红黑树进行添加或删除之后,都会用到旋转方法。添加或删除红黑树中的节点之后,红黑树就发生了变化,可能不满足红黑树的5条性质,也就不再是一颗红黑树了,而是一颗普通的树。而通过旋转,可以使这颗树重新成为红黑树。简单点说,旋转的目的是让树保持红黑树的特性。
红黑树有两大操作:
recolor (重新标记黑色或红色)
rotation (旋转,这是树达到平衡的关键)
4、LRU是Least Recently Used的缩写,即最近最少使用。LRU 算法的设计原则是:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰。
LRU算法中有两种基本操作:
get(key):查询key对应的节点,如果key存在,将节点移动至链表头部。
set(key, value): 设置key对应的节点的值。如果key不存在,则新建节点,置于链表开头。如果链表长度超标,则将处于尾部的最后一个节点去掉。如果节点存在,更新节点的值,同时将节点置于链表头部。
如何来设计一款LRU算法呢?对于这种类似序列的结构我们一般可以选择链表或者是数组来构建。
数组 查询比较快,但是对于增删来说是一个不是一个好的选择。
链表 查询比较慢,但是对于增删来说十分方便O(1)时间复杂度内搞定。
有没有办法既能够让其搜索快,又能够快速进行增删操作。
我们可以选择链表+hash表,hash表的搜索可以达到0(1)时间复杂度,这样就完美的解决我们搜索时间慢的问题了。
hash的value是一个node,多个value即多个node之间是一个双向链表。
维护一个链表,当数据每一次查询就将数据放到链表的head,当有新数据添加时也放到head上。这样链表的tail就是最久没用使用的缓存数据,每次容量不足的时候就可以删除tail,并将前一个元素设置为tail,显然这是一个双向链表结构
https://www.cnblogs.com/nicky-160330/archive/2018/08/18/9498481.html
5、链表
设计链表的实现。可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val和next。val是当前节点的值,next是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性prev以指示链表中的上一个节点
链表的实现原理

  • 创建一个节点类,其中节点类包含两个部分,第一个是数据域(你到时候要往节点里面储存的信息),第二个是引用域(相当于指针,单向链表有一个指针,指向下一个节点;双向链表有两个指针,分别指向下一个和上一个节点)
  • 创建一个链表类,其中链表类包含三个属性:头结点、尾节点和大小,方法包含添加、删除、插入等等方法。

在链表类中实现这些功能:

get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。
deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
6、链表中第一个结点(头节点)的存储位置叫做头指针。
头指针就是链表的名字。头指针仅仅是个指针而已,不包含数据。
链表是由一系列结点组成,结点在运行时动态生成,每个结点由两部分组成及:存储数据元素的数据域,和存储下一个结点的地址的指针域
在这里插入图片描述
7、树的遍历

public class test {
    public static void main(String[] args) {
        TreeNode t = new TreeNode(1);
        t.left = new TreeNode(2);
        t.left.left = new TreeNode(3);
        t.left.right = new TreeNode(4);
        t.right = new TreeNode(4);
        t.right.left = new TreeNode(5);
        t.right.right = new TreeNode(6);

        digui(t);
        System.out.println("===================");
        diedai(t);
    }

    //深度遍历:先遍历左半边树,再遍历右半边树
     static void digui(TreeNode t) {
        if (t == null) return;
        System.out.println(t.val);
        digui(t.left);
        digui(t.right);
    }

    //广度遍历:一层一层的遍历
    static void diedai(TreeNode t) {
        Queue<TreeNode> q = new LinkedList<TreeNode>();
        q.offer(t);
        while (!q.isEmpty()) {
            TreeNode tn = q.poll();
            System.out.println(tn.val);
            if (tn.left != null) q.offer(tn.left);
            if (tn.right != null) q.offer(tn.right);
        }
    }
}

8、B树的两个明显特点:1)树内的每个节点都存储数据 2)叶子节点之间无指针相邻
B+树的两个明显特点:1)数据只出现在叶子节点 2)所有叶子节点增加了一个链指针
针对上面的B+树和B树的特点,我们做一个总结:
(1)B树的树内存储数据,因此查询单条数据的时候,B树的查询效率不固定,最好的情况是O(1)。我们可以认为在做单一数据查询的时候,使用B树平均性能更好。但是,由于B树中各节点之间没有指针相邻,因此B树不适合做一些数据遍历操作。
(2)B+树的数据只出现在叶子节点上,因此在查询单条数据的时候,查询速度非常稳定。因此,在做单一数据的查询上,其平均性能并不如B树。但是,B+树的叶子节点上有指针进行相连,因此在做数据遍历的时候,只需要对叶子节点进行遍历即可,这个特性使得B+树非常适合做范围查询。
因此,我们可以做一个推论:没准是Mysql中数据遍历操作比较多,所以用B+树作为索引结构。而Mongodb是做单一查询比较多,数据遍历操作比较少,所以用B树作为索引结构。
在关系型数据中,遍历操作比较常见,因此采用B+树作为索引,比较合适。而在非关系型数据库中,单一查询比较常见,因此采用B树作为索引,比较合适。
9、数据库索引采用B+树的主要原因
B树在提高了磁盘IO性能的同时并没有解决元素遍历的效率低下的问题。正是为了解决这个问题,B+树应运而生。B+树只要遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,而B树不支持这样的操作(或者说效率太低)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值