C#数据结构09:集合和映射

说明
(此系列帖子记录数据结构学习成果,如侵犯视频作者权益,立删)
作者账号 哔哩哔哩:离忧夏天

本文实现队列需要用到单链表以及有序数组的相关知识,详细请看: C#数据结构专栏

集合

集合是一种存储容器,它允许我们在存储的过程中,对于相同的元素,只保留一份,快速的帮助我们进行去重操作,自动过滤掉重复的元素

接口

interface ISet<T>
{
	//集合元素数量
    int Count { get; }
    //判断是否为空
    bool IsEmpty { get; }
    //增
    void Add(T t);
    //删
    void Remove(T t);
    //是否包含某元素
    bool Contains(T t);
}

基于无序链表实现集合

链表集合时间复杂度
AddO(n)
RemoveO(1)
ContainsO(n)
CountO(1)
IsEmptyO(1)
    class LinkedList1Set<T> :ISet<T>
    {
        private LinkedList01<T> _list;

        public LinkedList1Set()
        {
            _list = new LinkedList01<T>();
        }
        public int Count => _list.Count;
        public bool IsEmpty => _list.IsEmpty;
        public void Add(T t)
        {
          if (!_list.Contains(t))
          	 _list.AddFirst(t);
        }

        public void Remove(T t)
        {
           _list.Remove(t);
        }

        public bool Contains(T t)
        {
            return _list.Contains(t);
        }
    }

基于有序数组实现集合

数组集合时间复杂度
AddO(n)
RemoveO(n)
ContainsO(log n)
class SortedArray1Set<Key> :ISet<Key> where Key :IComparable<Key>
{
    private SortedArray1<Key> s;

    public SortedArray1Set(int capacity)
    {
        s = new SortedArray1<Key>(capacity);
    }

    public SortedArray1Set()
    {
        s = new SortedArray1<Key>();
    }

    public int Count => s.Count;
    public bool IsEmpty  => s.IsEmpty;
    public void Add(Key key)
    {
        s.Add(key);
    }

    public void Remove(Key key)
    {
        s.Remove(key);
    }

    public bool Contains(Key key)
    {
        return s.Contains(key);
    }
}

映射(字典)

指两个元素呈现一一对应的关系,即一个key对应一个value,存储数据键值对

接口

    interface IDictionary<Key,Value>
    {
        //查看键值对的数量
        int Count { get; }
        bool IsEmpty { get; }
        void Add(Key key, Value value);
        void Remove(Key key);
        //查看是否与包含键
        bool ContainsKey(Key key);
        //获取键对应的值
        Value Get(Key key);
        //键对应的改为新值
        void Set(Key key, Value newValue);
    }

支持存储两个数据的链表(用于实现字典)


基于无序链表实现字典

链表字典时间复杂度
AddO(n)
RemoveO(n)
ContainsKeyO(n)
GetO(n)
SetO(n)
class LinkedList3Dictionary<Key ,Value> :IDictionary<Key,Value>
{
    private LinkedList3<Key, Value> List;
    
    public LinkedList3Dictionary()
    {
        List = new LinkedList3<Key, Value>();
    }

    public int Count => List.Count;
    public bool IsEmpty => List.IsEmpty;

    public void Add(Key key, Value value)
    {
        List.Add(key,value);
    }

    public void Remove(Key key)
    {
        List.Remove(key);
    }

    public bool ContainsKey(Key key)
    {
       return List.Contains(key);
    }

    public Value Get(Key key)
    {
        return List.Get(key);
    }
    
    public void Set(Key key, Value newValue)
    {
       List.Set(key,newValue);
    }
}

基于有序数组实现字典

数组字典时间复杂度
AddO(n)
RemoveO(n)
ContainsO(log n)
class SortedArray2Dictionary<Key, Value> : IDictionary<Key, Value> where Key : IComparable<Key>
{
    private SortedArray2<Key, Value> s2;

    public SortedArray2Dictionary(int capacity)
    {
        s2 = new SortedArray2<Key, Value>(capacity);
    }

    public SortedArray2Dictionary()
    {
        s2 = new SortedArray2<Key, Value>();
    }

