二叉树

二叉树

本篇纯属娱乐,源于整理代码,发现还曾实现过遍历二叉树。

虽然.NET/C#中的各种集合类已经实现了最优的排序设计,但了解基本的算法实现有助于软件开发中的各种权衡和选择。
比如,如果你实现过B+树排序和查找,并将树节点序列化至二进制文件块,则你应该已经了解了各种数据库索引的基本设计。

什么是二叉树?

http://en.wikipedia.org/wiki/Binary_tree

二叉树节点类定义

View Code
 1   /// <summary>
  2   /// 二叉树节点
  3   /// </summary>
  4   /// <typeparam name="T">The item type</typeparam>
  5   public class BinaryTreeNode<T>
  6   {
  7     #region Constructors
  8 
  9     /// <summary>
 10     /// 二叉树节点
 11     /// </summary>
 12     public BinaryTreeNode()
 13     {
 14     }
 15 
 16     /// <summary>
 17     /// 二叉树节点
 18     /// </summary>
 19     /// <param name="value">节点中的值</param>
 20     public BinaryTreeNode(T value)
 21     {
 22       this.Value = value;
 23     }
 24 
 25     /// <summary>
 26     /// 二叉树节点
 27     /// </summary>
 28     /// <param name="value">节点中的值</param>
 29     /// <param name="parent">节点的父节点</param>
 30     public BinaryTreeNode(T value, BinaryTreeNode<T> parent)
 31     {
 32       this.Value = value;
 33       this.Parent = parent;
 34     }
 35 
 36     /// <summary>
 37     /// 二叉树节点
 38     /// </summary>
 39     /// <param name="value">节点中的值</param>
 40     /// <param name="parent">节点的父节点</param>
 41     /// <param name="left">节点的左节点</param>
 42     /// <param name="right">节点的右节点</param>
 43     public BinaryTreeNode(T value, 
 44       BinaryTreeNode<T> parent, 
 45       BinaryTreeNode<T> left, 
 46       BinaryTreeNode<T> right)
 47     {
 48       this.Value = value;
 49       this.Right = right;
 50       this.Left = left;
 51       this.Parent = parent;
 52     }
 53 
 54     #endregion
 55 
 56     #region Properties
 57 
 58     /// <summary>
 59     /// 节点值
 60     /// </summary>
 61     public T Value { get; set; }
 62 
 63     /// <summary>
 64     /// 父节点
 65     /// </summary>
 66     public BinaryTreeNode<T> Parent { get; set; }
 67 
 68     /// <summary>
 69     /// 左节点
 70     /// </summary>
 71     public BinaryTreeNode<T> Left { get; set; }
 72 
 73     /// <summary>
 74     /// 右节点
 75     /// </summary>
 76     public BinaryTreeNode<T> Right { get; set; }
 77 
 78     /// <summary>
 79     /// 是否为根节点
 80     /// </summary>
 81     public bool IsRoot { get { return Parent == null; } }
 82 
 83     /// <summary>
 84     /// 是否为叶子节点
 85     /// </summary>
 86     public bool IsLeaf { get { return Left == null && Right == null; } }
 87 
 88     /// <summary>
 89     /// 是否为可访问的
 90     /// </summary>
 91     internal bool Visited { get; set; }
 92 
 93     #endregion
 94 
 95     #region Public Overridden Functions
 96 
 97     /// <summary>
 98     /// Returns a <see cref="System.String"/> that represents this instance.
 99     /// </summary>
100     /// <returns>
101     /// A <see cref="System.String"/> that represents this instance.
102     /// </returns>
103     public override string ToString()
104     {
105       return Value.ToString();
106     }
107 
108     #endregion
109   }

二叉树类实现

