数据结构-单链表
简单单链表
涉及知识点:
- 接口IEnumerable<T>,IEnumerator<T>, ICollection<T>,IEquatable<T>
- 泛型where使用
- 索引器
先上代码( //-_- )
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace SingleLinkedList 8 { 9 /// <summary> 10 /// 单链表节点对象 11 /// </summary> 12 public class NodeObj<T> 13 where T : IEquatable<T> 14 { 15 //下一个节点 16 public NodeObj<T> nextNode; 17 18 //节点值 19 public T value; 20 21 /// <summary> 22 /// 构造一个节点 23 /// </summary> 24 /// <param name="value">头对象的值</param> 25 public NodeObj(T value) 26 { 27 this.value = value; 28 } 29 } 30 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace SingleLinkedList 8 { 9 /// <summary> 10 /// 单链表 11 /// </summary> 12 /// <typeparam name="T"></typeparam> 13 public class SingleLinkedList<T> : IEnumerable<T>, ICollection<T> 14 where T : IEquatable<T> 15 { 16 //头节点 17 private NodeObj<T> headNode; 18 19 #region 构造函数 20 /// <summary> 21 /// 构造一个空的单链表 22 /// </summary> 23 public SingleLinkedList() { } 24 25 /// <summary> 26 /// 构造一个指定头的单链表 27 /// </summary> 28 /// <param name="value">单链表头节点的值</param> 29 public SingleLinkedList(T value) 30 { 31 NodeObj<T> node = new NodeObj<T>(value); 32 this.headNode = node; 33 } 34 35 /// <summary> 36 /// 构造一个指定头的单链表 37 /// </summary> 38 /// <param name="value">头节点</param> 39 public SingleLinkedList(NodeObj<T> node) 40 { 41 this.headNode = node; 42 } 43 #endregion 44 45 //索引器 46 public T this[int index] 47 { 48 get { return GetNodeByIndex(index).value; } 49 } 50 51 /// <summary> 52 /// 通过索引取得节点 53 /// </summary> 54 /// <param name="index">索引,从0开始</param> 55 /// <returns></returns> 56 public NodeObj<T> GetNodeByIndex(int index) 57 { 58 //初始索引 59 int i = 0; 60 //总长度 61 int count = this.Count; 62 //索引超出集合范围 63 if (index < 0 || index > count) 64 { 65 throw new Exception("索引超出集合范围"); 66 } 67 68 NodeObj<T> node = headNode; 69 while (node != null) 70 { 71 if (i == index) 72 { 73 return node; 74 } 75 node = node.nextNode; 76 i++; 77 } 78 79 return null; 80 } 81 82 /// <summary> 83 /// 找到值在集合中首次出现的位子 84 /// </summary> 85 /// <param name="item">值</param> 86 /// <returns>集合所在索引,未找到返回-1</returns> 87 public int GetFirstIndex(T item) 88 { 89 int index = -1; 90 for (int i = 0; i < this.Count; i++) 91 { 92 if (GetNodeByIndex(i).value.Equals(item)) 93 { 94 index = i; 95 break; 96 } 97 } 98 99 return index; 100 } 101 102 /// <summary> 103 /// 找到值在集合中最后一次出现的位子 104 /// </summary> 105 /// <param name="item">值</param> 106 /// <returns>集合所在索引,未找到返回-1</returns> 107 public int GetLastIndex(T item) 108 { 109 int index = -1; 110 for (int i = this.Count - 1; i >= 0; i--) 111 { 112 if (GetNodeByIndex(i).value.Equals(item)) 113 { 114 index = i; 115 break; 116 } 117 } 118 119 return index; 120 } 121 122 123 #region 实现接口IEnumerable 124 IEnumerator<T> IEnumerable<T>.GetEnumerator() 125 { 126 return new SingleLinkedListEnumerator(this); 127 } 128 129 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 130 { 131 return new SingleLinkedListEnumerator(this); 132 } 133 #endregion 134 135 #region 实现接口ICollection 136 137 public int Count 138 { 139 get 140 { 141 int count = 0; 142 143 NodeObj<T> node = headNode; 144 while (node != null) 145 { 146 node = node.nextNode; 147 count++; 148 } 149 return count; 150 } 151 } 152 153 bool ICollection<T>.IsReadOnly 154 { 155 get { return false; } 156 } 157 158 public void Add(T item) 159 { 160 NodeObj<T> node = new NodeObj<T>(item); 161 //根节点为空 162 if (this.headNode == null) 163 { 164 this.headNode = node; 165 return; 166 } 167 168 NodeObj<T> lastNode = headNode; 169 while (node.nextNode != null) 170 { 171 node = node.nextNode; 172 } 173 lastNode.nextNode = node; 174 175 } 176 177 public void Clear() 178 { 179 this.headNode = null; 180 } 181 182 public bool Contains(T item) 183 { 184 NodeObj<T> node = headNode; 185 while (node != null) 186 { 187 if (node.value.Equals(item)) 188 { 189 return true; 190 } 191 node = node.nextNode; 192 } 193 return false; 194 } 195 196 public void CopyTo(T[] array, int arrayIndex) 197 { 198 try 199 { 200 NodeObj<T> node = headNode; 201 int index = arrayIndex; 202 while (node != null) 203 { 204 array[index] = node.value; 205 node = node.nextNode; 206 } 207 } 208 catch (Exception e) 209 { 210 throw e; 211 } 212 } 213 214 public bool Remove(T item) 215 { 216 bool result = false; 217 218 NodeObj<T> node = headNode; 219 while (node != null) 220 { 221 //下一个节点匹配 222 if (node.nextNode.value.Equals(item)) 223 { 224 225 if (node.nextNode.nextNode != null) 226 { 227 //下一个节点 还存在 下一个节点 228 node.nextNode = node.nextNode.nextNode; 229 } 230 else 231 { 232 //下一个节点 不存在 下一个节点 233 node.nextNode = null; 234 } 235 result = true; 236 } 237 node = node.nextNode; 238 } 239 240 return result; 241 } 242 243 #endregion 244 245 public struct SingleLinkedListEnumerator : IEnumerator<T> 246 { 247 //集合 248 private SingleLinkedList<T> obj; 249 250 //开始索引 251 private int index; 252 253 /// <summary> 254 /// 构造一个单链表的枚举对象 255 /// </summary> 256 /// <param name="obj"></param> 257 public SingleLinkedListEnumerator(SingleLinkedList<T> obj) 258 { 259 this.obj = obj; 260 this.index = -1; 261 } 262 263 /// <summary> 264 /// 集合当前元素 265 /// </summary> 266 public T Current 267 { 268 get { return obj[this.index]; } 269 } 270 271 /// <summary> 272 /// 释放 273 /// </summary> 274 public void Dispose() 275 { 276 this.obj = null; 277 } 278 279 /// <summary> 280 /// 指向到下一个元素 281 /// </summary> 282 /// <returns></returns> 283 public bool MoveNext() 284 { 285 if (index < obj.Count-1) 286 { 287 this.index++; 288 return true; 289 } 290 else 291 { 292 return false; 293 } 294 } 295 296 /// <summary> 297 /// 重置指向 298 /// </summary> 299 public void Reset() 300 { 301 index = -1; 302 } 303 304 object System.Collections.IEnumerator.Current 305 { 306 get { return obj[this.index]; } 307 } 308 } 309 310 } 311 }
自定义集合支持foreach
foreach会调用对象的GetEnumerator()方法,该方法需要返回IEnumerator对象(这里没有强制要求继承IEnumerable,只要有GetEnumerator方法即可)
- IEnumerable 公开枚举数,只有一个方法GetEnumerator(),返回一个IEnumerator对象,IEnumerable<T>是对应的泛型版本
- IEnumerator有一个属性(Current集合当前元素),2个方法(MoveNext移动到集合下一个元素,Reset重置指向),IEnumerator<T> 是对应泛型版本,同时继承了IDisposable(定义一种释放资源的方法)
ICollection<T>接口
该接口用于统一对泛型集合的操作,这样是其他人用自定义集合就像使用c#中的其他集合一样方便
IEquatable<T>
同时还有 IComparable<T>,IComparer<T>
官方的描述是IEquatable :指示当前对象是否等于同一类型的另一个对象。
IComparer:比较两个对象并返回一个值,指示一个对象是小于、等于还是大于另一个对象。
IComparable:定义一种特定于类型的通用比较方法,值类型或类通过实现此方法对其实例进行排序。
第一个用来比较2个对象是否相等,第二个用来比较大小,第三个用来排序,但是个人感觉第二个和第三个实际用起来基本没差别
泛型where使用
在泛型中使用where限制类型 T 的范围
索引器
使用索引器,可以像访问数组一样使用索引访问集合中元素,索引器的索引数据类型可自定
这里实现了一个非常简单的单链表,c#提供了双链表可供使用 System.Collections.Generic.LinkedList<T>