MongoDB via Dotnet Core数据映射详解

用好数据映射,MongoDB via Dotnet Core开发变会成一件超级快乐的事。

一、前言

MongoDB这几年已经成为NoSQL的头部数据库。

由于MongoDB free schema的特性,使得它在互联网应用方面优于常规数据库,成为了相当一部分大厂的主数据选择;而它的快速布署和开发简单的特点,也吸引着大量小开发团队的支持。

关于MongoDB快速布署,我在15分钟从零开始搭建支持10w+用户的生产环境(二)里有写,需要了可以去看看。

作为一个数据库,基本的操作就是CRUD。MongoDB的CRUD,不使用SQL来写,而是提供了更简单的方式。

方式一、BsonDocument方式

BsonDocument方式,适合能熟练使用MongoDB Shell的开发者。MongoDB Driver提供了完全覆盖Shell命令的各种方式,来处理用户的CRUD操作。

这种方法自由度很高,可以在不需要知道完整数据集结构的情况下,完成数据库的CRUD操作。

方式二、数据映射方式

数据映射是最常用的一种方式。准备好需要处理的数据类,直接把数据类映射到MongoDB,并对数据集进行CRUD操作。

下面,对数据映射的各个部分,我会逐个说明。

二、开发环境&基础工程

这个Demo的开发环境是:Mac + VS Code + Dotnet Core 3.1.2。

建立工程:

% dotnet new sln -o demo
The template "Solution File" was created successfully.
% cd demo 
% dotnet new console -o demo
The template "Console Application" was created successfully.Processing post-creation actions...
Running 'dotnet restore' on demo/demo.csproj...Determining projects to restore...Restored demo/demo/demo.csproj (in 162 ms).Restore succeeded.
% dotnet sln add demo/demo.csproj 
Project `demo/demo.csproj` added to the solution.

建立工程完成。

下面,增加包mongodb.driver到工程:

% cd demo
% dotnet add package mongodb.driverDetermining projects to restore...
info : Adding PackageReference for package 'mongodb.driver' into project 'demo/demo/demo.csproj'.
info : Committing restore...
info : Writing assets file to disk. Path: demo/demo/obj/project.assets.json
log  : Restored /demo/demo/demo.csproj (in 6.01 sec).

项目准备完成。

看一下目录结构:

% tree .
.
├── demo
│   ├── Program.cs
│   ├── demo.csproj
│   └── obj
│       ├── demo.csproj.nuget.dgspec.json
│       ├── demo.csproj.nuget.g.props
│       ├── demo.csproj.nuget.g.targets
│       ├── project.assets.json
│       └── project.nuget.cache
└── demo.sln

mongodb.driver是MongoDB官方的数据库SDK,从Nuget上安装即可。

三、Demo准备工作

创建数据映射的模型类CollectionModel.cs,现在是个空类,后面所有的数据映射相关内容会在这个类进行说明:

public class CollectionModel
{
}

并修改Program.cs,准备Demo方法,以及连接数据库:

class Program
{private const string MongoDBConnection = "mongodb://localhost:27031/admin";private static IMongoClient _client = new MongoClient(MongoDBConnection);private static IMongoDatabase _database = _client.GetDatabase("Test");private static IMongoCollection<CollectionModel> _collection = _database.GetCollection<CollectionModel>("TestCollection");static async Task Main(string[] args){await Demo();Console.ReadKey();}private static async Task Demo(){}
}

四、字段映射

从上面的代码中,我们看到,在生成Collection对象时,用到了CollectionModel

IMongoDatabase _database = _client.GetDatabase("Test");
IMongoCollection<CollectionModel> _collection = _database.GetCollection<CollectionModel>("TestCollection");

这两行,其实就完成了一个映射的工作:把MongoDB中,Test数据库下,TestCollection数据集(就是SQL中的数据表),映射到CollectionModel这个数据类中。换句话说,就是用CollectionModel这个类,来完成对数据集TestCollection的所有操作。

保持CollectionModel为空,我们往数据库写入一行数据:

private static async Task Demo()
{CollectionModel new_item = new CollectionModel();await _collection.InsertOneAsync(new_item);
}

执行,看一下写入的数据:

{ "_id" : ObjectId("5ef1d8325327fd4340425ac9")
}

