原文链接: http://blog.csdn.net/shanyongxu/article/details/47024865

链表

LinkedList<T>集合类没有非泛型类的版本,它是一个双向链表,他的元素指向元素的前一个与后一个元素.

链表的有点事:如果要插入一个元素到链表的中间位置,效率很高,因为如果插入一个元素,只需要修改上一个元素的Next与下一个元素的Previous的引用即可.

链表的缺点是,链表只能是一个接着一个访问,这样就要用更长的时间来查找定位位于链表中间的元素.

LinkedListNode<T>被LinkedList<T>类包含,用LinkedListNode<T>类,可以获得元素的上一个与下一个元素的引用.

LinkedList<T>的属性

属性名

说明

Count

返回链表中的元素个数

First

返回链表中的第一个节点,其返回类型是一个节点类LinkedListNode<T>,用它可以迭代集合中的其他节点

Last

返回最后一个节点

LinkedList<T>的方法

方法名

说明

AddAfter(),

AddBefore(),

AddFirst(),

AddLast

使用这西方法,可以在变表中添加元素分别是链表的头部和尾部,还有一个节点的前面与后面

Remove(),

RemoveFirst(),

RemoveLast()

First与Last分别删除链表的头部元素与尾部元素,Remove是删除指定的一个匹配对象

CLear()

清除所有的元素

Contains()

搜索一个元素,如果找到返回True,找不到返回False

Find()

从链表头开始找一个元素,并返回他的节点类,LinkedListNode<T>

FindLast()

与Find()类似,不同的是从尾部来搜

案例:使用一个链表LinkedList<T>和一个列表List<T>,链表包含文档,与我们上一个队列的但文档有一个优先级,文档按优先级来排序,如查多个文档优先级相同.则按插入时间决定优先排序.

链表添加文档对象时,它们应放在优先级相同的最后一个文档后面,例如:要加一个文档,优先级数是3,那么,我们应放在3级文档组的最后一个,因为此时它是最晚插入的.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace 链表

{

class Program

{

static void Main(string[] args)

{

PriorityDocumentManager man = new PriorityDocumentManager();

man.AddDocument(new Document("一", "nihao", 8));

man.AddDocument(new Document("二", "nihao", 3));

man.AddDocument(new Document("三", "nihao", 4));

man.AddDocument(new Document("四", "nihao", 8));

man.AddDocument(new Document("五", "nihao", 1));

man.AddDocument(new Document("六", "nihao", 9));

man.AddDocument(new Document("七", "nihao", 1));

man.AddDocument(new Document("八", "nihao", 1));

man.DispalyAllNodes();

Console.Read();

}

}

public class Document

{

private string title;

public string Title

{

get { return title; }

set { title = value; }

}

private string content;

public string Content

{

get { return content; }

set { content = value; }

}

private int priority;

public int Priority

{

get { return priority; }

set { priority = value; }

}

public Document(string title, string content, byte priority)

{

this.title = title;

this.content = content;

this.priority = priority;

}

}

public class PriorityDocumentManager

{

//documentList包含所有的文档

private readonly LinkedList<Document> documentList;

//priorityNodes包含最多10个元素的引用

private readonly List<LinkedListNode<Document>> priorityNodes;

public PriorityDocumentManager()

{

//初始化

documentList = new LinkedList<Document>();

priorityNodes = new List<LinkedListNode<Document>>(10);

for (int i = 0; i < 10; i++)

{

priorityNodes.Add(new LinkedListNode<Document>(null));

}

}

/// <summary>

/// 添加文档

/// </summary>

/// <param name="d">要添加的文档对象</param>

public void AddDocument(Document d)

{

if (d==null)

{

//如果文档为空,抛出异常

throw new ArgumentNullException("d");

}

//调用添加方法

AddDocumentToPriorityNode(d, d.Priority);

}

private void AddDocumentToPriorityNode(Document doc, int priority)

{

if (priority>9||priority<0)

{

throw new ArgumentException("优先级异常");

}

if (this.priorityNodes[priority].Value==null)

{

priority--;

if (priority>=0)

{

AddDocumentToPriorityNode(doc, priority);

}

else

{

this.documentList.AddLast(doc);

this.priorityNodes[doc.Priority] = this.documentList.Last;

}

return;

}

else

{

LinkedListNode<Document> priorityNode=this.priorityNodes[priority];

if (priority==doc.Priority)

{

this.documentList.AddAfter(priorityNode, doc);

this.priorityNodes[doc.Priority] = priorityNode.Next;

}

else

{

LinkedListNode<Document> firstPriorityNode = priorityNode;

while (firstPriorityNode.Previous != null && firstPriorityNode.Previous.Value.Priority == priorityNode.Value.Priority)

{

firstPriorityNode = priorityNode.Previous;

}

this.documentList.AddBefore(firstPriorityNode, doc);

priorityNodes[doc.Priority] = firstPriorityNode.Previous;

}

}

}

public void DispalyAllNodes()

{

foreach (Document doc in this.documentList)

{

Console.WriteLine("文档标题:{0} 文档内容:{1} 优先级:{2}", doc.Title, doc.Content, doc.Priority);

}

}

}

}

