c# sortedlist_我如何发现C#SortedList使用二进制搜索以及为什么要关心

c# sortedlist

by Rina Artstain

通过丽娜·阿斯特斯坦

我如何发现C#SortedList使用二进制搜索以及为什么要关心 (How I Discovered that C# SortedList Uses Binary Search, and Why You Should Care)

There is an age old debate: can programmers make do with just knowing how to code? Or do they need to understand some of their framework internals, basic data structures, and search/sort algorithms?

有一个古老的争论:程序员可以只知道如何编写代码就能做到吗? 还是他们需要了解一些框架内部结构,基本数据结构和搜索/排序算法?

I have encountered many bugs created by being unaware of how hash tables are implemented. Or by a minor overlook which would have been a complete mystery to someone who didn’t know a binary search even existed. So you may guess that I’m of the opinion that you must have basic data structures/algorithms knowledge. I hope after reading this you will agree with me — but if not, you may leave your disagreements in the comment section below.

我遇到了许多由于不知道如何实现哈希表而产生的错误。 或是被一个小小的忽视,对于一个甚至不知道二进制搜索的人来说,这完全是个谜。 因此,您可能会认为我认为您必须具有基本的数据结构/算法知识。 我希望阅读完本文后您会同意我的意见,但是如果不同意,您可以在下面的评论部分中留下您的分歧。

系统总览 (System Overview)

Imagine a system of customer service reps, where each user writes notes for tracking actions and conversations with clients. If the note requires future action, the user can add a due date for a specific date and time, and it becomes a “task.” At any point, the user can mark the task as “done” and the task will be removed while remaining in the list of notes.

想象一下一个客户服务代表系统,其中每个用户都写笔记以跟踪操作和与客户的对话。 如果注释需要将来采取措施,则用户可以为特定日期和时间添加到期日期,这将成为“任务”。 用户可以随时将任务标记为“完成”,并且该任务将在保留在注释列表中的同时被删除。

For easy access, all the notes are displayed in a descending order by insert date (oldest note first). Tasks are displayed in ascending order by due date (upcoming/overdue tasks first).

为了便于访问,所有备忘均按插入日期降序显示(最旧的备忘在前)。 任务按截止日期的升序显示(首先显示即将到来的/过期的任务)。

As usual, some of the complexity of the original system is omitted for simplicity (persistency, multi threading etc.). I’ve also included a link to GitHub with a working version of the code included in this post. You can run it for yourself. (It’s at the bottom of the post, so even if you don’t read it you’ll have to scroll all the way down ha!).

通常,为简单起见,将省略原始系统的某些复杂性(持久性,多线程等)。 我还提供了到GitHub的链接,其中包含本文中包含的代码的有效版本。 您可以自己运行它。 (它在帖子的底部,所以即使您不阅读它,也必须一直向下滚动!!)。

实作 (Implementation)

Let’s start with the Note class definition:

让我们从Note类定义开始:

It’s a simple data object.

这是一个简单的数据对象。

Next, we’ll create a NotesManager class which holds all the notes/tasks and manages access to them:

接下来,我们将创建一个NotesManager类,其中包含所有注释/任务并管理对它们的访问:

The NotesManager class uses a SortedList to keep the Notes/Tasks in the correct order determined by the type of the list and SortDirection given to the NoteComparer. Notes are ordered by InsertDate, ascending and tasks are ordered by DueDate, descending. The NotesManager class takes care of creating the NoteIndex with the right date. It inserts the note in the appropriate list.

NotesManager类使用SortedList来使Notes / Tasks保持正确的顺序,该顺序由列表的类型和给NoteComparer的SortDirection确定。 注释按InsertDate排序,升序排序,任务按DueDate排序,降序排序。 NotesManager类负责创建具有正确日期的NoteIndex。 它将注释插入适当的列表中。

The last functionality we need is to mark a task as “done,” which then removes the task from the Tasks list.

我们需要的最后一个功能是将任务标记为“完成”,然后将其从“任务”列表中删除。

What was I thinking when I wrote this code? I honestly don’t remember. Probably not thinking much of anything. This is the underlying issue for many mistakes.

编写此代码时我在想什么? 老实说我不记得了。 大概什么也没想。 这是许多错误的根本问题。

Take a second before reading on and try to figure out where the problem is.

在继续阅读之前请花一秒钟,然后尝试找出问题所在。

这是怎么回事? (What’s Going On?)

Imagine my surprise when I started testing the NotesManager. I found that when I marked some Tasks as “done”, they were not removed from the Tasks list. It appeared to be totally random, sometimes working and sometimes not.

想象一下当我开始测试NotesManager时的惊讶。 我发现当我将某些任务标记为“完成”时,它们并未从“任务”列表中删除。 它似乎是完全随机的,有时有效,有时则无效。

There I was, staring at the debugger in disbelief. The Task is sitting right there in the tasks list, but “remove” wasn’t removing it. I had no idea what was going on.

