链表增、删、改、查的例子:
增:Add(int index,E e)方法 (1)如果索引为零,那就把新节点作为新的头部节点,而新节点的引用指向就是原来的头部节点 (2)如果不为零,就遍历到索引-1,因为要把新节点的引用指向索引的结点,然后把新节点设成索引-1的引用指向 改:Set(int index,E e)方法 (1)直接 for 循环到索引的位置,然后把索引到的链表元素设成新的值 查:Containa(E e)方法 (1)直接 while 循环(把指向下一个引用的本身换成自己),然后判断在这过程中有没有引用是传进来的值 删:RemoveAt(int index) 通过索引来删除遍历到的值 (1)如果索引为零,那就把头部节点的引用指向设为头部节点 (2)如果不为零,把索引 - 1的结点,其引用指向就是要删掉的值,然后把要删掉的值的引用指向设为索引-1的引用结点 Remove(E e)通过输入的值,删除链表中的值 (1)判断输入的值是否是头部节点,是:将头部节点的引用指向设为头部节点,然后长度自减。 否:声明 两个 Node 变量(cur[存储下一个的引用]、pre[存储上一个的引用]),while 循环(只要下一个引用不是空) ,在这其中再判断 cur 是否为输入的值。while之外再次判断将上一个引用的结点的结点,其引用指向设为上一个引用的引用结点。
class LinkedList1<E>{private class Node{public E e;public Node next;/// <summary>/// 指向下一个节点的方法/// </summary>/// <param name="e"></param>/// <param name="next"></param>public Node(E e, Node next){this.e = e;this.next = next;}/// <summary>/// 头部的节点/// </summary>/// <param name="e"></param>public Node(E e){this.e = e;this.next = null;}public override string ToString(){return e.ToString();}}private Node head;private int N;public LinkedList1() {head = null;N = 0;}public int Count{get { return N; }}public bool IsEmpty{get { return N == 0; }}public void Add(int index,E e){if (index < 0 || index > N)throw new ArgumentException("非法索引");if (index == 0){//如果index 等于零,那就说明我们将进行头部节点的添加//原来的头部节点就是新节点的引用指向//新节点就是新的头部结点//Node node = new Node(e);//node.next = head;//head = node;head = new Node(e, head);}else{Node pro = head;for (int i = 0; i < index - 1; i++)pro = pro.next;//.next 意思是:结点的引用指向//将 for循环遍历后的头部结点指向的引用 变为 新节点的引用指向//Node node = new Node(e); //新的链表=>只有头部节点//node.next = pro.next; //新链表的头部节点的引用指向 赋值成 旧链表的头部节点的引用指向//pro.next = node; //然后旧链表的头部节点的引用指向 赋值成 新链表的头部节点pro.next = new Node(e, pro.next);}N++;}public void AddFrist(E e){Add(0, e);}public void AddLast(E e){Add(N, e);}public E Get(int index){if (index < 0 || index > N)throw new ArgumentException("非法索引");Node cur = head;for (int i = 0; i < index; i++)cur = cur.next;return cur.e;}public E GetFirst(){return Get(0);}public E GetLast(){return Get(N - 1);}public void Set(int index, E newE){if (index < 0 || index > N)throw new ArgumentException("非法索引");Node cur = head;for (int i = 0; i < index; i++)cur = cur.next;cur.e = newE;}public bool Containa(E e){Node cur = head;while (cur != null){if (cur.e.Equals(e))return true;cur = cur.next;}return false;}public void Remove(E e){if (head == null)return;if (head.e.Equals(e)){head = head.next;N--;}else{Node cur = head;Node pre = null;while (cur != null){if (cur.e.Equals(e))break;pre = cur;cur = cur.next;}if (cur != null){pre.next = pre.next.next;N--;}}}public override string ToString(){StringBuilder res = new StringBuilder();Node cur = head;while (cur!=null){res.Append(cur + "->");cur = cur.next;}res.Append("null");return res.ToString();}}class Program{private static void Main(string[] args){LinkedList1<int> l = new LinkedList1<int>();for (int i = 0; i < 5; i++){l.AddFrist(i);Console.WriteLine(l);}l.AddLast(666);Console.WriteLine(l);l.Add(2, 1000);Console.WriteLine(l);l.Set(2, 200);Console.WriteLine(l);//4->3->200->2->1->0->666->nulll.Remove(200);Console.WriteLine(l);l.RemoveLast();Console.WriteLine(l);l.RemoveFirst();Console.WriteLine(l);Console.ReadKey();}}
运行结果:

基于无序链表实现集合、映射
集合:集合(Set)作为存储数据的容器时: 特点:他不允许存储相同元素,只能保留一份 应用:能快速的帮助我们进行去重操作,过滤掉重复的元素
映射:指两个元素之间相互“对应”的关系 在C#中用字典(Dictionary)来表示,储存键值对的数据
//集合
//以下方法的调用,都只是调用Linked List1 封装好的方法而已
//具体实现的逻辑看 LinkedList1
class LinkedLIstISet<E>:ISet<E>
{
LinkedList1<E> list;
public LinkedLIstISet()
{
list = new LinkedList1<E>();
}
public int Count { get { return list.Count; } }
public bool IsEmpty { get { return list.IsEmpty; } }
public void Add(E e)
{
if (!Contains(e))
list.AddFrist(e);
}
public bool Contains(E e)
{
return list.Containa(e);
}
public void Remove(E e)
{
list.Remove(e);
}
}
class Program
{
static void Main(string[] args)
{
Stopwatch t = new Stopwatch();
Console.WriteLine("双城记");
List<string> words=TestHelper.ReadFile("测试文件1/双城记.txt");
Console.WriteLine("总单词数: "+words.Count);
LinkedList1Set<string> set = new LinkedList1Set<string>();
t.Start();
foreach (var word in words)
set.Add(word); //添加的过程中会进行去重的操作,不允许添加重复元素
t.Stop();
Console.WriteLine("不同单词的总数: "+set.Count);
Console.WriteLine("运行时间: "+t.ElapsedMilliseconds);
Console.Read();
}
}
//集合
//映射
class LinkedList3Dictionary<Key,Value>:IDictionary<Key,Value>
{
private LinkedList3<Key,Value> List;
public LinkedList3Dictionary()
{
List = new LinkedList3<Key, Value>();
}
/// <summary>
/// 由于是直接返回《linked List3 的容量》,所以是O(1)
/// </summary>
public int Count { get { return List.Count; } }
/// <summary>
/// 同样直接返回《linked List的容量》
/// </summary>
public bool IsEmpty { get { return List.IsEmpty; } }
/// <summary>
/// 因为《linked List3 类中 Add 方法 是在头部进行添加数据的》
/// 所以时间复杂度是O(1)
/// </summary>
public void Add(Key key, Value value)
{
List.Add(key, value);
}
/// <summary>
/// 通过遍历《linkedList3.GetNode》数据,来查找链表中是否有 Key 值
/// 所以时间复杂度是O(N)
/// </summary>
public bool ContainKey(Key key)
{
return List.Contains(key);
}
/// <summary>
/// 同样是通过《linkedList3.GetNode》来获取键(key),然后返回键相应的值
/// 所以时间复杂度是O(N)
/// </summary>
public Value Get(Key key)
{
return List.Get(key);
}
/// <summary>
/// 通过传进去的键(key),判断《LinkedList3》中对应的键
/// 然后进行删除
/// 所以还是从头开始遍历,时间复杂度O(N)
/// </summary>
public void Remove(Key key)
{
List.Remove(key);
}
/// <summary>
/// 同样通过《linkedList3.GetNode》来找到对应的键(key)
/// 然后将 key.value = NewValue
/// 时间复杂度O(N)
/// </summary>
public void Set(Key key, Value NewValue)
{
List.Set(key, NewValue);
}
}
class Program
{
private static void Main(string[] args)
{
Console.WriteLine("双城记");
List<string> words = TestHelper.ReadFile("测试文件1/双城记.txt");
Console.WriteLine("总单词数:" + words.Count);
Stopwatch t = new Stopwatch();
LinkedList3Dictionary<string, int> dic = new LinkedList3Dictionary<string, int>();
t.Start();
foreach (var word in words)
{
if (!dic.ContainKey(word))
dic.Add(word, 1);
else
dic.Set(word, dic.Get(word) + 1);
}
t.Stop();
Console.WriteLine("不同单词的总数:" + dic.Count);
Console.WriteLine("City出现的频次:"+dic.Get("city"));
Console.WriteLine("运行时间" + t.ElapsedMilliseconds);
Console.ReadKey();
}
}
//映射
集合运行结果:
映射运行结果:

