C#进阶学习(八)常见的泛型数据结构类(3)SortedDictionary<TKey, TValue>与SortedList<TKey, TValue>

       

目录

       

        关于默认的排序可以看这篇文章的第二点中关于排序的部分:

一、SortedDictionary

1. 核心特性

2. 常用方法和属性

二、SortedList

1. 核心特性

2. 常用方法和属性

三、关于TryGetValue(TKey key, out TValue value) 方法的详细说明

(一)作用

(二)语法和参数 

注意一定要加这个out!!! 

(三)注意事项

四、总结


        关于默认的排序可以看这篇文章的第二点中关于排序的部分:

常见的泛型数据结构(2)

一、SortedDictionary<TKey, TValue>

1. 核心特性

  • 底层实现:基于 红黑树(自平衡二叉搜索树),确保元素始终按键排序。

  • 排序规则:默认按键的自然顺序(IComparable<TKey>)排序,或通过自定义 IComparer<TKey> 指定。

  • 性能特点

    插入/删除:时间复杂度为 O(log n)(高效动态调整树结构)。

    查找:时间复杂度为 O(log n)

    内存占用:较高(每个节点需要存储左右子树指针)。

  • 适用场景

    需要频繁插入/删除键值对,同时保持有序

    需要按键顺序遍历或范围查询(如获取某个区间内的键)。

2. 常用方法和属性

方法/属性说明
Add(TKey key, TValue value)添加键值对(若键已存在,抛出 ArgumentException)。
Remove(TKey key)删除指定键的键值对(返回是否成功)。
ContainsKey(TKey key)检查是否包含指定键。
TryGetValue(TKey key, out TValue value)安全获取键对应的值(返回是否成功)。
Keys获取按键排序的键集合(KeyCollection 类型)。
Values获取按键顺序排列的值集合(ValueCollection 类型)。
Count获取键值对的数量。

使用示例:

using System;
using System.Collections.Generic;

// 自定义比较器:按字符串长度排序
public class StringLengthComparer : IComparer<string>
{
    public int Compare(string x, string y)
    {
        int lengthCompare = x.Length.CompareTo(y.Length);
        // 长度相同则按字典序排序
        return lengthCompare != 0 ? lengthCompare : string.Compare(x, y, StringComparison.Ordinal);
    }
}

public class SortedDictionaryExample
{
    public static void Main()
    {
        // 使用自定义比较器初始化
        var dict = new SortedDictionary<string, int>(new StringLengthComparer());

        // 添加元素
        dict.Add("Banana", 3);
        dict.Add("Apple", 5);
        dict.Add("Cherry", 2);
        dict.Add("Kiwi", 7);

        // 删除元素
        bool removed = dict.Remove("Apple");
        Console.WriteLine($"删除 Apple: {removed}"); // True

        // 修改元素
        dict["Kiwi"] = 10;

        // 遍历输出(按键长度升序,长度相同按字典序)
        Console.WriteLine("SortedDictionary 元素:");
        foreach (var kvp in dict)
        {
            Console.WriteLine($"{kvp.Key} (长度 {kvp.Key.Length}): {kvp.Value}");
        }
        // 输出顺序:
        // Kiwi (长度 4): 10
        // Apple (长度 5): 5
        // Banana (长度 6): 3
        // Cherry (长度 6): 2
    }
}

 结果:

二、SortedList<TKey, TValue>

1. 核心特性

  • 底层实现:基于 两个动态数组,分别存储键和值,按键排序。

  • 排序规则:与 SortedDictionary 相同,默认按键的自然顺序或自定义 IComparer<TKey>

  • 性能特点

    插入/删除:时间复杂度为 O(n)(需移动元素以保持数组有序)。

    查找:时间复杂度为 O(log n)(二分查找)。

    内存占用:较低(数组连续存储,无额外指针开销)。

  • 适用场景

    键值对数量较少,且插入/删除操作不频繁。

    需要按键快速查找,且内存敏感的场景。

    需要通过索引(类似列表)访问键或值

2. 常用方法和属性

方法/属性说明
Add(TKey key, TValue value)添加键值对(若键已存在,抛出 ArgumentException)。
Remove(TKey key)删除指定键的键值对(返回是否成功)。
ContainsKey(TKey key)检查是否包含指定键。
TryGetValue(TKey key, out TValue value)安全获取键对应的值(返回是否成功)。
IndexOfKey(TKey key)返回键的索引(基于排序后的顺序)。
IndexOfValue(TValue value)返回值的索引(线性搜索,效率较低)。
Keys获取按键排序的键集合(IList<TKey> 类型)。
Values获取按键顺序排列的值集合(IList<TValue> 类型)。
Count获取键值对的数量。

使用示例:

using System;
using System.Collections.Generic;

// 自定义比较器:整型降序排序
public class ReverseIntComparer : IComparer<int>
{
    public int Compare(int x, int y)
    {
        return y.CompareTo(x); // 反转默认顺序
    }
}

public class SortedListExample
{
    public static void Main()
    {
        // 使用自定义比较器初始化
        var list = new SortedList<int, string>(new ReverseIntComparer());

        // 添加元素
        list.Add(3, "Three");
        list.Add(1, "One");
        list.Add(4, "Four");
        list.Add(2, "Two");

        // 删除元素
        bool removed = list.Remove(1);
        Console.WriteLine($"删除 1: {removed}"); // True

        // 修改元素
        list[4] = "Four (Updated)";

        // 遍历输出(按键降序)
        Console.WriteLine("SortedList 元素:");
        foreach (var kvp in list)
        {
            Console.WriteLine($"{kvp.Key}: {kvp.Value}");
        }
        // 输出顺序:
        // 4: Four (Updated)
        // 3: Three
        // 2: Two

        // 通过索引访问键和值
        Console.WriteLine("第一个键: " + list.Keys[0]); // 4
        Console.WriteLine("最后一个值: " + list.Values[list.Count - 1]); // Two
    }
}

三、关于TryGetValue(TKey key, out TValue value) 方法的详细说明

(一)作用

  TryGetValue 是字典类数据结构(如 Dictionary<TKey, TValue>SortedDictionary<TKey, TValue>SortedList<TKey, TValue>)中的一个核心方法,用于安全地获取与指定键关联的值。它的核心优势是避免因键不存在而抛出异常,同时通过一次查找操作完成“检查存在性”和“获取值”两个步骤。

(二)语法和参数 

bool TryGetValue(TKey key, out TValue value)
  • 输入参数

    • key:要查找的键。

  • 输出参数

    • value:当键存在时,此参数会被赋值为对应的值;当键不存在时,会被设置为 TValue 类型的默认值(如 int 的默认值是 0,引用类型是 null)。

  • 返回值

    • true:键存在,且 value 被正确赋值。

    • false:键不存在,value 被设为默认值。

注意一定要加这个out!!! 

在SortedDictioary中的示例:在SortedList中也一样,这里随便拿个示例。

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        var dict = new SortedDictionary<string, int>
        {
            { "Apple", 10 },
            { "Banana", 20 },
            { "Cherry", 30 }
        };

        // 尝试获取存在的键
        if (dict.TryGetValue("Banana", out int bananaValue))
        {
            Console.WriteLine($"Banana 的值是: {bananaValue}"); // 输出: 20
        }

        // 尝试获取不存在的键
        if (!dict.TryGetValue("Mango", out int mangoValue))
        {
            Console.WriteLine("Mango 不存在,mangoValue 被设为默认值: " + mangoValue); // 输出: 0
        }
    }
}

(三)注意事项

out 参数无需初始化: 

// 不需要提前初始化 value
if (dict.TryGetValue("key", out string value)) 
{
    // 仅在返回 true 时,value 是有效的
}

默认值的陷阱

  • 如果键不存在,value 会被设为 default(TValue)。对于引用类型是 null,值类型是 0false 等。

  • 必须检查返回值后再使用 value,否则可能因默认值导致逻辑错误。

与索引器的对比

方式键存在键不存在
dict[key]返回值抛出 KeyNotFoundException
TryGetValue返回 true返回 falsevalue 为默认值

四、总结

        在C#的泛型集合中,SortedDictionary<TKey, TValue>SortedList<TKey, TValue>均提供了按键自动排序的功能,但两者在实现机制、性能特性和适用场景上有显著差异,我们需根据实际需求选择合适的数据结构。

SortedDictionary的核心特性:​
        基于二叉搜索树(通常为红黑树)实现,插入和删除操作的时间复杂度为O(log n),适合频繁增删元素的场景。其内存布局非连续,因此在遍历时效率略低于数组结构。它不直接支持通过索引访问键值对,但提供按键排序的KeysValues集合。自定义排序规则需通过IComparer<TKey>实现,例如按字符串长度排序时,可在比较器中先比较长度再按字典序处理。

SortedList的核心特性:​
        基于动态数组实现,通过二分查找维护有序性。插入删除操作平均时间复杂度为O(n)(需移动元素),适合数据变动较少的场景。其优势在于内存连续,遍历和按索引访问(IndexOfKey)效率更高。此外,SortedList允许通过索引直接访问键值对(如Keys[0]),但IndexOfValue需线性搜索,效率较低。自定义比较器同样支持反向排序(如整型降序)。

TryGetValue方法的注意事项:​
        两者均提供TryGetValue(TKey key, out TValue value)方法,用于安全获取值。此方法通过out参数返回结果,调用前无需初始化value。若键存在,返回truevalue有效;若键不存在,返回falsevalue为类型默认值(如数值类型为0,引用类型为null)。我们需注意默认值陷阱,例如当值为0时,需结合返回值区分“键不存在”和“值本身为0”的情况。与索引器dict[key]相比,TryGetValue避免了KeyNotFoundException异常,更适合不确定键是否存在的场景。

选择策略:​

  • 优先选择SortedDictionary的场景​:数据频繁插入/删除、数据量较大、无需索引访问。
  • 优先选择SortedList的场景​:数据初始化后变动较少、需要按索引快速访问、内存使用需紧凑。

示例场景对比:​

  • 实时高频更新的缓存(如股票价格)适合用SortedDictionary
  • 配置项(启动时加载,后续只读)适合用SortedList以快速按索引访问。

        综上,理解两者的底层实现及性能特点,结合业务需求选择合适结构,是优化程序效率和资源消耗的关键。同时,合理使用TryGetValue替代索引器访问,可提升代码健壮性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FAREWELL00075

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值