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

本文主要是介绍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(最近最少使用)算法等
    • 而数组则更适用于需要频繁访问元素的场景,如搜索、排序等
    • 因此,在选择使用链表还是数组时,需要根据具体的应用场景和需求进行权衡

这篇关于Typescript高级: 对泛型和多态的应用, 实现Java中的ArrayList和LinkedList的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/983930

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.