双向循环链表跟单向循环链表差不多,多了一个指针。
部分代码可以优化:插入、删除、获取元素时可以根据count判断一下是前半部分还是后半部分,来决定是走Next还是Last。
节点类:
/// <summary>
/// 节点
/// </summary>
public class Node<T>
{
private T data;
private Node<T> last;
private Node<T> next;
public T Data
{
get
{
return data;
}
set
{
data = value;
}
}
public Node<T> Last
{
get
{
return last;
}
set
{
last = value;
}
}
public Node<T> Next
{
get
{
return next;
}
set
{
next = value;
}
}
public Node()
{
data = default;
next = null;
last = null;
}
public Node(T data, Node<T> next, Node<T> last)
{
this.data = data;
this.next = next;
this.last = last;
}
public Node(T data)
{
this.data = data;
this.next = null;
this.last = null;
}
public Node(Node<T> next,Node<T> last)
{
this.next = next;
this.last = last;
}
}
双向循环链表类:
public class QDoublCircularLinkedList<T>
{
/// <summary>
/// 头结点
/// </summary>
private Node<T> head;
public Node<T> Head
{
get { return head; }
set { head = value; }
}
public QDoublCircularLinkedList()
{
head = new Node<T>();
head.Next = head;
head.Last = head;
}
private int count;
public int Count
{
get { return count; }
set { count = value; }
}
public bool IsEmpty()
{
return head == null || head.Next == head || head.Last == head;
}
public void Clear()
{
head.Next = head;
head.Last = head;
count = 0;
}
/// <summary>
/// 在末尾添加数据:使用Last,时间复杂度为O(1)
/// </summary>
/// <param name="data"></param>
public void Append(T data)
{
if (head == null)
{
head = new Node<T>();
head.Next = head;
head.Last = head;
}
var node = new Node<T>(data);
node.Next = head;
node.Last = head.Last;
//1.无顺序要求
//node.Last.Next = node;
//head.Last = node;
//2.有顺序要求
head.Last.Next = node;
head.Last = node;
count++;
}
/// <summary>
/// 插入索引元素前面,所以不会插到最后
/// 可以根据Count的一半来判断插入的索引值大小,采用next还是last遍历
/// 此处未判断,采用Next
/// </summary>
/// <param name="index"></param>
/// <param name="data"></param>
public void Insert(int index, T data)
{
if (index < 1 || IsEmpty())
{
//throw new System.Exception("插入位置不允许或链表为空!");
return;
}
Node<T> p = head;
int i = 1;
while (p.Next != head && i < index)
{
p = p.Next;
++i;
}
if (p.Next == head || i > index)
{
//throw new System.Exception("插入位置不正确!");
return;
}
Node<T> node = new(data);
node.Next = p.Next;
node.Last = p;
1.第一种:无需注意顺序
//p.Next = node;
//node.Next.Last = node;
//2.第二种:注意顺序
p.Next.Last = node;
p.Next = node;
count++;
}
/// <summary>
/// 根据index的位置在前半部分还是后半部分,采用不同的遍历
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public T GetItem(int index)
{
if (index < 1 || IsEmpty())
{
//throw new System.Exception("获取位置不允许或链表为空!");
return default;
}
Node<T> p = default;
int i = 1;
if (i < count / 2)
{
p = head.Next;
while (p != head && i < index)
{
p = p.Next;
++i;
}
}
else
{
p = head.Last;
i = count;
while (p != head && i > index)
{
p = p.Last;
--i;
}
}
if (p == head)
{
//throw new System.Exception("未找到元素!");
return default;
}
return p.Data;
}
/// <summary>
/// 这里也可以优化
/// </summary>
/// <param name="index"></param>
public void Delete(int index)
{
if (index < 1 || IsEmpty())
{
//throw new System.Exception("删除位置不允许或链表为空!");
return;
}
Node<T> p = head;
int i = 1;
while (p.Next != head && i < index)
{
p = p.Next;
++i;
}
//删除的是p.Next
if (p.Next == head || i > index)
{
//throw new System.Exception("未找到元素!");
return;
}
p.Next = p.Next.Next;
p.Next.Last = p;
count--;
}
/// <summary>
/// 整表创建:头插
/// </summary>
/// <param name="n"></param>
public void CreatListHead(int n, T data = default)
{
head = new Node<T>();
head.Next = head;
head.Last = head;
int i = 1;
Node<T> p = default;
while (i++ <= n)
{
p = new Node<T>(data);
p.Next = head.Next;
p.Last = head;
head.Next.Last = p;
head.Next = p;
}
count = n;
}
/// <summary>
/// 整表创建:尾插:可以用Append方法
/// </summary>
/// <param name="n"></param>
public void CreatListEnd(int n, T data = default)
{
head = new Node<T>();
head.Next = head;
head.Last = head;
Node<T> p = head;
int i = 1;
while (i++ <= n)
{
p.Next = new Node<T>(data);
p.Next.Last = p;
p = p.Next;
}
p.Next = head;
head.Last = p;
count = n;
}
}