TS的数据结构使用实战(链表)——TypeScript 类、泛型的使用实践记录 | 青训营

引言

在 TypeScript 中,泛型是一项强大的特性,它可以帮助我们编写通用的、类型安全的代码。泛型是一种参数化类型的机制,它可以在定义函数、类或接口时使用,以增加代码的通用性。通过使用泛型,我们可以编写能够适用于不同类型的代码,从而提高代码的可复用性和灵活性。泛型还可以帮助我们在编译时捕获类型错误,提供更好的类型安全性。

数据结构,可以说是编程、计算机相关工作从业者的基本功。数据结构可通过编程语言所提供的数据类型引用及其他操作加以实现。

本系列文章会从实践的角度去讲解一些常用的数据结构在ts中的应用实例,因为要保证数据结构的通用性,把数据结构和数据本身的类型分离开,所以就会用到ts的泛型。

## 链表(Linked List)

链表是一种常见的数据结构,它由一系列节点组成,根据节点关系的不同,链表又分为单向链表和双向链表。

  • 单向链表:每个节点包含一个值和指向下一个节点的指针。
  • 双向链表:在单向链表的基础上,每个节点还增加一个指向上一个节点的指针。

通过使用泛型类和泛型接口,我们可以构建一个通用的单向链表数据结构。

链表的类式实现

链表的实现主要是维护一个链表头节点,然后对链表的各种操作都是以头节点为入口,遍历所有节点而进行操作的。所有数据节点像链子一样联系在一起,所以这个数据结构叫做链表。

ts 复制代码
class ListNode<T> {
  value: T;
  next: ListNode<T> | null;

  constructor(value: T) {
    this.value = value;
    this.next = null;
  }
}

class LinkedList<T> {
  private head: ListNode<T> | null;

  constructor() {
    this.head = null;
  }

  add(value: T) {
    const newNode = new ListNode(value);

    if (!this.head) {
      this.head = newNode;
    } else {
      let current = this.head;
      while (current.next) {
        current = current.next;
      }
      current.next = newNode;
    }
  }

  remove(value: T) {
    if (!this.head) {
      return;
    }

    if (this.head.value === value) {
      this.head = this.head.next;
      return;
    }

    let current = this.head;
    while (current.next) {
      if (current.next.value === value) {
        current.next = current.next.next;
        return;
      }
      current = current.next;
    }
  }

  print() {
    let current = this.head;
    while (current) {
      console.log(current.value);
      current = current.next;
    }
  }
}

通过使用泛型类 ListNode<T>LinkedList<T>,我们可以创建一个可以存储任意类型元素的链表。使用泛型约束,我们可以限制节点的值为特定类型,确保链表中的元素类型一致。

链表的函数式实现

链表的函数式实现与栈、队列的实现很像,都是把数据利用闭包存储,再返回数据的操作方法。

ts 复制代码
type ListNode<T> = {
  value: T;
  next: ListNode<T> | null;
};

type LinkedList<T> = {
  add: (value: T) => void;
  remove: (value: T) => void;
  print: () => void;
};

function newLinkedList<T>(): LinkedList<T> {
  let head: ListNode<T> | null = null;

  return {
    add: (value: T) => {
      const newNode: ListNode<T> = {
        value: value,
        next: null,
      };

      if (!head) {
        head = newNode;
      } else {
        let current = head;
        while (current.next) {
          current = current.next;
        }
        current.next = newNode;
      }
    },

    remove: (value: T) => {
      if (!head) {
        return;
      }

      if (head.value === value) {
        head = head.next;
        return;
      }

      let current = head;
      while (current.next) {
        if (current.next.value === value) {
          current.next = current.next.next;
          return;
        }
        current = current.next;
      }
    },

    print: () => {
      let current = head;
      while (current) {
        console.log(current.value);
        current = current.next;
      }
    },
  };
}

这样,一个链表的函数式实现(也可以叫工厂函数)就完成了


本系列文章比较注重实战,提供实战代码,并为想要了解原理的同学提供了相应链接,大家直接点击文章中的链接跳转即可。如果觉得文章有帮助,可以关注一下专栏噢~~

相关推荐
程序员黑豆6 小时前
Java类型推断完全指南:从var到菱形运算符,掌握使用限制与最佳实践
java·前端·ai编程
To_OC7 小时前
踩了个 TS 的坑之后,我终于把 type 和 interface 掰明白了
前端·react.js·typescript
GreenTea7 小时前
深度解读 Anthropic 多智能体报告:更强的模型 ≠ 更好的协调
前端·后端·算法
浮生望7 小时前
前端API工程化:用 Mock 数据与 Axios 配置实现独立于后端的并行开发
前端
万少8 小时前
给 DeepSeek Harness 装个"应用商店":一条命令,595 个插件随你逛
前端·javascript·后端
波波0078 小时前
C# 15 重磅新特性: 带标签 break 与 continue:重新定义嵌套循环控制流
服务器·前端·c#
Brown.alexis9 小时前
es6知识点1-自备使用
前端·ecmascript·es6
小爬的老粉丝10 小时前
JavaScript 纯前端预览 WPS:先识别容器,再路由解析器
前端·javascript·wps
计算机魔术师10 小时前
新兴多智能体系统的模式与问题
前端
用户0595401744611 小时前
AI Agent 上下文污染踩坑实录:用 pytest + Redis 揪出 3 类记忆串号 bug,排查 6 小时
前端·css