Typescript高级: 对泛型和多态的应用, 实现Java中的ArrayList和LinkedList

ArrayList


1 ) 概述

  • 在Java中,ArrayList是一个非常常用且强大的数据结构,它提供了动态数组的功能
  • 能够方便地添加、删除和访问元素。在TypeScript中,虽然并没有内置的ArrayList类型
  • 但我们可以通过类与接口来模拟实现ArrayList的功能

2 )实现

interface List<T> {size: number;add(item: T): void;get(index: number): T | undefined;remove(item: T): boolean;show(): void;
}class ArrayList<T> implements List<T> {public array: T[];private index: number = 0;public size: number = 0;constructor() {this.array = [];}// 添加元素,重载 add 方法add(item: T): void;add(item: any): void;add(item: number): void;add(item: string): void;add(item: any): void {this.array.push(item);this.size++;this.index = this.array.length; // 更新索引为数组最后一个元素的索引+1}// 获取元素get(index: number): T | undefined {return this.array[index];}// 删除元素,重载 remove 方法remove(item: T): boolean;remove(item: any): boolean;remove(item: number): boolean;remove(item: string): boolean;remove(item: any): boolean {const index = this.array.indexOf(item);if (index !== -1) {this.array.splice(index, 1);this.size--;return true;}return false;}// 显示全部数据show(): void {console.log(this.array);}// 更新元素,这里并没有在接口中定义,作为额外功能添加update(index: number, newValue: T): boolean {if (index >= 0 && index < this.size) {this.array[index] = newValue;return true;}return false;}
}const arrayList = new ArrayList<string>();// 添加元素
arrayList.add("Hello");
arrayList.add("World");
arrayList.add(42); // 这将不会报错,因为 TypeScript 中的泛型在运行时会被擦除,并且 add 方法被重载以接受 any 类型// 显示元素
arrayList.show(); // 输出: [ 'Hello', 'World', 42 ]// 获取元素
console.log(arrayList.get(0)); // 输出: Hello// 更新元素
arrayList.update(1, "TypeScript");
arrayList.show(); // 输出: [ 'Hello', 'TypeScript', 42 ]// 删除元素
console.log(arrayList.remove("TypeScript")); // 输出: true
arrayList.show(); // 输出: [ 'Hello', 42 ]// 获取数组大小
console.log(arrayList.size); // 输出: 2

3 )说明

  • 在基础List类型中,我们定义了如下方法和属性

    • add(item: T): 添加一个元素到ArrayList中
    • get(index: number): 根据索引获取元素
    • size: 存储ArrayList中元素的数量
    • remove(item: T): 删除一个元素
    • show(): 显示ArrayList中的所有元素
  • ArrayList 这个类继承List接口,并实现其所有的方法

  • 这里面实现了方法的多态和泛型

    • 1 )多态(Polymorphism)的主要优势在于提高了代码的可维护性和扩展性
    • 通过使用多态,我们可以编写更加灵活和可重用的代码
    • 因为我们可以定义通用的接口或方法,而不必关心具体实现细节
    • 2 ) 泛型(Generics)是TypeScript中一种强大的工具
    • 它允许我们在不丢失类型信息的前提下,编写可重用的组件
    • 这些组件可以与多种不同的类型一起工作,而不仅仅是一个类型
    • 泛型的主要作用是提供类型安全,同时确保代码的可复用性
    • 通过使用泛型,我们可以在保证类型安全的同时
    • 让函数与多种类型一起工作
  • 总结来说

    • 泛型和多态是TypeScript中两个强大的特性
    • 它们分别通过提供类型安全和允许统一操作不同数据类型来增强代码的可复用性和灵活性
    • 在实际开发中,结合使用泛型和多态可以帮助我们编写更加健壮、可维护和可扩展的代码

LinkedList


1 ) 概述

  • 在TypeScript中,实现一个双向链表(Doubly Linked List)相比于ArrayList会更加复杂
  • 因为我们需要维护每个节点的两个指针:一个指向前一个节点,另一个指向下一个节点
  • 同时,我们还要确保List接口的所有方法都能得到正确实现
  • 在数据结构中,链表是一种动态分配内存空间的线性数据结构
  • 由一系列的节点组成,每个节点通常包含两部分:
    • 一部分用于存储数据
    • 另一部分用于存储指向下一个节点的指针
  • 而双向链表,顾名思义,就是每个节点不仅包含指向下一个节点的指针
  • 还包含指向前一个节点的指针, 这使得双向链表在插入和删除节点时更为灵活

2 )实现

interface List<T> {add(element: T): void;get(index: number): T | undefined;size: number;remove(element: T): boolean;
}class N<T> {value: T;next: N<T> | null;prev: N<T> | null;constructor(value: T, next: N<T> | null = null, prev: N<T> | null = null) {this.value = value;this.next = next;this.prev = prev;}
}class LinkedList<T> implements List<T> {private head: N<T> | null = null;private tail: N<T> | null = null;public size = 0;add(element: T): void {const newNode = new N(element, null, this.tail);if (this.tail) {this.tail.next = newNode;} else {this.head = newNode;}this.tail = newNode;this.size++;}get(index: number): T | undefined {if (index < 0 || index >= this.size) {return undefined;}let current = this.head;for (let i = 0; i < index; i++) {current = current!.next;}return current?.value;}remove(element: T): boolean {let current = this.head;while (current) {if (current.value === element) {if (current.prev) {current.prev.next = current.next;} else {this.head = current.next;}if (current.next) {current.next.prev = current.prev;} else {this.tail = current.prev;}this.size--;return true;}current = current.next;}return false;}
}// 使用示例
const linkedList = new LinkedList<number>();
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);
console.log(linkedList.get(1)); // 输出: 2
console.log(linkedList.size); // 输出: 3
linkedList.remove(2);
console.log(linkedList.get(1)); // 输出: 3

3 )说明

  • 首先,我们定义了一个 List 接口,它规定了链表需要实现的基本方法:

    • 添加元素(add)
    • 获取指定位置的元素(get)
    • 获取链表大小(size)
    • 以及删除元素(remove)
    • 这个接口为后续的链表实现提供了统一的规范
  • 在 LinkedList 的实现中,节点被定义为一个名为 N 的内部类

    • 每个节点包含三个属性:value 用于存储数据,next 指向下一个节点,prev 指向前一个节点
    • 这样的结构使得链表能够双向遍历,从而更容易实现某些操作,如删除节点
  • LinkedList 类实现了 List 接口,并包含了维护链表状态的重要属性

    • head 指向链表的第一个节点,tail 指向链表的最后一个节点,size 记录链表的大小
  • 添加元素:add 方法在链表尾部添加一个新节点

    • 首先,创建一个新的节点,并设置其 next 为 null,prev 为当前的尾节点
    • 然后,更新尾节点为新节点,并如果原链表为空(即 head 和 tail 都为 null)
    • 则将 head 也指向新节点, 最后,链表的大小加一
  • 获取元素:get 方法通过遍历链表找到指定位置的元素

    • 它首先检查索引是否合法,然后从 head 开始遍历,直到找到对应位置的节点或遍历完整个链表
    • 这个过程的时间复杂度是 O(n),其中 n 是链表的大小
  • 删除元素:remove 方法遍历链表,查找并删除指定的元素

    • 当找到匹配的节点时,它更新相邻节点的指针以跳过该节点
    • 并调整 head 或 tail 如果被删除的是头节点或尾节点。最后,链表的大小减一
  • 总结

    • 双向链表 LinkedList 的实现简单而高效,通过双向指针实现了灵活的节点操作
    • 它的主要优势在于插入和删除节点时的性能,尤其是当需要在特定位置进行这些操作时
    • 然而,链表在随机访问元素方面的性能不如数组,因为需要从链表头部开始遍历以找到指定位置的元素
    • 在实际应用中,链表通常用于需要频繁插入和删除元素的场景,如实现缓存、LRU(最近最少使用)算法等
    • 而数组则更适用于需要频繁访问元素的场景,如搜索、排序等
    • 因此,在选择使用链表还是数组时,需要根据具体的应用场景和需求进行权衡

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

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

相关文章

省公派访学|社科老师赴世界名校牛津大学开展研究

F老师已获某省公派出国访学半年的资助&#xff0c;希望落实的学校尽量知名。但因为F老师只是硕士毕业而无博士学位&#xff0c;专业方向又是社科类&#xff0c;所以申请到世界知名高校有一定难度。经过努力&#xff0c;最终我们获得了世界顶尖高校-英国牛津大学的访问学者邀请函…

html5的一些新特性

最近总是碰到html5特性这种问题,虽然简单,但是也是自己平时不关注的东西,趁今天时间充裕,那就来总结一下吧 HTML5新特性包括新增了部分标签、表单元素增强、支持视频和音频、支持canvas绘图、提供web存储、提供地理定位功能、提供web workers机制、提供web socket协议、提供CS…

深入解析 @Transactional:Spring 事务管理的艺术及实战应对策略

在Spring框架的事务处理中&#xff0c;Transactional 注解扮演着核心角色&#xff0c;它极大地简化了开发者在应用中实施事务控制的复杂度。本文将全面解析 Transactional 注解的各个关键属性&#xff0c;并结合实际问题——多数据源配置中遇到的 PlatformTransactionManager 选…

【运维实践项目|001】:高可用性云基础设施部署与升级项目

目录 项目名称 项目背景 项目目标 项目成果 我的角色与职责 我主要完成的工作内容 本次项目涉及的技术 本次项目遇到的问题与解决方法 本次项目中可能被面试官问到的问题 1、什么是ELK&#xff1f; 2、什么是Elasticsearch、Logstash 和Kibana&#xff1f; 3、ELK 三…

《intel开发手册卷3》读书笔记1

1、CPU工作模式 1&#xff09;实模式&#xff1a;8086的寄存器只有16位&#xff0c;我们也习惯于称8086的工作模式为16位模式。后续的CPU为了保持兼容性&#xff0c;在芯片上了电以后&#xff0c;还必须运行于16位模式之下。这种模式还有个正式的名字叫做实模式。在实模式下&am…

【游戏引擎】unity

目录 Unity入门教程&#xff1a;从零到英雄的旅程前言第一步&#xff1a;下载和安装Unity第二步&#xff1a;创建你的第一个Unity项目第三步&#xff1a;熟悉Unity界面第四步&#xff1a;创建一个简单的游戏对象第五步&#xff1a;编写脚本赋予游戏对象生命第六步&#xff1a;运…

Leetcode 222:完全二叉树的节点个数

给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 递归遍历1 public static int countNodes(TreeNode root){return preorder(root);}//计算树的节点个数public static int preorder(TreeNode root){int count0;if(rootnull) return 0;int leftpreorder(…

C语言每日一题—查找子串个数

用函数编程实现计算字符串中子串出现的次数。 函数原型&#xff1a; int FindString(char *str,char *sub) 要求&#xff1a; 在主函数中输入字符串和子串&#xff0c;调用FindString()函数&#xff0c;输出子串出现的次数。输入格式&#xff1a;"%c" 输出格式&#…

探索车路云深度融合的优化与实践

项目背景与业务场景 目前&#xff0c;我国车联网行业处于与 5G 技术的深度融合时期。随着汽车从传统交通工具向着智能化、网联化和电动化方向演进&#xff0c;车联网成为 5G 交通和汽车领域跨界融合最具潜力的应用&#xff0c;已经成为我国战略性新兴产业的重要发展方向。通过…

【前端每日基础】day8 src和href

src 和 href 是两个常用的 HTML 属性&#xff0c;它们分别用于不同类型的资源引用&#xff0c;有以下区别&#xff1a; src&#xff08;source&#xff09;&#xff1a; src 属性用于指定外部资源的地址&#xff0c;比如图像、音频、视频、嵌入框架等的地址。 在 < img &g…

