C#编程(五十一)----------链表
原文链接: 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;
}
}
}