从上可以看出,

链表不仅能在列表中存储元素,还可以给每个元素存储下一个元素和上一个元素的信息.这就是LinkedList<T>包含LinkedListNode<T>类型的元素而定原因.使用LinkedListNode<T>类,可以获得列表中的下一个元素和上一个元素.

案例:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace 链表测试

{

public struct test

{

public string name;

public string num;

}

public struct test1

{

public test st;

public string name;

}

class Program

{

static void Main(string[] args)

{

LinkedList<test> t = new LinkedList<test>();

test t1, t2;

test1 tt1, tt2;

t1.name = "t1";

t2.name = "t2";

t1.num = "1";

t2.num = "2";

t.AddFirst(t1);

t.AddFirst(t2);

tt1.st = t1;

tt2.st = t2;

tt1.name = "tt1";

tt2.name = "tt2";

LinkedList<test1> tt = new LinkedList<test1>();

tt.AddFirst(tt1);

tt.AddFirst(tt2);

LinkedListNode<test1> current11 = tt.FindLast(tt1);

test1 tr1 = current11.Value;

LinkedListNode<test> current1 = t.FindLast(t1);

test tr = current1.Value;

string[] words = { "the", "fox", "jumped", "over", "the", "dog" };

LinkedList<string> sentence = new LinkedList<string>(words);

Display(sentence);

Console.WriteLine("sentence.Contain(\"jumped\")={0}", sentence.Contains("jumped"));

sentence.AddFirst("today");

Display(sentence);

LinkedListNode<string> mark1 = sentence.First;

sentence.RemoveFirst();

sentence.AddLast(mark1);

Display(sentence);

sentence.RemoveLast();

sentence.AddLast("yesterday");

Display(sentence);

mark1 = sentence.Last;

sentence.RemoveLast();

sentence.AddFirst(mark1);

Display(sentence);

sentence.RemoveFirst();

LinkedListNode<string> current = sentence.FindLast("the");

Display(sentence);

sentence.AddAfter(current, "old");

sentence.AddAfter(current, "lazy");

DIsplayNode(current);

current = sentence.Find("fox");

DIsplayNode(current);

sentence.AddBefore(current, "quick");

sentence.AddBefore(current, "brown");

DIsplayNode(current);

mark1 = current;

LinkedListNode<string> mark2 = current.Previous;

current = sentence.Find("dog");

DIsplayNode(current);

try

{

sentence.AddBefore(current, mark1);

}

catch (InvalidOperationException ex)

{

Console.WriteLine("Exception message: {0}", ex.Message);

}

sentence.Remove(mark1);

sentence.AddBefore(current, mark1);

DIsplayNode(current);

sentence.Remove(current);

DIsplayNode(current);

sentence.AddAfter(mark2, current);

DIsplayNode(current);

sentence.Remove("old");

Display(sentence);

sentence.RemoveLast();

ICollection<string> icoll = sentence;

icoll.Add("rhinoceros");

Display(sentence);

Console.WriteLine("\nCopy the list to an array.");

string[] sArray = new string[sentence.Count];

sentence.CopyTo(sArray, 0);

foreach (var item in sArray)

{

Console.WriteLine(item);

}

sentence.Clear();

}

private static void Display(LinkedList<string> words)

{

foreach (var item in words)

{

Console.WriteLine(item + " ");

}

Console.WriteLine();

}

private static void DIsplayNode(LinkedListNode<string> node)

{

if (node.List == null)

{

Console.WriteLine("Node \"{0}\" is not in a list.", node.Value);

return;

}

StringBuilder result = new StringBuilder("(" + node.Value + ")");

LinkedListNode<string> nodeP = node.Previous;

while (nodeP != null)

{

result.Insert(0, nodeP.Value + " ");

nodeP = nodeP.Previous;

}

node = node.Next;

while (node != null)

{

result.Append(" " + node.Value);

node = node.Next;

}

Console.WriteLine(result);

}

}

}

