集合
集合(set)作为存储数据容器时:
- 它不允许存储相同元素,只能保留一份。
- 能快速帮助我们进行去重操作,过滤掉重复元素。
典型应用
词汇量统计
统计一篇英文文章的总单词数,使用集合进行去重,判断英文文章难度。
创建集合接口
新建Iset接口
namespace AlgorithmTest11_集合ISet { interface Iset<T> { bool IsEmpty { get; }
int Count { get; }
void Add(T t);
void Remove(T t);
bool Contains(T e); } }
|
实现集合接口
使用无序链表LinkedList1Set实现集合接口
using AlgorithmTest08_链表;
namespace AlgorithmTest11_集合ISet { public class LinkedList1Set<T> : Iset<T> { private LinkedList1<T> list; public LinkedList1Set() { list = new LinkedList1<T>(); }
public bool IsEmpty { get { return list.IsEmpty; } }
public int Count { get { return list.Count; } }
public void Add(T t) { if (!list.Contains(t)) { list.AddFirst(t); } }
public bool Contains(T t) { return list.Contains(t); }
public void Remove(T t) { list.Remove(t); } } }
|
创建工具类
创建TestHelper,用来将文件里文本存储到列表
using System; using System.Collections.Generic; using System.IO;
namespace AlgorithmTest11_集合ISet { class TestHelper { public static List<string> ReadFile(string filename) { FileStream fs = new FileStream(filename, FileMode.Open); StreamReader sr = new StreamReader(fs); 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; } 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; } } }
|
添加文档,修改文档属性
测试结果
using System; using System.Collections.Generic; using System.Diagnostics;
namespace AlgorithmTest11_集合ISet { class Program { static void Main(string[] args) { #region 集合 Stopwatch t = new Stopwatch(); Console.WriteLine("双城记"); List<string> words = TestHelper.ReadFile("txt/A Tale Of Two Cities.txt"); Console.WriteLine("总单词数:" + words.Count); LinkedList1Set<string> linkedset = new LinkedList1Set<string>(); t.Start(); foreach (var item in words) { linkedset.Add(item); } t.Stop();
Console.WriteLine("去重后:" + linkedset.Count); Console.WriteLine("执行时长," + t.ElapsedMilliseconds + "ms");
#endregion Console.ReadKey(); } } }
|
用时接近六秒,可以看出顺序查找非常耗时
映射/字典
定义接口
创建IDictionary<Key, Value>
,定义接口
namespace AlgorithmTest12_映射or字典IDictionary { interface IDictionary<Key, Value> { void Add(Key key, Value value); void Remove(Key key); bool ContainsKey(Key key); Value Get(Key key); void Set(Key key, Value newValue); int Count { get; } bool IsEmpty { get; } } }
|
实现接口功能
新建字典专用链表
新建带两个泛型参数的链表
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;
namespace AlgorithmTest12_映射or字典IDictionary { class LinkedList3<Key, Value> { private class Node { public Key key; public Value value; public Node next;
public Node(Key key, Value value, Node next) { this.key = key; this.value = value; this.next = next; } public override string ToString() { return key.ToString() + ":" + value.ToString(); } } private Node head; private int N; public LinkedList3() { head = null; N = 0; } public int Count { get { return N; } } public bool IsEmpty { get { return N == 0; } }
private Node GetNode(Key key) { Node cur = head; while (cur != null) { if (cur.key.Equals(key)) { return cur; } cur = cur.next; } return null; } public void Add(Key key, Value value) { Node node = GetNode(key); if (node == null) { head = new Node(key, value, head); N++; } else { node.value = value; } } public bool Contains(Key key) { return GetNode(key) != null; } public Value Get(Key key) { Node node = GetNode(key); if (node == null) { throw new ArgumentException("键" + key + "不存在"); } else { return node.value; } } public void Set(Key key, Value newValue) { Node node = GetNode(key); if (node == null) { throw new ArgumentException("键" + key + "不存在"); } else { node.value = newValue; } } public void Remove(Key key) { if (head == null) { return; } if (head.key.Equals(key)) { head = head.next; N--; } else { Node cur = head; Node pre = null; while (cur != null) { if (cur.t.Equals(key)) { break; } pre = cur; cur = cur.next; } if (cur != null) { pre.next = pre.next.next; N--; } } } } }
|
实现字典类
新建字典类,通过链表实现字典功能
namespace AlgorithmTest12_映射or字典IDictionary { class LinkedList3Dictionary<Key, Value> : IDictionary<Key, Value> { private LinkedList3<Key, Value> list;
public LinkedList3Dictionary() { list = new LinkedList3<Key, Value>(); }
public int Count { get { return list.Count; } }
public bool IsEmpty { get { return list.IsEmpty; } }
public void Add(Key key, Value value) { list.Add(key, value); }
public bool ContainsKey(Key key) { return list.Contains(key); }
public Value Get(Key key) { return list.Get(key); }
public void Remove(Key key) { list.Remove(key); }
public void Set(Key key, Value newValue) { list.Set(key, newValue); } } }
|
运行调试
using System; using System.Collections.Generic; using System.Diagnostics;
namespace AlgorithmTest12_映射or字典IDictionary { class Program { static void Main(string[] args) { Console.WriteLine("字典双城记"); List<string> words = TestHelper.ReadFile("txt/A Tale Of Two Cities.txt"); Console.WriteLine("总单词数:" + words.Count); Stopwatch t = new Stopwatch(); LinkedList3Dictionary<string, int> dic = new LinkedList3Dictionary<string, int>(); t.Start(); foreach (var key in words) { if (!dic.ContainsKey(key)) { dic.Add(key, 1); } else { dic.Set(key, dic.Get(key) + 1); } } t.Stop(); Console.WriteLine("不同的单词总数: " + dic.Count); Console.WriteLine("city出现次数: " + dic.Get("city")); Console.WriteLine("运行时长: " + t.ElapsedMilliseconds + "ms"); Console.ReadKey(); } } }
|
总结
可以看出查找用时非常久,这是因为Set和Get每次都调用GetNode循环遍历节点,复杂度n。