Linux perf:系统性能监控和分析工具

1. 写在前面 Linux perf 是 Linux 2.6 后内置于内核源码树中的性能剖析&#xff08;profiling&#xff09;工具,它基于事件采样&#xff0c;以性能事件为基础&#xff0c;针对 CPU 相关性能指标与操作系统相关性能指标进行性能剖析&#xff0c;可用于性能瓶颈查找与热点代码的…

保研机试之【x86/x86-64体系结构中的寄存器】

先来看一下这六个选项的功能&#xff1a; 举一个例子&#xff1a; 对于CR2寄存器和中断向量表&#xff1a; 也就是先通过CR2寄存器找到引发错误的虚拟地址&#xff0c;然后操作系统分析错误原因&#xff0c;通过IDTR寄存器找到IDT&#xff08;中断向量表&#xff09;&#xff0…

栈与递归的实现

1. 栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。 进行数据插入和删除操作的一端 称为栈顶&#xff0c;另一端称为栈底。 栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则&#x…

光纤VS紫外:如何选择最适合您生产线的激光打标机?

光纤激光打标机和紫外激光打标机在制造业中都有其独特的应用&#xff0c;但两者在原理、特点和应用范围上存在一些差异。 光纤激光打标机是一种采用光纤输出激光&#xff0c;并通过高速扫描振镜系统实现打标功能的新一代激光打标机系统。它电光转换效率高&#xff0c;达到30%以…

【第21章】spring-mvc之整合druid

文章目录 前言一、准备1. 引入库2. 添加配置2.1 jdbc.properties2.2 spring-mvc.xml 二、测试1.测试类2.测试结果 总结 前言 【第5章】spring命名空间和数据源的引入 在spring章节已经简单的介绍了数据源的引入&#xff0c;两者差别不大。 一、准备 1. 引入库 <dependen…

Mockito框架,帮助创建模拟对象进行测试的利器

在现代软件开发中&#xff0c;单元测试作为确保代码质量和可靠性的重要环节&#xff0c;已逐渐成为开发流程中不可或缺的一部分。为了让单元测试更加灵活、独立&#xff0c;开发者们通常使用 Mocking&#xff08;模拟&#xff09;框架来替代真实对象&#xff0c;从而更好地模拟…

C++进阶:AVL树详解及模拟实现(图示讲解旋转过程)

C进阶&#xff1a;AVL树详解及模拟实现&#xff08;图示讲解旋转过程&#xff09; 之前在搜索二叉树最后早就埋下伏笔&#xff0c;来介绍AVL树和红黑树&#xff0c;今天就先来第一个吧 文章目录 1.AVL树介绍1.1概念介绍1.2核心性质 2.项目文件规划3.整体框架&#xff08;节点和…

JDK 1.8 HashMap扩容机制

我们首先来看利用无参构造函数创建HashMap如何扩容。首先创建一个无参构造出来的hashmap HashMap hashMap new HashMap();该构造函数源码如下&#xff1a; public HashMap() {this.loadFactor DEFAULT_LOAD_FACTOR; // all other fields defaulted}此时&#xff0c;该构造函…

linux笔记5--shell命令2

文章目录 一. linux中的任务管理1. 图形界面2. 命令① top命令② grep命令③ ps命令补充&#xff1a; ④ kill命令图形界面杀死进程 二. 挂载(硬盘方面最重要的一个知识点)1. 什么是挂载2. 关于挂载目录① Windows② linux查看硬件分区情况(/dev下)&#xff1a;更改挂载目录结束…

揭秘 HTTP 代理:增强在线活动的安全性和匿名性

HTTP 代理在保护您的在线隐私、增强安全性以及允许访问受限内容方面发挥着关键作用。了解 HTTP 代理的工作原理以及如何有效地利用它们可以让您掌控自己的在线状态和浏览体验。让我们深入研究 HTTP 代理的世界&#xff0c;探索它们的优势、应用程序以及最大化其效用的最佳实践。…