Flutter前缀树(Trie)数据结构插件itrie的使用

Flutter前缀树(Trie)数据结构插件itrie的使用

简介

ITrie 是一个高效的、不可变且栈安全的前缀树(Trie)数据结构的 Dart 实现。前缀树非常适合用于自动补全、文本搜索、拼写检查等场景,尤其是在处理字符串和前缀时。

安装

pubspec.yaml 文件中添加 itrie 依赖:

dependencies:
  itrie: ^0.0.1

使用方法

构造函数

ITrie 可以通过任何 Iterable 或者使用 empty 构造函数来创建:

/// 创建一个空的 [ITrie],值类型为 [int]
final empty = ITrie<int>.empty();
final copy = empty.insert("key", 10);

/// 从包含 (String, T) 记录的 [Iterable] 创建 [ITrie]
final fromIterable = ITrie.fromIterable([("key", 10)]);
Iterable

ITrie 继承自 Iterable,因此可以使用所有 Iterable API 中的方法,例如 mapfoldeveryiterator 等。

不可变操作

ITrie 是不可变的,所有的修改操作都会返回一个新的 ITrie 实例,而不会修改原始的 ITrie。以下是一些常见的修改操作:

final itrie = ITrie<int>.empty();

// 插入键值对
final insert = itrie.insert("key", 10);

// 删除键值对
final remove = itrie.remove("key");

// 修改键值对
final modify = itrie.modify("key", (value) => value + 1);

// 批量插入多个键值对
final insertMany = itrie.insertMany([("key2", 20)]);

// 批量删除多个键
final removeMany = itrie.removeMany(["key"]);
获取器

ITrie 提供了多种方法来根据键或前缀提取值:

final itrie = ITrie<int>.empty();

// 根据键获取值
final getV = itrie.get("key");

// 获取最长前缀
final longestPrefixOf = itrie.longestPrefixOf("keys");

// 获取具有指定前缀的所有键值对
final withPrefix = itrie.withPrefix("ke");

// 获取具有指定前缀的所有键
final keysWithPrefix = itrie.keysWithPrefix("ke");

// 获取具有指定前缀的所有值
final valuesWithPrefix = itrie.valuesWithPrefix("ke");

// 获取所有键
final keys = itrie.keys;

// 获取所有值
final values = itrie.values;

// 获取元素数量
final length = itrie.length;

// 检查是否存在指定键
final has = itrie.has("key");

属性

不可变性

ITrie 是不可变的,所有的修改操作都会返回一个新的 ITrie 实例。例如:

final itrie = ITrie<int>.empty();
final newITrie = itrie.insert("key", 10); /// 👈 `insert` 返回一个新的 [ITrie]

expect(itrie.length, 0); /// 👈 原始 `itrie` 未被修改
expect(newITrie.length, 1);
栈安全性

ITrie 不使用递归,因此无论执行多少操作或包含多少元素,都不会导致栈溢出问题。

空间效率

ITrie 内部实现为三元搜索树(Ternary Search Trie),这种数据结构允许任意大小的字符集,并且比其他前缀树实现更节省空间。

示例代码

以下是一个完整的示例代码,展示了如何使用 ITrie 进行单词查找和自动补全:

import 'dart:convert';
import 'dart:io';

import 'package:itrie/itrie.dart';

void main() async {
  /// 读取单词文件
  final file = File('./example/words.txt');
  Stream<String> lines = file.openRead().transform(utf8.decoder).transform(
        LineSplitter(),
      );

  try {
    // 读取所有单词并过滤掉不符合条件的单词
    final sourceList = await lines.toList();
    final selection = sourceList
        .where(
          (key) => key.length >= 2 && RegExp(r'^[A-Za-z]+$').hasMatch(key),
        )
        .map((e) => e.toLowerCase());

    // 将筛选后的单词保存到新文件
    await File('./example/selection.txt')
        .writeAsString(selection.toList().join("\n"));

    // 创建 ITrie,将每个单词作为键,单词长度作为值
    final itrie = ITrie<int>.fromIterable(
      selection
          .map(
            (key) => (key.toLowerCase(), key.length),
          )
          .toList(),
    );

    print("Loaded ${itrie.length} words");

    // 交互式命令行,用户可以输入单词进行查找
    while (true) {
      print("Search a word");
      final line = stdin.readLineSync(encoding: utf8);
      if (line != null) {
        if (line == "q") {
          break;
        }

        // 查找用户输入的单词
        final result = itrie.get(line);
        if (result != null) {
          print("Found word: $line, Length: $result");
        } else {
          print("Word not found: $line");
        }
      }
    }
  } catch (e) {
    print('Error: $e');
  }
}

更多关于Flutter前缀树(Trie)数据结构插件itrie的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter前缀树(Trie)数据结构插件itrie的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用itrie插件来实现前缀树(Trie)数据结构的示例代码。itrie是一个用于在Dart中创建和操作Trie数据结构的插件。

步骤 1: 添加依赖

首先,你需要在pubspec.yaml文件中添加itrie依赖:

dependencies:
  flutter:
    sdk: flutter
  itrie: ^x.y.z  # 请将x.y.z替换为最新版本号

然后运行flutter pub get来获取依赖。

步骤 2: 导入itrie

在你的Dart文件中导入itrie包:

import 'package:itrie/itrie.dart';

步骤 3: 使用Trie数据结构

下面是一个完整的示例,展示如何使用itrie包来创建和操作Trie数据结构:

import 'package:flutter/material.dart';
import 'package:itrie/itrie.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Trie Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  Trie<String> trie;

  @override
  void initState() {
    super.initState();
    trie = Trie<String>();
    // 插入单词
    trie.insert("apple");
    trie.insert("app");
    trie.insert("apricot");
    trie.insert("banana");
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Trie Example'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Search for prefix:'),
            TextField(
              decoration: InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Enter prefix',
              ),
              onChanged: (String value) {
                setState(() {
                  // 搜索前缀
                  Iterable<String> results = trie.keysWithPrefix(value);
                  print('Words with prefix "$value": $results');
                });
              },
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                setState(() {
                  // 检查单词是否存在
                  bool exists = trie.containsKey("app");
                  print('Does "app" exist? $exists');
                });
              },
              child: Text('Check if "app" exists'),
            ),
          ],
        ),
      ),
    );
  }
}

解释

  1. 依赖添加:首先在pubspec.yaml中添加itrie依赖。
  2. 导入包:在需要使用Trie的Dart文件中导入itrie包。
  3. 初始化Trie:在initState方法中创建一个Trie实例并插入一些单词。
  4. 搜索前缀:在TextFieldonChanged回调中,使用trie.keysWithPrefix(value)方法搜索以输入前缀开头的所有单词,并打印结果。
  5. 检查单词存在性:在按钮点击事件中,使用trie.containsKey("app")方法检查某个单词是否存在,并打印结果。

这个示例展示了如何使用itrie插件在Flutter应用中实现Trie数据结构的基本操作。你可以根据需要扩展这个示例来实现更多的功能。

回到顶部