View Code
1   /// <summary>
  2   /// 二叉树
  3   /// </summary>
  4   /// <typeparam name="T">二叉树中节点内容类型</typeparam>
  5   [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
  6   public class BinaryTree<T> : ICollection<T>, IEnumerable<T> where T : IComparable<T>
  7   {
  8     #region Constructor
  9 
 10     /// <summary>
 11     /// 二叉树
 12     /// </summary>
 13     public BinaryTree()
 14     {
 15       NumberOfNodes = 0;
 16     }
 17 
 18     /// <summary>
 19     /// 二叉树
 20     /// </summary>
 21     /// <param name="root">二叉树根节点</param>
 22     public BinaryTree(BinaryTreeNode<T> root)
 23       : this()
 24     {
 25       this.Root = root;
 26     }
 27 
 28     #endregion
 29 
 30     #region Properties
 31 
 32     /// <summary>
 33     /// 树的根节点
 34     /// </summary>
 35     public BinaryTreeNode<T> Root { get; set; }
 36 
 37     /// <summary>
 38     /// 树中节点的数量
 39     /// </summary>
 40     protected int NumberOfNodes { get; set; }
 41 
 42     /// <summary>
 43     /// 树是否为空
 44     /// </summary>
 45     public bool IsEmpty { get { return Root == null; } }
 46 
 47     /// <summary>
 48     /// 获取树中节点的最小值
 49     /// </summary>
 50     public T MinValue
 51     {
 52       get
 53       {
 54         if (IsEmpty)
 55           return default(T);
 56 
 57         BinaryTreeNode<T> minNode = Root;
 58         while (minNode.Left != null)
 59           minNode = minNode.Left;
 60 
 61         return minNode.Value;
 62       }
 63     }
 64 
 65     /// <summary>
 66     /// 获取树中节点的最大值
 67     /// </summary>
 68     public T MaxValue
 69     {
 70       get
 71       {
 72         if (IsEmpty)
 73           return default(T);
 74 
 75         BinaryTreeNode<T> maxNode = Root;
 76         while (maxNode.Right != null)
 77           maxNode = maxNode.Right;
 78 
 79         return maxNode.Value;
 80       }
 81     }
 82 
 83     #endregion
 84 
 85     #region IEnumerable<T> Members
 86 
 87     /// <summary>
 88     /// Returns an enumerator that iterates through the collection.
 89     /// </summary>
 90     /// <returns>
 91     /// A <see cref="T:System.Collections.Generic.IEnumerator`1"></see> 
 92     /// that can be used to iterate through the collection.
 93     /// </returns>
 94     public IEnumerator<T> GetEnumerator()
 95     {
 96       foreach (BinaryTreeNode<T> node in Traverse(Root))
 97       {
 98         yield return node.Value;
 99       }
100     }
101 
102     #endregion
103 
104     #region IEnumerable Members
105 
106     /// <summary>
107     /// Returns an enumerator that iterates through a collection.
108     /// </summary>
109     /// <returns>
110     /// An <see cref="T:System.Collections.IEnumerator"/> 
111     /// object that can be used to iterate through the collection.
112     /// </returns>
113     IEnumerator IEnumerable.GetEnumerator()
114     {
115       foreach (BinaryTreeNode<T> node in Traverse(Root))
116       {
117         yield return node.Value;
118       }
119     }
120 
121     #endregion
122 
123     #region ICollection<T> Members
124 
125     /// <summary>
126     /// 新增节点
127     /// </summary>
128     /// <param name="item">The object to add to the 
129     /// <see cref="T:System.Collections.Generic.ICollection`1"></see>.</param>
130     /// <exception cref="T:System.NotSupportedException">The 
131     /// <see cref="T:System.Collections.Generic.ICollection`1"></see> 
132     /// is read-only.</exception>
133     public void Add(T item)
134     {
135       if (Root == null)
136       {
137         Root = new BinaryTreeNode<T>(item);
138         ++NumberOfNodes;
139       }
140       else
141       {
142         Insert(item);
143       }
144     }
145 
146     /// <summary>
147     /// 清除树
148     /// </summary>
149     public void Clear()
150     {
151       Root = null;
152     }
153 
154     /// <summary>
155     /// 树中是否包含此节点
156     /// </summary>
157     /// <param name="item">The object to locate in the 
158     /// <see cref="T:System.Collections.Generic.ICollection`1"></see>.</param>
159     /// <returns>
160     /// true if item is found in the 
161     /// <see cref="T:System.Collections.Generic.ICollection`1"></see>; otherwise, false.
162     /// </returns>
163     public bool Contains(T item)
164     {
165       if (IsEmpty)
166         return false;
167 
168       BinaryTreeNode<T> currentNode = Root;
169       while (currentNode != null)
170       {
171         int comparedValue = currentNode.Value.CompareTo(item);
172         if (comparedValue == 0)
173           return true;
174         else if (comparedValue < 0)
175           currentNode = currentNode.Left;
176         else
177           currentNode = currentNode.Right;
178       }
179 
180       return false;
181     }
182 
183     /// <summary>
184     /// 将树中节点拷贝至目标数组
185     /// </summary>
186     /// <param name="array">The array.</param>
187     /// <param name="arrayIndex">Index of the array.</param>
188     public void CopyTo(T[] array, int arrayIndex)
189     {
190       T[] tempArray = new T[NumberOfNodes];
191       int counter = 0;
192       foreach (T value in this)
193       {
194         tempArray[counter] = value;
195         ++counter;
196       }
197       Array.Copy(tempArray, 0, array, arrayIndex, Count);
198     }
199 
200     /// <summary>
201     /// 树中节点的数量
202     /// </summary>
203     public int Count
204     {
205       get { return NumberOfNodes; }
206     }
207 
208     /// <summary>
209     /// 树是否为只读
210     /// </summary>
211     public bool IsReadOnly
212     {
213       get { return false; }
214     }
215 
216     /// <summary>
217     /// 移除节点
218     /// </summary>
219     /// <param name="item">节点值</param>
220     /// <returns>是否移除成功</returns>
221     public bool Remove(T item)
222     {
223       BinaryTreeNode<T> node = Find(item);
224       if (node == null)
225         return false;
226 
227       List<T> values = new List<T>();
228       foreach (BinaryTreeNode<T> l in Traverse(node.Left))
229       {
230         values.Add(l.Value);
231       }
232       foreach (BinaryTreeNode<T> r in Traverse(node.Right))
233       {
234         values.Add(r.Value);
235       }
236 
237       if (node.Parent.Left == node)
238       {
239         node.Parent.Left = null;
240       }
241       else
242       {
243         node.Parent.Right = null;
244       }
245 
246       node.Parent = null;
247 
248       foreach (T v in values)
249       {
250         this.Add(v);
251       }
252 
253       return true;
254     }
255 
256     #endregion
257 
258     #region Private Functions
259 
260     /// <summary>
261     /// 查找指定值的节点
262     /// </summary>
263     /// <param name="value">指定值</param>
264     /// <returns>
265     /// 指定值的节点
266     /// </returns>
267     protected BinaryTreeNode<T> Find(T value)
268     {
269       foreach (BinaryTreeNode<T> node in Traverse(Root))
270         if (node.Value.Equals(value))
271           return node;
272       return null;
273     }
274 
275     /// <summary>
276     /// 遍历树
277     /// </summary>
278     /// <param name="node">遍历搜索的起始节点</param>
279     /// <returns>
280     /// The individual items from the tree
281     /// </returns>
282     [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
283     protected IEnumerable<BinaryTreeNode<T>> Traverse(BinaryTreeNode<T> node)
284     {
285       // 遍历左子树
286       if (node.Left != null)
287       {
288         foreach (BinaryTreeNode<T> left in Traverse(node.Left))
289           yield return left;
290       }
291 
292       // 中序遍历二叉树, 顺序是 左子树,根,右子树
293       yield return node;
294 
295       // 遍历右子树
296       if (node.Right != null)
297       {
298         foreach (BinaryTreeNode<T> right in Traverse(node.Right))
299           yield return right;
300       }
301     }
302 
303     /// <summary>
304     /// 插入节点
305     /// </summary>
306     /// <param name="value">插入的节点值</param>
307     protected void Insert(T value)
308     {
309       // 从根节点开始比较
310       BinaryTreeNode<T> currentNode = Root;
311       
312       while (true)
313       {
314         if (currentNode == null)
315           throw new InvalidProgramException("The current tree node cannot be null.");
316 
317         // 比较当前节点与新节点的值
318         int comparedValue = currentNode.Value.CompareTo(value);
319         if (comparedValue < 0)
320         {
321           // 当前节点值小于新节点值
322           if (currentNode.Left == null)
323           {
324             currentNode.Left = new BinaryTreeNode<T>(value, currentNode);
325             ++NumberOfNodes;
326             return;
327           }
328           else
329           {
330             currentNode = currentNode.Left;
331           }
332         }
333         else if (comparedValue > 0)
334         {
335           // 当前节点值大于新节点值
336           if (currentNode.Right == null)
337           {
338             currentNode.Right = new BinaryTreeNode<T>(value, currentNode);
339             ++NumberOfNodes;
340             return;
341           }
342           else
343           {
344             currentNode = currentNode.Right;
345           }
346         }
347         else
348         {
349           // 当前节点值等于新节点值
350           currentNode = currentNode.Right;
351         }
352       }
353     }
354 
355     #endregion
356   }

使用举例

复制代码
 1   class Program
 2   {
 3     static void Main(string[] args)
 4     {
 5       Console.ForegroundColor = ConsoleColor.Green;
 6 
 7       BinaryTree<string> tree = new BinaryTree<string>();
 8       tree.Add("Dennis");
 9       tree.Add("Gao");
10       tree.Add("Is");
11       tree.Add("A");
12       tree.Add("C#");
13       tree.Add("Programmer");
14 
15       Console.WriteLine("Root Node Is : " + tree.Root.ToString());
16       Console.WriteLine();
17 
18       foreach (var node in tree)
19       {
20         Console.WriteLine(node);
21       }
22 
23       Console.ReadKey();
24     }
25   }
复制代码

中序遍历二叉树

C#生成MongoDB中的ObjectId

 

ObjectId介绍

在MongoDB中,文档(document)在集合(collection)中的存储需要一个唯一的_id字段作为主键。这个_id默认使用ObjectId来定义,因为ObjectId定义的足够短小,并尽最大可能的保持唯一性,同时能被快速的生成。

ObjectId 是一个 12 Bytes 的 BSON 类型,其包含:

  1. 4 Bytes 自纪元时间开始的秒数
  2. 3 Bytes 机器描述符
  3. 2 Bytes 进程ID
  4. 3 Bytes 随机数

从定义可以看出,在同一秒内,在不同的机器上相同进程ID条件下,非常有可能生成相同的ObjectId。
同时可以根据定义判断出,在给定条件下,ObjectId本身即可描述生成的时间顺序

ObjectId的存储使用Byte数组,而其展现需将Byte数组转换成字符串进行显示,所以通常我们看到的ObjectId都类似于:

ObjectId("507f191e810c19729de860ea")

C#定义ObjectId类

View Code
 1   public class ObjectId
  2   {
  3     private string _string;
  4 
  5     public ObjectId()
  6     {
  7     }
  8 
  9     public ObjectId(string value)
 10       : this(DecodeHex(value))
 11     {
 12     }
 13 
 14     internal ObjectId(byte[] value)
 15     {
 16       Value = value;
 17     }
 18 
 19     public static ObjectId Empty
 20     {
 21       get { return new ObjectId("000000000000000000000000"); }
 22     }
 23 
 24     public byte[] Value { get; private set; }
 25 
 26     public static ObjectId NewObjectId()
 27     {
 28       return new ObjectId { Value = ObjectIdGenerator.Generate() };
 29     }
 30 
 31     public static bool TryParse(string value, out ObjectId objectId)
 32     {
 33       objectId = Empty;
 34       if (value == null || value.Length != 24)
 35       {
 36         return false;
 37       }
 38 
 39       try
 40       {
 41         objectId = new ObjectId(value);
 42         return true;
 43       }
 44       catch (FormatException)
 45       {
 46         return false;
 47       }
 48     }
 49 
 50     protected static byte[] DecodeHex(string value)
 51     {
 52       if (string.IsNullOrEmpty(value))
 53         throw new ArgumentNullException("value");
 54 
 55       var chars = value.ToCharArray();
 56       var numberChars = chars.Length;
 57       var bytes = new byte[numberChars / 2];
 58 
 59       for (var i = 0; i < numberChars; i += 2)
 60       {
 61         bytes[i / 2] = Convert.ToByte(new string(chars, i, 2), 16);
 62       }
 63 
 64       return bytes;
 65     }
 66 
 67     public override int GetHashCode()
 68     {
 69       return Value != null ? ToString().GetHashCode() : 0;
 70     }
 71 
 72     public override string ToString()
 73     {
 74       if (_string == null && Value != null)
 75       {
 76         _string = BitConverter.ToString(Value)
 77           .Replace("-", string.Empty)
 78           .ToLowerInvariant();
 79       }
 80 
 81       return _string;
 82     }
 83 
 84     public override bool Equals(object obj)
 85     {
 86       var other = obj as ObjectId;
 87       return Equals(other);
 88     }
 89 
 90     public bool Equals(ObjectId other)
 91     {
 92       return other != null && ToString() == other.ToString();
 93     }
 94 
 95     public static implicit operator string(ObjectId objectId)
 96     {
 97       return objectId == null ? null : objectId.ToString();
 98     }
 99 
100     public static implicit operator ObjectId(string value)
101     {
102       return new ObjectId(value);
103     }
104 
105     public static bool operator ==(ObjectId left, ObjectId right)
106     {
107       if (ReferenceEquals(left, right))
108       {
109         return true;
110       }
111 
112       if (((object)left == null) || ((object)right == null))
113       {
114         return false;
115       }
116 
117       return left.Equals(right);
118     }
119 
120     public static bool operator !=(ObjectId left, ObjectId right)
121     {
122       return !(left == right);
123     }
124   }

C#实现ObjectId的生成器

View Code
1   internal static class ObjectIdGenerator
 2   {
 3     private static readonly DateTime Epoch = 
 4       new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
 5     private static readonly object _innerLock = new object();
 6     private static int _counter;
 7     private static readonly byte[] _machineHash = GenerateHostHash();
 8     private static readonly byte[] _processId = 
 9       BitConverter.GetBytes(GenerateProcessId());
10 
11     public static byte[] Generate()
12     {
13       var oid = new byte[12];
14       var copyidx = 0;
15 
16       Array.Copy(BitConverter.GetBytes(GenerateTime()), 0, oid, copyidx, 4);
17       copyidx += 4;
18 
19       Array.Copy(_machineHash, 0, oid, copyidx, 3);
20       copyidx += 3;
21 
22       Array.Copy(_processId, 0, oid, copyidx, 2);
23       copyidx += 2;
24 
25       Array.Copy(BitConverter.GetBytes(GenerateCounter()), 0, oid, copyidx, 3);
26 
27       return oid;
28     }
29 
30     private static int GenerateTime()
31     {
32       var now = DateTime.UtcNow;
33       var nowtime = new DateTime(Epoch.Year, Epoch.Month, Epoch.Day, 
34         now.Hour, now.Minute, now.Second, now.Millisecond);
35       var diff = nowtime - Epoch;
36       return Convert.ToInt32(Math.Floor(diff.TotalMilliseconds));
37     }
38 
39     private static byte[] GenerateHostHash()
40     {
41       using (var md5 = MD5.Create())
42       {
43         var host = Dns.GetHostName();
44         return md5.ComputeHash(Encoding.Default.GetBytes(host));
45       }
46     }
47 
48     private static int GenerateProcessId()
49     {
50       var process = Process.GetCurrentProcess();
51       return process.Id;
52     }
53 
54     private static int GenerateCounter()
55     {
56       lock (_innerLock)
57       {
58         return _counter++;
59       }
60     }
61   }

使用举例

复制代码
 1   class Program
 2   {
 3     static void Main(string[] args)
 4     {
 5       Console.ForegroundColor = ConsoleColor.Red;
 6 
 7       ObjectId emptyOid = ObjectId.Empty;
 8       Console.WriteLine(emptyOid);
 9 
10       Console.WriteLine();
11       Console.ForegroundColor = ConsoleColor.Green;
12 
13       for (int i = 0; i < 10; i++)
14       {
15         ObjectId oid = ObjectId.NewObjectId();
16         Console.WriteLine(oid);
17       }
18 
19       Console.WriteLine();
20       Console.ForegroundColor = ConsoleColor.Blue;
21 
22       ObjectId existingOid;
23       ObjectId.TryParse("507f191e810c19729de860ea", out existingOid);
24       Console.WriteLine(existingOid);
25 
26       Console.ReadKey();
27     }
28   }
复制代码

 
 
 
标签: C#MongoDB
原文地址:https://www.cnblogs.com/Leo_wl/p/3039793.html