[译]聊聊C#中的泛型的使用(新手勿入) Seaching TreeVIew WPF 可编辑树Ztree的使用(包括对后台数据库的增删改查) 字段和属性的区别 C# 遍历Dictionary并修改其中

[译]聊聊C#中的泛型的使用(新手勿入)

 

写在前面

今天忙里偷闲在浏览外文的时候看到一篇讲C#中泛型的使用的文章,所以加上本人的理解以及四级没过的英语水平斗胆给大伙进行了翻译,固然在翻译的过程当中发现了一些问题,所以也进行了纠正,固然,原文的地址我放在最下面,若是你的英文水平比较好的话,能够直接直接阅读全文。同时最近建了一个.NET Core实战项目交流群637326624,有兴趣的朋友能够来相互交流。目前.NET Core实战项目之CMS的教程也已经更新了6篇了,目前两到三天更新一篇。javascript

做者:依乐祝
原文地址:http://www.javashuo.com/article/p-ytlwppbl-gq.htmlhtml

介绍

C#和.NET中的泛型程序具备强类型集合的许多优势,并为代码提供更高质量和性能提高。泛型是C#语言和公共语言运行库(CLR)中的一个新功能,它将类型参数的概念引入.NET Framework。类型参数使得设计某些类和方法成为可能,例如,经过使用泛型类型参数T,能够大大简化类型之间的强制转换或装箱操做的过程(装箱、拆箱问题)。说白了,泛型就是经过参数化类型来实如今同一份代码上操做多种数据类型,利用“参数化类型”将类型抽象化,从而实现灵活的复用。每一个集合的详细规范能够在System.Collection.Generic名称空间下找到。前端

通用类C#

装箱和拆箱

.Net定义了两种主要的数据类型来表示变量,也就是传说中的值类型和引用类型。这是须要装箱和拆箱的地方。装箱是一种经过将变量存储到System.Object中来显式地将值类型转换为引用类型的机制。当您装入值时,CLR会将新对象分配到堆中,并将值类型的值复制到该实例中。例如,您建立了一个int类型的变量:java

int a = 20; object b = a; //装箱

相反的操做是拆箱,它是将引用类型转换回值类型的过程。此过程验证接收数据类型是否与装箱类型一致;node

int c = (int)b; // 拆箱

C#编译器能够看到从int到object的赋值,反之亦然。当编译该程序并经过IL解析器检查IL生成的代码时,您会注意到当b被赋值为a时,程序经过在IL中自动插入一个box指令来响应,当c被赋值为b时以下;程序员

IL-opcode.jpg

代码加载常量20并将其存储在本地插槽中;它将值20加载到堆栈中并将其装箱。最后,它将被装箱的20返回到堆栈上,并将其拆箱为int类型ajax

这个过程.NET CLR执行了一系列操做,例如,首先在托管堆中分配一个对象,而后在装箱中将值转换为内存位置,并在拆箱期间将值存储在堆上而且必须转回到堆栈。所以,从性能的角度来看,装箱和拆箱过程在泛型中具备很是重要的意义,由于这个过程若是不使用泛型的话会耗费更多地资源。算法

泛型类

能够经过在类名后面加上符号来定义泛型类。这里没有强制必须将“T”字放在泛型的定义中。您能够在TestClass <>类声明中使用任何单词。数据库

public class TestClass<T> { } 

System.Collection.Generic命名空间下还定义了许多实现了这些关键字接口的类型。下表列出了此命名空间的核心类类型。编程

泛型类 描述
Collection 泛型集合的基类,能够比较两个泛型对象是否相等
Dictionary<TKey, TValue> 键值对的泛型集合
List 可动态调整列表项的大小
Queue 先进先出(FIFO)列表的泛型实现
Stack 后进先出(LIFO)列表的泛型实现

简单的泛型类示例

如下示例显示了一个简单的泛型类型的操做。TestClass 定义一个长度为5的泛型类型数组。Add()方法负责将任何类型的对象添加到集合中,而Indexer属性是循环语句迭代的实现。最后在主类中,咱们使用整形类型来实例化TestClass 类,并使用Add()方法将一些整数类型数据添加到集合中。

