在java的编程语言中,主要有两种存储结构。一种是数组,另一种是指针。
在空间方面,数组的存储空间物理地址连续,每次要对原有的元素进行删除对后面的元素都要造成影响。事先必须定义好数组的大小,太大容易造成空间资源的浪费,太小又容易造成数据溢出。而链表的存储空间是动态的,只要内存空间有空闲,就不会造成数据溢出。而且由于链表之间是通过存储地址的节点维系的,要在中间任何位置插入或删除元素只需要修改相邻元素的节点即可,可以随意扩充。
java中自带的一些存储结构,既有数组存储(例如ArrayList),也有链表结构(例如Node)。但是当元素数量过于庞大时,尤其是在元素个数无法预测时,无论哪一种存储方式均有自己的弱点。数组存储不利于修改,链表不利于查询。
为此,我们可以结合数组存储与链表存储各自的优点,建立一个满足自己程序运用的数据结构。为此,有以下这个构想。
首先,我们可以根据数据的容量数量级建立一个数组,然后在每个数组处存储一条链表。
数组便于查询,但是如果我们必须在每次查询前快速定位要查找的数组元素,若遍历每一个数组的每一条链表进行查询速度依然很慢。因此我们要想一个办法,根据每个数组元素里存储的链表的特点给每条链表分类。例如数组的[0]元素中存储的是ID为1000的倍数的学生,[1]元素中存储的是ID为除1000余1的学生,以此类推……
这样,每次插入或查找对象时,只需根据特定规则先判断这个对象应该添加在数组哪个元素的队列里,再遍历这个队列进行插入或查询。而由于每条链表都是可以扩充的,于是空间上则能发挥出链表存储的优势。
用这种方法进行存储,在数据量比较少或定义的数组大小不合理的情况下,可能会由于数组元素与数组中存储的链表长度之比的不同显示出较强的数组性(空间占用过大,资源浪费)或较强的链表性(查找速度过慢),甚至会出现既不如单纯的数组存储,又不如单纯的链表存储的情况,因此在编写数据结构时,一定要处理好初始数组的大小。
在插入链表的时候,我们可以定义一个实体类,用来存储我们每个单位持有的属性与方法。这里举一个用户类的例子:
public class user {
int userID; //用户的ID属性,可以作为分类的标准
Object DataContent; //每个用户对象的具体属性
user Lastuser;//因为本HASH结构单向链就足够,可以不必定义前节点
user Nextuser;//后节点
public user GetNext(){
return Nextuser;
}
}
接下来切入正题,我们要正式编写我们的HASH数据结构类了:
public class MyHash {
//首先定义一个大小为10000的数组,用来存放链的数组
public user[] User = new user[10000];
int size; //结构内目前存放的元素个数
int ArrayNum = 10000;//数组的大小,初始为10000,最多可存10000条链
}
接下来,在MyHash中定义添加用户的方法。首先我们需要先定义一个HASH()方法,用来对用户进行分类。
public int HashCode(int userID){
return userID%ArrayNum ;
}
这个方法的目的是先将用户根据ID取模的方法将所有用户分成10000类。如果在user[]数组的那一类位置的元素是空的话,就把这个用户信息存在数组的相应位置,作为链的首元素。如果user[]的相应位置不为空,说明这条链已经建成,那就从链的首位置依次向后遍历,判断这条链的元素中有没有重复的元素,如果没有,则在这条链的末尾添加这个用户对象,杜绝了重复添加现象的发生。
public boolean add(user us) {
int Loc = HashCode(us.userID);
int ArrayBeishu =1;
if (size>10000*100*beishu){
reHash();
}
//判断是否为空,若为空,这个元素就存储在根节点,否则存储在下一结点
if(User[Loc]==null){
User[Loc]=us;
size++;
return true;
}else {
for (user u=User[Loc];u!=null;u=u.GetNext()){
//判断是否重复传入,若是,则不继续添加
if (u==us){
return false;
}else{
//若不是重复传入,则添加
if (u.GetNext()==null){
u.Nextuser = us;
size++;
return true;
}
}
}
}
return false;
}
同样的思路,我们可以写一个从这个结构中删除一个用户信息的方法:
public boolean remove(int ID) {
int Loc = HashCode(ID);
for (user u=User[Loc];u!=null;u=u.GetNext()){
if (u.userID==ID){
u = u.Nextuser;
size--;
return true;
}
}
return false;
}
如果担心用户数量的扩充会使得大小为10000的用户数组不够用,可继续添加一个reHash()方法。在此不赘述。
可能上面的描述过于抽象,我们举个形象的例子,例如我们有一个图书馆,我们的HASH结构相当于首先给书分成音乐类、艺术类、文学类、体育类……好几层。拥有很多层的书架相当于一个数组,每层书架独立构成一个链表。当我们要增加一本存数时,先用HASH()函数判断一下这本书应该放到哪个书架上,然后很快地从书架中找到相应的那一层(相当于找到对应的数组元素),再从这层书架的第一本书开始依次检索是否已经收藏了这本书(是否重复存入了对象),当检索到这层书架的最后一本书都没有发现有相同的书已经被收藏后(即遍历链未发现相同元素),就将书放在那一层书架的末尾(相当于链表增加一个元素)。当我们要查找一本书的时候,同样先用HASH()函数找到那本书的大体分类,然后再对应的书架寻找那本书,直到找到位置。所谓的reHash(),就是当书架的藏书量过多时,对书籍更细致地重新分类,让每个书架上的书目量减少(简短每条链的长度,以方便查寻)。
分享到:
相关推荐
在编程领域,自定义数据结构是提升程序效率和可维护性的重要工具。VB(Visual Basic)、C/C++以及C#都是广泛使用的编程语言,它们各自提供了不同的方式来创建和使用自定义数据结构。本篇文章将深入探讨这三种语言中...
### VB自定义数据结构的传输转换 在编程领域中,数据结构的传输转换是一项非常重要的技术,尤其是在不同的程序之间进行数据交换时。本篇文章将详细探讨如何在Visual Basic(简称VB)环境中实现自定义数据结构的传输...
局部变量 数据结构, 数据结构 .局部变量 标题, 文本型 标题 = 到文本 (取结构尺寸_GlobalSize (数据结构)) 调试输出 (标题) .子程序 取自定义数据长度_LocalSize .局部变量 数据结构, 数据结构 .局部变量 标题, ...
本篇将深入探讨如何使用易语言来调用DLL并处理返回的自定义数据结构。 易语言是一款基于中文编程的软件开发工具,其语法简洁明了,适合初学者快速上手。在易语言中,调用DLL主要通过“系统呼叫”或“动态调用”命令...
本文将深入探讨VB中自定义数据结构的传输转换技术,这一主题在《VB之精彩编程-VB自定义数据结构的传输转换》一文中被详细阐述,通过源代码示例展示了如何在不同场景下实现自定义数据结构的有效转换。 ### 自定义...
标题中的“类似protobuf的自定义数据结构”指的是Google开源的Protocol Buffers(protobuf)技术,它是一种高效的数据序列化协议,常用于结构化数据的存储和通信。protobuf提供了一种方式来定义数据结构,然后可以...
在Oracle数据库系统中,自定义数据结构和表类型是数据库设计和开发的重要组成部分。这些特性允许用户根据业务需求创建特定的数据存储解决方案,提高数据管理的灵活性和效率。本实验主要探讨了如何在Oracle中实现...
在编程领域,自定义数据结构是提升代码效率和灵活性的重要手段。本文将深入探讨如何仅通过数组实现泛型的Stack(栈)、Queue(队列)和Dictionary(字典)这三种基本数据结构,并且实现IEnumerable接口,使得这些...
实现了一个自定义的数据结构 —— 树,该自定义结构不同于二叉树及其他数据结构,每个节点的子节点个数不受限制,最大限度保留了数据的原始结构,并实现了其前序和后序遍历的方法。优点是节省了内存,但缺点则是基于...
说明: 自定义中的数据类型尽量不要用string如果使用那么在保存数据,与读取数据中增加转换var MyDynamicArray: array of Char;begin SetLength(MyDynamicArray, 48); // 设置数组长度为 48 StrPCopy(MyDynamicArray, ...
sercurity + oauth2 + durid + redis 实现用户认证和资源控制,本例子中包含对oauth2异常的统一处理格式,使用redis存储token提升访问性能等。还包含数据库建表语句。
自定义个一个数据结构,类似数组,每个成员4字节,记录内存地址 每个成员是一个内存地址,成员内存结构 +0=数据类型 +4实际数据 如果是字节集,+4是数据长度+8是实际数据,如果是文本型,+4是实际数据,以\0为结尾 如果对...
自定义数据结构的学习可以帮助我们更好地理解如何高效地存储和处理信息。在这个关于"SelfDefiningDataStructure"的主题中,我们将深入探讨使用Java语言实现自定义数据结构的过程,以及这对深化对数据结构理解的影响...
自定义个一个数据结构,类似数组,每个成员4字节,记录内存地址。每个成员是一个内存地址,成员内存结构 +0=数据类型 +4实际数据。如果是字节集,+4是数据长度+8是实际数据,如果是文本型,+4是实际数据,以\0为结尾。如果对...
在易语言中,自定义数据类型是实现复杂数据结构和逻辑的关键部分。自定义数据类型允许用户根据需求定义自己的数据结构,比如组合多个基本数据类型,形成新的复合类型。 本案例"易语言自定义数据类型变量保存"主要...
自定义数据类型可以组合多个基本数据类型,形成一个复合的数据结构,方便处理复杂的数据。 创建自定义数据类型的语法通常如下: ```易语言 .结构 结构名 .字段1 数据类型 .字段2 数据类型 ... .结束结构 ``` ...
微信小程序自定义省市区资源数据
在易语言中,自定义数据类型是一种重要的编程概念,它允许程序员根据需求定义自己的数据结构,比如组合多种基本数据类型,形成复合型的数据结构。本文将深入探讨易语言中自定义数据类型的内存存储方式及其相关知识点...
在易语言中,内存自定义数据类型是实现高效内存管理的重要手段,它允许程序员根据实际需求定义自己的数据结构。下面将详细阐述这个主题。 内存自定义数据类型是指在程序运行过程中,由程序员自行定义的一种数据结构...
在Spring Boot中,可以创建一个自定义注解,例如`@CustomResponse`,用于标记控制器方法,指示该方法应返回特定的数据结构。这个注解通常会包含一些元信息,如状态码、消息等,以便在处理过程中填充到返回结果中。...