2021-07-25

数据结构

模块一:数组和链表

1. 数组内存模型

  • 一维数组
      获取一维数组元素的方式:
    b a s e _ a d d r e s s + i n d e x ( 索 引 ) × d a t a _ s i z e ( 数 据 类 型 大 小 ) base\_address + index(索引)× data\_size(数据类型大小) base_address+index×data_size)
      例子:若data数组存放的是int类型数值,data[0]的地址为0x80000000,则data[4]的地址为 0x80000000+4*4=0x80000010
  • 二维数组
      声明一个二维数组:int[][] data=new int[2][3]
    (1) 行优先存储
       b a s e _ a d d r e s s + d a t a _ s i z e × ( i × n u m b e r _ o f _ c o l u m n + j ) base\_address + data\_size × (i × number\_of\_column + j) base_address+data_size×(i×number_of_column+j)
      例:data[0][0]的地址为0x80000000,则data[0][1]的地址为: 0 x 80000000 + 4 × ( 0 × 3 + 1 ) = 0 x 80000004 0x80000000+4×(0×3+1)=0x80000004 0x80000000+4×(0×3+1)=0x80000004
    (2) 列优先存储
       b a s e _ a d d r e s s + d a t a _ s i z e × ( i + n u m b e r _ o f _ r o w × j ) base\_address + data\_size × (i + number\_of\_row × j) base_address+data_size×(i+number_of_row×j)
       例:data[0][0]的地址为0x80000000,则data[0][1]的地址为: 0 x 80000000 + 4 × ( 0 + 2 × 1 ) = 0 x 80000008 0x80000000+4×(0+2×1)=0x80000008 0x80000000+4×(0+2×1)=0x80000008
  • java集合add()函数源码
    假设有ElementData数组,add()的源码:
   public void add(int index, E element) {
        this.rangeCheckForAdd(index);
        ++this.modCount;
        int s;
        Object[] elementData;
        if ((s = this.size) == (elementData = this.elementData).length) {
            elementData = this.grow();
        }
        //主要调用该函数
        System.arraycopy(elementData, index, elementData, index + 1, s - index);
        elementData[index] = element;
        this.size = s + 1;
    }

在这里插入图片描述
如果在ElementData要执行add(1,4)的操作,就要执行*arraycopy(ElementData,1,ElementData,2,6-1)*它的意思是将从 ElementData 数组 index 为 1 的地址开始,复制往后的 5 个元素到 ElementData 数组 index 为 2 的地址位置,如下图所示:
在这里插入图片描述
2. 位数组在Redis中的应用
  拥有两个元素的 int 数组的内存模型
在这里插入图片描述
  第i个比特位的位置为:

所在数组中的元素为: i / data_size,例:35/32=1
比特位在元素中的位置为:i % data_size,例35%32=3
  • GetBit
      核心算法:
boolean GetBit(int[] array, int index) {
      ...
      int elementIndex = index / 32;
      int position = index % 32;
      long flag = 1;
      flag = flag << position;
      if ((array[elementIndex] & flag) != 0) {
          return true;
      } else {
          return false;
      }
}

  GetBit(d, 35) 这条语句,将得到 elementIndex 为 1、position 为 3、flag 为 0x08,将 d[1] 和 0x08 进行位操作的与运算,最后可以得出一个非 0 的结果,所以这个函数返回 true。
  而如果调用了 GetBit(d, 32) 这条语句,我们将得到 elementIndex 为 1、position 为 0、flag 为 0x1,将 d[1] 和 0x1 进行位操作的与运算,最后可以得出一个 0 的结果,所以这个函数返回 false。

  • SetBit
      核心算法:
void SetBit(int[] array, int index) {
      ...
      int elementIndex = index / 32;
      int position = index % 32;
      long flag = 1;
      flag = flag << position;
      array[elementIndex] = array[elementIndex] | flag;
}

  原数组为:
在这里插入图片描述
  调用了 SetBit(d, 35) 这条语句,elementIndex=1,position=3,flag=0x08,进行或运算得到:
在这里插入图片描述

  • ClearSetBit
      核心算法:
void ClearBit(int[] array, int index) {
      ...
      int elementIndex = index / 32;
      int position = index % 32;
      long flag = 1;
      flag = ~(flag << position);
      array[elementIndex] & flag;
}

  原位数组:
在这里插入图片描述
调用了 ClearBit(d,32) 这条语句,得到elementIndex=1,position=3,flag=0xFFFFFFFE,位运算得到:
在这里插入图片描述

模块二:哈希表的应用
1. 哈希函数的本质及生成方式
  String类型的哈希函数公式:
在这里插入图片描述

  • 常用的哈希函数算法
    在这里插入图片描述SHA-1加密算法
      运行“git commit”命令的时候,Git 会将所有的这些文件,外加一些元数据(Metadata)再做一次 SHA-1 运算来得到一个新的哈希值。

2. 哈希碰撞的本质及解决方式

  • 开放寻址法
      开放寻址法本质上是在数组中寻找一个还未被使用的位置,将新的值插入。这样做的好处是利用数组原本的空间而不用开辟额外的空间来保存值。最简单明了的方法就是沿着数组索引,往下一个一个地去寻找还未被使用的空间,这种方法叫做线性探测(Linear Probing)。
    在这里插入图片描述

  • 负载因子
      负载因子可以被定义为是哈希表中保存的元素个数 / 哈希表中底层数组的大小

  • 分离链接法
    在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值