using System; using System.Collections.Generic; namespace GenericApp { public class TestClass<T> { // 定义一个长度为5的泛型类型的数组 T[] obj = new T[5]; int count = 0; // 向检讨类型添加数据 public void Add(T item) { //checking length if (count + 1 < 6) { obj[count] = item; } count++; } //foreach语句迭代索引 public T this[int index] { get { return obj[index]; } set { obj[index] = value; } } } class Program { static void Main(string[] args) { //用整形来实例化泛型类 TestClass<int> intObj = new TestClass<int>(); //向集合中添加int数据 intObj.Add(1); intObj.Add(2); intObj.Add(3); //没有装箱 intObj.Add(4); intObj.Add(5); //遍历显示数据 for (int i = 0; i < 5; i++) { Console.WriteLine(intObj[i]); //没有拆箱 } Console.ReadKey(); } } } 

在构建并运行该程序以后,程序的输出以下所示;

简单仿制Example.jpg

泛型的主要特性

泛型类型的一些重要特征使它们相比传统的非泛型类型具备以下的显著特征:

  • 类型安全
  • 性能
  • 二进制代码复用

类型安全

泛型最重要的特征之一是类型安全性。对于非泛型ArrayList类,若是使用对象类型,则能够向集合中添加任何类型,这些类型有时会致使严重的问题。下面的示例显示向ArrayList类型的集合添加一个整数、字符串和对象;

ArrayList obj = new ArrayList(); obj.Add(50); obj.Add("Dog"); obj.Add(new TestClass()); 

如今,若是使用整数对象来使用foreach语句进行遍历的话,当编译器接受到代码,可是由于集合中的全部元素都不是整数,因此会致使运行时异常;

foreach(int i in obj) { Console.WriteLine(i); } 

编程的经验法则是应该尽早检测到错误。对于泛型类Test,泛型类型T定义容许哪些类型。经过使用Test的定义,只能向集合添加整型类型的数据。这时候当Add()方法具备如下无效参数的时候编译器将不编译代码;

Test<int> obj = new Test<int>(); obj.Add(50); obj.Add("Dog"); //编译错误 obj.Add(new TestClass()); //编译错误

性能

在下面的示例中,ArrayList类存储对象,而且定义了Add()方法来存储一些整型参数。所以,整数类型被装箱。当使用foreach语句读取ArrayList中的值时,将发生拆箱。

ArrayList  obj = new ArrayList(); obj.Add(50); //装箱- 值类型转换成引用类型 int x= (int)obj[0]; //拆箱 foreach(int i in obj) { Console.WriteLine(i); // 拆箱 } 

注意:泛型比其余集合(如ArrayList)更快。

代替使用对象类型,TestClass类的泛型类型被定义为int,所以在从编译器动态生成的类中将使用int类型。因此将不会发生装箱和拆箱,以下所示;

TestClass<int> obj = new TestClass<int>(); obj.Add(50); //没有装箱 int x= obj[0]; // 没有拆箱 foreach(int i in obj) { Console.WriteLine(i); //没有拆箱 } 

二进制代码复用

泛型类型提供了一种源代码保护机制。泛型类能够定义一次,而且可使用许多不一样类型来进行实例化。泛型能够在一种CLR支持的语言中定义,并能够被另外一种.NET语言使用。如下TestClass 使用int和string类型进行实例化:

TestClass<int> obj = new TestClass<int>(); obj.Add(50); TestClass<string> obj1 = new TestClass<string>(); Obj1.Add("hello"); 

通用方法

虽然大多数开发人员一般会使用基类库中的现有泛型类型,但也有可能会构建本身的泛型成员和自定义的泛型类型。

本示例的目的是构建一个交换方法,该方法可使用单个类型参数对任何可能的数据类型(基于值或基于引用)进行操做。因为交换算法的性质,传入的参数将做为使用ref关键字修饰的引用类型来进行发送。

using System; using System.Collections.Generic; namespace GenericApp { class Program { //泛型方法 static void Swap<T>(ref T a, ref T b) { T temp; temp = a; a = b; b = temp; } static void Main(string[] args) { //交换两个整形数据 int a = 40, b = 60; Console.WriteLine("Before swap: {0}, {1}", a, b); Swap<int>(ref a, ref b); Console.WriteLine("After swap: {0}, {1}", a, b); Console.ReadLine(); } } } 

编译此泛型方法实现的程序后,输出以下所示;

通用-Methods.jpg

字典

字典也被称为映射或散列表。它表示容许您基于关键字来访问元素的数据结构。字典的一个重要特征是更快的查找; 您能够添加或删除选项而不会产生性能开销。

.Net提供了几个字典类,例如Dictionary <TKey,TValue>。类型参数TKey和TValue分别表示关键字的类型和它能够存储的值。

简单的字典示例

如下示例演示使用泛型的简单字典集合。在此程序中,将建立一个Dictionary类型对象,该对象接受int做为键,字符串做为值。而后咱们将一些字符串值添加到字典集合中,最后显示字典集合元素。

using System; using System.Collections.Generic; namespace GenericApp { public class Program { static void Main(string[] args) { //定义一个字典集合 Dictionary<int,string> dObj = new Dictionary<int,string>(5); //向字典中添加类型 dObj.Add(1,1,"Tom"); dObj.Add(2,"John"); dObj.Add(3, "Maria"); dObj.Add(4, "Max"); dObj.Add(5, "Ram"); //输出数据 for (int i = 1; i <= dObj.Count;i++) { Console.WriteLine(dObj[i]); } Console.ReadKey(); } } } 

如下示例经过定义附加类emp来描述一些更复杂的问题,其中咱们覆盖ToString()方法以显示特定员工的名称和薪水。稍后在Main()方法中,建立一个新的Dictionary <TKey,TValue)的实例,其中键的类型为string,值为emp类型。构造函数分配2个元素的容量。emp对象和做为键的字符串值被添加到字典集合中。最后,使用foreach语句迭代集合元素并显示在屏幕上。

using System; using System.Text; using System.Collections.Generic; namespace GenericApp { public class emp { private string name; private int salary; public emp(string name,int salary) { this.name = name; this.salary = salary; } public override string ToString() { StringBuilder sb = new StringBuilder(200); sb.AppendFormat("{0},{1}",name,salary); return sb.ToString(); } } public class Program { static void Main(string[] args) { //定义一个字典集合 Dictionary<string, emp> dObj = new Dictionary<string, emp>(2); //向字典中添加元素 emp tom = new emp("tom", 2000); dObj.Add("tom",tom); // 键,值 emp john = new emp("john", 4000); dObj.Add("john",john); //print data foreach(Object str in dObj.Values) { Console.WriteLine(str); } Console.ReadKey(); } } } 

队列

队列是一种特殊类型的容器,可确保以FIFO(先进先出)方式访问元素。队列集合最适合实现消息传递的组件。咱们可使用如下语法定义Queue集合对象:

Queue qObj = new Queue();

Queue集合的属性,方法和其余规则定义都位于Sysyem.Collection命名空间下。下表定义了关键成员;

System.Collection.Queue成员 定义
Enqueue() 将对象添加到队列的末尾。
Dequeue() 从队列的开头删除对象。
Peek() 返回队列开头的对象而不删除它。

下面演示了一个基本的队列类型的集合,将一些字符串类型值添加到集合中,最后使用while语句来显示整个集合中的数据 。

using System; using System.Collections; namespace GenericApp { class Program { static void Main(string[] args) { //定义一个队列 Queue qObj = new Queue(); //向队列中添加字符串数据 qObj.Enqueue("Tom"); qObj.Enqueue("Harry"); qObj.Enqueue("Maria"); qObj.Enqueue("john"); //显示队列中的数据 while(qObj.Count !=0 ) { Console.WriteLine(qObj.Dequeue()); } Console.ReadKey(); } } } 

堆栈

Stack集合是LIFO的抽象(后进先出)。咱们可使用如下语法定义Stack集合对象:

Stack qObj = new Stack();

下表说明了堆栈的关键成员;

System.Collection.Stack成员 定义
Contains() 若是在集合中找到特定元素,则返回true。
Clear() 删除集合的全部元素。
Peek() 预览堆栈中的最新元素。
Push() 它将元素推入堆栈。
Pop() 返回并删除堆栈的顶部元素。

如下演示了堆栈集合。首先,将数组类型对象引用到堆栈集合中。而后使用Pop()方法从堆栈中删除集合中元素的值并显示在屏幕上。

using System; using System.Collections; namespace GenericApp { class Program { static void Main(string[] args) { int[] iArray = new int[] {1,2,3,4,5,6,7,8,9,10 }; //定义一个堆栈 Stack sObj = new Stack(iArray); Console.WriteLine("Total items="+sObj.Count); //显示集合数据 for (int i = 0; i < sObj.Count;++i ) { Console.WriteLine(sObj.Pop()); } Console.ReadKey(); } } } 

在使用泛型实现的另外一个示例中,使用Push()方法将5个项添加到堆栈中。而后使用循环迭代输出堆栈中的数据。堆栈的枚举器不会删除数据; 它只是以LIFO方式返回每一个项目,以下所示:

using System; using System.Collections; namespace GenericApp { class Program { static void Main(string[] args) { //定义一个堆栈 Stack sObj = new Stack(); //向集合添加数据 for (int i = 0; i < 5; ++i) { sObj.Push(i+1); } Console.WriteLine("Total items=" + sObj.Count); //打印数据 foreach (int i in sObj) { Console.WriteLine(i); } Console.ReadKey(); } } } 

总结

今天忙里偷闲,在浏览外文的时候看到一篇讲泛型的文章,所以就加上本身的理解进行了相关翻译,也加深了本身对泛型的理解!若是英文比较好的话能够直接访问https://www.c-sharpcorner.com/UploadFile/84c85b/using-generics-with-C-Sharp/ 自行查看!固然,我在翻译的过程当中也发现了文中的一些错误,因此进行了更正!同时最近建了一个.NET Core实战项目交流群637326624,有兴趣的朋友能够来相互交流。目前.NET Core实战项目之CMS的教程也已经更新了6篇了,目前两到三天更新一篇。最后感谢你们的阅读。

 

 

 

Seaching TreeVIew WPF

 

项目中有一个树形结构的资源,须要支持搜索功能,搜索出来的结果仍是须要按照树形结构展现,下面是简单实现的demo。

1.首先建立TreeViewItem的ViewModel,通常状况下,树形结构都包含DisplayName,Deepth,Parent,Children,Id, IndexCode,Visibility等属性,具体代码以下所示:

复制代码
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Collections.ObjectModel;
  4 using System.Linq;
  5 using System.Text;
  6 using System.Threading.Tasks;
  7 using System.Windows;
  8 
  9 namespace TreeViewDemo
 10 {
 11     public class TreeViewItemVM : NotifyPropertyChangedBase
 12     {
 13         public TreeViewItemVM ()
 14         {
 15             Visible = Visibility.Visible;
 16         }
 17 
 18         private TreeViewItemVM parent;
 19         public TreeViewItemVM Parent
 20         {
 21             get
 22             {
 23                 return this.parent;
 24             }
 25             set
 26             {
 27                 if (this.parent != value)
 28                 {
 29                     this.parent = value;
 30                     this.OnPropertyChanged(() => this.Parent);
 31                 }
 32             }
 33         }
 34 
 35         private ObservableCollection<TreeViewItemVM> children;
 36         public ObservableCollection<TreeViewItemVM> Children
 37         {
 38             get
 39             {
 40                 return this.children;
 41             }
 42             set
 43             {
 44                 if (this.children != value)
 45                 {
 46                     this.children = value;
 47                     this.OnPropertyChanged(() => this.Children);
 48                 }
 49             }
 50         }
 51 
 52         private string id;
 53         public string ID
 54         {
 55             get
 56             {
 57                 return this.id;
 58             }
 59             set
 60             {
 61                 if (this.id != value)
 62                 {
 63                     this.id = value;
 64                     this.OnPropertyChanged(() => this.ID);
 65                 }
 66             }
 67         }
 68 
 69         private string indexCode;
 70         public string IndexCode
 71         {
 72             get { return indexCode; }
 73             set
 74             {
 75                 if (indexCode != value)
 76                 {
 77                     indexCode = value;
 78                     this.OnPropertyChanged(() => IndexCode);
 79                 }
 80             }
 81         }
 82 
 83         private string displayName;
 84         public string DisplayName
 85         {
 86             get
 87             {
 88                 return this.displayName;
 89             }
 90             set
 91             {
 92                 if (this.displayName != value)
 93                 {
 94                     this.displayName = value;
 95                     this.OnPropertyChanged(() => this.DisplayName);
 96                 }
 97             }
 98         }
 99 
100         private int deepth;
101         public int Deepth
102         {
103             get
104             {
105                 return this.deepth;
106             }
107             set
108             {
109                 if (this.deepth != value)
110                 {
111                     this.deepth = value;
112                     this.OnPropertyChanged(() => this.Deepth);
113                 }
114             }
115         }
116 
117         private bool hasChildren;
118         public bool HasChildren
119         {
120             get
121             {
122                 return this.hasChildren;
123             }
124             set
125             {
126                 if (this.hasChildren != value)
127                 {
128                     this.hasChildren = value;
129                     this.OnPropertyChanged(() => this.HasChildren);
130                 }
131             }
132         }
133 
134         private NodeType type;
135         public NodeType Type
136         {
137             get { return type; }
138             set
139             {
140                 if (type != value)
141                 {
142                     type = value;
143                     OnPropertyChanged(() => this.Type);
144                 }
145             }
146         }
147 
148         private Visibility visible;
149         public Visibility Visible
150         {
151             get { return visible; }
152             set
153             {
154                 if (visible != value)
155                 {
156                     visible = value;
157                     OnPropertyChanged(() => this.Visible);
158                 }
159             }
160         }
161 
162         public bool NameContains(string filter)
163         {
164             if (string.IsNullOrWhiteSpace(filter))
165             {
166                 return true;
167             }
168 
169             return DisplayName.ToLowerInvariant().Contains(filter.ToLowerInvariant());
170         }
171     }
172 }
复制代码

2.建立TreeViewViewModel,其中定义了用于过滤的属性Filter,以及过滤函数,并在构造函数中初始化一些测试数据,具体代码以下:

复制代码
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Collections.ObjectModel;
  4 using System.ComponentModel;
  5 using System.Linq;
  6 using System.Text;
  7 using System.Threading.Tasks;
  8 using System.Windows.Data;
  9 
 10 namespace TreeViewDemo
 11 {
 12     public class TreeViewViewModel : NotifyPropertyChangedBase
 13     {
 14         public static TreeViewViewModel Instance = new TreeViewViewModel();
 15 
 16         private TreeViewViewModel()
 17         {
 18             Filter = string.Empty;
 19 
 20             Root = new TreeViewItemVM()
 21             {
 22                 Deepth = 0,
 23                 DisplayName = "五号线",
 24                 HasChildren = true,
 25                 Type = NodeType.Unit,
 26                 ID = "0",
 27                 Children = new ObservableCollection<TreeViewItemVM>() { 
 28                     new TreeViewItemVM() { DisplayName = "站台", Deepth = 1, HasChildren = true, ID = "1", Type = NodeType.Region,
 29                         Children = new ObservableCollection<TreeViewItemVM>(){
 30                             new TreeViewItemVM() { DisplayName = "Camera 01", Deepth = 2, HasChildren = false, ID = "3",Type = NodeType.Camera },
 31                             new TreeViewItemVM() { DisplayName = "Camera 02", Deepth = 2, HasChildren = false, ID = "4",Type = NodeType.Camera },
 32                             new TreeViewItemVM() { DisplayName = "Camera 03", Deepth = 2, HasChildren = false, ID = "5",Type = NodeType.Camera },
 33                             new TreeViewItemVM() { DisplayName = "Camera 04", Deepth = 2, HasChildren = false, ID = "6",Type = NodeType.Camera },
 34                             new TreeViewItemVM() { DisplayName = "Camera 05", Deepth = 2, HasChildren = false, ID = "7", Type = NodeType.Camera},
 35                         }},
 36                     new TreeViewItemVM() { DisplayName = "进出口", Deepth = 1, HasChildren = true, ID = "10", Type = NodeType.Region,
 37                         Children = new ObservableCollection<TreeViewItemVM>(){
 38                             new TreeViewItemVM() { DisplayName = "Camera 11", Deepth = 2, HasChildren = false, ID = "13",Type = NodeType.Camera },
 39                             new TreeViewItemVM() { DisplayName = "Camera 12", Deepth = 2, HasChildren = false, ID = "14",Type = NodeType.Camera },
 40                             new TreeViewItemVM() { DisplayName = "Camera 13", Deepth = 2, HasChildren = false, ID = "15",Type = NodeType.Camera },
 41                             new TreeViewItemVM() { DisplayName = "Camera 14", Deepth = 2, HasChildren = false, ID = "16", Type = NodeType.Camera},
 42                             new TreeViewItemVM() { DisplayName = "Camera 15", Deepth = 2, HasChildren = false, ID = "17", Type = NodeType.Camera},
 43                         }},
 44                 }
 45             };
 46 
 47             InitTreeView();
 48         }
 49 
 50         private ObservableCollection<TreeViewItemVM> selectedCameras = new ObservableCollection<TreeViewItemVM>();
 51 
 52         private TreeViewItemVM root;
 53         public TreeViewItemVM Root
 54         {
 55             get
 56             {
 57                 return this.root;
 58             }
 59             set
 60             {
 61                 if (this.root != value)
 62                 {
 63                     this.root = value;
 64                     this.OnPropertyChanged(() => this.Root);
 65                 }
 66             }
 67         }
 68 
 69         /// <summary>
 70         /// 过滤字段
 71         /// </summary>
 72         private string filter;
 73         public string Filter
 74         {
 75             get
 76             {
 77                 return this.filter;
 78             }
 79             set
 80             {
 81                 if (this.filter != value)
 82                 {
 83 
 84                     this.filter = value;
 85                     this.OnPropertyChanged(() => this.Filter);
 86 
 87                     this.Refresh();
 88                 }
 89             }
 90         }
 91 
 92         /// <summary>
 93         /// View
 94         /// </summary>
 95         protected ICollectionView view;
 96         public ICollectionView View
 97         {
 98             get
 99             {
100                 return this.view;
101             }
102             set
103             {
104                 if (this.view != value)
105                 {
106                     this.view = value;
107                     this.OnPropertyChanged(() => this.View);
108                 }
109             }
110         }
111 
112         /// <summary>
113         /// 刷新View
114         /// </summary>
115         public void Refresh()
116         {
117             if (this.View != null)
118             {
119                 this.View.Refresh();
120             }
121         }
122 
123         private bool DoFilter(Object obj)
124         {
125             TreeViewItemVM item = obj as TreeViewItemVM;
126             if (item == null)
127             {
128                 return true;
129             }
130 
131             bool result = false;
132             foreach (var node in item.Children)
133             {
134                 result = TreeItemDoFilter(node) || result;
135             }
136 
137             return result || item.NameContains(this.Filter);
138         }
139 
140         private bool TreeItemDoFilter(TreeViewItemVM vm)
141         {
142             if (vm == null)
143             {
144                 return true;
145             }
146 
147             bool result = false;
148             if (vm.Type == NodeType.Region || vm.Type == NodeType.Unit)
149             {
150                 foreach (var item in vm.Children)
151                 {
152                     result = TreeItemDoFilter(item) || result;
153                 }
154             }
155 
156             if (result || vm.NameContains(this.Filter))
157             {
158                 result = true;
159                 vm.Visible = System.Windows.Visibility.Visible;
160             }
161             else
162             {
163                 vm.Visible = System.Windows.Visibility.Collapsed;
164             }
165 
166             return result;
167         }
168 
169         public void InitTreeView()
170         {
171             this.View = CollectionViewSource.GetDefaultView(this.Root.Children);
172             this.View.Filter = this.DoFilter;
173             this.Refresh();
174         }
175     }
176 }
复制代码

3.在界面添加一个TreeView,并添加一个简单的Style,将ViewModel中必要数据进行绑定:

复制代码
 1 <Window x:Class="TreeViewDemo.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         Title="MainWindow" Height="450" Width="525">
 5     <Window.Resources>
 6         <Style x:Key="style" TargetType="{x:Type TreeViewItem}">
 7             <Setter Property="Template">
 8                 <Setter.Value>
 9                     <ControlTemplate TargetType="{x:Type TreeViewItem}">
10                         <Grid Visibility="{Binding Visible}" Background="{Binding Background}">
11                             <ContentPresenter ContentSource="Header"/>
12                         </Grid>
13                         
14                         <ControlTemplate.Triggers>
15                             <Trigger Property="IsSelected" Value="true">
16                                 <Setter Property="Background" Value="Green"/>
17                             </Trigger>
18                         </ControlTemplate.Triggers>
19                     </ControlTemplate>
20                 </Setter.Value>
21             </Setter>
22         </Style>
23     </Window.Resources>
24     <Grid>
25         <Grid.RowDefinitions>
26             <RowDefinition Height="Auto"/>
27             <RowDefinition Height="*"/>
28         </Grid.RowDefinitions>
29 
30         <TextBox x:Name="searchTxt" Width="200" HorizontalAlignment="Center" Height="40"
31                  Margin="20" Text="{Binding Filter, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
32 
33         <TreeView
34                   Grid.Row="1"
35                   ItemsSource="{Binding View}">
36             <TreeView.ItemTemplate>
37                 <HierarchicalDataTemplate ItemContainerStyle ="{StaticResource style}"  ItemsSource="{Binding Children}">
38                     <Grid Height="25" >
39                         <TextBlock
40                             x:Name="txt"
41                             VerticalAlignment="Center"
42                             Text="{Binding DisplayName}"    
43                             TextTrimming="CharacterEllipsis"
44                             ToolTip="{Binding DisplayName}" />
45                     </Grid>
46                 </HierarchicalDataTemplate>
47             </TreeView.ItemTemplate>
48         </TreeView>
49     </Grid>
50 </Window>
复制代码

4.在给界面绑定具体的数据

复制代码
 1 using System.Windows;
 2 
 3 namespace TreeViewDemo
 4 {
 5     /// <summary>
 6     /// MainWindow.xaml 的交互逻辑
 7     /// </summary>
 8     public partial class MainWindow : Window
 9     {
10         public MainWindow()
11         {
12             InitializeComponent();
13             this.Loaded += MainWindow_Loaded;
14         }
15 
16         void MainWindow_Loaded(object sender, RoutedEventArgs e)
17         {
18             this.DataContext = TreeViewViewModel.Instance;
19         }
20     }
21 }
复制代码

5.运行结果:

 

 

 

可编辑树Ztree的使用(包括对后台数据库的增删改查)

 

找了不少网上关于Ztree的例子和代码才搞定。

首先,关于Ztree的代码不介绍了,网上下载以后,引用下列四个文件就能使用了。

 

 

 

1.关于配置选项。主要经过回调函数来实现向后台发送数据,实现增删改查。

 

复制代码
 1  var setting = {
 2         view: {
 3             addHoverDom: addHoverDom,//显示操做图标
 4             removeHoverDom: removeHoverDom,//移除图标
 5             selectedMulti: false
 6         },
 7         check: {
 8             enable: true
 9         },
10         data: {
11             simpleData: {
12                 enable: true
13             }
14         },
15         callback: {
16             onRename: zTreeOnRename,//修改
17             onRemove: zTreeOnRemove,//删除
18             onClick: zTreeOnClickRight,
19 
20         },
21         edit: {
22             enable: true,
23             showRemoveBtn: true,
24             showRenameBtn: true,
25             removeTitle: "删除",
26             renameTitle: "修改"
27         }
28     };


复制代码
复制代码
 $(document).ready(function () {
        $.ajax({
            url: "GetZtreeJson",
            data: { ProjectId: "@ViewBag.ProjectId" },
            type: "post",
            dataType: "json",
            success: function (data) {
                $.fn.zTree.init($("#test"), setting, data);//实现加载树的方法
            }
        })
        $("#btnReturn").click(function () {
            window.parent.frameReturnByClose();
        });
        //$.fn.zTree.init($("#treeDemo"), setting, zNodes);
    });

    var newCount = 1;
    function addHoverDom(treeId, treeNode) {
        var sObj = $("#" + treeNode.tId + "_span");
        if (treeNode.editNameFlag || $("#addBtn_" + treeNode.tId).length > 0) return;
        var addStr = "<span class='button add' id='addBtn_" + treeNode.tId
            + "' title='add node' onfocus='this.blur();'></span>";
        sObj.after(addStr);
        var btn = $("#addBtn_" + treeNode.tId);
        if (btn) btn.bind("click", function () {
            var zTree = $.fn.zTree.getZTreeObj("test");
   //增长节点的方法
            $.ajax({
                url: "AddNode",
                data: { ParentId: treeNode.id },
                type: "post",
                success: function (data) {
                    if (data.message == "success") {
//此方法是js在前段增长节点方法,必定要经过后台返回的id来增长,否则新增的节点会出现节点id为null的问题 zTree.addNodes(treeNode, { id: data.id, ParentId: treeNode.id, name: "new node" + (newCount++) }); } else { $.messageBox5s('@Resource.Tip', "新增节点失败!联系管理员!"); } } }) return false; }); };
//删除节点 function zTreeOnRemove(event, treeId, treeNode) { { $.ajax({ url: "DeleteNode", type: "post", data: { NodeId: treeNode.id }, success: function (data) { if (data == "success") { } else { $.messageBox5s('@Resource.Tip', "删除节点失败!联系管理员!"); } } }) } } function removeHoverDom(treeId, treeNode) { $("#addBtn_" + treeNode.tId).unbind().remove(); }; //修改节点 function zTreeOnRename(event, treeId, treeNode) { $.ajax({ url: "EditNode", type: "post", data: { NodeId: $.trim(treeNode.id), name: treeNode.name }, success: function (data) { if (data != "success") { $.messageBox5s('@Resource.Tip', "修改节点失败!联系管理员!"); } } }) }; // 树的单击事件 function zTreeOnClickRight(event, treeId, treeNode) { var treeid = treeNode.id; $("#hidId").val(treeid); $("#ifm").attr("src", "FileView?NodeId=" + treeid); } function treeShow(data) { zTreeObj = $.fn.zTree.init($("#test"), setting, data); zTreeObj.expandAll(true); }
复制代码

2.后台处理的方法。。我项目中是使用C#代码写的,mvc框架

 

 

复制代码
 1  [Description("项目资料-树形")]
 2         [KeyCode(Name = "Tree")]
 3         [IsModule]
 4         [SupportFilter(ActionName = "Tree")]
 5         public ActionResult TreeIndex(Guid ProjectId)
 6         {
 7 
 8             ViewBag.ProjectId = ProjectId;
 9             var ProjectCode = IProjectContract.GetProjectInputById(ProjectId).ProjectCode;
10             string count = ProjectResourceContract.CountNumber(ProjectCode);
11             ViewBag.Count = count;
12             return View();
13         }
14      
15         public JsonResult GetZtreeJson(Guid ProjectId)
16         {
17             var list = ProjectResourceContract.GetNodeJsonByProject(ProjectId);
18 
19 
20             return Json((from p in list
21                          select new
22                          {
23                              id = p.Id,
24                              pId = p.pid,
25                              open = "true",
26                              name = p.name
27                          }).ToList());
28         }
29         public JsonResult AddNode(string ParentId)
30         {
31             int sort = ProjectResourceContract.GetLastNodeSortFormParent(ParentId);
32             //string nodeid = ProjectResourceContract.GetCurrentNewNodeId(ParentId);
33             if (sort == 1)
34             {
35                 var node = ProjectResourceContract.GetNodeByNodeId(ParentId);
36                 node.type = "1";
37                 ProjectResourceContract.EditNode(ParentId, node.type);
38             }
39             Guid nodeId = Guid.NewGuid();
40             var ProjectCode = ProjectResourceContract.GetNodeByNodeId(ParentId).ProjectCode;
41             var result = ProjectResourceContract.AddNode(new TB_Project_Nodes()
42             {
43                 Id = nodeId,
44                 name = "New Node" + sort,
45                 type = "2",
46                 pid = ParentId,
47                 sort = sort,
48                 state = "true",
49                 ProjectCode = ProjectCode,
50             });
51             if (result.Successed)
52             {
53                 return Json(new { message = "success", id = nodeId });
54             }
55             else
56             {
57                 return Json("error");
58             }
59         }
60         public JsonResult DeleteNode(string NodeId)
61         {
62             var result = ProjectResourceContract.DeleteNode(NodeId);
63             if (result.Successed)
64             {
65                 return Json("success");
66             }
67             else
68             {
69                 return Json("error");
70             }
71         }
72         public JsonResult EditNode(string NodeId, string name, string path = "", string ProjectCode = "")
73         {
74             OperationResult result;
75             if (!string.IsNullOrEmpty(path))
76             {
77                 path = path.TrimEnd('+');
78 
79                 path = "UpDir/" + ProjectCode + "/施工资料/" + path;
80                 result = ProjectResourceContract.EditNode(NodeId, name, path);
81             }
82             else
83             {
84                 result = ProjectResourceContract.EditNode(NodeId, name, "");
85             }
86             if (result.Successed)
87             {
88                 return Json("success");
89             }
90             else
91             {
92                 return Json("error");
93             }
94         }
复制代码

 

我项目中的状况是须要用ztree来实现建立目录,而后上传施工资料的方法。因此,projectid字段,你们不须要在乎。是项目的id

 

3.给你们看一下个人数据库字段设计,附上关于增删改查操做数据库的代码。

 

 

 这里顶级节点的pid为0,其次projectcode是我项目中使用到的,能够不用考虑。state原本是用于ztree中open配置信息用的。默认展开节点的配置。

type是我用于判断此节点是否包是文件节点用的。(包含子节点的为文件夹节点,没有子节点的就是文件节点)

 

4.serveices代码

复制代码
  1  //获取树全部节点显示
  2         public List<TB_Project_Nodes> GetNodeJsonByProject(Guid ProjectId)
  3         {
  4 
  5 
  6             var project = ProjectsRepository.GetByKey(ProjectId);
  7             string TopNode = project.ProjectCode;
  8             List<TB_Project_Nodes> ALLLIST = NodesRepository.Entities.Where(t => t.ProjectCode == TopNode).ToList();
  9             //var top = NodesRepository.Entities.FirstOrDefault(t => t.Id.ToString() == TopNode);
 10             TB_Project_Nodes top = ALLLIST.FirstOrDefault(t => t.ProjectCode == TopNode&&t.pid=="0");
 11             if (top == null)//第一次建立
 12             {
 13                 TB_Project_Nodes pn = new TB_Project_Nodes() { ProjectCode = TopNode, Id = Guid.NewGuid(), type = "1", pid = "0", sort = 1, name = project.ProjectName, state = "true" };
 14                 NodesRepository.Insert(pn);
 15                 return new List<TB_Project_Nodes>() { pn };
 16             }
 17             else//存在顶级节点
 18             {
 19 
 20                 //List<TB_Project_Nodes> nodes = NodesRepository.Entities.Where(t => t.pid == TopNode).OrderBy(t => t.sort).ToList();//顶级节点下面的一级节点
 21                 List<TB_Project_Nodes> nodes = ALLLIST.Where(t => t.pid == top.Id.ToString()).OrderBy(t => t.sort).ToList();//顶级节点下面的一级节点
 22 
 23                 if (nodes.Count <= 0)//没有子节点
 24                 {
 25                     return new List<TB_Project_Nodes>() { top };
 26                 }
 27                 else//存在子节点,遍历全部的子节点
 28                 {
 29 
 30                     List<TB_Project_Nodes> LIST = new List<TB_Project_Nodes>();
 31                     LIST.Add(top);
 32                     LIST.AddRange(nodes); //添加一级节点
 33            
 34                     LIST = Test(nodes, LIST, ALLLIST);
 35 
 36                     return LIST;
 37                 }
 38 
 39             }
 40 
 41         }
 42         //递归函数---把全部二级节点以及如下全部节点获取
 43         public List<TB_Project_Nodes> Test(List<TB_Project_Nodes> list, List<TB_Project_Nodes> LIST, List<TB_Project_Nodes> ALLLIST)
 44         {
 45             List<TB_Project_Nodes> NEWLIST = new List<TB_Project_Nodes>();
 46             foreach (var item2 in list)
 47             {
 48                 var secondNodes = ALLLIST.Where(t => t.pid == item2.Id.ToString()).OrderBy(t => t.sort).ToList();
 49                 if (secondNodes.Count > 0)
 50                 {
 51 
 52                     NEWLIST.AddRange(secondNodes);
 53                 }
 54             }
 55             LIST.AddRange(NEWLIST);
 56             //已经添加完本级节点
 57             //添加下一级节点
 58             if (NEWLIST.Count > 0)
 59             {
 60                 Test(NEWLIST, LIST, ALLLIST);
 61             }
 62             return LIST;
 63         }
 64         //增长节点信息
 65         public OperationResult AddNode(TB_Project_Nodes node)
 66         {
 67 
 68             int result = NodesRepository.Insert(node);
 69             if (result == 0)
 70             {
 71                 return new OperationResult(OperationResultType.Error, "error");
 72             }
 73             else
 74             {
 75                 return new OperationResult(OperationResultType.Success, "success");
 76             }
 77 
 78         }
 79         /// <summary>
 80         /// 修改节点类型
 81         /// </summary>
 82         /// <param name="NodeId"></param>
 83         /// <param name="type"></param>
 84         /// <returns></returns>
 85         public OperationResult EditNode(string NodeId, string type)
 86         {
 87             var node = NodesRepository.Entities.FirstOrDefault(t => t.Id.ToString() == NodeId);
 88             node.type = type;
 89             int result = NodesRepository.Update(node);
 90             if (result == 0)
 91             {
 92                 return new OperationResult(OperationResultType.Error, "error");
 93             }
 94             else
 95             {
 96                 return new OperationResult(OperationResultType.Success, "success");
 97             }
 98         }
 99 
100         /// <summary>
101         /// 获取父级节点下面最大的一个排序+1
102         /// </summary>
103         /// <param name="ParentId"></param>
104         /// <returns></returns>
105 
106         public int GetLastNodeSortFormParent(string ParentId)
107         {
108             var list = NodesRepository.Entities.Where(t => t.pid == ParentId).OrderByDescending(t => t.sort).ToList();
109             if (list.Count <= 0)
110             {
111                 return 1;
112             }
113             else
114             {
115                 return list[0].sort + 1;
116             }
117         }
118 
119         /// <summary>
120         /// 删除此节点时候,要把下面全部子节点删除
121         /// </summary>
122         /// <param name="NodeId"></param>
123         /// <returns></returns>
124         public OperationResult DeleteNode(string NodeId)
125         {
126             List<TB_Project_Nodes> ALLLIST = NodesRepository.Entities.ToList();
127             // var node = NodesRepository.Entities.FirstOrDefault(t => t.Id.ToString() == NodeId);
128             var node = ALLLIST.FirstOrDefault(T => T.Id.ToString() == NodeId);
129             //获取下面的全部子节点
130             List<TB_Project_Nodes> LIST = new List<TB_Project_Nodes>();
131             LIST.Add(node);
132             var list = ALLLIST.Where(t => t.pid == NodeId).ToList();
133             if (list.Count > 0)
134             {
135                 LIST.AddRange(list);
136                 LIST = Test(list, LIST, ALLLIST);
137             }
138             for (int i = LIST.Count - 1; i >= 0; i--)
139             {
140                 try
141                 {
142                     int result = NodesRepository.Delete(LIST[i].Id);
143                 }
144                 catch (Exception ex)
145                 {
146                     return new OperationResult(OperationResultType.Error, "error");
147                     throw ex;
148                 }
149 
150             }
151 
152             return new OperationResult(OperationResultType.Success, "success");
153 
154         }
复制代码

 

 

今天写一个wpf的demo,用到绑定数据,给控件绑定了数据源,可是数据却没有显示出来,排查代码发现绑定数据源的的成员用的是字段不是属性。

前端代码:

复制代码
<Grid>
  <StackPanel Grid.Row="2" Margin="10">
  <ListBox x:Name="listBox" Height="100">

  </ListBox>
  </StackPanel>
</Grid>
复制代码

 

后台代码:

复制代码
public Window3()
        {
            InitializeComponent();
            List<Employe> list = new List<Employe>()
                {
                    new Employe() { name="jack",age=18},
                    new Employe() { name="bob",age=20},
                     new Employe() { name="alice",age=21}
                };
            listBox.ItemsSource = list;
            listBox.DisplayMemberPath = "name";
            listBox.SelectedValuePath = "age";
        }
复制代码
//实体 
public class Employe
        {
            public string name { get; set; }
            public int age { get; set; }
        }

若是把Employe的name,去掉{get;set;},改成一个字段, public string name;数据就没法绑定了。缘由是属性的访问是由访问器完成的,于是属性能够进行数据绑定。

 

网上的文章有不少,可是好些没说到重点,基本都是说属性能够保护数据安全云云之类,整理了一下,有一下几个区别:

 

相同点:
都是类的成员,属性是类的属性,而字段是类的数据成员

不一样点:
1 属性可进行数据绑定
2 属性可经过set和get方法进行数据安全性检验,而字段不行
3 属性可进行线程同步
public string Name
{
     set{
        lock(this)
        {
        }
     }
}
4 属性能够是抽象的,而字段不行
5 属性能够接口的形式表现
6 基于属性的索引
7 不要直接把字段转化为属性

 

MSDN:

属性与字段

属性与字段均可在对象中存储和检索信息。它们的类似性使得在给定状况下很难肯定哪一个是更好的编程选择。
在如下状况下使用属性过程:
   1. 须要控制设置或检索值的时间和方式时。
   2. 属性有定义完善的一组值须要进行验证时。
   3. 设置值致使对象的状态发生某些明显的变化(如 IsVisible 属性)。
   4. 设置属性会致使更改其余内部变量或其余属性的值时。
   5.必须先执行一组步骤,而后才能设置或检索属性时。
在如下状况下使用字段:
   1. 值为自验证类型时。例如,若是将 True 或 False 之外的值赋给 Boolean 变量,就会发生错误或自动数据转换。
   2. 在数据类型所支持范围内的任何值均有效时。Single 或 Double 类型的不少属性属于这种状况。
   3. 属性是 String 数据类型,且对于字符串的大小或值没有任何约束时

 

 

C# 遍历Dictionary并修改其中的Value

 

C#的Dictionary类型的值,知道key后,value能够修改吗?答案是确定能修改的。我在遍历的过程当中能够修改Value吗?答案是也是确定能修改的,可是不能用For each循环。不然会报如下的Exception.

System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.'

之因此会报Exception是For each自己的问题,和Dictionary不要紧。For each循环不能改变集合中各项的值,若是须要迭代并改变集合项中的值,请用For循环。

你们来看下例子:

复制代码
 1             // defined the Dictionary variable
 2             Dictionary<int, string> td = new Dictionary<int, string>();
 3             td.Add(1, "str1");
 4             td.Add(2, "str2");
 5             td.Add(3, "str3");
 6             td.Add(4, "str4");
 7             // test for
 8             TestForDictionary(td);
 9             // test for each
10             TestForEachDictionary(td);
复制代码
TestForDictionary Code
复制代码
1         static void TestForDictionary(Dictionary<int, string> paramTd)
2         {
3             
4             for (int i = 1;i<= paramTd.Keys.Count;i++)
5             {
6                 paramTd[i] = "string" + i;
7                 Console.WriteLine(paramTd[i]);
8             }
9         }
复制代码
TestForDictionary的执行结果
string1
string2
string3
string4
 
          
TestForEachDictionary Code
复制代码
 1         static void TestForEachDictionary(Dictionary<int, string> paramTd)
 2         {
 3             int forEachCnt = 1;
 4             foreach (KeyValuePair<int,string> item in paramTd)//System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.'
 5             {
 6                 paramTd[item.Key] = "forEach" + forEachCnt;
 7                 Console.WriteLine(paramTd[item.Key]);
 8                 forEachCnt += 1;
 9             }
10         }
复制代码
TestForEachDictionary里的For each会在循环第二次的时候报错,也就是说它会在窗口中打印出“forEach1”后断掉。



学习笔记——异步

 

1.异步同步的定义

同步方法:多个任务一个一个执行,同一时刻系统中只有一个任务在执行

异步方法:发起一个调用,并不等着计算结束,而是直接去运行下一行;刚才的计算,会启动一个新的线程去执行

 

2.异步同步的比较

2.1. 同步方法卡界面,由于UI线程忙于计算;异步多线程方法不卡界面,主线程闲置,计算任务交给子线程在作;

2.2. 同步方法慢,只有一个线程计算;异步多线程方法快,多个线程并发计算;

       多线程的资源消耗更多,线程并非越多越好(资源有限/管理线程也消耗资源)

2.3. 异步多线程是无序的:启动无序 执行时间不肯定  结束无序,,

       因此不要试图经过启动顺序或者时间等待来控制流程

 

3.异步如何控制执行顺序

3.1.回调

//IasyncResult,可用于监视调用进度

//DoSomethingLong方法名称(要执行的操做)

 Action<string> act = this.DoSomethingLong;

 IAsyncResult iAsyncResult = null;

 AsyncCallback callback = ar =>

 {

    // Console.WriteLine(object.ReferenceEquals(ar, iAsyncResult));

     Console.WriteLine(ar.AsyncState);

     Console.WriteLine($"这里是BeginInvoke调用完成以后才执行的。。。{Thread.CurrentThread.ManagedThreadId.ToString("00")}");

 };

 iAsyncResult = act.BeginInvoke("btnAsync_Click", callback, "异步学习");

3.2.等待

//IAsyncResult.IsCompeted肯定异步调用什么时候完成(轮询)

Action<string> act = this.DoSomethingLong;

IAsyncResult iAsyncResult = act.BeginInvoke("btnAsync_Click", null, null);

int i = 1;

while (!iAsyncResult.IsCompleted)//1 卡界面,主线程在等待   2 边等待边作事儿  3有偏差(时间)

{

    if (i < 10)

    {

        Console.WriteLine($"文件上传{i++ * 10}%。。。请等待");

    }

    else

    {

        Console.WriteLine("已完成99%。。。立刻结束");

    }

    Thread.Sleep(200);//偏差时间

}

Console.WriteLine("文件上传成功!!!");

3.3.状态

//使用 IAsyncResult.AsyncWaitHandle 获取 WaitHandle,使用它的 WaitOne 方法将执行一直阻塞到发出 //WaitHandle 信号,而后调用

Action<string> act = this.DoSomethingLong;

IAsyncResult iAsyncResult = act.BeginInvoke("btnAsync_Click", null, null);

//异步变同步(状态)

 iAsyncResult.AsyncWaitHandle.WaitOne();//一直等待任务完成,第一时间进入下一行

iAsyncResult.AsyncWaitHandle.WaitOne(-1);//一直等待任务完成,第一时间进入下一行

//最多等待1000ms,超时控制

iAsyncResult.AsyncWaitHandle.WaitOne(1000);//最多等待1000ms,不然就进入下一行,能够作一些超时控制

//调用 BeginInvoke 后可随时调用 EndInvoke 方法;若是异步调用未完成,EndInvoke 将一直阻塞到

//异步调用完成。

act.EndInvoke(iAsyncResult);//等待

 

4.其余相关知识

任何的异步多线程,都是跟委托相关。委托中的Invoke方法 是同步的。BeginInvoke开始一个异步的请求,调用线程池中一个线程来执行。

4.1.异步获取返回值

Func<int, string> func = i => i.ToString();

IAsyncResult iAsyncResult = func.BeginInvoke(DateTime.Now.Year, ar =>

 {

     string resultIn = func.EndInvoke(ar);//对于每一个异步操做,只能调用一次 EndInvoke。

     Console.WriteLine($"This is {ar.AsyncState} 的异步调用结果 {resultIn}");

 }, "异步参数");

//string result = func.EndInvoke(iAsyncResult);//获取返回值

 

 

程序员常说的「哈希表」是个什么鬼?

 
「哈希表」主要做用在于高效查找。 在编程实现中,经常面临着两个问题:存储和查找,存储和查找的效率每每决定了整个程序的效率。 脑补下,你在家里忘记了指甲刀放在哪里,一般要在你家全部抽屉中顺序寻找,直到找到,最差状况下,有N个抽屉,你就要打开N个抽屉。这种存储方式叫数组,查找方法称为「遍历」。 脑补下,你是一个整理控,全部物品必须分门别类放入整理箱,再将整理箱编号,好比1号放入针线,2号放入证件,3号放入细软。这种存储和查找方式称为「哈希」,若是这个时候要查找护照,你不准要再翻全部抽屉,直接可在2号整理箱中获取,一般只用一次查找便可,如何编号整理箱,称为哈希算法。 一样是查找,差距怎么那么大涅~,假设咱们有100亿条数据记录,那差距就变得明显,遍历须要查找最多100亿次,最少1次,哈希只需1次。 让咱们正式介绍哈希和哈希算法,哈希也称散列,哈希表是一种与数组、链表等不一样的数据结构,与他们须要不断的遍历比较来查找的办法,哈希表设计了一个映射关系f(key)= address,根据key来计算存储地址address,这样能够1次查找,f既是存储数据过程当中用来指引数据存储到什么位置的函数,也是未来查找这个位置的算法,叫作哈希算法。 让咱们举个例子,好比下面这几我的物,按数组存储: 余罪(133123111243)=>傅老大(13888888888)=>沈嘉文(13452342349)=>大胸姐(13890380934) 这样我要找到大胸姐的电话号码,须要顺序查找对比整个数组,第一个余罪,不是,第二个不是,第三个不是,直到第四个找到大胸姐。 若是以hash存储呢?首先让咱们来看看如何设计哈希算法,哈希算法能够随意设计,教科书上通常会说如下几种方法:直接定址发,平方取中法,除数取余法,哈希算法的本质上是计算一个数字,若是用这几种方法讲解会稍显晦涩,咱们假设咱们的哈希算法是取姓名的首字母。因此f(余罪) = y, f(傅老大) = f,f(沈嘉文) = s,f(大胸姐) = d。 构建的hash表以下: a b c y .133123111243 d .13890380934 g z 位置7 f .13888888888 s .13452342349 咱们看到他们分别以姓名首字母的位置插入到这一张表格中,这样咱们构建了这样一个Key-Value表格,此表就是哈希表,也称为Hash Table。将来,当咱们要查找余罪的时候,经过计算,余罪在y位置,能够经过1次查找,找到这条记录,也即手机号。 这个时候有客官问了,那以首字母为哈希函数的话,应该有不少好比以y的姓名啊,这个时候就不是一次查找了吧,其实有不少条记录都映射到一个位置上,称为哈希冲突。 哈希冲突是跟哈希函数的设计正相关的,你的随机性越大,那么产生哈希冲突的可能性越小,在小几率下,若是还有冲突怎么办,这个时候要作些有损的设计,好比若是有两个首字母为y的姓名,那么能够接到余罪的后面,当查找的时候,须要先查找到y,而后再顺序查找,以下所示: a b c y .133123111243 1332232323于谦 d .13890380934 g z 位置7 f .13888888888 s .13452342349 还有一些解决哈希冲突的办法叫「哈希再哈希」,也就是针对第一次哈希的结果再进行一次hash来减少冲突的几率。 这就是Hash表,首先Ta是一种数据结构,是一种效率极高的查找方式,哈希表的核心在于哈希函数的设计,哈希冲突了没关系,咱们要增长随机性以及对冲突进行适当的有损化的处理。
相关文章
相关标签/搜索