我在那里,难以置信地盯着调试器。 任务是坐在那里在任务列表中,但“删除”并没有删除它。 我不知道发生了什么事。

I assumed something was wrong with the NoteComparer implementation. I added a breakpoint in the Compare method. There I found something strange: The tasks weren’t being scanned sequentially. The debugger seemed to be randomly accessing items in the task list.

我认为NoteComparer实现存在问题。 我在Compare方法中添加了一个断点。 在那里,我发现了一些奇怪的事情:任务没有按顺序进行扫描。 调试器似乎正在随机访问任务列表中的项目。

Hmmmm. Weird. For a second I thought there might be some multithreading weirdness going on, but this was a local development environment — there was nobody else who could be accessing my web server (and if there was, how likely was it that they are testing the same user and data I was currently using?). Nope, the answer had to be somewhere else.

嗯 奇怪的。 有一秒钟我以为可能会出现一些多线程怪异现象,但这是一个本地开发环境-没有其他人可以访问我的Web服务器(如果有,他们测试同一用户的可能性有多大?和我当前正在使用的数据?)。 不,答案必须在其他地方。

After a couple more tests, a pattern emerged. The first access to Compare was somewhere in the middle of the list. Then it jumped to another location. Then another jump and another, before finally giving up on the whole thing. Then came the #facepalm moment, and I realized that SortedList must use binary search for finding items in the list! It should have been obvious (anything else would be silly, really).

经过多次测试后,出现了一种模式。 对Compare的首次访问位于列表的中间。 然后它跳到另一个位置。 然后又跳又跳,最终放弃了整个事情。 然后是#facepalm时刻,我意识到SortedList必须使用二进制搜索来查找列表中的项目! 它应该是显而易见的(其他任何事情实际上都是愚蠢的)。

I tried to verify my idea by searching MSDN Documentation, and there it was — Remove uses binary search. OK then, my guess was right — but why wasn’t the binary search working?

我试图通过搜索MSDN文档来验证我的想法,这就是— 删除使用二进制搜索。 好的,我的猜测是正确的-但是为什么二进制搜索不起作用

This time I moved the breakpoint a little further down in the Comparer implementation. I immediately saw where the problem was. I was passing the NoteIndex with only the Id, assuming that would be enough for equality.

这次,我在Comparer实现中将断点向下移了一点。 我立即看到问题出在哪里。 我只通过Id传递NoteIndex,假设这足以满足相等要求。

If this was a regular List, that would have worked. But cutting that corner in combination with binary search (instead of a sequential scan which I was implicitly assuming) resulted in the SortedList being unable to find the Note it was looking for. So I changed the implementation of “MarkDone”.

如果这是常规列表,那将是可行的。 但是,与二进制搜索(而不是我隐式假设的顺序扫描)结合起来,导致SortedList无法找到它正在寻找的Note。 因此,我更改了“ MarkDone”的实现。

And it worked!

而且有效!

(There’s a bug in this implementation as well, but I wanted to focus on the issue at hand. Can you find the problem?)

(此实现中也存在一个错误,但我想重点关注手头的问题。您能找到问题吗?)

You can download a working example which shows the bug, and its solution here.

您可以在此处下载显示该错误及其解决方案的工作示例。

重要要点 (Key Takeaways)

Here are my key takeaways from this case:

这是我从此案例中获得的主要收获:

  1. If you’re using a new service or data structure, take 5 minutes to read the documentation. If I had done that and realized that the key on the SortedList was used for uniqueness and not only sorting, I probably wouldn’t have made the mistake that I did.

    如果您使用的是新服务或数据结构,请花5分钟阅读文档。 如果我做到了这一点,并且意识到SortedList上的键不仅用于唯一性,而且不仅用于排序,我可能不会犯我所犯的错误。
  2. Having a good grasp of basic data structures and algorithms is essential for day-to-day work. This type of bug is extremely hard to find and solve. It happens sporadically with no apparent logic. It’s best to avoid that type of bug altogether, but if you can’t avoid it — at least be able to analyze it after it happens.

    掌握基本数据结构和算法对于日常工作至关重要。 这种类型的错误非常难以发现和解决。 它零星地发生,没有明显的逻辑。 最好完全避免这种类型的错误,但是,如果您无法避免它,至少可以在它发生后对其进行分析。

奖金问题 (Bonus Question)

Why did I override GetHashCode() on the Note class? Why should you always override GetHashCode() if you’ve overridden Equals()?

为什么我在Note类上重写GetHashCode()? 如果覆盖了Equals(),为什么还要始终覆盖GetHashCode()?

Hint: which data structure uses hash codes?

提示:哪种数据结构使用哈希码?

Like what you read? Share the love by clapping. Have a question or comment? Let me know in the comments section.

喜欢你读的书吗? 通过鼓掌分享爱。 有问题或意见吗? 让我知道在评论部分。

翻译自: https://www.freecodecamp.org/news/how-i-discovered-c-sortedlist-uses-binary-search-and-why-you-should-care-a88cce40f49b/

c# sortedlist

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值