OK,我们已经写进去一条数据了。因为映射类是空的,所以写入的数据,也只有_id一行内容。

但是,为什么会有一个_id呢?

1. ID字段

MongoDB数据集中存放的数据,称之为文档(Document)。每个文档在存放时,都需要有一个ID,而这个ID的名称,固定叫_id

当我们建立映射时,如果给出_id字段,则MongoDB会采用这个ID做为这个文档的ID,如果不给出,MongoDB会自动添加一个_id字段。

例如:

public class CollectionModel
{public ObjectId _id { get; set; }public string title { get; set; }public string content { get; set; }
}

public class CollectionModel
{public string title { get; set; }public string content { get; set; }
}

在使用上是完全一样的。唯一的区别是,如果映射类中不写_id,则MongoDB自动添加_id时,会用ObjectId作为这个字段的数据类型。

ObjectId是一个全局唯一的数据。

当然,MongoDB允许使用其它类型的数据作为ID,例如:stringintlongGUID等,但这就需要你自己去保证这些数据不超限并且唯一。

例如,我们可以写成:

public class CollectionModel
{public long _id { get; set; }public string title { get; set; }public string content { get; set; }
}

我们也可以在类中修改_id名称为别的内容,但需要加一个描述属性BsonId

public class CollectionModel
{[BsonId]public ObjectId topic_id { get; set; }public string title { get; set; }public string content { get; set; }
}

这儿特别要注意:BsonId属性会告诉映射,topic_id就是这个文档数据的ID。MongoDB在保存时,会将这个topic_id转成_id保存到数据集中。

在MongoDB数据集中,ID字段的名称固定叫_id。为了代码的阅读方便,可以在类中改为别的名称,但这不会影响MongoDB中存放的ID名称。

修改Demo代码:

private static async Task Demo()
{CollectionModel new_item = new CollectionModel(){title = "Demo",content = "Demo content",};await _collection.InsertOneAsync(new_item);
}

跑一下Demo,看看保存的结果:

{ "_id" : ObjectId("5ef1e1b1bc1e18086afe3183"), "title" : "Demo", "content" : "Demo content"
}

2. 简单字段

就是常规的数据字段,直接写就成。

public class CollectionModel
{[BsonId]public ObjectId topic_id { get; set; }public string title { get; set; }public string content { get; set; }public int favor { get; set; }
}

保存后的数据:

{ "_id" : ObjectId("5ef1e9caa9d16208de2962bb"), "title" : "Demo", "content" : "Demo content", "favor" : NumberInt(100)
}

3. 一个的特殊的类型 - Decimal

说Decimal特殊,是因为MongoDB在早期,是不支持Decimal的。直到MongoDB v3.4开始,数据库才正式支持Decimal。

所以,如果使用的是v3.4以后的版本,可以直接使用,而如果是以前的版本,需要用以下的方式:

[BsonRepresentation(BsonType.Double, AllowTruncation = true)]
public decimal price { get; set; }

其实就是把Decimal通过映射,转为Double存储。

4. 类字段

把类作为一个数据集的一个字段。这是MongoDB作为文档NoSQL数据库的特色。这样可以很方便的把相关的数据组织到一条记录中,方便展示时的查询。

我们在项目中添加两个类ContactAuthor

public class Contact
{public string mobile { get; set; }
}
public class Author
{public string name { get; set; }public List<Contact> contacts { get; set; }
}

然后,把Author加到CollectionModel中:

public class CollectionModel
{[BsonId]public ObjectId topic_id { get; set; }public string title { get; set; }public string content { get; set; }public int favor { get; set; }public Author author { get; set; }
}

嗯,开始变得有点复杂了。

完善Demo代码:

private static async Task Demo()
{CollectionModel new_item = new CollectionModel(){title = "Demo",content = "Demo content",favor = 100,author = new Author{name = "WangPlus",contacts = new List<Contact>(),}};Contact contact_item1 = new Contact(){mobile = "13800000000",};Contact contact_item2 = new Contact(){mobile = "13811111111",};new_item.author.contacts.Add(contact_item1);new_item.author.contacts.Add(contact_item2);await _collection.InsertOneAsync(new_item);
}

保存的数据是这样的:

{ "_id" : ObjectId("5ef1e635ce129908a22dfb5e"), "title" : "Demo", "content" : "Demo content", "favor" : NumberInt(100),"author" : {"name" : "WangPlus", "contacts" : [{"mobile" : "13800000000"}, {"mobile" : "13811111111"}]}
}

这样的数据结构,用着不要太爽!

5. 枚举字段

枚举字段在使用时,跟类字段相似。

创建一个枚举TagEnumeration

public enum TagEnumeration
{CSharp = 1,Python = 2,
}

加到CollectionModel中:

public class CollectionModel
{[BsonId]public ObjectId topic_id { get; set; }public string title { get; set; }public string content { get; set; }public int favor { get; set; }public Author author { get; set; }public TagEnumeration tag { get; set; }
}

修改Demo代码:

private static async Task Demo()
{CollectionModel new_item = new CollectionModel(){title = "Demo",content = "Demo content",favor = 100,author = new Author{name = "WangPlus",contacts = new List<Contact>(),},tag = TagEnumeration.CSharp,};/* 后边代码略过 */
}

运行后看数据:

{ "_id" : ObjectId("5ef1eb87cbb6b109031fcc31"), "title" : "Demo", "content" : "Demo content", "favor" : NumberInt(100), "author" : {"name" : "WangPlus", "contacts" : [{"mobile" : "13800000000"}, {"mobile" : "13811111111"}]}, "tag" : NumberInt(1)
}

在这里,tag保存了枚举的值。

我们也可以保存枚举的字符串。只要在CollectionModel中,tag声明上加个属性:

public class CollectionModel
{[BsonId]public ObjectId topic_id { get; set; }public string title { get; set; }public string content { get; set; }public int favor { get; set; }public Author author { get; set; }[BsonRepresentation(BsonType.String)]public TagEnumeration tag { get; set; }
}

数据会变成:

{ "_id" : ObjectId("5ef1ec448f1d540919d15904"), "title" : "Demo", "content" : "Demo content", "favor" : NumberInt(100), "author" : {"name" : "WangPlus", "contacts" : [{"mobile" : "13800000000"}, {"mobile" : "13811111111"}]}, "tag" : "CSharp"
}

6. 日期字段

日期字段会稍微有点坑。

这个坑其实并不源于MongoDB,而是源于C#的DateTime类。我们知道,时间根据时区不同,时间也不同。而DateTime并不准确描述时区的时间。

我们先在CollectionModel中增加一个时间字段:

public class CollectionModel
{[BsonId]public ObjectId topic_id { get; set; }public string title { get; set; }public string content { get; set; }public int favor { get; set; }public Author author { get; set; }[BsonRepresentation(BsonType.String)]public TagEnumeration tag { get; set; }public DateTime post_time { get; set; }
}

修改Demo:

private static async Task Demo()
{CollectionModel new_item = new CollectionModel(){/* 前边代码略过 */post_time = DateTime.Now, /* 2020-06-23T20:12:40.463+0000 */};/* 后边代码略过 */
}

运行看数据:

{ "_id" : ObjectId("5ef1f1b9a75023095e995d9f"), "title" : "Demo", "content" : "Demo content", "favor" : NumberInt(100), "author" : {"name" : "WangPlus", "contacts" : [{"mobile" : "13800000000"}, {"mobile" : "13811111111"}]}, "tag" : "CSharp", "post_time" : ISODate("2020-06-23T12:12:40.463+0000")
}

对比代码时间和数据时间,会发现这两个时间差了8小时 - 正好的中国的时区时间。

MongoDB规定,在数据集中存储时间时,只会保存UTC时间。

如果只是保存(像上边这样),或者查询时使用时间作为条件(例如查询post_time < DateTime.Now的数据)时,是可以使用的,不会出现问题。

但是,如果是查询结果中有时间字段,那这个字段,会被DateTime默认设置为DateTimeKind.Unspecified类型。而这个类型,是无时区信息的,输出显示时,会造成混乱。

为了避免这种情况,在进行时间字段的映射时,需要加上属性:

