符号表--01---概述与实现

发布时间:2026/10/23 16:11:09

符号表--01---概述与实现 符号表定义:符号表最主要的目的就是将一个键和一个值联系起来符号表能够将存储的数据元素是一个键和一个值共同组成的键值对数据我们可以根据键来查找对应的值。符号表中键具有唯一性。使用场景:符号表在实际生活中的使用场景是非常广泛的见下表链表实现符号表API设计:结点类符号表代码实现:publicclassSymbolTableKey,Value{//记录首结点privateNodehead;//记录符号表中元素的个数privateintN;publicSymbolTable(){this.headnewNode(null,null,null);this.N0;}//获取符号表中键值对的个数publicintsize(){returnN;}//往符号表中插入键值对publicvoidput(Keykey,Valuevalue){//符号表中已经存在了键为key的键值对那么只需要找到该结点替换值为value即可Nodenhead;while(n.next!null){//变换nnn.next;//判断n结点存储的键是否为key如果是则替换n结点的值if(n.key.equals(key)){n.valuevalue;return;}}//如果符号表中不存在键为key的键值对只需要创建新的结点保存要插入的键值对把新结点插入到链表的头部 head.next新结点即可NodenewNodenewNode(key,value,null);NodeoldFirsthead.next;newNode.nextoldFirst;head.nextnewNode;//元素个数1N;}//删除符号表中键为key的键值对publicvoiddelete(Keykey){//找到键为key的结点把该结点从链表中删除Nodenhead;while(n.next!null){//判断n结点的下一个结点的键是否为key如果是就删除该结点if(n.next.key.equals(key)){n.nextn.next.next;N--;return;}//变换nnn.next;}}//从符号表中获取key对应的值publicValueget(Keykey){//找到键为key的结点Nodenhead;while(n.next!null){//变换nnn.next;if(n.key.equals(key)){returnn.value;}}returnnull;}//节点类privateclassNode{//键publicKeykey;//值publicValuevalue;//下一个结点publicNodenext;publicNode(Keykey,Valuevalue,Nodenext){this.keykey;this.valuevalue;this.nextnext;}}}测试:publicclassSymbolTableTest{publicstaticvoidmain(String[]args){//创建符号表对象SymbolTableInteger,StringsymbolTablenewSymbolTable();//测试put方法插入,替换symbolTable.put(1,乔峰);symbolTable.put(2,虚竹);symbolTable.put(3,段誉);System.out.println(插入完毕后元素的个数为:symbolTable.size());symbolTable.put(2,慕容复);System.out.println(替换完毕后的元素的个数为:symbolTable.size());//测试get方法System.out.println(替换完毕后键2对应的值为:symbolTable.get(2));//测试删除方法symbolTable.delete(2);System.out.println(删除完毕后元素的个数:symbolTable.size());}}有序符号表刚才实现的符号表我们可以称之为无序符号表因为在插入的时候并没有考虑键值对的顺序而在实际生活中有时候我们需要根据键的大小进行排序插入数据时要考虑顺序那么接下来我们就实现一下有序符号表。有序链表实现:publicclassOrderSymbolTableKeyextendsComparableKey,Value{//记录首结点privateNodehead;//记录符号表中元素的个数privateintN;privateclassNode{//键publicKeykey;//值publicValuevalue;//下一个结点publicNodenext;publicNode(Keykey,Valuevalue,Nodenext){this.keykey;this.valuevalue;this.nextnext;}}publicOrderSymbolTable(){this.headnewNode(null,null,null);this.N0;}//获取符号表中键值对的个数publicintsize(){returnN;}//往符号表中插入键值对publicvoidput(Keykey,Valuevalue){//定义两个Node变量分别记录当前结点和当前结点的上一个结点Nodecurrhead.next;Nodeprehead;while(curr!nullkey.compareTo(curr.key)0){//变换当前结点和前一个结点即可precurr;currcurr.next;}//如果当前结点curr的键和要插入的key一样则替换if(curr!nullkey.compareTo(curr.key)0){curr.valuevalue;return;}//如果当前结点curr的键和要插入的key不一样把新的结点插入到curr之前NodenewNodenewNode(key,value,curr);pre.nextnewNode;//元素的个数1N;}//删除符号表中键为key的键值对publicvoiddelete(Keykey){//找到键为key的结点把该结点从链表中删除Nodenhead;while(n.next!null){//判断n结点的下一个结点的键是否为key如果是就删除该结点if(n.next.key.equals(key)){n.nextn.next.next;N--;return;}//变换nnn.next;}}//从符号表中获取key对应的值publicValueget(Keykey){//找到键为key的结点Nodenhead;while(n.next!null){//变换nnn.next;if(n.key.equals(key)){returnn.value;}}returnnull;}}debug测试:数组二分查找实现:使用一对平行数组一个存储键一个存储值。二分查找的思想是在内部维护一个按照key排好序的二维数组每一次查找的时候跟中间元素进行比较如果该元素小则继续左半部分递归查找否则继续右半部分递归查找。整个实现代码如下二分查找的 rank() 方法至关重要当键在表中时它能够知道该键的位置当键不在表中时它也能知道在何处插入新键。/** * 有序数组符号表 */publicclassSymbolTableKextendsComparableK,V{privateK[]keys;//键数组privateV[]values;//值数组publicintsize;privatestaticfinalintinitSize10;//默认数组初始大小publicSymbolTable(){this(initSize);}publicSymbolTable(intcapacity){keys(K[])newComparable[capacity];values(V[])newObject[capacity];}/** * 查找键为K的值 */publicVget(Kk){if(isEmpty()){returnnull;}//在数组中找出值intirank(k);if(isizekeys[i].compareTo(k)0){returnvalues[i];}returnnull;}/** * 插入要给键值对 */publicvoidput(Kk,Vv){intirank(k);//如果已经存在了键就交换值if(isizekeys[i].compareTo(k)0){values[i]v;return;}//否则就把键值插入到最小于K的值之后for(intjsize;ji;j--){keys[j]keys[j-1];values[j]values[j-1];}keys[i]k;values[i]v;size;}publicbooleanisEmpty(){returnsize0;}publicintrank(Kk){intlow0;//低位起始下标inthighsize-1;//高位下标长度-1//高低交叉之前都一直查询while(lowhigh){intmidlow(high-low)/2;//找到中位下标intcmdk.compareTo(keys[mid]);//获取数组中中位值与比较K的大小//如果两个值相等说明找到了if(cmd0){returnmid;//小于0说明比中位值小从数组中中位置左侧搜索}elseif(cmd0){highmid-1;//和上面相反从数组右侧搜索}else{lowmid1;}}//否侧返回低位的值这个值就是小于被查找值的数量returnlow;}}debug测试:总结:本文介绍了符号表这一抽象数据结构然后介绍了两种基本实现基于无序链表的实现和基于有序数组的实现两种实现的时间复杂度如下无序链表实现:插入的时候先要查找如果存在则更新value查找的时候需要从链表头进行查找所以插入和查找的平均时间复杂度均为O(n)数组二分查找:采用二分查找只需要最多 logN1次的比较即可找到对应元素所以查找效率比较高。但是对于插入元素来说每一次插入不存在的元素需要将该元素放到指定的位置然后将他后面的元素依次后移所以平均时间复杂度O(n)对于插入来说效率仍然比较低。使用有序数组的二分查找法提高了符号表的查找速度但是插入效率仍旧没有得到提高而且在要维护数组有序还需要进行排序操作。这两种实现方式简单直观但是无法同时达到较高查找和插入效率。本文只是一个引子后面的系列文章将会介绍二叉查找树平衡查找树以及哈希表。数组实现和链表实现对比:
延伸阅读

更多相关文章

2026/10/22 18:28:49

I2C协议进阶:快速模式、高速模式与10位寻址详解

1. 从标准模式到性能跃迁:为什么需要更快的I2C?搞嵌入式开发的朋友,对I2C(Inter-Integrated Circuit)协议肯定不陌生。它那两根线(SDA数据线、SCL时钟线)的简洁设计,让连接多个低速外…

2026/10/21 17:42:09

Mendeley文献管理工具:从入门到精通,打造高效学术工作流

1. 从文献混乱到高效管理:为什么你需要Mendeley如果你正在读研、搞科研,或者从事任何需要大量阅读和引用文献的工作,那么你肯定对下面这个场景不陌生:电脑里塞满了从各个数据库下载的PDF文件,文件名千奇百怪&#xff0…

2026/10/23 16:09:16

CentOS 7 Docker RPM 离线安装避坑指南:版本对齐与依赖验证

简介:本资源是一套专为CentOS 7系统离线部署Docker环境准备的完整RPM软件包集合,面向Linux系统运维人员、容器技术初学者及需在无网络环境安装Docker的工程师。资源包含16个文件,主体为9个核心RPM包(如docker-1.12.6、docker-clie…

2026/10/23 16:09:16

CUPS 2.3.3源码部署:调度器、过滤链与二次开发实战

简介:面向Linux与类Unix系统管理员、打印服务开发者及运维学习者的CUPS 2.3.3源代码包,适合本地编译、裁剪和定制打印服务,也可用于研究打印作业管理、过滤器驱动模型、网页管理界面及加密传输等机制。压缩包共1294个文件、约7.76MB&#xff…

2026/10/23 16:09:16

C语言课程设计实战:纯C实现控制台ATM系统源码解析

简介:这份C语言课程设计ATM机源代码面向高校计算机相关专业学生及C语言初学者,用于完成课程设计作业或巩固基础语法与逻辑训练。资源包共3个文件,以cpp源文件为核心,搭配2个txt文本文件分别存放账户信息与密码数据,压缩…

2026/10/23 16:09:16

Blender自动绑定工具auto_rig_pro实战:骨架生成与权重调优指南

简介:Auto_Rig_Pro 3.40z 是一款面向 Blender 用户的自动绑定插件资源包,主要服务于需要快速完成角色骨骼搭建与蒙皮权重的 3D 艺术家、动画师及绑定初学者。它通过自动骨骼生成、智能蒙皮、IK/FK 无缝切换、骨骼重定向与预设管理等功能,显著…

2026/10/23 16:09:16

MATLAB非线性方程组求解:15种算法源码包解析与工程实践

简介:面向MATLAB数值计算学习者与科研人员,这份资源包系统整理了求解非线性方程组的多种数值方法。从基础的不动点迭代、经典牛顿法,到牛顿雅可比、牛顿-SOR、离散牛顿、牛顿下山、两点割线、拟牛顿、对称秩1、DFP/BFS、数值延拓、参数微分、…

2026/10/23 16:04:09

50M Linux虚拟机Qume:冷启动、网络互通与瘦身避坑

简介:这份Qume绿色版Linux虚拟机合辑面向想在Windows环境中低成本体验Linux、做轻量系统实验的初学者与教学使用者,核心是免安装、解压即用的虚拟机方案,通过批处理入口快速启动内置的极简Linux LiveCD,解决传统虚拟机配置繁琐、占…

2026/10/22 11:29:28

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/23 0:02:26

Verilog实现FPGA密码锁:矩阵键盘与状态机设计实战

说实话,这几年接触了不少想入门FPGA的朋友,如果你问哪个项目能一口气把Verilog的核心基本功串起来,我通常会推荐电子密码锁。这个项目看着不起眼,却把矩阵键盘扫描、按键消抖、状态机设计、动态显示刷新、外设控制这些数字逻辑里的…

2026/10/23 0:02:26

数据服务监控运维实战:从指标体系到告警治理与故障排查

周末凌晨两点,手机震了。第一反应是“数据服务挂了”。打开电脑看了下,果然,某张核心报表的数据产出时间已经超过SLA两小时,下游三个业务方连着发来问询。这种场景,做过大数据运维的人都不会陌生。数据服务的监控与运维…

2026/10/23 0:02:26

FreeRTOS任务通知实战详解:内核原理、API与避坑指南

裸机编程切到RTOS之后,任务之间的通信和同步永远是躲不开的坎。前面聊过队列、信号量、互斥锁、事件组,这次把FreeRTOS任务通知(Task Notification)单独拎出来讲透。原因很简单:任务通知是FreeRTOS里最容易用错、也最容…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