算法第二部分(4)

红黑树

定义:红黑树是一颗二分搜索树,并保证自己是一颗平衡二叉树
红黑树性质
1.每个

2 - 3树

满足二分搜索树的基本性质
节点可以存放一个元素或两个元素
每个节点可以有两个孩子或三个孩子
二三树是一颗绝对平衡的树
在这里插入图片描述
二三树添加节点,永远不会添加到一个空的节点,当某一个节点为4节点时,就会分裂成一个三个节点的树。如果分裂后的树不是一颗绝对平衡二叉树,则将中间节点向上融合,形成:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
红黑树和二三树是等价的
引入红色节点和父亲节点一起表示原来的三节点
所有的红色节点是向左倾斜的
在这里插入图片描述
红黑树的增删改查的时间复杂度是O(logN)

当我们向一颗树中添加元素,可能需要进行左旋转,让其对应三节点
在这里插入图片描述
在这里插入图片描述
比添加的三节点的右节点还要大的情况
在这里插入图片描述
右旋转
在这里插入图片描述
左旋转相当于如果添加的元素在二三树二节点的右边,则需要进行左旋转把他变成左边为红子树,右边为黑子树的情况ho时是三节点。
颜色翻转相当于添加在一个三节点的右边,此时需要把节点变成一个二叉树,中间的节点向上抽离,所以需要进行颜色翻转,变成左右子树为黑色,头结点为红色。
右旋转为当节点添加在一个三节点的最左边,则需要进行右旋转,并将node.color赋值给x.color

在这里插入图片描述

哈希表

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以对一个素数进行取模
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
java中hash的设置:

@Override
    public int hashCode(){

        int B = 31;
        int hash = 0;
        hash = hash * B + ((Integer)grade).hashCode();
        hash = hash * B + ((Integer)cls).hashCode();
        hash = hash * B + firstName.toLowerCase().hashCode();
        hash = hash * B + lastName.toLowerCase().hashCode();
        return hash;
    }

链地址法

hash表的本质是数组
对于hash冲突的键,可以对于冲突的地方使用链表或红黑树treeMap数据结构的方法链接解决。

在这里插入图片描述
在这里插入图片描述
hash表的性能得到了极大的优化,但是牺牲了顺序性。
在这里插入图片描述

hash表:

public class HashTable<K, V> {

    private final int[] capacity
            = {53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
            49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
            12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741};

    private static final int upperTol = 10;
    private static final int lowerTol = 2;
    private  int capacityIndex = 0;
    //红黑树底层,直接使用就行
    private TreeMap<K, V>[] hashtable;
    private int size;
    private int M;

    public HashTable(){
        this.M = capacity[capacityIndex];
        size = 0;
        hashtable = new TreeMap[M];
        //一个treeMap下有多个treeMap
        for(int i = 0 ; i < M ; i ++)
            hashtable[i] = new TreeMap<>();
    }

    private int hash(K key){
        return (key.hashCode() & 0x7fffffff) % M;
    }

    public int getSize(){
        return size;
    }

    public void add(K key, V value){
        TreeMap<K, V> map = hashtable[hash(key)];
        if(map.containsKey(key))
            map.put(key, value);
        else{
            //新增
            map.put(key, value);
            size ++;

            //可能需要进行扩容
            if(size >= upperTol * M && capacityIndex + 1 < capacity.length){
                capacityIndex ++;
                resize(capacity[capacityIndex]);
            }
        }
    }

    public V remove(K key){
        V ret = null;
        TreeMap<K, V> map = hashtable[hash(key)];
        if(map.containsKey(key)){
            ret = map.remove(key);
            size --;

            //可能需要进行缩容
            if(size < lowerTol * M && capacityIndex - 1 >= 0){
                capacityIndex --;
                resize(capacity[capacityIndex]);
            }
        }
        return ret;
    }

    private void resize(int newM) {
        TreeMap<K,V>[] newHashTable = new TreeMap[newM];
        for (int i = 0;i < newM;i ++){
            newHashTable[i] = new TreeMap<>();
        }
        int oldM = M;
        this.M = newM;
        for (int i = 0;i < oldM;i ++){
            TreeMap<K,V> map =hashtable[i];
            for (K key:map.keySet()){
                newHashTable[(hash(key))].put(key,map.get(key));
            }
        }
        this.hashtable = newHashTable;
    }

    public void set(K key, V value){
        TreeMap<K, V> map = hashtable[hash(key)];
        if(!map.containsKey(key))
            throw new IllegalArgumentException(key + " doesn't exist!");

        map.put(key, value);
    }

    public boolean contains(K key){
        return hashtable[hash(key)].containsKey(key);
    }

    public V get(K key){
        return hashtable[hash(key)].get(key);
    }
}

其他处理hash冲突的方法
开放地址法
每一个地址对所有元素都是开放的
在这里插入图片描述

总结

在这里插入图片描述
线性表表示数据是按照线性排列的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值