目录
- 前言
- SortedSet
- C#自带类型
- 自定义类
- SortedSet权值重复
- 需求
- 自定义容器 -- MultiplySortedSet
- 核心实现思路
- MultiplySortedSet 使用
- C#自带类型
- 自定义类
前言
最近需要在C#中实现一个功能
有一个容器,该容器能自动对里面的元素进行排序,类似C++的优先队列,也就是堆。
但是查询了C#提供的一些容器,只有 SortedSet 和我们的需求很符合。
SortedSet
其实就是一个可以自动排序的容器
我们在Unity下使用看看
C#自带类型
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SortedSetTest : MonoBehaviour
{
private void Awake()
{
SortedSet<int> ssi = new SortedSet<int>();
ssi.Add(10);
ssi.Add(1);
ssi.Add(5);
ssi.Add(-1);
foreach (var item in ssi)
{
print(item);
}
}
}
自定义类
public class Student : IComparable<Student>
{
private int id;
public Student(int id_in)
{
id = id_in;
}
public int CompareTo(Student other)
{
return id.CompareTo(other.id);
}
public override string ToString()
{
return $"Student ID {id}";
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SortedSetTest : MonoBehaviour
{
private void Awake()
{
SortedSet<Student> sss = new SortedSet<Student>();
sss.Add(new Student(10));
sss.Add(new Student(1));
sss.Add(new Student(5));
sss.Add(new Student(-1));
foreach (var item in sss)
{
print(item);
}
}
}
SortedSet权值重复
我们能看出来它可以自动进行排序
但是如果权值重复了该怎么办?我们来试试看
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SortedSetTest : MonoBehaviour
{
private void Awake()
{
SortedSet<int> ssi = new SortedSet<int>();
ssi.Add(10);
ssi.Add(1);
ssi.Add(1);
ssi.Add(-1);
foreach (var item in ssi)
{
print(item);
}
}
}
我们发现相同的 1 并没有被加入到集合中,这也算是 SortedSet 的特性,毕竟是 Set 嘛。
需求
但是我们现在需要的是重复的权值也可以保存下来,并且进行排序。那该怎么办呢?
这里我并没有找到C#自带的符合需求的容器(C++有优先队列),所以我们这里自定义一个容器来实现。
自定义容器 – MultiplySortedSet
多说无益,直接上代码。
using System;
using System.Collections;
using System.Collections.Generic;
namespace Util
{
//排序方法
public enum MultiplySortedType
{
Ascending, //升序
Descending, //降序
}
public class MultiplySortedSet<T> : IEnumerable<T> where T : IComparable<T>
{
private SortedSet<KeyValuePair<T, Guid>> _elements;
private Dictionary<T, Guid> _elementIds;
public MultiplySortedSet(IComparer<KeyValuePair<T, Guid>> comparer = null)
{
//默认为升序
if(comparer == null)
{
comparer = new ComparerAscending();
}
_elements = new SortedSet<KeyValuePair<T, Guid>>(comparer);
_elementIds = new Dictionary<T, Guid>();
}
public MultiplySortedSet(MultiplySortedType sortedType)
{
IComparer<KeyValuePair<T, Guid>> comparer = null;
switch (sortedType)
{
case MultiplySortedType.Ascending:
comparer = new ComparerAscending();
break;
case MultiplySortedType.Descending:
comparer = new ComparerDescending();
break;
}
_elements = new SortedSet<KeyValuePair<T, Guid>>(comparer);
_elementIds = new Dictionary<T, Guid>();
}
public void Add(T element)
{
Guid guid = Guid.NewGuid();
_elements.Add(new KeyValuePair<T, Guid>(element, guid));
_elementIds[element] = guid;
}
public void Remove(T element)
{
//如果Ids存在,则说明_elements里面肯定有该元素
//RemoveWhere是为了删除单一元素
//因为不同T对象的Compare可能相同,但是Guid肯定不同
if (_elementIds.ContainsKey(element))
{
_elements.RemoveWhere(x => x.Key.CompareTo(element) == 0 && x.Value.CompareTo(_elementIds[element]) == 0);
_elementIds.Remove(element);
}
}
public bool Contains(T element)
{
return _elementIds.ContainsKey(element);
}
public int Count
{
get { return _elements.Count; }
}
public IEnumerator<T> GetEnumerator()
{
foreach (var element in _elements)
{
yield return element.Key;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private class ComparerAscending : IComparer<KeyValuePair<T, Guid>>
{
public int Compare(KeyValuePair<T, Guid> x, KeyValuePair<T, Guid> y)
{
//先调用T的Compare,如果相等就比较Guid
int result = x.Key.CompareTo(y.Key);
if (result == 0)
{
result = x.Value.CompareTo(y.Value);
}
return result;
}
}
private class ComparerDescending : IComparer<KeyValuePair<T, Guid>>
{
public int Compare(KeyValuePair<T, Guid> x, KeyValuePair<T, Guid> y)
{
//先调用T的Compare,如果相等就比较Guid
int result = y.Key.CompareTo(x.Key);
if (result == 0)
{
result = x.Value.CompareTo(y.Value);
}
return result;
}
}
}
}
核心实现思路
其实核心思路就一点,多做一层封装,当对象权重相等时,比较另外一个值。
- 首先 SortedSet 不可以存储相同权重,所以我们这里使用 KeyValuePair 来封装一层。
Key为排序的对象,这里就拿泛型T替代。
Value存在的意义就是,当某些T对象权重相等时,拿Value的值来作比较。也就是说每一个相等权重的对象T的Value一定要不一样。所以这里Value可以拿System.Guid来做。
- 自定义一个 Comparer ,如果Key值相等,那么就比较Value值。
MultiplySortedSet 使用
C#自带类型
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Victor_Util;
public class Test : MonoBehaviour
{
private void Awake()
{
MultiplySortedSet<int> vs = new MultiplySortedSet<int>();
vs.Add(9);
vs.Add(1);
vs.Add(1);
vs.Add(1);
vs.Add(-5);
vs.Add(100);
foreach (var item in vs)
{
print(item);
}
}
}
自定义类
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Victor_Util;
public class Test : MonoBehaviour
{
private void Awake()
{
MultiplySortedSet<Student> vs2 = new MultiplySortedSet<Student>();
vs2.Add(new Student(9));
vs2.Add(new Student(1));
vs2.Add(new Student(1));
vs2.Add(new Student(1));
vs2.Add(new Student(-5));
vs2.Add(new Student(100));
foreach (var item in vs2)
{
print(item);
}
}
}