c#之字典学习笔记
来源:互联网 发布:台州房销售数据下载 编辑:程序博客网 时间:2024/05/21 15:51
字典表示一种非常复杂的数据结构,这种数据结构允许按照某个键来访问元素。字典也称为映射或散列表。字典的主要特性是能根据键快速查找值。也可以自由添加和删除元素,这有点像List类,但没有在内存中移动元素的性能开销。字典的性能取决于GetHashCode()方法的实现代码。
(1).键值
用作字典中键的类型必须重写Object类的GetHashCode()方法。只要字典类需要确定元素的位置,它就要调用GetHashCode()方法。GetHashCode()方法返回的int由字典用于计算在对应位置放置元素的索引。
GetHashCode()方法的实现代码必须满足以下要求:
①相同的对象应总是返回相同的值
②不同的对象可以返回相同的值。
③它应执行得比较快,计算的开销不大
④它不能抛出异常
⑤它应至少使用一个实例字段
⑥散列代码值应平均分布在int可以存储的整个数字范围上
⑦散列代码最好在对象的生存期中不发生变化。
其中要使散列代码值平均分布在整数的取值范围内,因为如果两个键返回的散列代码值会得到相同的索引,字典类就必须寻找最近的可用空闲位置来存储第二个数据项,这需要进行一定的搜索。这会降低性能,如果在排序的时候许多键都有相同的索引,这类冲突就更可能出现。根据Microsoft的部分算法的工作方式,当计算出来的散列代码值评价分布在int.MinValue和int.Max.Value之间时,这种风险会降低到最小。
除了实现GetHashCode()方法之外,键类型还必须实现IEquatable.Equals()方法,或重写Object类的Equals()方法。因为不同的键对象可能返回相同的散列代码,所以字典使用Equals()方法来比较键。字典检查两个键A和B是否相等,并调用A.Equals(B)方法。这表示必须确保下述条件总是成立:如果A.Equals(B)方法返回true,则A.GetHashCode()和B.GetHashCode()方法必须总是返回相同的散列代码。
当为Equals()方法提供了重写版本,但没有提供GetHashCode()方法的重写版本,C#编译器会显示一个编译警告。
如果需要使用的键类型没有实现IEquatable接口,并根据存储在字典中的键值重载GetHashCode()方法,就可以创建一个实现IEqualityComparer接口的比较器。IEqualityComparer接口定义了GetHashCode()和Equals()方法,并将传递的对象作为参数,因此可以提供与对象类型不同的实现方式。Dictionary
using System;using System.Collections.Generic;[Serializable]public class EmployeeIdException : Exception{ public EmployeeIdException(string message) : base(message) { }}[Serializable]public struct EmployeeId : IEquatable<EmployeeId>{ private readonly char prefix; private readonly int number; public EmployeeId(string id) { if (id == null) throw new ArgumentNullException("id"); prefix = (id.ToUpper())[0]; int numLength = id.Length-1; try { number = int.Parse(id.Substring(1, numLength > 6 ? 6 : numLength)); } catch (FormatException) { throw new EmployeeIdException("Invalid EmployeeId format"); } } public override string ToString() { return prefix.ToString() + string.Format("{0:000000}", number); } public override int GetHashCode() { //由于数字是可变的,因此员工可以取1~190000的一个值。这并没有填满整数取值范围。 //可以将数字向左移动16位,再与原来的数字进行异或操作,最后将结果乘以十六进制数15051505 //以上处理可以使散列代码在整数取值区域上的分布相当均匀。 //不理解16跟0x15051505怎么得到的。 return (number ^ number << 16) * 0x15051505; } public bool Equals(EmployeeId other) { if (other == null) return false; return (prefix == other.prefix && number == other.number); } public override bool Equals(object obj) { return Equals((EmployeeId)obj); } public static bool operator ==(EmployeeId left, EmployeeId right) { return left.Equals(right); } public static bool operator !=(EmployeeId left, EmployeeId right) { return !(left == right); }}[Serializable]public class Employee{ private string name; private decimal salary; private readonly EmployeeId id; public Employee(EmployeeId id, string name, decimal salary) { this.id = id; this.name = name; this.salary = salary; } public override string ToString() { return String.Format("{0}:{1,-20} {2:c}", id.ToString(), name, salary); } static void Main() { //构造函数指定了31个元素的容量。注意容量一般是素数。如果指定了一个不是素数的值。 //Dictionary<TKey,TValue>类会使用传递给构造函数的整数后面紧接着的一个素数,来指定容量。 var employees = new Dictionary<EmployeeId, Employee>(31); var idKyle = new EmployeeId("T3755"); var kyle = new Employee(idKyle, "Kyle Bush", 5443890.00m); employees.Add(idKyle, kyle); Console.WriteLine(kyle.ToString()); var idCarl = new EmployeeId("F3547"); var carl = new Employee(idCarl, "Carl Edwards", 5597120.00m); employees.Add(idCarl, carl); Console.WriteLine(carl.ToString()); var idJimmie = new EmployeeId("C3386"); var jimmie = new Employee(idJimmie, "Jimmie Johnson", 5024710.00m); employees.Add(idJimmie, jimmie); Console.WriteLine(jimmie.ToString()); var idDale = new EmployeeId("C3323"); var dale = new Employee(idDale, "Dale Earnhardt Jr.", 3522740.00m); employees[idDale] = dale; Console.WriteLine(dale.ToString()); var idJeff = new EmployeeId("C3235"); var jeff = new Employee(idJeff, "Jeff Burton", 3879540.00m); employees[idJeff] = jeff; Console.WriteLine(jeff.ToString()); while (true) { Console.Write("Enter employee id (X to exit) > "); var userInput = Console.ReadLine(); userInput = userInput.ToUpper(); if (userInput == "X") break; EmployeeId id; try { id = new EmployeeId(userInput); Employee employee; if (!employees.TryGetValue(id, out employee)) { Console.WriteLine("Employee with id {0} does not exist", id); } else { Console.WriteLine(employee); } } catch (EmployeeIdException ex) { Console.WriteLine(ex.Message); } } }}
using System;using System.Collections.Generic;namespace csharpTest{ class Program { public static int GetNumber(int number) { return (number ^ number << 16) * 0x15051505; } static void Main(string[] args) { List<int> data = new List<int>() { 0, int.MinValue, 0, int.MaxValue }; for (int i = 1; i <= 190000;++i) { int num = GetNumber(i); if(data[1] < num) { data[0] = i; data[1] = num; } if (data[3] > num) { data[2] = i; data[3] = num; } } Console.WriteLine("{0} {1} {2} {3}",data[0],data[1],data[2],data[3]); Console.WriteLine("{0} {1}", int.MinValue, int.MaxValue); } }}
(2) Lookup
Dictionary < TKey,TValue > 类支持每个键关联一个值。Lookup < TKey,TElement > 非常类似于Dictionary < TKey,TValue > 类,但它把键映射到一个值集上。这个类在程序集System.Core中实现,用System.Linq名称空间定义。Lookup < TKey,TElement > 类不能像一般的字典那样创建,而必须调用ToLookup()方法,该方法返回一个Lookup < TKey,TElement > 对象。ToLookup()方法是一个扩展方法,它可以用于实现了IEnumerable接口的所有类。
using System;using System.Linq;using System.Collections.Generic;[Serializable]public class Racer{ public string FirstName{get;set;} public string LastName{get;set;} public string Country{get;set;} public int Wins{get;set;} public Racer(string firstName,string lastName,string country = null,int wins = 0) { this.FirstName = firstName; this.LastName = lastName; this.Country = country; this.Wins = wins; } public override string ToString() { return String.Format("{0} {1}", FirstName, LastName); }}public class Test{ static void Main() { var racers = new List<Racer>(); racers.Add(new Racer("Jacques", "Villeneuve", "Canada", 11)); racers.Add(new Racer("Alan", "Jones", "Australia", 12)); racers.Add(new Racer("Jackie", "Stewart", "United Kingdom", 10)); racers.Add(new Racer("James", "Hunt", "United Kingdom", 10)); racers.Add(new Racer("Jack", "Brabham", "Australia", 14)); var lookupRacers = racers.ToLookup(r => r.Country); foreach(Racer r in lookupRacers["Australia"]) { Console.WriteLine(r); } }}
(3)有序字典
SortedDictionary < TKey,TValue > 类是一个二叉搜索树,其中的元素根据键来排序。该键类型必须实现IComparable接口。如果键的类型不能排序,可以创建一个实现了IComparer接口的比较器,将比较器用作有序字典的构造函数的一个参数。
SortedDictionary < TKey,TValue > 类和SortedList < TKey,TValue > 类的功能类似。但因为SortedList < TKey,TValue > 实现为一个基于数组的列表,而SortedDictionary < TKey,TValue > 类实现为一个字典,所以它们有不同的特征。
SortedList < TKey,TValue > 类使用的内存比SortedDictionary < TKey,TValue > 类少
SortedDictionary < TKey,TValue > 类的元素插入和删除速度比较快。
在用已排好序的数据填充集合时,若不需要修改容量,SortedList < TKey,TValue > 类比较快。
- c#之字典学习笔记
- python 学习笔记之字典
- Python学习笔记之字典
- python 学习笔记之字典
- Symbian学习笔记9 之 流字典
- Oracle学习笔记之二 数据字典
- Python学习笔记-数据结构之字典
- swift学习笔记之数组与字典
- iOS学习笔记之字典排序
- C#回顾学习笔记三十六:字典集合Dictionary
- C#学习日记 字典
- c#之字典
- python学习笔记 字典
- 数据字典学习笔记
- python-字典学习笔记
- 字典树 学习笔记
- python字典学习笔记
- Python 学习笔记-字典
- HTML5 canvas画板的制作
- Aerospike数据库实战(三) -- Aerospike数据库压力测试报告
- iOS 点击图片放大效果
- fopen函数的使用
- C++ fstream二进制读写示例
- c#之字典学习笔记
- LLVM 加载bc文件
- 使用Faster-Rcnn进行目标检测(实践篇)
- UbuntuServer/CentOS安装require CD-ROM问题
- 自定义View之CircleImageView
- DecelerateInterpolator(float factor)
- bzoj 3011: [Usaco2012 Dec]Running Away From the Barn (可并堆)
- for循环删除(ArrayList.remove)及改进方法及对象在内存中的理解
- 【Get深一度】MATLAB中对信号做 fft 后为何还要做 fftshift ?