算法 - 符号表-上

img

🏠个人主页:尘觉主页

文章目录

  • 算法 - 符号表
    • 前言
    • 初级实现
      • 1. 链表实现无序符号表
      • 2. 二分查找实现有序符号表
    • 二叉查找树
      • 1. get()
      • 2. put()
      • 3. 分析
      • 4. floor()
      • 5. rank()
      • 6. min()
      • 7. deleteMin()
      • 8. delete()
      • 9. keys()
      • 10. 分析

算法 - 符号表

前言

符号表(Symbol Table)是一种存储键值对的数据结构,可以支持快速查找操作。

符号表分为有序和无序两种,有序符号表主要指支持 min()、max() 等根据键的大小关系来实现的操作。

有序符号表的键需要实现 Comparable 接口。

public interface UnorderedST<Key, Value> {int size();Value get(Key key);void put(Key key, Value value);void delete(Key key);
}
public interface OrderedST<Key extends Comparable<Key>, Value> {int size();void put(Key key, Value value);Value get(Key key);Key min();Key max();int rank(Key key);List<Key> keys(Key l, Key h);
}

初级实现

1. 链表实现无序符号表

public class ListUnorderedST<Key, Value> implements UnorderedST<Key, Value> {private Node first;private class Node {Key key;Value value;Node next;Node(Key key, Value value, Node next) {this.key = key;this.value = value;this.next = next;}}@Overridepublic int size() {int cnt = 0;Node cur = first;while (cur != null) {cnt++;cur = cur.next;}return cnt;}@Overridepublic void put(Key key, Value value) {Node cur = first;// 如果在链表中找到节点的键等于 key 就更新这个节点的值为 valuewhile (cur != null) {if (cur.key.equals(key)) {cur.value = value;return;}cur = cur.next;}// 否则使用头插法插入一个新节点first = new Node(key, value, first);}@Overridepublic void delete(Key key) {if (first == null)return;if (first.key.equals(key))first = first.next;Node pre = first, cur = first.next;while (cur != null) {if (cur.key.equals(key)) {pre.next = cur.next;return;}pre = pre.next;cur = cur.next;}}@Overridepublic Value get(Key key) {Node cur = first;while (cur != null) {if (cur.key.equals(key))return cur.value;cur = cur.next;}return null;}
}

2. 二分查找实现有序符号表

使用一对平行数组,一个存储键一个存储值。

二分查找的 rank() 方法至关重要,当键在表中时,它能够知道该键的位置;当键不在表中时,它也能知道在何处插入新键。

二分查找最多需要 logN+1 次比较,使用二分查找实现的符号表的查找操作所需要的时间最多是对数级别的。但是插入操作需要移动数组元素,是线性级别的。

public class BinarySearchOrderedST<Key extends Comparable<Key>, Value> implements OrderedST<Key, Value> {private Key[] keys;private Value[] values;private int N = 0;public BinarySearchOrderedST(int capacity) {keys = (Key[]) new Comparable[capacity];values = (Value[]) new Object[capacity];}@Overridepublic int size() {return N;}@Overridepublic int rank(Key key) {int l = 0, h = N - 1;while (l <= h) {int m = l + (h - l) / 2;int cmp = key.compareTo(keys[m]);if (cmp == 0)return m;else if (cmp < 0)h = m - 1;elsel = m + 1;}return l;}@Overridepublic List<Key> keys(Key l, Key h) {int index = rank(l);List<Key> list = new ArrayList<>();while (keys[index].compareTo(h) <= 0) {list.add(keys[index]);index++;}return list;}@Overridepublic void put(Key key, Value value) {int index = rank(key);// 如果找到已经存在的节点键为 key,就更新这个节点的值为 valueif (index < N && keys[index].compareTo(key) == 0) {values[index] = value;return;}// 否则在数组中插入新的节点,需要先将插入位置之后的元素都向后移动一个位置for (int j = N; j > index; j--) {keys[j] = keys[j - 1];values[j] = values[j - 1];}keys[index] = key;values[index] = value;N++;}@Overridepublic Value get(Key key) {int index = rank(key);if (index < N && keys[index].compareTo(key) == 0)return values[index];return null;}@Overridepublic Key min() {return keys[0];}@Overridepublic Key max() {return keys[N - 1];}
}

二叉查找树

二叉树 是一个空链接,或者是一个有左右两个链接的节点,每个链接都指向一颗子二叉树。

image-20240404154010822

二叉查找树 (BST)是一颗二叉树,并且每个节点的值都大于等于其左子树中的所有节点的值而小于等于右子树的所有节点的值。

BST 有一个重要性质,就是它的中序遍历结果递增排序。

image-20240404154034969

基本数据结构:

public class BST<Key extends Comparable<Key>, Value> implements OrderedST<Key, Value> {protected Node root;protected class Node {Key key;Value val;Node left;Node right;// 以该节点为根的子树节点总数int N;// 红黑树中使用boolean color;Node(Key key, Value val, int N) {this.key = key;this.val = val;this.N = N;}}@Overridepublic int size() {return size(root);}private int size(Node x) {if (x == null)return 0;return x.N;}protected void recalculateSize(Node x) {x.N = size(x.left) + size(x.right) + 1;}
}

为了方便绘图,下文中二叉树的空链接不画出来。

1. get()

