[譯]聊聊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是一種數據結構,是一種效率極高的查找方式,哈希表的核心在於哈希函數的設計,哈希衝突了沒關係,咱們要增長隨機性以及對衝突進行適當的有損化的處理。
相關文章
相關標籤/搜索