C#双向循环链表

本文详细介绍了双向循环链表的结构及其操作,包括插入、删除、获取元素等方法,并探讨了如何通过count属性优化这些操作。通过实例展示了如何根据元素位置在链表前半部分或后半部分进行不同方式的遍历,以提高效率。此外,还提供了完整的双向循环链表类实现代码。
摘要由CSDN通过智能技术生成

双向循环链表跟单向循环链表差不多,多了一个指针。

部分代码可以优化:插入、删除、获取元素时可以根据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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值