  • 如果树是空的,则查找未命中;
  • 如果被查找的键和根节点的键相等,查找命中;
  • 否则递归地在子树中查找:如果被查找的键较小就在左子树中查找,较大就在右子树中查找。
@Override
public Value get(Key key) {return get(root, key);
}private Value get(Node x, Key key) {if (x == null)return null;int cmp = key.compareTo(x.key);if (cmp == 0)return x.val;else if (cmp < 0)return get(x.left, key);elsereturn get(x.right, key);
}

2. put()

当插入的键不存在于树中,需要创建一个新节点,并且更新上层节点的链接指向该节点,使得该节点正确地链接到树中。

image-20240404154054094

 @Override
public void put(Key key, Value value) {root = put(root, key, value);
}private Node put(Node x, Key key, Value value) {if (x == null)return new Node(key, value, 1);int cmp = key.compareTo(x.key);if (cmp == 0)x.val = value;else if (cmp < 0)x.left = put(x.left, key, value);elsex.right = put(x.right, key, value);recalculateSize(x);return x;
}

3. 分析

二叉查找树的算法运行时间取决于树的形状,而树的形状又取决于键被插入的先后顺序。

最好的情况下树是完全平衡的,每条空链接和根节点的距离都为 logN。

image-20240404154208696

在最坏的情况下,树的高度为 N。

image-20240404154139062

4. floor()

floor(key):小于等于键的最大键

  • 如果键小于根节点的键,那么 floor(key) 一定在左子树中;
  • 如果键大于根节点的键,需要先判断右子树中是否存在 floor(key),如果存在就返回,否则根节点就是 floor(key)。
public Key floor(Key key) {Node x = floor(root, key);if (x == null)return null;return x.key;
}private Node floor(Node x, Key key) {if (x == null)return null;int cmp = key.compareTo(x.key);if (cmp == 0)return x;if (cmp < 0)return floor(x.left, key);Node t = floor(x.right, key);return t != null ? t : x;
}

5. rank()

rank(key) 返回 key 的排名。

  • 如果键和根节点的键相等,返回左子树的节点数;
  • 如果小于,递归计算在左子树中的排名;
  • 如果大于,递归计算在右子树中的排名,加上左子树的节点数,再加上 1(根节点)。
@Override
public int rank(Key key) {return rank(key, root);
}private int rank(Key key, Node x) {if (x == null)return 0;int cmp = key.compareTo(x.key);if (cmp == 0)return size(x.left);else if (cmp < 0)return rank(key, x.left);elsereturn 1 + size(x.left) + rank(key, x.right);
}

6. min()

@Override
public Key min() {return min(root).key;
}private Node min(Node x) {if (x == null)return null;if (x.left == null)return x;return min(x.left);
}

7. deleteMin()

令指向最小节点的链接指向最小节点的右子树。

image-20240404154255376

public void deleteMin() {root = deleteMin(root);
}public Node deleteMin(Node x) {if (x.left == null)return x.right;x.left = deleteMin(x.left);recalculateSize(x);return x;
}

8. delete()

