рдПрдХрд▓ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХрд╛ рд╡рд┐рдХрд╛рд╕

рдХреБрдЫ рд╕рдордп рдкрд╣рд▓реЗ, рдореЗрд░реЗ рд╕рд╣рдпреЛрдЧреА рдиреЗ рдореБрдЭреЗ рдПрдХ рд╕рдорд╕реНрдпрд╛ рдХреЗ рд╕рд╛рде рдЙрд╕рдХреА рдорджрдж рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╣рд╛ред рдореИрдВрдиреЗ рдЙрд╕рдХреЗ рд▓рд┐рдП рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд┐рдпрд╛, рд▓реЗрдХрд┐рди рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдореБрдЭреЗ рдпрд╣ рдкреНрд░рддреАрдд рд╣реБрдЖ рдХрд┐ рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдкрд░, рдХрдИ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдФрд░ рддрдХрдиреАрдХреЛрдВ рдХреЛ рд╕рдордЭрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдФрд░ 25 рд╕реЗрдХрдВрдб рд╕реЗ 40 рдПрдордПрд╕ рддрдХ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреЗ рдирд┐рд╖реНрдкрд╛рджрди рд╕рдордп рдХреЗ рддреНрд╡рд░рдг рдХреЛ рднреА рджрд┐рдЦрд╛рддреЗ рд╣реИрдВред


рд╕рдорд╕реНрдпрд╛ рдХрд╛ рдмрдпрд╛рди


рдПрдХ рд╡реНрдпрдХреНрддрд┐рдЧрдд рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рд▓рд┐рдП, рдореЗрд░реЗ рд╕рд╣рдпреЛрдЧреА рдХреЛ рдХрд┐рд╕реА рджрд┐рдП рдЧрдП рд╡реАрдбрд┐рдпреЛ рдХреЗ рд▓рд┐рдП рдкрдЪрд╛рд╕ рд╕рдорд╛рди рд╡реАрдбрд┐рдпреЛ рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдереАред рдорд┐рд▓рд╛рди рдХрд┐рдП рдЧрдП рдЯреИрдЧ рдХреА рд╕рдВрдЦреНрдпрд╛ рд╕реЗ рд╕рдорд╛рдирддрд╛ рдХрд╛ рдЕрдиреБрдорд╛рди рд▓рдЧрд╛рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдерд╛ред рд╡реАрдбрд┐рдпреЛ рдЬрд┐рддрдиреЗ рдЯреИрдЧреНрд╕ рд╕реЗ рдореЗрд▓ рдЦрд╛рддреЗ рд╣реИрдВ, рд╡реЗ рдЙрддрдиреЗ рд╣реА рдорд┐рд▓рддреЗ-рдЬреБрд▓рддреЗ рд╣реИрдВред рдЗрд╕рд╕реЗ рд╣рдо рддреБрд░рдВрдд рдХрдИ рдирд┐рд╖реНрдХрд░реНрд╖ рдирд┐рдХрд╛рд▓ рд╕рдХрддреЗ рд╣реИрдВ:


  • рд╡реАрдбрд┐рдпреЛ рдХреЗ рддрд╣рдд рд╕рднреА рдЯреИрдЧ рдХреЛ рдПрдХ рд╕рдореВрд╣ рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ;
  • рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рд╡реАрдбрд┐рдпреЛ рд╕реЗ рдЕрдзрд┐рдХ рдРрд╕реЗ рд╕рдореВрд╣ рдирд╣реАрдВ рд╣реЛрдВрдЧреЗ;
  • рдпрджрд┐ рд╡реАрдбрд┐рдпреЛ рдЯреИрдЧ рдХреЗ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд╕рдореВрд╣ рдХреЗ рдЕрдиреНрдп рд╡реАрдбрд┐рдпреЛ рдХреЗ рд╕рдорд╛рди рд╣реИ, рддреЛ рдпрд╣ рдЗрд╕ рд╕рдореВрд╣ рдХреЗ рдЕрдиреНрдп рд╡реАрдбрд┐рдпреЛ рдХреЗ рд╕рдорд╛рди рд╣реИ;

рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ рдХрд┐ рдпрд╣ рдХреЗрд╡рд▓ рдЯреИрдЧ рд╕рдореВрд╣реЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИред рдкрд╣рд▓реЗ рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ, рдПрдХ рд╕рд╣рдХрд░реНрдореА рдиреЗ рдЯреИрдЧ рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдЯреИрдЧ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдпрд╛: рдкреНрд░рддреНрдпреЗрдХ рд╡реАрдбрд┐рдпреЛ рдореЗрдВ рдЯреИрдЧ рд╕рдореВрд╣ рдЖрдИрдбреА рдХрд╛ рдПрдХ рд▓рд┐рдВрдХ рд╣реЛрддрд╛ рд╣реИ, рдФрд░ рд╕рдореВрд╣ рд╕реНрд╡рдпрдВ рдмреВрд▓рд┐рдпрди рдорд╛рдиреЛрдВ рдХрд╛ рдПрдХ рдХреНрд░рдо рд╣реЛрддреЗ рд╣реИрдВ рдЬреЛ рдЗрдВрдЧрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рд╕рдВрдмрдВрдзрд┐рдд рдЯреИрдЧ рд╕реЗрдЯ рд╣реИ рдпрд╛ рдирд╣реАрдВред C # рдореЗрдВ, рдПрдХ рдЯреИрдЧ рд╕рдореВрд╣ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:


public class TagsGroup { bool[] InnerTags { get; } } 

рдПрдХ рд╕рд╣рдХрд░реНрдореА рдиреЗ рд╕реБрдЭрд╛рд╡ рджрд┐рдпрд╛ рдХрд┐ рд╕рд╛рдЗрдЯ рдкрд░ рдЙрд╕рдХреЗ рдкрд╛рд╕ рдПрдХ рдорд┐рд▓рд┐рдпрди рд╕реЗ рдЕрдзрд┐рдХ рд╡реАрдбрд┐рдпреЛ рдирд╣реАрдВ рд╣реЛрдВрдЧреЗ, рдФрд░ рд╡рд┐рднрд┐рдиреНрди рдЯреИрдЧ 4000 рд╕реЗ рдЕрдзрд┐рдХ рдирд╣реАрдВ рд╣реИрдВ, рдПрдХ рдЧреЛрд▓ рдЦрд╛рддреЗ рдХреЗ рд▓рд┐рдП рдЖрдк 4096 = 2 ^ 12 рд▓реЗ рд╕рдХрддреЗ рд╣реИрдВред
рдлрд┐рд░ рдЗрд╕ рддрд░рд╣ рд╕реЗ TagsGroup рд╡рд░реНрдЧ рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:


 public class TagsGroup { public const int TagsGroupLength = 4096; bool[] InnerTags { get; } public TagsGroup(bool[] innerTags) { if (innerTags == null) throw new ArgumentException(nameof(innerTags)); if (innerTags.Length != TagsGroupLength) { throw new ArgumentException(nameof(innerTags)); } InnerTags = innerTags; } } 

рдЕрдм рдЖрдкрдХреЛ рд╕рдорд╛рдирддрд╛ рдХреЗ рд▓рд┐рдП рдЯреИрдЧ рдХреЗ рджреЛ рд╕рдореВрд╣реЛрдВ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╡рд░реНрддрдорд╛рди рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдХреЗ рддрд╣рдд, рдпрд╣ рдЯреИрдЧ рдХреЗ рджреЛ рд╕рдореВрд╣реЛрдВ рдХреЗ InnerTags рд╕рд░рдгрд┐рдпреЛрдВ рдХреЗ рд╕рдВрдмрдВрдзрд┐рдд рддрддреНрд╡реЛрдВ рдореЗрдВ рд╕рдЪ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд░рд▓ рдЬрд╛рдВрдЪ рдореЗрдВ рдмрджрд▓ рдЬрд╛рддрд╛ рд╣реИ:


 public static int MeasureSimilarity(TagsGroup a, TagsGroup b) { int result = 0; for (int i = 0; i < TagsGroupLength; i++) { if (a.InnerTags[i] && a.InnerTags[i] == b.InnerTags[i]) result++; } return result; } 

рдЕрдм рдпрд╣ рдХреЗрд╡рд▓ рдкреНрд░рддреНрдпреЗрдХ рдореМрдЬреВрджрд╛ рд╕рдореВрд╣ рдХреЗ рд╕рд╛рде рд╡рд╛рдВрдЫрд┐рдд рдЯреИрдЧ рд╕рдореВрд╣ рдХреА рд╕рдорд╛рдирддрд╛ рдХреА рдЧрдгрдирд╛ рдХрд░рдиреЗ рдФрд░ рдХреЗрд╡рд▓ рдкрдЪрд╛рд╕ рд╕рдорд╛рди рд▓реЛрдЧреЛрдВ рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдиреА рд╣реБрдИ рд╣реИред рдореИрдВрдиреЗ рдирдореВрдиреЗ рдХреА рд╕реНрдерд┐рд░рддрд╛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЦреБрдж рдХреЛ рдПрдХ рдФрд░ рд╢рд░реНрдд рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХреА, рдЕрд░реНрдерд╛рддреНред рдЕрдВрддрд┐рдо рдирдореВрдиреЗ рдореЗрдВ, рдкрдЪрд╛рд╕ рдЯреИрдЧ рд╕рдореВрд╣ рд╣реЛрдВрдЧреЗ, рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП MeasureSimilarity рдиреЗ рдЙрдЪреНрдЪрддрдо рдкрд░рд┐рдгрд╛рдо рджрд┐рдпрд╛, рдЬрдмрдХрд┐ рд╕рдорд╛рди MeasureSimilarity рдЯреИрдЧ рд╕рдореВрд╣реЛрдВ рдХреЗ MeasureSimilarity рдЙрди рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП MeasureSimilarity рдХрдо рд╕реВрдЪрдХрд╛рдВрдХ MeasureSimilarity рдЬрд┐рдирдХреЗ рдкрд╛рд╕ рдореВрд▓ рдореМрдЬреВрджрд╛ рд╕рдореВрд╣ рдореЗрдВ рдХрдо рд╕реВрдЪрдХрд╛рдВрдХ рдерд╛ред рдЕрдзрд┐рдХ рд╡рд┐рд╡рд░рдг рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрд╣рд╛рдБ: https://ru.wikipedia.org/wiki/Sistentable_Sort ред
рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдЗрд╕реА рддрд░рд╣ рдХреЗ SimilarTagsCalculator рдХреНрд▓рд╛рд╕ рдмрдирд╛рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛, рдпрд╣рд╛рдБ рдЗрд╕рдХрд╛ рдХреЛрдб рд╣реИ:


SimilarTagsCalculator
 class SimilarTagsCalculator { TagsGroup[] Groups { get; } public SimilarTagsCalculator(TagsGroup[] groups) { if (groups == null) throw new ArgumentException(nameof(groups)); Groups = groups; } public TagsGroup[] GetFiftyMostSimilarGroups(TagsGroup value) { const int resultLength = 50; //,          var list = new List<TagsSimilarityInfo>(resultLength); //      for (int groupIndex = 0; groupIndex < Groups.Length; groupIndex++) { TagsGroup tagsGroup = Groups[groupIndex]; //      int similarityValue = TagsGroup.MeasureSimilarity(value, tagsGroup); // -  TagsSimilarityInfo newInfo = new TagsSimilarityInfo(groupIndex, similarityValue); //    ,     , if (list.Count == resultLength && list[resultLength - 1].CompareTo(newInfo) == -1) { continue; //     } //   ,    -  int index = ~list.BinarySearch(newInfo); list.Insert(index, newInfo); // if (list.Count > resultLength) { //    , //   , ..    list.RemoveAt(resultLength); } } // -   TagsGroup[] result = new TagsGroup[resultLength]; for (int i = 0; i < resultLength; i++) { result[i] = Groups[list[i].Index]; } return result; } } 

рдФрд░ TagsSimilarityInfo рд╕рдВрд░рдЪрдирд╛:


TagsSimilarityInfo
 struct TagsSimilarityInfo : IComparable<TagsSimilarityInfo>, IComparable { public int Index { get; } public int Similarity { get; } public TagsSimilarityInfo(int index, int similarity) { Index = index; Similarity = similarity; } public bool Equals(TagsSimilarityInfo other) { return Index == other.Index && Similarity == other.Similarity; } public override bool Equals(object obj) { return obj is TagsSimilarityInfo other && Equals(other); } public override int GetHashCode() { unchecked { return (Index * 397) ^ Similarity; } } public int CompareTo(TagsSimilarityInfo other) { int similarityComparison = other.Similarity.CompareTo(Similarity); return similarityComparison != 0 ? similarityComparison : Index.CompareTo(other.Index); } public int CompareTo(object obj) { if (ReferenceEquals(null, obj)) return 1; return obj is TagsSimilarityInfo other ? CompareTo(other) : throw new ArgumentException($"Object must be of type {nameof(TagsSimilarityInfo)}"); } } 

рдореИрдВрдиреЗ рдЗрд╕ рдПрд▓реНрдЧреЛрд░рд┐рдердо рдХреЗ рд▓рд┐рдП рддреАрди рдмреЗрдВрдЪрдорд╛рд░реНрдХ рддреИрдпрд╛рд░ рдХрд┐рдП:


  • рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рдмреЗрдВрдЪрдорд╛рд░реНрдХ, рдЕрд░реНрдерд╛рддреНред рд╕рдореВрд╣реЛрдВ рдореЗрдВ рд╕реЗрдЯ рдЯреИрдЧ рдХреА рд╕рдВрдЦреНрдпрд╛ рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рд╣реИ рдФрд░ рдЯреИрдЧ рд╕рдореВрд╣ рдЬрд┐рд╕рдХреА рд╣рдо рддреБрд▓рдирд╛ рдХрд░реЗрдВрдЧреЗ, рд╡рд╣ рднреА рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рд╣реИ;
  • рд╕рдореВрд╣реЛрдВ рдореЗрдВ рд╕реЗрдЯ рдХрд┐рдП рдЧрдП рдЯреИрдЧ рдХреА рд╕рдВрдЦреНрдпрд╛ рдмрдврд╝ рд░рд╣реА рд╣реИ, рд╣рдо рдЙрд╕ рд╕рдореВрд╣ рдХреЗ рд╕рд╛рде рддреБрд▓рдирд╛ рдХрд░реЗрдВрдЧреЗ рдЬрд┐рд╕рдореЗрдВ рд╕рднреА рдЯреИрдЧ рд╕реЗрдЯ рд╣реИрдВред рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ рдХрд┐ рдЯреИрдЧ рдХреЗ рдЕрдВрддрд┐рдо рд╕рдореВрд╣реЛрдВ рдореЗрдВ рд╕реЗ рдХреБрдЫ рд╕рдмрд╕реЗ рдЙрдкрдпреБрдХреНрдд рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП;
  • рдКрдкрд░ рдЬреИрд╕рд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЙрдЬрд╛рдЧрд░ рдЯреИрдЧ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХрдо рд╣реЛ рд░рд╣реА рд╣реИред рдЯреИрдЧ рдХреЗ рдкрд╣рд▓реЗ 50 рд╕рдореВрд╣ рд╕рдмрд╕реЗ рдЙрдкрдпреБрдХреНрдд рд╣реЛрдВрдЧреЗ;

рдпрд╣рд╛рдВ рдПрдХ рд▓рд╛рдЦ рд╕рдореВрд╣реЛрдВ рдХреЗ рд▓рд┐рдП рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдкрд░рд┐рдгрд╛рдо рд╣реИрдВ:


рдмреЗрдВрдЪрдорд╛рд░реНрдХрдбреЙрдЯрдиреЗрдЯ = v0.11.5, рдУрдПрд╕ = рд╡рд┐рдВрдбреЛрдЬ 10.0.17134.765 (1803 / рдЕрдкреНрд░реИрд▓ 2018 рдпреВрдкреАрдбреЗрдЯ / рд░реЗрдбрд╕реНрдЯреЛрди 4)
Intel Core i7-6700 CPU 3.40GHz (Skylake), 1 CPU, 8 рддрд╛рд░реНрдХрд┐рдХ рдФрд░ 4 рднреМрддрд┐рдХ рдХреЛрд░
рдлреНрд░реАрдХреНрд╡реЗрдВрд╕реА = 3328126 рд╣рд░реНрдЯреНрдЬ, рд░рд┐рдЬрд╝реЙрд▓реНрдпреВрд╢рди = 300.4694 рдПрдирдПрд╕, рдЯрд╛рдЗрдорд░ = рдЯреАрдПрд╕рд╕реА
.NET рдХреЛрд░ рдПрд╕рдбреАрдХреЗ = 3.0.100-рдкреВрд░реНрд╡рд╛рд╡рд▓реЛрдХрди 5-011568
[рд╣реЛрд╕реНрдЯ]: .NET рдХреЛрд░ 3.0.0-рдкреВрд░реНрд╡рд╛рд╡рд▓реЛрдХрди 5-27626-15 (CoreCLR 4.6.27622.75, CoreFX 4.700.19.22408), 64 рдмрд┐рдЯ RyuJIT


рд╡рд┐рдзрд┐рдореАрдирддреНрд░реБрдЯрд┐StdDevрдЖрд╡рдВрдЯрд┐рдд
RandomTest25.054 рдПрд╕0.1786 рдПрд╕0.1670 рдПрд╕1.53 рдХреЗрдмреА
AscendantTest4.180 рдПрд╕0.0174 рдПрд╕0.0162 рдПрд╕1.53 рдХреЗрдмреА
DescendantTest4.147 рдПрд╕0.0118 рдПрд╕рд╣реЙрдк 4 рдПрд╕1.53 рдХреЗрдмреА

рдирд┐рд╖реНрдкрд╛рджрди рд╕рдордп рдХрд╛ рдкреНрд░рд╕рд╛рд░ рдмрд╣реБрдд рдмрдбрд╝рд╛ рд╣реИ, рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛ 25 рд╕реЗрдХрдВрдб рдмрд╣реБрдд рд▓рдВрдмрд╛ рд╕рдордп рд╣реИ, рдореЗрд░реЗ рд╕рд╣рдпреЛрдЧреА рдЗрддрдиреЗ рд▓рдВрдмреЗ рд╕рдордп рддрдХ рдЗрдВрддрдЬрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рд╣рдордд рдирд╣реАрдВ рд╣реИрдВред рддреЛ рдЪрд▓реЛ рдЕрдиреБрдХреВрд▓рди рдХрд░рддреЗ рд╣реИрдВред рдЕрдм рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЛ рдЧрддрд┐ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рддреАрди рдореБрдЦреНрдп рдХреНрд╖реЗрддреНрд░ рд╣реИрдВ:


  • MeasureSimilarity ;
  • GetFiftyMostSimilarGroups рдореЗрдВ рдкрд╛рд╢ рдХреЗ рд╢рд░реАрд░ рдореЗрдВ рдПрдХ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо;
  • GetFiftyMostSimilarGroups рдореЗрдВ рд╕реНрд╡рдпрдВ рд▓реВрдк;

рд╣рдо рдХреНрд░рдо рдореЗрдВ рддреАрди рджрд┐рд╢рд╛рдУрдВ рдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВрдЧреЗред


рд╢рд╛рдЦрд╛ рдХреА рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгреА


рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, MeasureSimilarity рд╡рд┐рдзрд┐ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВред


 public static int MeasureSimilarity(TagsGroup a, TagsGroup b) { int result = 0; for (int i = 0; i < TagsGroupLength; i++) { if (a.InnerTags[i] && a.InnerTags[i] == b.InnerTags[i]) result++; } return result; } 

рдкрд┐рдЫрд▓реЗ рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдореЗрдВ, рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рдкрд░реАрдХреНрд╖рдг рдФрд░ рдХреНрд░рдорд┐рдХ рдХрд┐рд╕реА рдХреЗ рдмреАрдЪ рд░рдирдЯрд╛рдЗрдо рдореЗрдВ рдмрд╣реБрдд рдмрдбрд╝реА рднрд┐рдиреНрдирддрд╛ рдереАред рдЕрдиреБрдХреНрд░рдорд┐рдХ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЗ рд▓рд┐рдП рдЯреИрдЧ рд╕рдореВрд╣ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рд┐рджреНрдзрд╛рдВрдд рджреНрд╡рд╛рд░рд╛ рдмрдирд╛рдП рдЧрдП рдереЗ:


  • рд╕рдореВрд╣реЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХ рд╕рдВрдЦреНрдпрд╛ рдХреЛ рд╕рдВрдХреБрд▓ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рдкреИрдХреЗрдЯ рдХреА рд╕рдВрдЦреНрдпрд╛ - рд╕рдореВрд╣ рдореЗрдВ рдЯреИрдЧ рдХреА рдЕрдзрд┐рдХрддрдо рд╕рдВрдЦреНрдпрд╛;
  • i-th рдкреИрдХреЗрдЬ рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рд╕рдореВрд╣ рдХреЗ рд▓рд┐рдП, рдкрд╣рд▓реЗ i рдЯреИрдЧ рд╕реЗрдЯ рдХрд┐рдП рдЧрдП рдереЗ;

рдпрд╣ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ рдХрд┐ рдЗрди рдкрд░реАрдХреНрд╖рдгреЛрдВ рдореЗрдВ рдЯреИрдЧ рдХреЗ рдкреНрд░рддреНрдпреЗрдХ рд╕рдореВрд╣ рдореЗрдВ рдЙрдЬрд╛рдЧрд░ рдФрд░ рдЕрдирдПрдореНрдкреЛрдЬрд╝реНрдб рдЯреИрдЧ рдХреЗ рджреЛ рд▓рдЧрд╛рддрд╛рд░ рднрд╛рдЧ рд╣реЛрддреЗ рд╣реИрдВред MeasureSimilarity рдореЗрдВ рдкреНрд░реЛрд╕реЗрд╕рд░ рдХреА рдкреВрд░реНрд╡ рд╕реНрдерд┐рддрд┐ рдХреЗ рд▓рд┐рдП рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рд╢рд░реНрддреЗрдВ рд╣реИрдВ рдЬреЛ рд╡рд░реНрддрдорд╛рди рдкрд░рд┐рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдореЗрдВ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдкреНрд░рднрд╛рд╡ рдбрд╛рд▓рддреА рд╣реИрдВред рдЗрд╕реЗ рдЬрд╛рдВрдЪрдиреЗ рдХреЗ рд▓рд┐рдП, рдмрд╕ рдПрдХ рдорд╛рдирджрдВрдб рд▓рд┐рдЦреЗрдВ, рдЬреЛ рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рдбреЗрдЯрд╛ рдХреЗ рд▓рд┐рдП рдФрд░ рдЕрдиреБрдХреНрд░рдорд┐рдХ рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдорд╛рдк-рдХреНрд╖рдорддрд╛ рдХреЗ рдХреНрд░рдо рдХреА рддреБрд▓рдирд╛ рдХрд░рддрд╛ рд╣реИ:


 int GetSimilaritySum(TagsGroup[] tagsGroups) { int result = 0; foreach (TagsGroup tagsGroup in tagsGroups) { result += TagsGroup.MeasureSimilarity(tagsGroup, etalon); } return result; } [Benchmark] public int Sorted() => GetSimilaritySum(sortedGroups); [Benchmark] public int Unsorted() => GetSimilaritySum(unsortedGroups); 

рд╡рд┐рдзрд┐рдореАрдирддреНрд░реБрдЯрд┐StdDev
рдХреНрд░рдордмрджреНрдз3.704 рдПрд╕0.0411 рдПрд╕0.0364 рдПрд╕
рдЕрд╡рд░реНрдЧреАрдХреГрдд8.211 рд╕реЗ0.0381 рдПрд╕0.0338 рдПрд╕

рдПрдХ рд▓рд╛рдЦ рдЯреИрдЧ рд╕рдореВрд╣реЛрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рд▓реЗрдХрд┐рди рдкрд╣рд▓реЗ рдкреНрд░рддреНрдпреЗрдХ рд╕рдореВрд╣ рдореЗрдВ Sorted рд╕реЗ рдХрдИ рдЙрдЬрд╛рдЧрд░ рдЯреИрдЧ рдереЗ, рдФрд░ рдлрд┐рд░ рдЕрдирдПрдХреНрд╕рдкреЛрдЬрд╝реНрдб рд╡рд╛рд▓реЗ, рдФрд░ Unsorted рдореЗрдВ рд╕рдорд╛рди рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдЙрдЬрд╛рдЧрд░ рдХрд┐рдП рдЧрдП рдЯреИрдЧ рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рд░реВрдк рд╕реЗ рдкреВрд░реЗ рд╕рдореВрд╣ рдореЗрдВ рдмрд┐рдЦрд░реЗ рд╣реБрдП рдереЗред
5 рд╕реЗрдХрдВрдб рдХрд╛ рдЕрдВрддрд░ рдкреНрд░рднрд╛рд╡рд╢рд╛рд▓реА рд╣реИ, рдФрд░ рдХреБрдЫ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╢рд╛рдЦрд╛ рднрд╡рд┐рд╖реНрдпрд╡рд╛рдгреА рдХреЗ рдкреНрд░рднрд╛рд╡ рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдФрд░ рдЖрдо рддреМрд░ рдкрд░ рдЗрд╕ рд╡рд┐рдзрд┐ рдХреЛ рдЧрддрд┐ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдЦреБрдж рд╢рд╛рдЦрд╛рдУрдВ рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред MeasureSimilarity рдореЗрдВ рдХреЗрд╡рд▓ рдПрдХ рд╢рд╛рдЦрд╛ рд╣реИ - рдпрд╣ рдЬрд╛рдВрдЪрдирд╛ рдХрд┐ рд╕рдВрдмрдВрдзрд┐рдд рдЯреИрдЧ рджреЛ рд╕рдореВрд╣реЛрдВ рдореЗрдВ рд╕реЗрдЯ рдХрд┐рдП рдЧрдП рд╣реИрдВред рдЖрдЗрдП рдЕрдиреБрдорд╛рди рд▓рдЧрд╛рддреЗ рд╣реИрдВ рдХрд┐ рдХрд┐рди рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдореЗрдВ рд╕реНрдерд┐рддрд┐ рд╕рд╣реА рд╣реЛрдЧреА, рдЗрд╕рдХреЗ рд▓рд┐рдП рд╣рдо рд╕реНрдерд┐рддрд┐ рдХреА рд╕рдЪреНрдЪрд╛рдИ рдХреА рдПрдХ рддрд╛рд▓рд┐рдХрд╛ рдмрдирд╛рдПрдВрдЧреЗ:


рдП.рдЗрдирд░рдЯреИрдЧреНрд╕ [i]b.InnerTags [i]рдкрд░рд┐рдгрд╛рдо
рдЭреВрдард╛рдЭреВрдард╛рдЭреВрдард╛
рдЭреВрдард╛рдпрд╣ рд╕рдЪ рд╣реИрдЭреВрдард╛
рдпрд╣ рд╕рдЪ рд╣реИрдЭреВрдард╛рдЭреВрдард╛
рдпрд╣ рд╕рдЪ рд╣реИрдпрд╣ рд╕рдЪ рд╣реИрдпрд╣ рд╕рдЪ рд╣реИ

рд╕рддреНрдп рддрд╛рд▓рд┐рдХрд╛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рддрд╛рд░реНрдХрд┐рдХ "рдФрд░" рдХреЗ рд╕рд╛рде рдореЗрд▓ рдЦрд╛рддреА рд╣реИ, рдЕрд░реНрдерд╛рддред рдкрд░рд┐рдгрд╛рдо рд╕рд╣реА рд╣реИ рдЕрдЧрд░ рдФрд░ рдХреЗрд╡рд▓ рдпрджрд┐ рджреЛрдиреЛрдВ рдЯреИрдЧ рд╕рддреНрдп рд╣реИрдВ, рддреЛ рд╕реНрдерд┐рддрд┐ рдХреЛ рдХрдо рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ: if (a.InnerTags[i] && b.InnerTags[i]) ред рд▓реЗрдХрд┐рди рдЗрд╕ рддрд░рд╣ рд╕реЗ рд╣рд╛рд▓рдд рдЕрднреА рднреА рдмрдиреА рд╣реБрдИ рд╣реИред рдЕрдЧрд▓реЗ рдЪрд░рдг рдореЗрдВ, рд╣рдо рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВрдЧреЗ рдХрд┐ рдкрд░рд┐рдгрд╛рдо рдореЗрдВ рд╡реГрджреНрдзрд┐ рд╣рдореЗрд╢рд╛ рдХреА рдЬрд╛рддреА рд╣реИ, рдЗрд╕рдХреЗ рд▓рд┐рдП рд╣рдо рд▓реВрдк рдХреЗ рд╢рд░реАрд░ рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрддреЗ рд╣реИрдВ рдЬреИрд╕реЗ:


 int t = a.InnerTags[i] && b.InnerTags[i] ? 1 : 0; result += t; 

рд╣рдордиреЗ рдЕрднреА рднреА рд╣рд╛рд▓рдд рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдирд╣реАрдВ рдкрд╛рдпрд╛ рд╣реИ рдФрд░ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рднреА рдЗрд╕ рд╡рд┐рдзрд┐ рдХреЛ рдзреАрдорд╛ рдХрд░ рджрд┐рдпрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдЕрдм рдпрд╣ рд╕реНрдкрд╖реНрдЯ рд╣реЛ рдЧрдпрд╛ рд╣реИ рдХрд┐ рдЕрдЧрд░ InnerTags рдкреНрд░рдХрд╛рд░ рдмреВрд▓ рд╕реЗ рдмрд╛рдЗрдЯ рдореЗрдВ рдмрджрд▓ рдЬрд╛рддрд╛ рд╣реИ (рд╕рдЪ рдХреЗ рд▓рд┐рдП 1, рдФрд░ рдЧрд▓рдд рдХреЗ рд▓рд┐рдП 0), рддреЛ рдЖрдк рдЯрд░реНрдирд░реА рдСрдкрд░реЗрдЯрд░ рдореЗрдВ рд╕реНрдерд┐рддрд┐ рд╕реЗ рдЫреБрдЯрдХрд╛рд░рд╛ рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВред рддрдм TagsGroup рдХреНрд▓рд╛рд╕ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрд╛рдИ рджреЗрдЧреА:


TagsGroup
 public class TagsGroup { public const int TagsGroupLength = 4096; byte[] InnerTags { get; } public static int MeasureSimilarity(TagsGroup a, TagsGroup b) { int result = 0; for (int i = 0; i < TagsGroupLength; i++) { int t = a.InnerTags[i] & b.InnerTags[i]; result += t; } return result; } public TagsGroup(bool[] innerTags) { if (innerTags == null) throw new ArgumentException(nameof(innerTags)); if (innerTags.Length != TagsGroupLength) { throw new ArgumentException(nameof(innerTags)); } InnerTags = new byte[TagsGroupLength]; for (int i = 0; i < TagsGroupLength; i++) { InnerTags[i] = (byte) (innerTags[i] ? 1 : 0); } } } 

рдпрд╣рд╛рдБ рдЕрджреНрдпрддрди MeasureSimilarity рд▓рд┐рдП рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдкрд░рд┐рдгрд╛рдо рд╣реИрдВ:


рд╡рд┐рдзрд┐рдореАрдирддреНрд░реБрдЯрд┐StdDev
рдХреНрд░рдордмрджреНрдз3.180 рдПрд╕0.0118 рдПрд╕0.0111 рдПрд╕
рдЕрд╡рд░реНрдЧреАрдХреГрдд3.236 рдПрд╕0.0622 рдПрд╕0.0764 рдПрд╕

рдпрд╣ рдерд╛:
рд╡рд┐рдзрд┐рдореАрдирддреНрд░реБрдЯрд┐StdDev
рдХреНрд░рдордмрджреНрдз3.704 рдПрд╕0.0411 рдПрд╕0.0364 рдПрд╕
рдЕрд╡рд░реНрдЧреАрдХреГрдд8.211 рд╕реЗ0.0381 рдПрд╕0.0338 рдПрд╕

рд▓реЗрдХрд┐рди рдЕрджреНрдпрддрди рдХрд┐рдП рдЧрдП рдореБрдЦреНрдп рдмреАрдЪрдорд╛рд░реНрдХ рдХреЗ рд▓рд┐рдП:


рд╡рд┐рдзрд┐рдореАрдирддреНрд░реБрдЯрд┐StdDevрдЖрд╡рдВрдЯрд┐рдд
RandomTestрей.реирез реп рдПрд╕0.0492 рдПрд╕0.0436 рдПрд╕1.53 рдХреЗрдмреА
AscendantTest3.223 рдПрд╕0.0117 рдПрд╕0.0110 рдПрд╕1.53 рдХреЗрдмреА
DescendantTestрей.рекреиреи рд╕0.0697 рдПрд╕0.0999 рдПрд╕1.53 рдХреЗрдмреА

рдпрд╣ рдерд╛:
рд╡рд┐рдзрд┐рдореАрдирддреНрд░реБрдЯрд┐StdDevрдЖрд╡рдВрдЯрд┐рдд
RandomTest25.054 рдПрд╕0.1786 рдПрд╕0.1670 рдПрд╕1.53 рдХреЗрдмреА
AscendantTest4.180 рдПрд╕0.0174 рдПрд╕0.0162 рдПрд╕1.53 рдХреЗрдмреА
DescendantTest4.147 рдПрд╕0.0118 рдПрд╕рд╣реЙрдк 4 рдПрд╕1.53 рдХреЗрдмреА

рдореЗрд░реА рд░рд╛рдп рдореЗрдВ, рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдерд╛ред рдЙрди рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЬреЛ рдЖрд╢реНрд╡рд╕реНрдд рдереЗ рдХрд┐ рд╕рднреА рддреНрд╡рд░рдг рдХреЗрд╡рд▓ рдЗрд╕рд▓рд┐рдП рд╣реБрдП рдХреНрдпреЛрдВрдХрд┐ рдмреВрд▓рд┐рдпрди рдкреНрд░рдХрд╛рд░ рдХреЛ рдмрд╛рдЗрдЯ рдХреЗ рд╕рд╛рде рдмрджрд▓ рджрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдореИрдВрдиреЗ рдРрд╕реЗ рд▓реВрдк рдмреЙрдбреА рдХреЗ рд▓рд┐рдП рдПрдХ рдмреЗрдВрдЪрдорд╛рд░реНрдХ рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛:


 int t = a.InnerTags[i] & b.InnerTags[i]; if (t == 1) result += t; 

рдФрд░ рдпреЗ рдкрд░рд┐рдгрд╛рдо рд╣реИрдВ:


рд╡рд┐рдзрд┐рдореАрдирддреНрд░реБрдЯрд┐StdDev
рдХреНрд░рдордмрджреНрдз3.760 рдПрд╕0.0746 рдПрд╕0.1541 рдПрд╕
рдЕрд╡рд░реНрдЧреАрдХреГрдд8.628 рд╕реЗ0.1699 рдПрд╕0.2382 рдПрд╕

рдбреЗрдЯрд╛ рдкреИрдХреЗрдЬрд┐рдВрдЧ


рдкреНрд░рддреНрдпреЗрдХ рд╕рдореВрд╣ рдХреЗ рдХрдИ рдЯреИрдЧ рд╣реИрдВ, рдФрд░ рдЙрдирдХреА рд╕рдВрдЦреНрдпрд╛ рдХрд┐рд╕реА рднреА рддрд░рд╣ рд╕реЗ рдХрдо рдирд╣реАрдВ рдХреА рдЬрд╛ рд╕рдХрддреА рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЖрдкрдХреЛ рдПрдХ рд╣реА рд╕реВрдЪрдХрд╛рдВрдХ рдХреЗ рд╕рд╛рде рдЯреИрдЧреНрд╕ рдХреА рддреБрд▓рдирд╛ рдХрд░рдиреА рдЪрд╛рд╣рд┐рдП, рдФрд░ рдЖрдк рд╕рднреА рдЯреИрдЧреЛрдВ рдХреА рдЬрд╛рдВрдЪ рдХрд┐рдП рдмрд┐рдирд╛ рдЕрдВрддрд┐рдо рдЬрд╡рд╛рдм рдирд╣реАрдВ рджреЗ рд╕рдХрддреЗред рдЗрд╕рд▓рд┐рдП, рдХрд┐рд╕реА рднреА рдорд╛рдорд▓реЗ рдореЗрдВ, рд╣рдореЗрдВ рдЯреИрдЧ рдХреЗ рдкреВрд░реЗ рд╕рдореВрд╣ рдкрд░ рдкреБрдирд░рд╛рд╡реГрддрд┐ рдХрд░рдиреА рд╣реЛрдЧреАред рдЗрд╕ рдХрд╛рд░реНрдп рдХреЛ рдХрд┐рд╕реА рднреА рддрд░рд╣ рд╕реЗ рд╕рдорд╛рдирд╛рдВрддрд░ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдирд╛ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реЛрдЧрд╛, рддрд╛рдХрд┐ рдПрдХ рд╕рд╢рд░реНрдд рд╕рдВрдЪрд╛рд▓рди рдореЗрдВ рдХрдИ рдЯреИрдЧ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реЛрдЧрд╛ред рдЖрдк рдЗрд╕реЗ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕рдорд╛рдирд╛рдВрддрд░рдХрд░рдг рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╛ рдЖрдк рд╡рд┐рд╢реЗрд╖ рдбреЗрдЯрд╛ рдкреИрдХреЗрдЬрд┐рдВрдЧ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХрд╛ рд╣рдо рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рдкреНрд░рддреНрдпреЗрдХ рдЯреИрдЧ рдЕрдм 1 рдпрд╛ 0. рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд░рддрд╛ рд╣реИред рдкрд░рд┐рдгрд╛рдо рдореЗрдВ, рдСрдкрд░реЗрд╢рди "AND" рдХрд╛ рдкрд░рд┐рдгрд╛рдо рдХреЗрд╡рд▓ рдЬрдорд╛ рд╣реЛрддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдПрдХ рд╣реА рддрд╛рд░реНрдХрд┐рдХ рд╕рдВрдЪрд╛рд▓рди рди рдХреЗрд╡рд▓ рдПрдХрд▓-рдмрд┐рдЯ рд╕рдВрдЦреНрдпрд╛рдУрдВ рдкрд░ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред C # рдЖрдкрдХреЛ рдмрд┐рдирд╛ рдХрд┐рд╕реА рд╕рдорд╕реНрдпрд╛ рдХреЗ 64 рдмрд┐рдЯ рдирдВрдмрд░ рддрдХ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ (рдЖрдк BitArray рдорд╛рдзреНрдпрдо рд╕реЗ рдЕрдзрд┐рдХ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдРрд╕рд╛ рдирд╣реАрдВ рд╣реИ)ред рдпрджрд┐ рд╣рдо рд╕рдВрдмрдВрдзрд┐рдд рдмрд┐рдЯреНрд╕ рдХреЗ рд╕реЗрдЯ рдХреЗ рд╕рд╛рде 64 рдмрд┐рдЯ рдирдВрдмрд░реЛрдВ рдХреЗ рд╕рдореВрд╣ рдХреЗ рд░реВрдк рдореЗрдВ рдЯреИрдЧ рдХреЗ рджреЛ рд╕рдореВрд╣реЛрдВ рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ 64 рдмрд┐рдЯ рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЗ рдРрд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рд╕рдореВрд╣ рдкрд░ рдПрдХ "рдФрд░" рдСрдкрд░реЗрд╢рди рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реЛрдЧрд╛ред рдпрд╣ рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рд╣реИ рдХрд┐ рдкрд░рд┐рдгрд╛рдо рдХреЗ рд╕рд╛рде рдХреНрдпрд╛ рдХрд░рдирд╛ рд╣реИред рдЖрдЗрдП рдлрд┐рд░ рд╕реЗ рд▓реВрдк рдХреЗ рд╢рд░реАрд░ рдкрд░ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВ:


 int t = a.InnerTags[i] & b.InnerTags[i]; result += t; 

рдкрд░рд┐рдгрд╛рдо 1 рд╣рд░ рдмрд╛рд░ t == 1 рд╕реЗ рдмрдврд╝рддрд╛ рд╣реИ рдФрд░ рдЬрдм t == 0. рдирд╣реАрдВ рдмрджрд▓рддрд╛ рд╣реИ, рддреЛ рдкрд░рд┐рдгрд╛рдо рдХреЗ рд░реВрдк рдореЗрдВ рдкрд░рд┐рдгрд╛рдо рдХрд┐рддрдиреЗ рдмрд╛рд░ рдХреЗ рдмрд░рд╛рдмрд░ рд╣реЛрдЧрд╛ред a.InnerTags[i] & b.InnerTags[i] рдПрдХ рдерд╛ред рддрджрдиреБрд╕рд╛рд░, рдХрд┐рд╕реА рд╕рд░рдгреА рдореЗрдВ a.InnerTags[i] & b.InnerTags[i] рд╕рднреА рдкрд░рд┐рдгрд╛рдо рд╕рд╣реЗрдЬрдирд╛ рд╕рдВрднрд╡ рд╣реЛрдЧрд╛, рдФрд░ рдкрд░рд┐рдгрд╛рдо рдореЗрдВ рдЗрд╕ рд╕рд░рдгреА рдореЗрдВ рдХреЗрд╡рд▓ рдЗрдХрд╛рдЗрдпреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рд▓рд┐рдЦреЗрдВред рдПрди-рдмрд┐рдЯ рд╕рдВрдЦреНрдпрд╛ рд╕реЗ рдЕрдзрд┐рдХ рдкрд░ рдПрдВрдб рдСрдкрд░реЗрд╢рди рдХрд░рддреЗ рд╕рдордп, рдПрдХ рдПрди-рдмрд┐рдЯ рдкрд░рд┐рдгрд╛рдо рд╣реЛрдЧрд╛ рдФрд░ рдпрд╣ рдХреЗрд╡рд▓ рдпрд╣ рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реЛрдЧрд╛ рдХрд┐ рдПрди рдХреЗ рдмреАрдЪ рдХрд┐рддрдиреЗ рдмрд┐рдЯ рд╕реЗрдЯ рд╣реИрдВред рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рд╕реЗрдЯ рдмрд┐рдЯреНрд╕ рдЕрдкрд░рд┐рд╡рд░реНрддрд┐рдд рд╣реИрдВ, рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рдЖрдк рдЗрди рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЛ рдЧрд┐рди рд╕рдХрддреЗ рд╣реИрдВред 64 рдмрд┐рдЯреНрд╕ рдХреА рдЧрд┐рдирддреА рдХреЗ рд▓рд┐рдП рдХреЛрдИ рдорддрд▓рдм рдирд╣реАрдВ рд╣реИ, рдЬреИрд╕рд╛ рдХрд┐ рд╣рдореЗрдВ рдЗрддрдиреА рд░реИрдо рдирд╣реАрдВ рдорд┐рд▓реЗрдЧреАред 32 рдмрд┐рдЯреНрд╕ рдХреЗ рд▓рд┐рдП рдЖрдк рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЖрдзреБрдирд┐рдХ рдХрдВрдкреНрдпреВрдЯрд░ рдкрд░ рдЬрдЧрд╣ рдкрд╛ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдпрд╣ рдЕрднреА рднреА рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╣реИред 16 рдмрд┐рдЯреНрд╕ рдХреЗ рддрд╣рдд рдореЗрдореЛрд░реА рдХреЛ рдвреВрдВрдврдирд╛ рдореБрд╢реНрдХрд┐рд▓ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдЧрдгрдирд╛ рдЕрдкреЗрдХреНрд╖рд╛рдХреГрдд рд▓рдВрдмреА рд╣реЛрдЧреАред рдПрдХ рд╕рдордЭреМрддреЗ рдХреЗ рд░реВрдк рдореЗрдВ, рдЖрдЗрдП 8 рдмрд┐рдЯ рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдЧрдгрдирд╛ рдХрд░реЗрдВ:


GenerateCountOfSettedBits
 static readonly byte[] CountOfSettedBits = GenerateCountOfSettedBits(); static byte[] GenerateCountOfSettedBits() { //  result   i      i- . byte[] result = new byte[256]; //  ,      i   , //        int[] b = new int[8]; //     for (int i = 1; i < 256; i++) { //       int settedBitsCount = 0; //,       int m = 1; //   for (int j = 0; j < 8; j++) { //     b[j] += m; //  ,       2. m = b[j] >> 1; //        b[j] = b[j] & 1; //,        settedBitsCount += b[j]; } result[i] = (byte) settedBitsCount; //   } return result; } 

рдЕрдм рдЯреИрдЧрдЧреНрд░реБрдк рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:


 const int BucketSize = 8; public TagsGroup(bool[] innerTags) { if (innerTags == null) throw new ArgumentException(nameof(innerTags)); if (innerTags.Length != TagsGroupLength) { throw new ArgumentException(nameof(innerTags)); } int index = 0; //    InnerTags = new byte[TagsGroupLength / BucketSize]; //   for (int i = 0; i < TagsGroupLength / BucketSize; i++) { //     for (int j = 0; j < BucketSize; j++, index++) { //    2,      InnerTags[i] <<= 1; //    InnerTags[i] += (byte) (innerTags[index] ? 1 : 0); } } } 

рдФрд░ MeasureSimilarity рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрдирд╛ рд╢реБрд░реВ рд╣реБрдИ:


 public static int MeasureSimilarity(TagsGroup a, TagsGroup b) { int result = 0; for (int i = 0; i < TagsGroupLength / BucketSize; i++) { int t = a.InnerTags[i] & b.InnerTags[i]; result += CountOfSettedBits[t]; } return result; } 

рдЖрдк рдПрдХ рдмрдбрд╝рд╛ рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдЪрд▓рд╛ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рд╕рдм рдХреБрдЫ рдмреЗрд╣рддрд░ рд╣реИ:


рд╡рд┐рдзрд┐рдореАрдирддреНрд░реБрдЯрд┐StdDevрдЖрд╡рдВрдЯрд┐рдд
RandomTest560.5 рдорд┐8.285 рдорд┐7.344 рдорд┐1.53 рдХреЗрдмреА
AscendantTest570.1 рдорд┐4.108 рдорд┐3.431 рдПрдордПрд╕1.53 рдХреЗрдмреА
DescendantTest608.1 рдорд┐5.691 рдорд┐5.324 рдорд┐1.53 рдХреЗрдмреА

рдХреНрдпрд╛ MeasureSimilarity рд╡рд┐рдзрд┐ рдХреЛ рдФрд░ рднреА рддреЗрдЬ рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИ? рдмреЗрд╢рдХ! рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдпрд╣ рдЗрд╕ рддрдереНрдп рдХреЛ рдорд╣рд╕реВрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ рдХрд┐ рд╕рд╛рдорд╛рдиреНрдп рдкреНрд░рдпреЛрдЬрди рд░рдЬрд┐рд╕реНрдЯрд░ рдЕрдм рдЬреНрдпрд╛рджрд╛рддрд░ 64 рдмрд┐рдЯ рд╣реИрдВ, рдФрд░ рд╣рдо рдЙрдирдореЗрдВ рдЖрда-рдмрд┐рдЯ рдбреЗрдЯрд╛ рдЪрд▓рд╛рддреЗ рд╣реИрдВред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдкреИрдХреЗрдЯ рдХрд╛ рдЖрдХрд╛рд░ рдмрдврд╝рд╛рдПрдВ рдЬрд┐рд╕рдореЗрдВ рдореВрд▓ рдЯреИрдЧ рдкреИрдХ рдХрд┐рдП рдЧрдП рд╣реЛрдВ, 64 рдмрд┐рдЯ рддрдХ рдмрдврд╝реЗрдВ рдФрд░ рдЖрд╡рд╢реНрдпрдХ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦреЗрдВ:


 const int BucketSize = 64; ulong[] InnerTags { get; } public static int MeasureSimilarity(TagsGroup a, TagsGroup b) { int result = 0; for (int i = 0; i < TagsGroupLength / BucketSize; i++) { ulong t = a.InnerTags[i] & b.InnerTags[i]; for (int j = 0; j < BucketSize / 8; j++) { result += CountOfSettedBits[t & 255]; t >>= 8; } } return result; } 

рдФрд░ рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ:


рд╡рд┐рдзрд┐рдореАрдирддреНрд░реБрдЯрд┐StdDevрдЖрд╡рдВрдЯрд┐рдд
RandomTest533.3 рдорд┐4.802 рдорд┐4.492 рдорд┐1.53 рдХреЗрдмреА
AscendantTest550.9 рдПрдордПрд╕5.435 рдорд┐5.084 рдПрдордПрд╕1.53 рдХреЗрдмреА
DescendantTest567.6 рдорд┐3.879 рдорд┐рей.рекрей реп рдорд┐1.53 рдХреЗрдмреА

рдлрд┐рд░ рдЖрдк рдЖрдВрддрд░рд┐рдХ рд▓реВрдк рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:


MeasureSimilarity
 public static int MeasureSimilarity(TagsGroup a, TagsGroup b) { int result = 0; for (int i = 0; i < TagsGroupLength / BucketSize; i++) { ulong t = a.InnerTags[i] & b.InnerTags[i]; result += CountOfSettedBits[t & 255]; t >>= 8; result += CountOfSettedBits[t & 255]; t >>= 8; result += CountOfSettedBits[t & 255]; t >>= 8; result += CountOfSettedBits[t & 255]; t >>= 8; result += CountOfSettedBits[t & 255]; t >>= 8; result += CountOfSettedBits[t & 255]; t >>= 8; result += CountOfSettedBits[t & 255]; t >>= 8; result += CountOfSettedBits[t & 255]; } return result; } 

рд╡рд┐рдзрд┐рдореАрдирддреНрд░реБрдЯрд┐StdDevрдЖрд╡рдВрдЯрд┐рдд
RandomTest370.5 рдорд┐2.802 рдПрдордПрд╕2.484 рдПрдордПрд╕1.53 рдХреЗрдмреА
AscendantTest395.8 рдПрдордПрд╕2.682 рдПрдордПрд╕2.509 рдорд┐1.53 рдХреЗрдмреА
DescendantTest419.5 рдПрдордПрд╕3.352 рдПрдордПрд╕2.971 рдПрдордПрд╕1.53 рдХреЗрдмреА

рдХреНрдпрд╛ рдпрд╣ рдФрд░ рднреА рддреЗрдЬ рд╣реИ? рд╣рд╛рдБ! рдпрджрд┐ рдЖрдк .NET рдХреЛрд░ 3.0 рд╕реЗ рдирд╡рд╛рдЪрд╛рд░реЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рд╣рд╛рд▓рд╛рдВрдХрд┐ рдпрд╣ рд╕рдВрд╕реНрдХрд░рдг рдЕрднреА рднреА рдкреВрд░реНрд╡рд╛рд╡рд▓реЛрдХрди рдореЗрдВ рд╣реИ, рд▓реЗрдХрд┐рди рд╢реБрд░реБрдЖрдд рд╕реЗ рд╣реА рдХреБрдЫ рдЖрдВрддрд░рд┐рдХ рд╡рд┐рд╖рдпреЛрдВ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реИред рдЗрдВрдЯреЗрд▓ рдЖрдВрддрд░рд┐рдХ рдЧрд╛рдЗрдб рдореЗрдВ рдЖрдВрддрд░рд┐рдХ _mm_popcnt_u64 ред рдЬреИрд╕рд╛ рдХрд┐ рд╡рд░реНрдгрд┐рдд рд╣реИ: " рдЕрд╣рд╕реНрддрд╛рдХреНрд╖рд░рд┐рдд 64-рдмрд┐рдЯ рдкреВрд░реНрдгрд╛рдВрдХ рдореЗрдВ 1 рдореЗрдВ рд╕реЗрдЯ рдмрд┐рдЯреНрд╕ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреА рдЧрдгрдирд╛ рдХрд░реЗрдВ, рдФрд░ рдЙрд╕ dst рдореЗрдВ рд▓реМрдЯреЗрдВред " рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╣рдо рдХреНрдпрд╛ рд╣рд╛рд╕рд┐рд▓ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣реЗ рд╣реИрдВ! .NET Core 3.0 рдкреВрд░реНрд╡рд╛рд╡рд▓реЛрдХрди 5 рдореЗрдВ, рдпрд╣ рдЖрдВрддрд░рд┐рдХ System.Runtime.Intrinsics.X86.Popcnt.X64.IsSupported System.Runtime.Intrinsics.X86.Popcnt.X64.PopCount рдореЗрдВ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ (рдЬреИрд╕рд╛ рдХрд┐ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдПрдХ tk рдХреА рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдореЗрдВ рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдЖрдкрдХреЛ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдкреНрд░реЛрд╕реЗрд╕рд░ рдЖрдВрддрд░рд┐рдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЙрдирдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, System.Runtime.Intrinsics.X86.Popcnt.X64.IsSupported рд╕реНрдерд┐рддрд┐ рдХреА рдЬрд╛рдВрдЪ рдХрд░реЗрдВред System.Runtime.Intrinsics.X86.Popcnt.X64.IsSupported )ред рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, MeasureSimilarity рд╡рд┐рдзрд┐ рдХрд╛ рдХреЛрдб рдЗрд╕ рддрд░рд╣ рдмрди рдЬрд╛рдПрдЧрд╛:


 public static int MeasureSimilarity(TagsGroup a, TagsGroup b) { int result = 0; for (int i = 0; i < TagsGroupLength / BucketSize; i++) { ulong t = a.InnerTags[i] & b.InnerTags[i]; result += (int) System.Runtime.Intrinsics.X86.Popcnt.X64.PopCount(t); } return result; } 

рдФрд░ рдирд┐рд╖реНрдкрд╛рджрди рд╕рдордп:


рд╡рд┐рдзрд┐рдореАрдирддреНрд░реБрдЯрд┐StdDevрдЖрд╡рдВрдЯрд┐рдд
RandomTest59.33 рдорд┐1.148 рдорд┐0.9585 рдорд┐1.53 рдХреЗрдмреА
AscendantTest74.87 рдорд┐1.479 рдорд┐1.9748 рдПрдордПрд╕1.53 рдХреЗрдмреА
DescendantTest119.46 рдорд┐2.321 рдПрдордПрд╕2.8509 рдПрдордПрд╕1.53 рдХреЗрдмреА

рдкреНрд░рднрд╛рд╡рд╢рд╛рд▓реАред
рдореБрдЭреЗ рдЙрди рддрд░реАрдХреЛрдВ рдХреА рдЬрд╛рдирдХрд╛рд░реА рдирд╣реАрдВ рд╣реИ, рдЬреЛ MeasureSimilarity рдХрд╛рдлреА рддреЗрдЬреА рд▓рд╛ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рд╕рд╛рде рд╣реА рд╕рд╛рде рдкрдардиреАрдпрддрд╛ рдХреЛ рдмрд╣реБрдд рдЦрд░рд╛рдм рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВред рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЖрдк рдЗрд╕ рд╡рд┐рдзрд┐ рдХреЛ рд╕рдорд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред


рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛рдПрдВ


рдЕрдм рд╣рдо GetFiftyMostSimilarGroups рд╡рд┐рдзрд┐ рдореЗрдВ рд▓реВрдк рдХреЗ рд╢рд░реАрд░ рдХреЗ рд╕рд╛рде GetFiftyMostSimilarGroups рдХрд░реЗрдВрдЧреЗ:


GetFiftyMostSimilarGroups
 public TagsGroup[] GetFiftyMostSimilarGroups(TagsGroup value) { const int resultLength = 50; List<TagsSimilarityInfo> list = new List<TagsSimilarityInfo>(50); for (int groupIndex = 0; groupIndex < Groups.Length; groupIndex++) { TagsGroup tagsGroup = Groups[groupIndex]; int similarityValue = TagsGroup.MeasureSimilarity(value, tagsGroup); TagsSimilarityInfo newInfo = new TagsSimilarityInfo(groupIndex, similarityValue); if (list.Count == resultLength && list[resultLength - 1].CompareTo(newInfo) == -1) { continue; } int index = ~list.BinarySearch(newInfo); list.Insert(index, newInfo); if (list.Count > resultLength) { list.RemoveAt(resultLength); } } TagsGroup[] result = new TagsGroup[resultLength]; for (int i = 0; i < resultLength; i++) { result[i] = Groups[list[i].Index]; } return result; } 

рдореБрдЭреЗ рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ рдпрд╛рдж рджрд┐рд▓рд╛рдПрдВ рдХрд┐ рдпрд╣рд╛рдВ рдХреНрдпрд╛ рд╣реЛ рд░рд╣рд╛ рд╣реИ:


  • рд╕реВрдЪреА рдХреЗ рдЕрдВрджрд░, рдкрдЪрд╛рд╕ рд╕рдмрд╕реЗ рдЙрдкрдпреБрдХреНрдд рдЯреИрдЧ рд╕рдореВрд╣реЛрдВ рдХреА рдПрдХ рдХреНрд░рдордмрджреНрдз рд╕реВрдЪреА рд╕рдВрдЧреНрд░рд╣реАрдд рдХреА рдЬрд╛рддреА рд╣реИ, рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдЫреЛрдЯреЗ рд╕реЗ рдмрдбрд╝реЗ рддрдХ, рдпрджрд┐ рдЖрдк TagsSimilarityInfo рддреБрд▓рдирд╛ TagsSimilarityInfo ;
  • рдЫрдБрдЯрд╛рдИ рдХреЛ рд╕рдВрд░рдХреНрд╖рд┐рдд рдХрд░рддреЗ рд╣реБрдП рд╕реВрдЪреА рдореЗрдВ рдирдП рд╕рдореВрд╣ рдХреЛ рд╕рдореНрдорд┐рд▓рд┐рдд рдХрд░реЗрдВ;
  • рдпрджрд┐ рд╕реВрдЪреА рдореЗрдВ рдкрдЪрд╛рд╕ рд╕реЗ рдЕрдзрд┐рдХ рддрддреНрд╡ рд╣реИрдВ, рддреЛ рдХрдо рд╕реЗ рдХрдо рд╕рдорд╛рди рд╕рдореВрд╣ рдХреЛ рд╣рдЯрд╛ рджреЗрдВ (рдЗрд╕рдХреА рдЬрд╛рдирдХрд╛рд░реА-рд╡рд╕реНрддреБ рд╕рдмрд╕реЗ рдмрдбрд╝реА рд╣реЛрдЧреА рдФрд░ list рдХреЗ рдмрд╣реБрдд рдЕрдВрдд рдореЗрдВ рд╣реЛрдЧреА);

рдпрд╛рдиреА рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ рдХрд┐ рд╣рдореЗрдВ рд╕рдВрдЧреНрд░рд╣ рдореЗрдВ рд╕рдмрд╕реЗ рдмрдбрд╝рд╛ рддрддреНрд╡ рдЦреЛрдЬрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЬрд▓реНрджреА рд╕реЗ рдбрд╛рд▓рдиреЗ рдФрд░ рд╣рдЯрд╛рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛред рдРрд╕реА рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╡рд┐рд╢реЗрд╖ рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛рдПрдВ рд╣реИрдВред рдкрд╣рд▓реА рдмрд╛рдд рдЬреЛ рдорди рдореЗрдВ рдЖрддреА рд╣реИ рд╡рд╣ рд╣реИ рдПрдХ рдЧреБрдЪреНрдЫрд╛ ред рдЙрд╕рдХреА рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ O (рд▓реЙрдЧ рдПрди) рдореЗрдВ рдХреА рдЬрд╛рддреА рд╣реИ, рдУ (1 рдПрди) рдореЗрдВ рдПрдХ рддрддреНрд╡ рдХреЛ рд╣рдЯрд╛рддреЗ рд╣реБрдП, рдУ (1) рдореЗрдВ рдЕрдзрд┐рдХрддрдо рд╣реЛ рд░рд╣реА рд╣реИред рдПрдХрдорд╛рддреНрд░ рд╕рдорд╕реНрдпрд╛ рдпрд╣ рд╣реИ рдХрд┐ рдвреЗрд░ рдХреЛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд┐рдП рдмрд┐рдирд╛ рдмрдврд╝рддреЗ рддрддреНрд╡реЛрдВ рджреНрд╡рд╛рд░рд╛ рдкреБрдирд░рд╛рд╡реГрддреНрдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред BCL рдореЗрдВ рдХреЛрдИ рдмрд╛рдЗрдирд░реА рд╣реАрдк рдирд╣реАрдВ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдЗрд╕реЗ рд╕реНрд╡рдпрдВ рд▓рд┐рдЦрд╛:


BinaryHeap
 public class BinaryHeap<T>:IEnumerable<T> where T : IComparable<T> { readonly List<T> innerList; public BinaryHeap(int capacity) { innerList = new List<T>(capacity); } public int Count => innerList.Count; public T Max => innerList[0]; public void Add(T value) { innerList.Add(value); int i = Count - 1; int parent = (i - 1) >> 1; while (i > 0 && innerList[parent].CompareTo(innerList[i]) == -1) { Swap(i, parent); i = parent; parent = (i - 1) >> 1; } } void Swap(int a, int b) { T temp = innerList[a]; innerList[a] = innerList[b]; innerList[b] = temp; } void Heapify(int i) { for (;;) { int leftChild = (i << 1) | 1; int rightChild = (i + 1) << 1; int largestChild = i; if (leftChild < Count && innerList[leftChild].CompareTo(innerList[largestChild]) == 1) { largestChild = leftChild; } if (rightChild < Count && innerList[rightChild].CompareTo(innerList[largestChild]) == 1) { largestChild = rightChild; } if (largestChild == i) { break; } Swap(i, largestChild); i = largestChild; } } public void RemoveMax() { innerList[0] = innerList[Count - 1]; innerList.RemoveAt(Count - 1); Heapify(0); } public IEnumerator<T> GetEnumerator() { return innerList.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable) innerList).GetEnumerator(); } } 

GetFiftyMostSimilarGroups рд╡рд┐рдзрд┐ рдХрд╛ рд╕рдВрдЧрдд рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд▓реЗрдЦ рдХреЗ рд╕реНрд░реЛрдд рдХреЛрдб (рдиреАрдЪреЗ рд▓рд┐рдВрдХ) рдореЗрдВ рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рдвреЗрд░ рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдПрдХ рдмрд╛рдЗрдирд░реА рд╕рд░реНрдЪ рдЯреНрд░реА рдКрдкрд░ рдЖ рд╕рдХрддрд╛ рд╣реИред рдПрдХ рд╕рдВрддреБрд▓рд┐рдд рдмрд╛рдЗрдирд░реА рд╕рд░реНрдЪ рдЯреНрд░реА рдУ (рд▓реЙрдЧ рдПрди) рдХреЗ рд▓рд┐рдП рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдкреНрд░рджрд╛рди рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдУ рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХрддрдо рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддрд╛ рд╣реИ (рд▓реЙрдЧ рдПрди), рдУ (рд▓реЙрдЧ рдПрди) рдХреЗ рд▓рд┐рдП рдПрдХ рддрддреНрд╡ рдХреЛ рд╣рдЯрд╛ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕ рд╕рдВрд░рдЪрдирд╛ рдХрд╛ рд▓рд╛рдн рдпрд╣ рд╣реИ рдХрд┐ рдЗрд╕реЗ рдЖрд░реЛрд╣реА рдХреНрд░рдо рдореЗрдВ рдкреБрдирд░рд╛рд╡реГрддреНрдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдФрд░, рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдмреАрд╕реАрдПрд▓ рдореЗрдВ рд▓рд╛рд▓-рдХрд╛рд▓реЗ рд░рдВрдЧ рдХреЗ рдЦреЛрдЬ рдХреЛ рд╕реЙрд░реНрдЯреЗрдбрд╕реЗрдЯ (рдПрдХ рдмрдбрд╝реЗ рдврд╛рдВрдЪреЗ рдореЗрдВ, рдЕрдзрд┐рдХрддрдо .net 3.0 рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдзреАрдореА рдЧрддрд┐ рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдФрд░ рдореЗрдореЛрд░реА рдЖрд╡рдВрдЯрд┐рдд рдХрд░рдирд╛) рдореЗрдВ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред GetFiftyMostSimilarGroups рд▓рд┐рдП GetFiftyMostSimilarGroups рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд▓реЗрдЦ рдХреЗ рд╕реНрд░реЛрдд рдХреЛрдб рдореЗрдВ рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рд╕рднреА рддреАрди GetFiftyMostSimilarGroups рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд▓рд┐рдП рдмреЗрдВрдЪрдорд╛рд░реНрдХ рдкрд░рд┐рдгрд╛рдо:


рд╡рд┐рдзрд┐рдЫрдБрдЯрд╛рдИ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдордореАрдирдЖрд╡рдВрдЯрд┐рдд
RandomTestрд╕реВрдЪреА60.06 рдорд┐1704 рдм
RandomTestSortedSet65.46 рдорд┐24384 рдмреА
RandomTestрдвреЗрд░60.55 рдорд┐2912 рдмреА
AscendantTestрд╕реВрдЪреА75.42 рдорд┐1704 рдм
AscendantTestSortedSet161.12 рдПрдордПрд╕9833424 рдмреА
AscendantTestрдвреЗрд░86.87 рдорд┐2912 рдмреА
DescendantTestрд╕реВрдЪреА119.23 рдорд┐880 рдмреА
DescendantTestSortedSet125.03 рдПрдордПрд╕3024 рдмреА
DescendantTestрдвреЗрд░118.62 рдорд┐2088 рдмреА

рдПрдХ рдкрддреНрддреЗ рдХреЗ рд╕рд╛рде рдореВрд▓ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд▓рдЧрднрдЧ рд╣рд░ рдЬрдЧрд╣ рд╕рдордп рдореЗрдВ рдЬреАрддрддрд╛ рд╣реИ, рдФрд░ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рд╣рд░ рдЬрдЧрд╣ рд╕реНрдореГрддрд┐ рдореЗрдВред рдпрд╣ рдЗрд╕ рддрдереНрдп рдХреЗ рдХрд╛рд░рдг рд╣реЛрддрд╛ рд╣реИ рдХрд┐ рд╢реАрдЯ рдХреЗ рд╕рд╛рде рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХреЗ рд▓рд┐рдП, рдЦреЛрдЬ рдХреЗ рд▓рд┐рдП рдУ (рд▓реЙрдЧ рдПрди) рдореЗрдВ рд╕рдореНрдорд┐рд▓рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдбрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рд▓рдЧрднрдЧ рдУ (1), рдХреНрдпреЛрдВрдХрд┐ рддрддреНрд╡реЛрдВ рдХреА рдЗрддрдиреА рдХрдо рд╕рдВрдЦреНрдпрд╛ рдХреА рдирдХрд▓ рдХрд░рдирд╛ рдмрд╣реБрдд рдЬрд▓реНрджреА рд╣реЛрддрд╛ рд╣реИ, рдУ (1) рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХрддрдо рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛, рдУ (1) рдХреЗ рд▓рд┐рдП рднреА рдПрдХ рддрддреНрд╡ рдХреЛ рд╣рдЯрд╛рдирд╛, рдХреНрдпреЛрдВрдХрд┐ , .net, рд╢реАрдЯ рд╕реЗ рдЕрдВрддрд┐рдо рддрддреНрд╡ рдХреЛ рд╣рдЯрд╛рдХрд░ рдЕрдВрддрд┐рдо рддрддреНрд╡ рдХреЛ рдПрдХ рдЦрд╛рд▓реА рдорд╛рди рд▓рд┐рдЦрдХрд░ рдмрджрд▓ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ (рдЗрди .net рдХреЛрд░ рдХреБрдЫ рднреА рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдирд╣реАрдВ рд▓рд┐рдЦрд╛ рдЬрд╛рддрд╛ рд╣реИ) рдпрджрд┐ рдЗрд╕реЗ 50 рдирд╣реАрдВ рджреЗрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рд▓реЗрдХрд┐рди рдЪрд▓реЛ 1000 рд╕рдмрд╕реЗ рд╕рдорд╛рди рд╕рдореВрд╣реЛрдВ рдХреЛ рдХрд╣рддреЗ рд╣реИрдВ, рддреЛ рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рд╕рдВрднрд╛рд╡рдирд╛ рд╣реИ, рд╢реАрдЯ рдХреЗ рд╕рд╛рде рдПрдХ рдПрд▓реНрдЧреЛрд░рд┐рдереНрдо рдХрд╛рдо рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдпрд╣ рд╕рдм рдереЛрдбрд╝рд╛ рд╕рдЯреНрдЯрд╛ рддрд░реНрдХ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЖрдк рдЕрднреА рднреА рдкреНрд░рддреНрдпреЗрдХ рдПрд▓реНрдЧреЛрд░рд┐рджрдо рдХреЛ рд╕рдорд╛рдпреЛрдЬрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред


рдмрд╣реБ рд╕реВрддреНрд░рдг


рдЕрдм рдпрд╣ GetFiftyMostSimilarGroups рдореЗрдВ рдкрд╛рд╢ рдХреЛ рдмреЗрд╣рддрд░ рдмрдирд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдиреА рд╣реБрдИ рд╣реИред рдХреЗрд╡рд▓ рдорд▓реНрдЯреАрдереНрд░реЗрдбрд┐рдВрдЧ рджрд┐рдорд╛рдЧ рдореЗрдВ рдЖрддрд╛ рд╣реИред рд╡рд┐рдЪрд╛рд░ рд╕рдореВрд╣реЛрдВ рдХреА рдкреВрд░реА рд╕реВрдЪреА рдХреЛ рдХрдИ рдкреИрдХреЗрдЬреЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░рдирд╛ рд╣реИред рдкреНрд░рддреНрдпреЗрдХ рдкреИрдХреЗрдЬ рдореЗрдВ, 50 рд╕рдмрд╕реЗ рд╕рдорд╛рди рдЯреИрдЧ рд╕рдореВрд╣ рдвреВрдВрдвреЗрдВ, рдФрд░ рдлрд┐рд░ рдЙрдирдореЗрдВ рд╕реЗ рдЕрдВрддрд┐рдо 50 рд╕рдмрд╕реЗ рд╕рдорд╛рди рдорд┐рд▓рддреЗ рд╣реИрдВред
GetFiftyMostSimilarGroups рдХрд╛ рдмрд╣реБ-рд╕рдВрд╕реНрдХрд░рдг рд╕рдВрд╕реНрдХрд░рдг рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:


GetFiftyMostSimilarGroupsMultiThread
 public TagsGroup[] GetFiftyMostSimilarGroupsMultiThread(TagsGroup value) { const int resultLength = 50; // ,     const int threadsCount = 4; //   int bucketSize = Groups.Length / threadsCount; var tasks = new Task<List<TagsSimilarityInfo>>[threadsCount]; for (int i = 0; i < threadsCount; i++) { int leftIndex = i * bucketSize; //    int rightIndex = (i + 1) * bucketSize; //    //    tasks[i] = Task<List<TagsSimilarityInfo>>.Factory.StartNew(() => GetFiftyMostSimilarGroupsMultiThreadCore(value, leftIndex, rightIndex)); } Task.WaitAll(tasks); //    var taskResults = new List<TagsSimilarityInfo>[threadsCount]; for (int i = 0; i < threadsCount; i++) { taskResults[i] = tasks[i].Result; } //      return MergeTaskResults(resultLength, threadsCount, taskResults); } 

GetFiftyMostSimilarGroupsMultiThreadCore GetFiftyMostSimilarGroups :


GetFiftyMostSimilarGroupsMultiThreadCore
 List<TagsSimilarityInfo> GetFiftyMostSimilarGroupsMultiThreadCore(TagsGroup value, int leftIndex, int rightIndex) { const int resultLength = 50; List<TagsSimilarityInfo> list = new List<TagsSimilarityInfo>(resultLength); for (int groupIndex = leftIndex; groupIndex < rightIndex; groupIndex++) { TagsGroup tagsGroup = Groups[groupIndex]; int similarityValue = TagsGroup.MeasureSimilarity(value, tagsGroup); TagsSimilarityInfo newInfo = new TagsSimilarityInfo(groupIndex, similarityValue); if (list.Count == resultLength && list[resultLength - 1].CompareTo(newInfo) == -1) { continue; } int index = ~list.BinarySearch(newInfo); list.Insert(index, newInfo); if (list.Count > resultLength) { list.RemoveAt(resultLength); } } return list; } 

MergeTaskResults . - taskResults . , , . , threadsCount , : , , , :


MergeTaskResults
 TagsGroup[] MergeTaskResults(int resultLength, int threadsCount, List<TagsSimilarityInfo>[] taskResults) { TagsGroup[] result = new TagsGroup[resultLength]; int[] indices = new int[threadsCount]; for (int i = 0; i < resultLength; i++) { int minIndex = 0; TagsSimilarityInfo currentBest = taskResults[minIndex][indices[minIndex]]; for (int j = 0; j < threadsCount; j++) { var current = taskResults[j][indices[j]]; if (current.CompareTo(currentBest) == -1) { minIndex = j; currentBest = taskResults[minIndex][indices[minIndex]]; } } int groupIndex = currentBest.Index; result[i] = Groups[groupIndex]; indices[minIndex]++; } return result; } 

  • indices taskResults ;
  • minIndex тАФ taskResults , ;
  • currentBest тАФ - ;
  • current тАФ - ;

:


MethodMeanErrorStdDevAllocated
RandomTest28.76 ms0.5677 ms1.414 ms1.4 KB
AscendantTest32.36 ms0.8930 ms2.591 ms1.4 KB
DescendantTest41.36 ms0.8908 ms2.626 ms1.4 KB

:
MethodMeanErrorStdDevAllocated
RandomTest25054 ms1786 ms1670 ms1.53 KB
AscendantTest4180 ms174 ms162 ms1.53 KB
DescendantTest4147 ms118 ms104 ms1.53 KB

. . , , 4 50. , , .


Source: https://habr.com/ru/post/hi454850/


All Articles