数据结构基础——数组、散列表

数组

数组是指的有限个类型相同的变量的集合。组成数组的各个变量称为数组的元素,有时也称为下标变量。

数组的特点

对于数组有以下特点

  1. 数组内的元素应该具有相同的数据类型
  2. 数组元素用整个数组的名字和它自己在数组中的顺序位置来表示,如array[1]
  3. 数组创建后其长度就不能发生变化
  4. 数组所占用的存储空间是固定且连续的
  5. 数组中各个元素可以使用数组名称和下标进行直接访问

优点

  1. 因为长度固定,集合内元素类型一致,整个数据结构非常简单
  2. 从数组中查找元素的时候,只需要知道其所在数组以及其下标就可以直接获得数,查询数据效率很高。

缺点

  1. 资源浪费,数组声明的时候求需要申请所有存储空间,即使最终没有使用那么多空间。
  2. 修改自困难,在实际使用空间大于申请空间的时候,需要重新申请新的数组并将旧数据转移至新数组中。
  3. 当删除数组中元素的时候,会导致连续的存储空间中出现未使用的存储空间会遍布数组各处,而不是集中在尾部。

java中的数组

声明数组

  1. 数据类型[] 数组名 : String[] str = new String[10];
  2. 数据类型 数组名[] : String str[] = new String[10];

赋值

str[2] = “data”

输出值

System.out.println(str[2]);

初始化赋值

String[] str = new String{“data1”,“datat2”,“data3”};

二维数组

二维数组可以认为是每个数组的元素也是一个一维数组。二维数组可以理解为存在横纵结构的网状结构

声明二维数组组

  1. 数据类型[][] 数组名 : String[][] str = new String[10][10];
  2. 数据类型 数组名[][] : String str[][] = new String[10][10];
  3. 数据类型[] 数组名[] : String[] str[] = new String[10][10];

赋值

str[2][3] = “data”

输出值

System.out.println(str[2][3]);

初始化赋值

String[] str = new String{{“data1”,“datat2”,“data3”},{“val1”,“val2”,“val3”},{“num1”,“num2”,“num3”}};

散列表

散列表也叫哈希表。是根据关键码值而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。

在JAVA中的HashMap就是通过于散列函数获得数组下标,然后去对应的下标位置去获取数据。

散列函数(哈希函数)

对于线性表、树来说记录在结构中的位置是随机的,记录的值和关键key不存在确定关系。所以在此类结构中查找数据需要进行一系列的比较操作。这类比较操作的效率取决于进行比较的次数。而散列函数则实现了通过关键字(key)经过计算得到了一个散列值。而通过这个值可以确定数据结构中一个唯一的存储位置。

使用散列函数可以得到下面的内容;

  1. 因为是确定数组下标,所以散列函数计算到的值是一个非负整数
  2. 同样的关键字经过函数计算得到的值是相同的
  3. 虽然散列函数极力尝试避免出现不同的关键字(key)出现一样的散列值。但是实际上这种情况总会发生。

哈希碰撞

上面说到,散列函数可能出现不同的关键字(key)获得相同的散列表。这种情况我们称为哈希碰撞。哈希碰撞将会使数据返回一个错误的内容。

解决冲突

目前解决哈希碰撞主要有下面几个方法:

  1. 开放寻址法
  2. 再哈希法
  3. 链表法
  4. 建立一个公共溢出区

开放寻址法

开放寻址法主要是根据下面的函数

Hi=(H(key) + di) MOD m,i=1,2,…,k(k<=m-1)

上面函数中:Hi为最终地址,H(key)为哈希函数,di为增量。当出现冲突的时候,使用上面公式,在哈希函数之后添加增量来寻找空闲的地址。而di计算的结果主要有三种方式

线性探测再散列

依次向后查询

di=1,2,3,…,m-1

二次探测再散列

依次向前后查询,增量为1、2、3、…………的二次方

di=1^2,-1^2,2^2,-2^2,⑶^2,…,±(k)^2,(k<=m/2)

伪随机探测再散列

使用随机的方式产生一个增量

优点

所有的数据都都保存到数组中,查找起来会比较快。

缺点
  1. 删除数据的时候并不能直接删除,需要标记为deleted,所以相比链表方法会消耗更多内存空间。
  2. 当数据量较少的时候,产生冲突的几率不高,但是当数据量较大的时候,出现散列冲突的概率就越大,插入数据需要经过很多次的寻址或者拉很长的链,查找过程也会很慢。

再哈希法

当出现冲突的时候,使用其他的哈希函数计算,直到冲突消失

链表法

链表法也是目前最常用且简单的方法。

每个数组对应一个链表,所有散列值相同的元素,被放在对应链表中,链表中保存关键字以及其对应的值。当出现冲突的时候,通过遍历链表,对比关键字以及链表中的关键字,来确定最终数据的位置。

优点
  1. 链表法处理冲突方式简单,即非同义词决不会发生冲突,因此平均查找长度较短
  2. 因为链表法中的链表节点可以动态扩容,所以它适用于无法确定表长的情况
  3. 对于有大量元素的时候,使用寻址法可能产生大量冲突导致性能下降。而链表法对于链表法,使用链表保存了冲突的数据,查询虽然会有所下降但是相比于寻址法好很多
  4. 在用链表法构造的散列表中,删除结点只要简单地删去链表上相应的结点即可,非常简单
缺点
  1. 链表法需要保存指针地址,指针需要额外的空间
  2. 和数组不同链表会零散的分布在内存的各个位置中,非连续数据无法使用CPU的查询优化。

个人水平有限,上面的内容可能存在没有描述清楚或者错误的地方,假如开发同学发现了,请及时告知,我会第一时间修改相关内容。假如我的这篇内容对你有任何帮助的话,麻烦给我点一个赞。你的点赞就是我前进的动力。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大·风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值