C#单向链表的冒泡排序

C#单向链表的冒泡排序
标签: csharp 链表 单向链表 排序 冒泡 分类: 技术总结
///
/// 链表节点类
///
/// 节点中的存放的数据类型
public class Node where T : IComparable
{
///
/// 当前节点的数据
///
T data;
///
/// 节点中存放的数据
///
public T Data
{
get { return this.data; }
set { this.data = value; }
}
///
/// 当前节点的下一个节点
///
Node next;
///
/// 下一个节点
///
public Node Next
{
get { return this.next; }
set { this.next = value; }
}
///
/// 无参构造:数据为默认值,下一个节点为null
///
public Node()
{
this.data = default(T);
this.next = null;
}
///
/// 构造方法:数据为传过来的t,下一个节点为null
///
/// 传入的元素值
public Node(T t)
{
this.data = t;
this.next = null;
}
///
/// 构造方法:数据为t,下一个节点为node
///
/// 传入的元素值
/// 下一个节点
public Node(T t, Node node)
{
this.data = t;
this.next = node;
}

    public override string ToString()
    {
        T t = this.next == null ? default(T) : this.next.data;
        string s = string.Format("Data:{0},Next:{1}", data, t);
        return s;
    }
}

public interface ILinkList<T> where T : IComparable<T>
{
    void AddFirst(T t);
    void AddLast(T t);
    void Clear();
    int Count { get; }
    Node<T> Head { get; set; }
    void Insert(int index, T t);
    bool IsEmpty { get; }
    void RemoveAt(int index);
    void RemoveFirst();
    void RemoveLast();
    Node<T> this[int index] { get; }
}


/// <summary>
/// 链表操作类
/// </summary>
/// <typeparam name="T">链表中元素的类型</typeparam>
public class LinkList<T> : ILinkList<T> where T : IComparable<T>
{
    /// <summary>
    /// 链表头节点
    /// </summary>
    Node<T> head;
    /// <summary>
    /// 链表头部节点
    /// </summary>
    public Node<T> Head
    {
        get { return head; }
        set { head = value; }
    }
    /// <summary>
    /// 链表大小
    /// </summary>
    int size = 0;

    /// <summary>
    /// 添加节点到链表的开头
    /// </summary>
    /// <param name="t">要添加的数据</param>
    public void AddFirst(T t)
    {
        Node<T> node = new Node<T>(t);
        //如果头为null
        if (head == null)
        {
            //把头节点设置为node
            head = node;
            //大小加一
            size++;
            return;
        }
        //设置要添加的节点的下一个为当前链表的头节点
        node.Next = head;
        //将当前链表的头节点设置为要添加的节点。
        head = node;
        //大小加一
        size++;
    }

    /// <summary>
    /// 添加节点到链表的末尾
    /// </summary>
    /// <param name="t">要添加的数据</param>
    public void AddLast(T t)
    {
        Node<T> node = new Node<T>(t);
        //如果头为null
        if (head == null)
        {
            //把头节点设置为node
            head = node;
            //大小加一
            size++;
            return;
        }
        //获取链表的头节点
        Node<T> current = new Node<T>();
        current = head;
        //遍历整个链表
        while (true)
        {
            //直到某个节点的下一个为null的时候,就找到了链表的尾部了
            if (current.Next == null)
            {
                //将链表尾部的下一个设置为要添加的节点
                current.Next = node;
                //大小加一
                size++;
                break;
            }
            //如果不为null,那么将下一个节点作为当前节点,继续找
            current = current.Next;
        }
    }
    /// <summary>
    /// 在给定的索引处插入数据
    /// </summary>
    /// <param name="index">索引</param>
    /// <param name="t">要插入的数据</param>
    public void Insert(int index, T t)
    {
        Node<T> node = new Node<T>(t);
        //索引过小
        if (index < 0)
        {
            throw new IndexOutOfRangeException();
        }
        //索引过大
        if (index >= Count)
        {
            throw new IndexOutOfRangeException();
        }
        //如果链表是空的,而且索引大于0
        if (IsEmpty && index > 0)
        {
            throw new IndexOutOfRangeException();
        }
        //如果索引为0,意味着向链表头部添加节点。
        if (index == 0)
        {
            AddFirst(t);
            return;
        }
        //要插入位置的节点
        Node<T> current = head;
        //要插入位置的节点之前的节点
        Node<T> before = new Node<T>();
        int i = 0;
        while (true)
        {
            if (i == index - 1)
            {
                before = current;
            }
            if (i == index)
            {
                break;
            }
            i++;
            current = current.Next;
        }
        //把要插入的节点的下一个节点设置为current
        node.Next = current;
        //将上一个的下一个设置为node
        before.Next = node;
        //大小加一
        size++;
    }
    /// <summary>
    /// 移除链表中的节点
    /// </summary>
    /// <param name="index">要移除的节点的索引</param>
    public void RemoveAt(int index)
    {
        //链表头节点是空的
        if (IsEmpty)
        {
            throw new Exception("链表是空的。");
        }
        //索引过小
        if (index < 0)
        {
            throw new IndexOutOfRangeException();
        }
        //索引过大
        if (index >= Count)
        {
            throw new IndexOutOfRangeException();
        }
        //如果要移除的是头节点
        if (index == 0)
        {
            head = head.Next;
            //大小减一
            size--;
            return;
        }
        //要移除的节点
        Node<T> current = head;
        //要移除的前一个节点
        Node<T> before = new Node<T>();
        int i = 0;
        while (true)
        {
            if (i == index - 1)
            {
                before = current;
            }
            if (i == index)
            {
                break;
            }
            i++;
            current = current.Next;
        }
        //把下一个作为已经移除的节点
        current = current.Next;
        //把新的当前节点设置为上一个的Next
        before.Next = current;
        //大小减一
        size--;
    }
    /// <summary>
    /// 移除头节点
    /// </summary>
    public void RemoveFirst()
    {
        //链表头节点是空的
        if (IsEmpty)
        {
            throw new Exception("链表是空的。");
        }
        head = head.Next;
        //大小减一
        size--;
    }
    /// <summary>
    /// 移除尾节点
    /// </summary>
    public void RemoveLast()
    {
        //链表头节点是空的
        if (IsEmpty)
        {
            throw new Exception("链表是空的。");
        }
        if (size == 1)
        {
            RemoveFirst();
            return;
        }
        //要移除的节点
        Node<T> current = head;
        //要移除的前一个节点
        Node<T> before = new Node<T>();
        int i = 0;
        while (true)
        {
            if (i == size - 1 - 1)
            {
                before = current;
            }
            if (i == size - 1)
            {
                break;
            }
            i++;
            current = current.Next;
        }
        //把下一个作为已经移除的节点
        current = current.Next;
        //把新的当前节点设置为上一个的Next
        before.Next = current;
        //大小减一
        size--;
    }
    /// <summary>
    /// 判断链表是否是空的
    /// </summary>
    public bool IsEmpty
    {
        get
        {
            return head == null;
        }
    }
    /// <summary>
    /// 链表中元素的个数
    /// </summary>
    public int Count
    {
        get
        {
            也可以采用遍历的方法获得长度
            //int count = 0;
            取得链表头部节点
            //Node<T> current = new Node<T>();
            //current = head;
            遍历整个链表,直到最后一个Next为null的节点为止
            //while (current!=null)
            //{
            //    count++;
            //    current = current.Next;
            //}
            //return count;
            return size;
        }
    }
    /// <summary>
    /// 清除链表中的数据
    /// </summary>
    public void Clear()
    {
        head = null;
        size = 0;
    }
    /// <summary>
    /// 根据索引获取链表中的节点
    /// </summary>
    /// <param name="index">整型索引</param>
    /// <returns>节点</returns>
    public Node<T> this[int index]
    {
        get
        {
            //链表头节点是空的
            if (head == null)
            {
                throw new Exception("链表是空的。");
            }
            //索引过小
            if (index < 0)
            {
                throw new IndexOutOfRangeException();
            }
            //索引过大
            if (index >= Count)
            {
                throw new IndexOutOfRangeException();
            }
            //取得头节点
            Node<T> current = new Node<T>();
            current = head;
            int i = 0;
            //遍历链表
            while (true)
            {
                //找到第index个节点
                if (i == index)
                {
                    break;
                }
                current = current.Next;
                i++;
            }
            return current;
        }
    }

    /// <summary>
    /// 冒泡排序,不改变节点的位置,只交换节点的值
    /// 和数组的冒泡排序最接近
    /// </summary>
    public void BubbleSort1()
    {
        //如果链表是空的或者链表中只有一个节点,那不需要排序
        if (IsEmpty || size == 1)
        {
            return;
        }
        //外层循环节点
        Node<T> i;
        //内层循环节点
        Node<T> j;

        i = head;
        //循环不改变每个节点的先后次序,仅仅交换节点的值
        while (i.Next != null)
        {
            j = head;
            while (j.Next != null)
            {
                //比较前后两个节点的数据
                if (j.Data.CompareTo(j.Next.Data) > 0)
                {
                    //交换两个节点的数据
                    T temp = j.Data;
                    j.Data = j.Next.Data;
                    j.Next.Data = temp;
                }
                j = j.Next;
            }
            i = i.Next;
        }
    }

    /// <summary>
    /// 用交换节点的方法冒泡
    /// 这种方法需要额外的的新节点
    /// </summary>
    public void BubbleSort2()
    {
        //如果链表是空的或者链表中只有一个节点,那不需要排序
        if (IsEmpty || size == 1)
        {
            return;
        }
        //临时加的新节点
        Node<T> newNode;
        //外层循环变量
        Node<T> tail;
        //外层循环变量每次改变的值
        Node<T> loopValue;
        //交换两个节点的临时变量
        Node<T> temp;
        //在链表的头部加一个新的辅助接点
        newNode = new Node<T>();
        newNode.Next = head;
        head = newNode;
        //外层循环从链表尾部开始,尾部从最后一个节点开始
        //到达链表的头部为止
        for (tail = null; tail != head; tail = loopValue)
        {
            //开始让p等于链表头
            //在里层循环中更改p的位置
            loopValue = head;
            //里层循环从head开始,到要交换的两个节点的后一个是尾部位置,每次向后前进一个节点
            //因为一次循环就将一个最大的元素沉到最末尾了,所以下次不用到达末尾
            //而第一次遍历的时候第二个元素的下一个就是null
            for (Node<T> j = head; j.Next.Next != tail; j = j.Next)
            {
                //j其实就是要交换的两个节点的前一个节点
                //比较前后两个元素谁大谁小
                if (j.Next.Data.CompareTo(j.Next.Next.Data) > 0)
                {
                    //交换两个元素
                    //这一句temp中存的是两个元素中的后面一个
                    temp = j.Next.Next;
                    //这一句的意思是将后面一个节点的下一个设置成前面一个节点
                    j.Next.Next = temp.Next;
                    //temp中存的是后一个节点,那么这一句的意思是将原来后一个节点的Next设置成原来上一个节点,达到两个节点交换的目的
                    temp.Next = j.Next;
                    //j中存的是两个节点的上一个,这一句的意思是将原来的后一个接到原来两个要交换的节点的前一个
                    j.Next = temp;
                    //让loopValue指向交换过以后的第二个节点那里
                    //精髓就在这一句,通过在里层循环改变外层循环的条件
                    loopValue = j.Next.Next;
                }
            }
        }
        //最后去掉那个添加上了的辅助节点
        head = head.Next;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值