[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
public DateTime post_time { get; set; }

这样做,会强制DateTime类型的字段为DateTimeKind.Local类型。这时候,从显示到使用就正确了。

但是,别高兴的太早,这儿还有一个但是。

这个但是是这样的:数据集中存放的是UTC时间,跟我们正常的时间有8小时时差,如果我们需要按日统计,比方每天的销售额/点击量,怎么搞?上面的方式,解决不了。

当然,基于MongoDB自由的字段处理,可以把需要统计的字段,按年月日时分秒拆开存放,像下面这样的:

class Post_Time
{public int year { get; set; }public int month { get; set; }public int day { get; set; }public int hour { get; set; }public int minute { get; set; }public int second { get; set; }
}

能解决,但是Low哭了有没有?

下面,终极方案来了。它就是:改写MongoDB中对于DateTime字段的序列化类。当当当~~~

先创建一个类MyDateTimeSerializer

public class MyDateTimeSerializer : DateTimeSerializer
{public override DateTime Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args){var obj = base.Deserialize(context, args);return new DateTime(obj.Ticks, DateTimeKind.Unspecified);}public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, DateTime value){var utcValue = new DateTime(value.Ticks, DateTimeKind.Utc);base.Serialize(context, args, utcValue);}
}

代码简单,一看就懂。

注意,使用这个方法,上边那个对于时间加的属性[BsonDateTimeOptions(Kind = DateTimeKind.Local)]一定不要添加,要不然就等着哭吧:P

创建完了,怎么用?

如果你只想对某个特定映射的特定字段使用,比方只对CollectionModelpost_time字段来使用,可以这么写:

[BsonSerializer(typeof(MyDateTimeSerializer))]
public DateTime post_time { get; set; }

或者全局使用:

BsonSerializer.RegisterSerializer(typeof(DateTime), new MongoDBDateTimeSerializer());

BsonSerializer是MongoDB.Driver的全局对象。所以这个代码,可以放到使用数据库前的任何地方。例如在Demo中,我放在Main里了:

static async Task Main(string[] args)
{BsonSerializer.RegisterSerializer(typeof(DateTime), new MyDateTimeSerializer());await Demo();Console.ReadKey();
}

这回看数据,数据集中的post_time跟当前时间显示完全一样了,你统计,你分组,可以随便霍霍了。

7. Dictionary字段

这个需求很奇怪。我们希望在一个Key-Value的文档中,保存一个Key-Value的数据。但这个需求又是真实存在的,比方保存一个用户的标签和标签对应的命中次数。

数据声明很简单:

public Dictionary<string, int> extra_info { get; set; }

MongoDB定义了三种保存属性:DocumentArrayOfDocumentsArrayOfArrays,默认是Document

属性写法是这样的:

[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfDocuments)]
public Dictionary<string, int> extra_info { get; set; }

这三种属性下,保存在数据集中的数据结构有区别。

DictionaryRepresentation.Document

{ "extra_info" : {"type" : NumberInt(1), "mode" : NumberInt(2)}
}

DictionaryRepresentation.ArrayOfDocuments

{ "extra_info" : [{"k" : "type", "v" : NumberInt(1)}, {"k" : "mode", "v" : NumberInt(2)}]
}

DictionaryRepresentation.ArrayOfArrays

{ "extra_info" : [["type", NumberInt(1)], ["mode", NumberInt(2)]]
}

这三种方式,从数据保存上并没有什么区别,但从查询来讲,如果这个字段需要进行查询,那三种方式区别很大。

如果采用BsonDocument方式查询,DictionaryRepresentation.Document无疑是写着最方便的。

如果用Builder方式查询,DictionaryRepresentation.ArrayOfDocuments是最容易写的。

DictionaryRepresentation.ArrayOfArrays就算了。数组套数组,查询条件写死人。

我自己在使用时,多数情况用DictionaryRepresentation.ArrayOfDocuments

五、其它映射属性

上一章介绍了数据映射的完整内容。除了这些内容,MongoDB还给出了一些映射属性,供大家看心情使用。

1. BsonElement属性

这个属性是用来改数据集中的字段名称用的。

看代码:

[BsonElement("pt")]
public DateTime post_time { get; set; }

在不加BsonElement的情况下,通过数据映射写到数据集中的文档,字段名就是变量名,上面这个例子,字段名就是post_time

加上BsonElement后,数据集中的字段名会变为pt

2. BsonDefaultValue属性

看名称就知道,这是用来设置字段的默认值的。

看代码:

[BsonDefaultValue("This is a default title")]
public string title { get; set; }

