双向链表:
- 了解双向链表和单向链表的区别
- 了解双向链表的优缺点
- 了解双向链表的运用场景
- C# 中双向链表的实现
双向链表和单向链表的区别:
如下图:
区别如下:
- 单向链表只能next ,双向链表可以return。
- 单向链表只有一个指向下一结点的指针,双向链表除了有一个指向下一结点的指针外,还有一个指向前一结点的指针。
- 单链表只能单向读取,双向链表可以通过prev()快速找到前一结点。
双向链表的优缺点:
优点:
- 可以找到前驱和后继,可进可退;
缺点:
- 增加删除节点复杂,需要多分配一个指针存储空间
双向链表的运用场景:
系统开发时缓存的LRU算法就是双向链表的运用场景之一
C# 中双向链表的实现
模型
/// <summary>
/// 双向链表节点
/// </summary>
/// <typeparam name="T"></typeparam>
public class BdNode<T>
{
public T Data { set; get; }
public BdNode<T> Next { set; get; }
public BdNode<T> Prev { set; get; }
public BdNode(T val, BdNode<T> prev, BdNode<T> next)
{
this.Data = val;
this.Prev = prev;
this.Next = next;
}
}
操作代码
public class DoubleLink<T>
{
//表头
private readonly BdNode<T> _linkHead;
//节点个数
private int _size;
public DoubleLink()
{
_linkHead = new BdNode<T>(default(T), null, null);//双向链表 表头为空
_linkHead.Prev = _linkHead;
_linkHead.Next = _linkHead;
_size = 0;
}
public int GetSize() => _size;
public bool IsEmpty() => (_size == 0);
//通过索引查找
private BdNode<T> GetNode(int index)
{
if (index < 0 || index >= _size)
throw new IndexOutOfRangeException("索引溢出或者链表为空");
if (index < _size / 2)//正向查找
{
BdNode<T> node = _linkHead.Next;
for (int i = 0; i < index; i++)
node = node.Next;
return node;
}
//反向查找
BdNode<T> rnode = _linkHead.Prev;
int rindex = _size - index - 1;
for (int i = 0; i < rindex; i++)
rnode = rnode.Prev;
return rnode;
}
public T Get(int index) => GetNode(index).Data;
public T GetFirst() => GetNode(0).Data;
public T GetLast() => GetNode(_size - 1).Data;
// 将节点插入到第index位置之前
public void Insert(int index, T t)
{
if (_size < 1 || index >= _size)
throw new Exception("没有可插入的点或者索引溢出了");
if (index == 0)
Append(_size, t);
else
{
BdNode<T> inode = GetNode(index);
BdNode<T> tnode = new BdNode<T>(t, inode.Prev, inode);
inode.Prev.Next = tnode;
inode.Prev = tnode;
_size++;
}
}
//追加到index位置之后
public void Append(int index, T t)
{
BdNode<T> inode;
if (index == 0)
inode = _linkHead;
else
{
index = index - 1;
if (index < 0)
throw new IndexOutOfRangeException("位置不存在");
inode = GetNode(index);
}
BdNode<T> tnode = new BdNode<T>(t, inode, inode.Next);
inode.Next.Prev = tnode;
inode.Next = tnode;
_size++;
}
public void Del(int index)
{
BdNode<T> inode = GetNode(index);
inode.Prev.Next = inode.Next;
inode.Next.Prev = inode.Prev;
_size--;
}
public void DelFirst() => Del(0);
public void DelLast() => Del(_size - 1);
public void ShowAll()
{
Console.WriteLine("******************* 链表数据如下 *******************");
for (int i = 0; i < _size; i++)
Console.WriteLine("(" + i + ")=" + Get(i));
Console.WriteLine("******************* 链表数据展示完毕 *******************\n");
}
}
调用例子
DoubleLink<int> dlink = new DoubleLink<int>();// 创建双向链表
Console.WriteLine("将 20 插入到表头之后");
dlink.Append(0, 10);
dlink.ShowAll();
Console.WriteLine("将 40 插入到表头之后");
dlink.Append(1, 30);
dlink.ShowAll();
Console.WriteLine("将 10 插入到表头之前");
dlink.Insert(0, 40);
dlink.ShowAll();
Console.WriteLine("将 30 插入到第一个位置之前");
dlink.Insert(1, 20);
dlink.ShowAll();
Console.WriteLine("展示第一个:" + dlink.GetFirst());
Console.WriteLine("删除第一个");
dlink.DelFirst();
Console.WriteLine("展示第一个:" + dlink.GetFirst());
Console.WriteLine("展示最后一个:" + dlink.GetLast());
Console.WriteLine("删除最后一个");
dlink.DelLast();
Console.WriteLine("展示最后一个:" + dlink.GetLast());
dlink.ShowAll();
Console.ReadKey();