自定义链表:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace 自定义链表

{

class Program

{

static void Main(string[] args)

{

}

}

public class Node<T>

{

public T data;

public Node()

{ }

public Node(T data)

{

this.data = data;

}

public Node<T> next = null;

}

public class Link<T>

{

//定义链表的头节点

private Node<T> head;

//链表初始化

public Link()

{

head = null;

}

/// <summary>

/// 链表的长度,遍历整个链表,知道链表结尾

/// </summary>

/// <returns></returns>

public int Count()

{

//定义一个节点

Node<T> p = head;

int count = 0;//链表计数器

//遍历链表

while (p!=null)

{

count++;

p = p.next;//移到下一个节点

}

return count;

}

/// <summary>

/// 取链表的第i个节点的值

/// </summary>

/// <param name="i">第i个节点</param>

/// <returns></returns>

public T GetElem(int i)

{

//定义一个节点

Node<T> p = head;

int k = 0;//计数器

//如果i大于链表的长度或i小于0,则报出异常

if (i>=Count()||i<0)

{

throw new Exception("error");

}

//如果i大于0且小于链表长度,则遍历链表知道第i个节点为止

while (k<i)

{

k++;

p = p.next;

}

return p.data;

}

/// <summary>

/// 在链表的第i个位置上插入新的节点

/// </summary>

/// <param name="e">要插入节点的值</param>

/// <param name="i">链表的第i个节点</param>

public void Insert(T e, int i)

{

Node<T> p = new Node<T>(e);//要插入的节点

Node<T> q = head;

int k = 0;//计数器

//如果i大于链表的长度或i小于0,则抛出异常

if (i>=Count()||i<0)

{

Console.WriteLine("Error");

return;

}

//如果再链表头插入,移动头指针

if (i==0)

{

p.next = head;

head = p;

return;

}

//遍历链表直到i-1个节点为止

while (k<i-1)

{

k++;

q = q.next;

}

//把新节点插入在第i以个点的位置

p.next = q.next;

q.next = p;

}

/// <summary>

/// 删除第i个节点

/// </summary>

/// <param name="i">链表的第i个节点</param>

public void RemoveAt(int i)

{

Node<T> p = head;

int k = 0;//计数器

// //如果i大于链表的长度或i小于0,则抛出异常

if (i >= Count() || i < 0)

{

Console.WriteLine("Error");

return;

}

//如果删除链表头,移动头指针

if (i==0)

{

head.next = head.next.next;

return;

}

//遍历链表直到第i-1个节点为止

while (k<i-1)

{

k++;

p = p.next;

}

//删除第i个节点

p.next = p.next.next;

}

/// <summary>

/// 在链表尾加入一个新的节点

/// </summary>

/// <param name="e">新的节点的值</param>

public void Add(T e)

{

Node<T> p = new Node<T>(e);//创建一个新的节点

Node<T> q = new Node<T>();

//如果链表为空,则将新的节点作为头

if (head==null)

{

head = p;

return;

}

//如果链表不为空,则在链表尾加入新的节点

//从头指针开始遍历,直至链表尾

q = head;

while (q.next!=null)

{

q = q.next;

}

//在链表尾插入新节点

q.next = q;

}

/// <summary>

/// 查找某个元素在立案表中第一次出现的位置

/// </summary>

/// <param name="e">要查找的元素</param>

/// <returns></returns>

public int IndexOf(T e)

{

Node<T> p = head;

int k = 0;//计数器

/*

* 遍历整个链表,知道找到第一个节点的值

* 与钙元素相等退出,并返回相应的位置索引.

* 如果没有找到,则返回-1

*/

//从头指针开始遍历,找到退出,并返回相应的位置索引

while (p.next!=null)

{

if (p.data.Equals(e))

{

return k;

}

k++;

p = p.next;

}

if (!p.data.Equals(e))

{

k++;

}

//如果没有找到,则返回-1

return k >= Count() ? -1 : k;

}

/// <summary>

/// 查找某个元素在链表中最后一次出现的位置

/// </summary>

/// <param name="e">要查找的元素</param>

/// <returns>这个元素在链表中最后一次出现的位置的索引</returns>

public int LastIndexOf(T e)

{

Node<T> p = head;

int index = -1;//最后一次出现的位置索引

int k = 0;//计数器

/*

* 遍历整个链表,每发现相应节点的值与该元素相等

* 则将该节点的位置所以赋给index,

* 这样index的值就是最后一次的值.如果没有,则返回-1

*

*/

while (p.next!=null)

{

if (p.data.Equals(e))

{

index = k;

}

k++;

p = p.next;

}

if (p.data.Equals(e))

{

index = k;

}

return index;

}

/// <summary>

/// 判断链表是否为空

/// </summary>

/// <returns></returns>

public bool Empty()

{

return head == null ? true : false;

}

/// <summary>

/// 清空链表

/// </summary>

public void Clear()

{

head = null;

}

/// <summary>

/// 将链表转成数组

/// </summary>

/// <returns>转换后的数组</returns>

public T[] ToArray()

{

T[] array = new T[Count()];//定义一个与链表长度相同的数组

/*

* 遍历链表,将链表的每个节点的值放到相应的数组里

*

*/

Node<T> p = head;

int i = 0;//数组下标计数器

while (p.next!=null)

{

array[i++] = p.data;

p = p.next;

}

array[Count() - 1] = p.data;

return array;

}

/// <summary>

/// 将一个数组加到链表中

/// </summary>

/// <param name="a">要加入链表的数组</param>

public void AddRange(T[] a)

{

//遍历整个数组,将数组中的每个元素作为一个新的节点加入到链表中

for (int i = 0; i < a.Length; i++)

{

Add(a[i]);

}

}

/// <summary>

/// 删除链表中值为某个元素的所有节点

/// </summary>

/// <param name="e">要删除节点的值</param>

public void Remove(T e)

{

//如果头指针的值等于这个元素,则删除这个元素,并将头指针后移

while (head.data.Equals(e))

{

head = head.next;

}

//如果不是头指针,则删除该节点

Node<T> p = head;

while (p.next.next!=null)

{

if (p.next.data.Equals(e))

{

p.next = p.next.next;

continue;

}

p = p.next;

}

if (p.next.data.Equals(e))

{

p.next = null;

}

}

/// <summary>

///将链表中所有为某个值的节点替换为另一个值

/// </summary>

/// <param name="first"></param>

/// <param name="second"></param>

public void Replace(T first, T second)

{

Node<T> p = head;

while (p.next!=null)

{

if (p.data.Equals(first))

{

p.data = second;

}

p = p.next;

}

if (p.data.Equals(first))

{

p.data = second;

}

}

/// <summary>

/// 链表反转

/// </summary>

public void Reverse()

{

Node<T> p = head;

Node<T> newhead = head;

Node<T> q = p;

p = p.next;

newhead.next = null;

while (p.next!=null)

{

q = p;

p = p.next;

q.next = newhead;

newhead = q;

}

q = p;

q.next = newhead;

newhead = p;

head = newhead;

}

}

}