当写入的时候,如果映射中不传入值,则数据库会把这个默认值存到数据集中。

3. BsonRepresentation属性

这个属性是用来在映射类中的数据类型和数据集中的数据类型做转换的。

看代码:

[BsonRepresentation(BsonType.String)]
public int favor { get; set; }

这段代表表示,在映射类中,favor字段是int类型的,而存到数据集中,会保存为string类型。

前边Decimal转换和枚举转换,就是用的这个属性。

4. BsonIgnore属性

这个属性用来忽略某些字段。忽略的意思是:映射类中某些字段,不希望被保存到数据集中。

看代码:

[BsonIgnore]
public string ignore_string { get; set; }

这样,在保存数据时,字段ignore_string就不会被保存到数据集中。

六、总结

数据映射本身没什么新鲜的内容,但在MongoDB中,如果用好了映射,开发过程从效率到爽的程度,都不是SQL可以相比的。正所谓:

一入Mongo深似海,从此SQL是路人。

谢谢大家!

(全文完)

本文的配套代码在https://github.com/humornif/Demo-Code/tree/master/0015/demo

点「在看」,让更多人因你而受益

↘  ↘  ↘

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

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

相关文章

算法-排序-归并排序

归并排序 特点&#xff1a;非原址排序&#xff0c;比较排序&#xff0c;时间复杂度O&#xff08;nlgn&#xff09; 稳定 // // Created by 许加权 on 2021/6/18. //#include <iostream> void merge_sort(int *arr,int start,int end) {if(start < end){int middle …

FreeSql.Generator命令行代码生成器是如何实现的

目录FreeSql介绍FreeSql.GeneratorRazorEngine.NetCore源码解析FreeSql.ToolsFreeSqlFreeSql 是功能强大的对象关系映射技术(O/RM)&#xff0c;支持 .NETCore 2.1 或 .NETFramework 4.0 或 Xamarin。有一个强大的ORM&#xff0c;也方便我们开发一个代码生成器。一般情况下&…

算法-排序-选择排序

选择排序 特点&#xff1a;原址排序&#xff0c;比较排序&#xff0c;时间复杂度O&#xff08;n^2&#xff09; // // Created by 许加权 on 2021/6/19. //#include <iostream>void selection_sort(int *arr,int start,int end) {for (int i start 1; i < end1; i…

.Net Core Configuration Etcd数据源

前言.Net Core为我们提供了一套强大的Configuration配置系统&#xff0c;使用简单扩展性强。通过这套配置系统我们可以将Json、Xml、Ini等数据源加载到程序中,也可以自己扩展其他形式的存储源。今天我们要做的就是通过自定义的方式为其扩展Etcd数据源操作。何为Etdc在使用etcd之…

算法-二分查找

二分查找 特点&#xff1a; T(n) T(n/2 - 1) c 时间复杂度O&#xff08;lgn) 前提&#xff1a;需要已排序的集合 int binary_search(int *arr,int start,int end,int key) {if(start<end){int middle (startend)/2;if(arr[middle] key) return middle;if(key<arr[m…

Java IDEA断点调试

断点调试(debug) 断点调试应用案例 01&#xff1a; package Assign;public class Debug01 {public static void main(String[] args) {int sum 0;for (int i 0;i<5;i){sumi;System.out.println(i);System.out.println(sum);}System.out.println("continue");} …

.NET Core请求控制器Action方法正确匹配,但为何404?

【导读】提前预祝各位端午节快乐。有时候我们会发现方法名称都正确匹配&#xff0c;但就是找不到对应请求接口&#xff0c;所以本文我们来深入了解下何时会出现接口请求404的情况。匹配控制器Action方法&#xff08;404&#xff09;首先我们创建一个web api应用程序&#xff0c…

布斯乘法以及带符号数的运算

乘法理解 对于最熟悉的十进制乘法很最基本的运算原理就是一个乘数乘以另一个乘数的个位、十位、百位数字然后求和。比如 放到二进制来看其实它也是这样的&#xff0c;多位数的乘法就是一个乘数乘上另一个乘数的各位求和。那么&#xff1a; 布斯算法及原理 原理 已经知道两…

算法-排序-冒泡排序