    public int Count =>s2.Count;
    public bool IsEmpty =>s2.IsEmpty;
    public void Add(Key key, Value value)
    {
        s2.Add(key,value);
    }

    public void Remove(Key key)
    {
        s2.Remove(key);
    }

    public bool ContainsKey(Key key)
    {
        return s2.Contains(key);
    }

    public Value Get(Key key)
    {
        return s2.Get(key);
    }

    public void Set(Key key, Value newValue)
    {
        s2.Add(key,newValue);
    }
}

性能分析比较

TestHelper方法用于测试

//辅助测试类
class TestHelper
{
    //私有的构造函数,不允许外部进行实例化
    //换句话说就是不能通过new关键字创建一个TestHelper类对象
    private TestHelper() { }

    //读取名为filename的文件并将它进行简单分词后存入动态数组List中
    public static List<string> ReadFile(string filename)
    {
        //使用FileStream类打开filename文件
        FileStream fs = new FileStream(filename, FileMode.Open);

        //使用StreamReader读取filename文件信息
        StreamReader sr = new StreamReader(fs);

        //将读取的单词存入动态数组words中
        List<string> words = new List<string>();

        while (!sr.EndOfStream)
        {
            string contents = sr.ReadLine().Trim();
            int start = FirstCharacterIndex(contents, 0);

            for (int i = start + 1; i <= contents.Length;)
            {
                if (i == contents.Length || !Char.IsLetter(contents[i]))
                {
                    string word = contents.Substring(start, i - start).ToLower();
                    words.Add(word);
                    start = FirstCharacterIndex(contents, i);
                    i = start + 1;
                }
                else
                    i++;
            }
        }

        fs.Close();
        sr.Close();

        return words;
    }

    // 寻找字符串s中,从start的位置开始的第一个字母字符的位置
    private static int FirstCharacterIndex(string s, int start)
    {
        for (int i = start; i < s.Length; i++)
            if (Char.IsLetter(s[i]))
                return i;

        return s.Length;
    }
}

两种集合比较

        public static long TestSet(ISet<string> set, List<string> words)
        {
            Stopwatch t = new Stopwatch();
            t.Start();
            foreach (var s in words)
            {
                set.Add(s);
            }
            t.Stop();
            return t.ElapsedMilliseconds;
        }
        static void Main(string[] args)
        {
            Console.WriteLine("双城记");

            List<string> words = TestHelper.ReadFile("测试文件1/双城记.txt");
            Console.WriteLine("词汇量总数:" + words.Count);

            Console.WriteLine();

            Console.WriteLine("链表集合");
            LinkedList1Set<string> linkedList1Set = new LinkedList1Set<string>();
            long t1 = TestSet(linkedList1Set, words);
            Console.WriteLine("不同单词的总数: "+linkedList1Set.Count);
            Console.WriteLine("运行时间: " + t1 + "ms");

            Console.WriteLine();

            Console.WriteLine("有序数组集合");
            SortedArray1Set<string> sortedArray1Set = new SortedArray1Set<string>();
            long t2 = TestSet(sortedArray1Set, words);
            Console.WriteLine("不同单词的总数: " + sortedArray1Set.Count);
            Console.WriteLine("运行时间: " + t2 + "ms");
        }

在这里插入图片描述
可以看到,由有序数组实现的集合性能比链式集合是非常优的

两种字典比较

        //字典(链表和数组)
        public static long TestDicionary(IDictionary<string, int> dic, List<string> words)
        {
            Stopwatch t = new Stopwatch();
            t.Start();
            foreach (var word in words)
            {
                //如果单词不存在字典中,说明是第一次遇见这个单词,频次设为1
                if (!dic.ContainsKey(word))
                    dic.Add(word, 1);
                else//如果已经存在在字典中,那么将单词对应的频次+1
                    dic.Set(word, dic.Get(word) + 1);
            }
            t.Stop();
            return t.ElapsedMilliseconds;
        }

在这里插入图片描述

可以看到,有序数组实现的字典,运行时间更短,这里的差距主要就体现在二分查找和有序查找的区别。

  • 29
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值