C#编程(五十一)----------链表的更多相关文章

  1. 《剑指Offer》题五十一~题六十

    五十一.数组中的逆序对 题目:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数.例如,在数组{7, 5, 6, 4}中,一共存 ...

  2. Java进阶(五十一)必须记住的Myeclipse快捷键

    Java进阶(五十一)必须记住的Myeclipse快捷键 在调试程序的时候,我们经常需要注释一些代码,在用Myeclipse编程时,就可以用 Ctrl+/ 为选中的一段代码加上以 // 打头的注释:当 ...

  3. 孤荷凌寒自学python第五十一天初次尝试使用python连接Firebase数据库

    孤荷凌寒自学python第五十一天初次尝试使用python连接Firebase数据库 (完整学习过程屏幕记录视频地址在文末) 今天继续研究Firebase数据库,利用google免费提供的这个数据库服 ...

  4. Linux网络编程(五)

    /*Linux网络编程(五)——多路IO复用之select() 网络编程中,使用IO复用的典型场合: 1.当客户处理多个描述字时(交互式输入以及网络接口),必须使用IO复用. 2.一个客户同时处理多个 ...

  5. Gradle 1.12用户指南翻译——第五十一章. 发布构件

    本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见:http://blog.csdn.net/column/details/gradle-translation.html翻译项目请关注Github上 ...

  6. Java进阶(五十一)Could not create the view: An unexpected exception was thrown

    Java进阶(五十一)Could not create the view: An unexpected exception was thrown 今天打开Myeclipse10的时候,发现server ...

  7. SQL注入之Sqli-labs系列第五十关,第五十一关,第五十二关,第五十三关(ORDER BY堆叠注入)

    0x1第五十关 源码中使用的mysqli_multi_query()函数,而之前使用的是mysqli_query(),区别在于mysqli_multi_query()可以执行多个sql语句,而mysq ...

  8. 第三百五十一节,Python分布式爬虫打造搜索引擎Scrapy精讲—将selenium操作谷歌浏览器集成到scrapy中

    第三百五十一节,Python分布式爬虫打造搜索引擎Scrapy精讲—将selenium操作谷歌浏览器集成到scrapy中 1.爬虫文件 dispatcher.connect()信号分发器,第一个参数信 ...

  9. “全栈2019”Java第五十一章:继承与final关键字详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  10. Python第五十一天 python2升级为python3

    Python第五十一天  python2升级为python3 公司使用的生产环境系统是centos7,所以这里以centos7系统为基础,讲解将python2升级为python3的方法 centos7 ...

随机推荐

  1. The project cannot be built until its prerequisite base-service is built. Cleaning and building all projects is recommended

    参考网址:http://chiangfai.iteye.com/blog/2223661,谢谢! 果然如文中所述,close,重新编译即可!

  2. Java8系列之重新认识HashMap

    转自:  http://www.importnew.com/20386.html   简介 Java为数据结构中的映射定义了一个接口java.util.Map,此接口主要有四个常用的实现类,分别是Ha ...

  3. jexus http to https

    一.摘要 1.80端口上只要没有网站使用 hosts=* 这样的配置,jexus会自动将域名跳转到 https 上.也就是说,你把网站默认配置文件default中的hosts=*改成具体的其它的域名, ...

  4. java 嵌套接口

    接口可以嵌套在其它类或接口中,可以拥有public和"包访问权限"两种可见性 作为一种新添加的方式,接口也可以实现为private 当实现某个接口时,并不需要实现嵌套在其内的任何接 ...

  5. tomcat错误信息解决方案【严重:StandardServer.await: create[8005]】

    错误信息:   严重: StandardServer.await: create[8005]:  java.net.BindException: Address already in use: JVM ...

  6. 跟据经纬度实现附近搜索Java实现

    现在很多手机软件都用附近搜索功能,但具体是怎么实现的呢>在网上查了很多资料,mysql空间数据库.矩形算法.geohash我都用过了,当数据上了百万之后mysql空间数据库方法是最强最精确的(查 ...

  7. input标签的事件汇总

    我在做一个注册时用到了,在网上查的,比较碎.就汇总了下, 1.onfocus  当input 获取到焦点时触发 2.onblur  当input失去焦点时触发,注意:这个事件触发的前提是已经获取了焦点 ...

  8. .NetCore 使用Jenkins发布多环境下的项目并适配数据库EFCore数据库更新及替换配置文件

    说明 1.git上的配置地址可能都是本地环境,提交到git server后怎么来使用发布不同环境? 2.关于EFCore本地数据库有更新的情况 添加了 Migrations文件 怎么在构建的时候去更新 ...

  9. Android Studio 3.0正式版填坑之路

    原文:https://www.jianshu.com/p/9b25087a5d7d   Android Studio 3.0启动图 序言 总看别人的文章,今天尝试着自己来写一篇.在逛论坛时候,无意间发 ...

  10. 【笔试题】在 Java 中,如何跳出当前的多重嵌套循环?

    笔试题 在 Java 中,如何跳出当前的多重嵌套循环? public class Demo { public static void main(String[] args) { System.out. ...