本文将会根据c#从双链表的特点、用途、实现来介绍双向链表。本人属于“懒散型”不逼到最后就不会去总结的人,实在是遇到双向链表问题较为频繁,错失众多机会,今在这不得不总结一下,让自己去更好的了解一下。(看到一句话挺好的:Technology is all!)
首先要知道的是:当我们碰见一个新的东西要去了解一下它是用来解决哪个问题的,才会能更好的理解好使用它。
链表的特点:一组任意储存单元来存储线性表的数据元素,每个数据元素不仅储存本身信息之外还需要储存指向另一个数据元素的信息。双向链表即数据元素除了储存自身信息外还储存指向上一个数据元素和下一个数据元素的两个信息。
链表的用途:所有的数据容器无非就是用来储存和管理需要的数据,即数据的增、删、改、查。双向链表的存在就是为了解决顺序表增删的耗费性能,单链表查询耗性能的问题。(由于链表申请的内存在堆中且位置是任意的,因此在增删时不必像顺序表一样需要依次移动后续元素。双向链表的数据元素储存了指向它的前驱元素和后继元素信息,因此查询时不必像单链表一样只能从头节点开始查询)
双向链表的实现:除了c#封装好的链表,自己去实现一个链表会对它有更好的理解。
using System;
//using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 双向链表
{
class Program
{
public static LinkList<int> intlist = new LinkList<int>();
static void Main(string[] args)
{
intlist.AddData(1);
intlist.AddData(2);
intlist.AddData(3);
Console.WriteLine(intlist.GetNode(1).Data);
intlist.Append(1,4);
Console.ReadKey();
}
}
//双向链表的节点类 //里面存放数据信息和 指向 前驱数据元素和后继元素的信息 指针
public class LinkListNode<T>
{
public T Data;//储存的信息
public LinkListNode<T> Next;//指向后继的指针
public LinkListNode<T> Prev;//指向前驱的指针
public LinkListNode(T date)
{
this.Data = date;
}
///构造函数
public LinkListNode(T data, LinkListNode<T> next, LinkListNode<T> prev)
{
this.Data = data;
this.Next = next;
this.Prev = prev;
}
}
//双向链表操作 //链表的 增 删 改 查
public class LinkList<T>
{
public readonly LinkListNode<T> LinkHead;//链表的表头 声明链表就是声明一个表头初始化表头
public int Size;
public LinkList()
{
//default关键字 类型的默认值 引用类型 null int类型 0 bool类型 false
LinkHead = new LinkListNode<T>(default(T), null, null);
LinkHead.Next = LinkHead;
LinkHead.Prev = LinkHead;
Size = 0;
}
public bool IsEmpty() => (Size == 0);
public int GetSize() => (Size);
//添加数据元素
public void AddData(T t)
{
LinkListNode<T> node = new LinkListNode<T>(t);
if (Size.Equals(0))
{
LinkHead.Next = node;
LinkHead.Prev = node;
node.Prev = LinkHead;
node.Next = LinkHead;
}
else
{
node.Next = LinkHead;
node.Prev = LinkHead.Prev;
LinkHead.Prev = node;
LinkHead.Prev.Prev.Next = node;
}
Size++;
}
//通过下表查找数据元素(节点)
public LinkListNode<T> GetNode(int index)
{
if (index < 0 || index >= Size)
{
throw new IndexOutOfRangeException("下标有错");
}
//正向查找
LinkListNode<T> node = LinkHead;
if (index < Size / 2)
{
for (int i = 0; i < Size / 2; i++)
{
node = node.Next;
}
}
if (index >= Size / 2)
{
for (int i = 0; i < Size - index; i++)
{
node = node.Prev;
}
}
return node;
}
//在index下标插入数据元素t
public void Append(int index, T t)
{
LinkListNode<T> node = new LinkListNode<T>(t);
LinkListNode<T> node1 ;
if (index < 0 || index >= Size)
{
throw new IndexOutOfRangeException("下标有错");
}
else
{
node1 = GetNode(index);
node.Next = node1;
node.Prev = node1.Prev;
node1.Prev.Next = node;
node1.Prev = node;
Size++;
}
}
//删除下表index的数据元素
public void Delete(int index)
{
LinkListNode<T> node = GetNode(index);
node.Prev.Next = node.Next;
node.Next.Prev = node.Prev;
Size--;
}
//改变下标的值
public void ChangeDate(int index, T t)
{
LinkListNode<T> node = GetNode(index);
node.Data = t;
}
}
}