  • 如果待删除的节点只有一个子树, 那么只需要让指向待删除节点的链接指向唯一的子树即可;
  • 否则,让右子树的最小节点替换该节点。

image-20240404154326939

public void delete(Key key) {root = delete(root, key);
}
private Node delete(Node x, Key key) {if (x == null)return null;int cmp = key.compareTo(x.key);if (cmp < 0)x.left = delete(x.left, key);else if (cmp > 0)x.right = delete(x.right, key);else {if (x.right == null)return x.left;if (x.left == null)return x.right;Node t = x;x = min(t.right);x.right = deleteMin(t.right);x.left = t.left;}recalculateSize(x);return x;
}

9. keys()

利用二叉查找树中序遍历的结果为递增的特点。

@Override
public List<Key> keys(Key l, Key h) {return keys(root, l, h);
}private List<Key> keys(Node x, Key l, Key h) {List<Key> list = new ArrayList<>();if (x == null)return list;int cmpL = l.compareTo(x.key);int cmpH = h.compareTo(x.key);if (cmpL < 0)list.addAll(keys(x.left, l, h));if (cmpL <= 0 && cmpH >= 0)list.add(x.key);if (cmpH > 0)list.addAll(keys(x.right, l, h));return list;
}

10. 分析

二叉查找树所有操作在最坏的情况下所需要的时间都和树的高度成正比。

算法 - 符号表-下

😁热门专栏推荐
想学习vue的可以看看这个

java基础合集

数据库合集

redis合集

nginx合集

linux合集

手写机制

微服务组件

spring_尘觉

springMVC

mybits

等等等还有许多优秀的合集在主页等着大家的光顾感谢大家的支持

🤔欢迎大家加入我的社区 尘觉社区

文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起来评论区一起讨论😁
希望能和诸佬们一起努力,今后我们一起观看感谢您的阅读🍻
如果帮助到您不妨3连支持一下,创造不易您们的支持是我的动力🤞

img

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/792997.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

intellij idea 使用git撤销(取消)commit

git撤销(取消) 未 push的 commit Git&#xff0c;选择分支后&#xff0c;右键 Undo Commit &#xff0c;会把这个 commit 撤销。 git撤销(取消) 已经 push 的 commit 备份分支内容&#xff1a; 选中分支&#xff0c; 新建 分支&#xff0c;避免后续因为操作不当&#xff0c;导…

iOS-App:App Store新的审核政策,在应用隐私清单中声明和解释使用特定API的原因

App Store新的审核政策&#xff0c;在应用隐私清单中声明和解释使用特定API的原因 设备/引擎&#xff1a;Mac&#xff08;11.6&#xff09;/Mac Mini 开发工具&#xff1a;终端 开发需求&#xff1a;苹果官方邮件通知&#xff0c; App Store新的审核政策&#xff0c;在应用隐…

【Java笔记】多线程0:JVM线程是用户态还是内核态?Java 线程与OS线程的联系

文章目录 JVM线程是用户态线程还是内核态线程什么是用户态线程与内核态线程绿色线程绿色线程的缺点 线程映射稍微回顾下线程映射模型JVM线程映射 线程状态操作系统的线程状态JVM的线程状态JVM线程与OS线程的状态关系 Reference 今天复盘一下Java中&#xff0c;JVM线程与实际操作…

CCIE-08-BGP-Listen

目录 实验条件网络拓朴实验目的 开始配置配置动态路由协议配置BGP检查邻居配置 实验条件 网络拓朴 实验目的 将R1配置成Listen状态&#xff0c;自动接收来自其它路由器的建邻居请求、建立邻居 开始配置 配置动态路由协议 这里用EIGRP来配置&#xff0c;保证网络的可达性&a…

替代 Redis 和 Memcached:25 倍吞吐量! | 开源日报 No.213

dragonflydb/dragonfly Stars: 22.4k License: NOASSERTION Dragonfly 是一个内存数据存储&#xff0c;适用于现代应用工作负载&#xff0c;可替代 Redis 和 Memcached。与传统的内存数据存储相比&#xff0c;Dragonfly 提供了 25 倍的吞吐量、更高的缓存命中率和更低尾部延…

基于springboot的粮仓管理系统

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…

java数组.day16(冒泡排序,稀疏数组)

冒泡排序 冒泡排序无疑是最为出名的排序算法之一&#xff0c;总共有八大排序! 冒泡的代码还是相当简单的&#xff0c;两层循环&#xff0c;外层冒泡轮数&#xff0c;里层依次比较&#xff0c;江湖中人人尽皆知。 我们看到嵌套循环&#xff0c;应该立马就可以得出这个算法的时…

1.Spring Boot框架整合

Spring Boot项目创建&#xff08;约定大于配置&#xff09; 2.1.3.RELEASE版本示例 idea创建 从官网下载&#xff08;https://start.spring.io/&#xff09;单元测试默认依赖不对时&#xff0c;直接删除即可 Web支持&#xff08;SpringMVC&#xff09; <dependency>&…

Collection与数据结构 链表与LinkedList(三):链表精选OJ例题(下)

1. 分割链表 OJ链接 class Solution {public ListNode partition(ListNode head, int x) {if(head null){return null;//空链表的情况}ListNode cur head;ListNode formerhead null;ListNode formerend null;ListNode latterhead null;ListNode latterend null;//定义…

见证历史:Quantinuum与微软取得突破性进展,开启了可靠量子计算的新时代!

Quantinuum与微软的合作取得了重大突破&#xff0c;将可靠量子计算带入了新的时代。他们结合了Quantinuum的System Model H2量子计算机和微软创新的量子比特虚拟化系统&#xff0c;在逻辑量子比特领域取得了800倍于物理电路错误率的突破。这一创新不仅影响深远&#xff0c;加速…

目标检测——监控下的汽车

一、重要性及意义 首先&#xff0c;车辆检测技术是保证视频监控系统正常运行的基础。通过监控摄像头实时获取的图像&#xff0c;可以自动检测出图像中的车辆&#xff0c;并进行车辆类型的分类和识别。这对于优化城市交通管理、实现智能交通系统具有重要意义。此外&#xff0c;…

【SQL Server的详细使用教程】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

【QT+QGIS跨平台编译】056:【pdal_lepcc+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

点击查看专栏目录 文章目录 一、pdal_lepcc介绍二、pdal下载三、文件分析四、pro文件五、编译实践一、pdal_lepcc介绍 pdal_lepcc 是 PDAL(Point Data Abstraction Library)的一个插件,用于点云数据的压缩。它基于 EPCC(Entwine Point Cloud Compression)算法,提供了对点…

51单片机入门之独立按键

目录 1.按键简介 2.独立按键控制LED亮灭 3.独立按键控制LED移位 1.按键简介 在生活中&#xff0c;我们常常会见到各种按键&#xff0c;我们的开发板上也有按键&#xff0c;就在左下角有四个按键&#xff0c;我们把它们叫做独立按键。 独立按键的原理比较简单&…

【机器学习】《机器学习算法竞赛实战》第7章用户画像

文章目录 第7章 用户画像7.1 什么是用户画像7.2 标签系统7.2.1 标签分类方式7.2.2 多渠道获取标签7.2.3 标签体系框架 7.3 用户画像数据特征7.3.1 常见的数据形式7.3.2 文本挖掘算法7.3.3 神奇的嵌入表示7.3.4 相似度计算方法 7.4 用户画像的应用7.4.1 用户分析7.4.2 精准营销7…

vscode-keil一起用

安装插件 1、C/C Extension Pack 2、Keil Assistant 配置 重启生效&#xff01;&#xff01;&#xff01; 下载安装 Mingw 下载链接&#xff1a; 添加环境变量&#xff1a; 注意确认&#xff01;&#xff01;&#xff01; 报错 gccC:\迅雷下载\MinGW\MinGW\bin…

力扣爆刷第111天之CodeTop100五连刷41-45

力扣爆刷第111天之CodeTop100五连刷41-45 文章目录 力扣爆刷第111天之CodeTop100五连刷41-45一、232. 用栈实现队列二、4. 寻找两个正序数组的中位数三、31. 下一个排列四、69. x 的平方根五、8. 字符串转换整数 (atoi) 一、232. 用栈实现队列 题目链接&#xff1a;https://le…

注解(Annotation)

10.1 注解概述 10.1.1 什么是注解 注解&#xff08;Annotation&#xff09;是从JDK5.0开始引入&#xff0c;以“注解名”在代码中存在。例如&#xff1a; Override Deprecated SuppressWarnings(value”unchecked”) Annotation 可以像修饰符一样被使用&#xff0c;可用于修饰…

ChatGPT 之赋能提示词工程

原文&#xff1a;Chatgpt Empowers Your Prompt Engineering with AI Tools 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 介绍 在当今这个时代&#xff0c;设计和人工智能工具对于企业在不断发展的市场中蓬勃发展至关重要。ChatGPT 为探索一系列可能性提供了机会&am…

中兴天机A31 A31PRO 5G zte A2122H te A2022H 解锁BootLoader root权限 教程magisk,原厂刷机包

zte A2122H P768A02 zte A2022H P875A02 中兴天机A31 A31PRO 5G zte A2122H te A2022H 解锁BootLoader root教程magisk&#xff0c;原厂刷机包 感谢 某大神支持&#xff0c;已经解锁root 刷了面具&#xff1b; 中兴天机A31 A31PRO 5G zte A2122H te A2022H 解锁BootLoad…