冒泡排序 特点&#xff1a;原址排序&#xff0c;比较排序 时间复杂度O&#xff08;n^2) void bubble_sort(int *arr,int start,int end) {for (int i start; i < end; i) {for (int j end; j >i ; j--) {if(arr[j-1]>arr[j]){int temp arr[j];arr[j] arr[j-1];a…

C++重载输出操作符<<,为什么要返回引用

针对&#xff1a;ostream & operator <<(ostream & os, const ClassType &object) 说明几点&#xff1a; 1.第一个形参为对ostream对象的引用&#xff0c;在该对象上将产生输出&#xff0c;ostream为非const&#xff0c;因为写入到流会改变流的状态&#x…

angular 接入 IdentityServer4

angular 接入 IdentityServer4Intro最近把活动室预约的项目做了一个升级&#xff0c;预约活动室需要登录才能预约&#xff0c;并用 IdentityServer4 做了一个统一的登录注册中心&#xff0c;这样以后就可以把其他的需要用户操作的应用统一到 IdentityServer 这里&#xff0c;这…

算法-计算逆序对个数

求逆序对的个数 特点&#xff1a;利用归并排序中合并的步骤&#xff0c;计算逆序对 时间复杂度O&#xff08;nlgn&#xff09; int merge_inversion(int *arr,int start,int end,int middle); int count_inversion(int *arr,int start,int end) {if(start<end){int middle…

主机Redis服务迁移到现有Docker Overlay网络

“《麻雀虽小&#xff0c;五脏俱全》之主机现有Redis服务迁移到Docker Swarm Overlay网络&#xff0c;并搭建高可用容器集群。hello, 好久不见&#xff0c;之前文章记录了一个实战的2C分布式项目的改造过程&#xff0c;结果如下&#xff1a;其中Redis并未完成容器化改造&#x…

堆排序(包含最大堆和最小堆)

堆排序&#xff08;包含最大堆和最小堆&#xff09; 堆排序 时间复杂度nlgn&#xff0c;原址排序。 通用函数 int parent(int i) {return (i - 1) >> 1; } int left(int i) {return (i << 1) 1; } int right(int i) {return (i << 1) 2; }最大堆排序 v…

Java控制结构

控制结构 程序流程控制介绍 顺序控制 分支控制if-else 单分支 案例演示 01: import java.util.Scanner; public class IfWorkDemo {public static void main(String[] args){Scanner myScanner new Scanner(System.in);System.out.println("input your age");int…

.Net Core Configuration源码探究

前言上篇文章我们演示了为Configuration添加Etcd数据源&#xff0c;并且了解到为Configuration扩展自定义数据源还是非常简单的&#xff0c;核心就是把数据源的数据按照一定的规则读取到指定的字典里&#xff0c;这些都得益于微软设计的合理性和便捷性。本篇文章我们将一起探究…

最大堆实现优先队列

最大堆实现优先队列 头文件 #include "heap_sort.h" #include "stdexcept" #include <iostream> class MaxHeapPriorityQueue { public:int heap_size; private:int capacity;int *array;void increase_key(int key,int index); public:void inser…

面试官:你说你喜欢研究新技术,那么请说说你对 Blazor 的了解

阅读本文大概需要 1.5 分钟。最近在几个微信 .NET 交流群里大家讨论比较频繁的话题就是这几天自己的面试经历。面试官&#xff1a;“你刚说你喜欢研究新技术&#xff0c;那么你对 Blazor 了解多少&#xff1f;”作为一位专注于 .NET 开发的软件工程师&#xff0c;你好意思说你对…

Java变量

变量 ​ 变量是程序的基本组成单位 变量的介绍 概念 变量相当于内存中一个数据存储空间的表示&#xff0c;你可以把变量看做是一个房间的门牌号&#xff0c;通过门牌号我们可以找到房间&#xff0c;而通过变量名可以访问到变量(值)。 01&#xff1a; class Test {public s…

将k个有序链表合并成一个有序链表

将k个有序链表合并成一个有序链表 这里以从小到大排序为例&#xff0c; 时间复杂度为O&#xff08;nlgk&#xff09;。 特点&#xff1a;利用最小堆来完成k路归并 思路&#xff1a;取每个列表中的第一个元素&#xff0c;并将其放在最小堆中。与每个元素一起&#xff0c;必须跟…