链表特点(单链表 双链表)

优点:插入和删除非常快。因为单链表只需要修改Next指向的节点,双链表只需要指向Next和Prev的节点就可以完成插入和删除操作。

缺点:当需要查找某一个节点的时候就需要一个节点一个节点去访问,这样所花的时候就比较多了。(顺序表可以弥补这缺点,但插入和删除就非常耗性能)

单链表

单链表的构成:必须要有一个链表头(head),每个节点里面有一个Next用于指向下一个节点(类似于指针)。最后一个节点的Next为null来标识链表的尾。

如下图

代码实现

 /* ------------  单链表 ------------- */
//链表头
SingleLink head = new SingleLink();
SingleLink node;
 
//添加节点
node = new SingleLink(, "刘德华");
SingleLink.Add(ref head, node);
 
node = new SingleLink(, "张学友");
SingleLink.Add(ref head, node);
 
node = new SingleLink(, "郭富城");
SingleLink.Add(ref head, node);
 
node = new SingleLink(, "黎明");
SingleLink.Add(ref head, node);
 
 
//删除节点
SingleLink.Remove(ref head, );
 
//遍历所有节点
SingleLink cursor = head;
while (cursor.Next != null)
{
    Console.WriteLine(cursor.Next.ToString());
    cursor = cursor.Next;
}
 
 
/// <summary>
/// 单链表
/// </summary>
public class SingleLink
{
    public int No { get; set; }
 
    public string Name { get; set; }
 
    //指向下一个节点(有点像指针)
    public SingleLink Next { get; set; }
 
    public SingleLink() { }
 
    public SingleLink(int no, string name)
    {
        this.No = no;
        this.Name = name;
    }
 
 
    /// <summary>
    /// 添加
    /// </summary>
    /// <param name="head">链表头</param>
    /// <param name="addNode">添加节点</param>
    public static void Add(ref SingleLink head, SingleLink addNode)
    {
        SingleLink cursor = head;
        while (cursor.Next != null)
        {
            cursor = cursor.Next;
        }
        cursor.Next = addNode;
    }
 
 
    /// <summary>
    /// 删除
    /// </summary>
    /// <param name="head">链表头</param>
    /// <param name="no">删除编号</param>
    public static void Remove(ref SingleLink head, int no)
    {
        SingleLink cursor = head;
        while (cursor.Next !=null)
        {
            if (cursor.Next.No == no)
            {
                cursor.Next = cursor.Next.Next;
                return;
            }
            cursor = cursor.Next;
        }
    }
 
 
    /// <summary>
    /// 输入信息(重写ToString方法)
    /// </summary>
    /// <returns></returns>
    public override string ToString()
    {
        return "No---> " + No + "  Name---> " + Name;
    }
}

代码分析图

双链表

  双链表的构成:双链表跟单链表差不多,也是必须要有一个链表头(head),每个节点里面有一个Next,最后一个节点的Next为null来标识链表的尾。只不过双链表在每个节点上面添加一个Prev,来标识当前节点的上一个节点。

如图:

代码实现

 /* ------------  双链表 ------------- */
//链表头
DoubleLink head = new DoubleLink();
DoubleLink node;
 
//添加节点
node = new DoubleLink(,"刘德华");
DoubleLink.Add(ref head, node);
 
node = new DoubleLink(, "张学友");
DoubleLink.Add(ref head, node);
 
node = new DoubleLink(, "郭富城");
DoubleLink.Add(ref head, node);
 
node = new DoubleLink(, "黎明");
DoubleLink.Add(ref head, node);
 
//删除节点
DoubleLink.Remove(ref head,);
 
//遍历所有节点
DoubleLink cursor = head;
while (cursor.Next != null)
{
    Console.WriteLine(cursor.Next.ToString());
    cursor = cursor.Next;
}
 
 
/// <summary>
/// 双链表
/// </summary>
public class DoubleLink
{
    public int No { get; set; }
 
    public string Name { get; set; }
 
    //下个节点
    public DoubleLink Prev { get; set; }
 
    //上个节点
    public DoubleLink Next { get; set; }
 
    public DoubleLink() { }
 
    public DoubleLink(int no, string name)
    {
        this.No = no;
        this.Name = name;
    }
 
 
    /// <summary>
    /// 添加
    /// </summary>
    /// <param name="head">链表头</param>
    /// <param name="addNode"></param>
    public static void Add(ref DoubleLink head, DoubleLink addNode)
    {
        DoubleLink cursor = head;
        while (cursor.Next != null)
        {
            cursor = cursor.Next;
        }
        cursor.Next = addNode;
        cursor.Next.Prev = cursor;
    }
 
 
    /// <summary>
    /// 删除
    /// </summary>
    /// <param name="head">链表头</param>
    /// <param name="no">删除编号</param>
    public static void Remove(ref DoubleLink head, int no)
    {
        DoubleLink cursor = head.Next;
        while (cursor != null)
        {
            if (cursor.No == no)
            {
                //防止是删除最后一个
                if (cursor.Next != null)
                {
                    cursor.Next.Prev = cursor.Prev;
                }
                cursor.Prev.Next = cursor.Next;
                return;
            }
            cursor = cursor.Next;
        }
    }
 
 
    /// <summary>
    /// 输入信息(重写ToString方法)
    /// </summary>
    /// <returns></returns>
    public override string ToString()
    {
        return "No---> " + No + "  Name---> " + Name;
    }
}

代码分析图

环形链表

  环形链表是在单链表基础之上把尾指向头就构成了一个环形的链表了。也就是单链表最后一个节点的Next指Head就可以了。

 如图:

  

代码实现

 //环形链表
LoopLink head = new LoopLink();
LoopLink node; //添加节点
node = new LoopLink(, "刘德华");
LoopLink.Add(ref head, node); node = new LoopLink(, "张学友");
LoopLink.Add(ref head, node); node = new LoopLink(, "郭富城");
LoopLink.Add(ref head, node); node = new LoopLink(, "黎明");
LoopLink.Add(ref head, node); LoopLink.Remove(ref head, ); //遍历所有节点(遍历需要拿到它的头或者尾来标识链表的结束位置,我是拿到头来遍历的)
LoopLink cursor = head;
LoopLink first = head;
//首先输出头的信息
Console.WriteLine(head);
//遍历所有节点,如果遍历到头节点就退出循环,链表打印完成
while (!Object.ReferenceEquals(cursor.Next, first))
{
Console.WriteLine(cursor.Next.ToString());
cursor = cursor.Next;
} /// <summary>
/// 环形链表
/// </summary>
class LoopLink
{ public int No { get; set; } public string Name { get; set; } public LoopLink Next { get; set; } public LoopLink() { } public LoopLink(int no, string name)
{
this.No = no;
this.Name = name;
} public static LoopLink Cursor { get; set; } /// <summary>
/// 添加
/// </summary>
/// <param name="head">链表头</param>
/// <param name="addNode">所要添加节点</param>
public static void Add(ref LoopLink head, LoopLink addNode)
{
if (head.Next == null)
{
head = addNode;
head.Next = addNode;
Cursor = head;
}
else
{
Cursor.Next = addNode;
addNode.Next = head;
Cursor = Cursor.Next;
}
} /// <summary>
/// 删除节点
/// </summary>
/// <param name="head">链表头</param>
/// <param name="no">所要删除编号</param>
public static void Remove(ref LoopLink head, int no)
{
LoopLink cur = head; while (true)
{
if (cur.Next.No == no)
{
cur.Next = cur.Next.Next;
return;
}
cur = cur.Next;
}
} /// <summary>
/// 输入信息(重写ToString方法)
/// </summary>
/// <returns></returns>
public override string ToString()
{
return "No---> " + No + " Name---> " + Name;
}
}

扩展训练(面试题)

  题目:有一颗炸弹,有N个人围成一个圆形,从第K个人开始数数,数M就退出圆。最后算出留下来要被炸死是第几个人。请用代码实现。

  代码如下:

 //N个人
int n = ; //第K个人开始数数
int k = ; //数到M就退出
int m = ; Game head = new Game(); //构建一个由N个人组成的圆形
Game.Add(ref head, n);
//查找谁会被炸死
Game.Bomb(ref head, k, m); /// <summary>
/// 游戏类
/// </summary>
public class Game
{
public int No { get; set; } public Game Next { get; set; } public Game() { } public Game(int no)
{
this.No = no;
} public static void Add(ref Game head, int n)
{
Game cursor = null;
for (int i = ; i < n; i++)
{
Game temp = new Game(i+);
if (i == )
{
head.Next = temp;
head = temp;
cursor = head;
}
else
{
cursor.Next = temp;
temp.Next = head;
cursor = cursor.Next;
}
}
} /// <summary>
/// 查找谁会被炸死
/// </summary>
/// <param name="head">链表头</param>
/// <param name="k">开始数数的人</param>
/// <param name="m">数几就退出圆圈</param>
public static void Bomb(ref Game head,int k, int m)
{
Game tail = head; //拿到最后一个节点
while (!Object.ReferenceEquals(tail.Next,head))
{
tail = tail.Next;
} //从第K个人开始数数
for (int i = ; i < k; i++)
{
head = head.Next;
tail = tail.Next;
} //当头跟尾是同一个节点说明找到最终的节点
int mark = ;
while (!object.ReferenceEquals(tail,head))
{
for (int i = ; i < m-; i++)
{
head = head.Next;
tail = tail.Next;
} Console.WriteLine(@"第"+mark+@"个安全退出人的编号:"+head.No); head = head.Next;
tail.Next = head;
mark++;
} Console.WriteLine(@"最后被炸死人的编号:" + head.No);
}
}

  总结:

    1.扩展训练题其实考的就是环形链表,这个题目跟约瑟夫问题是一样的(实现思路是一样的)

    2.“程序=算法+数据结构”,但是在我们真正开发的时候算法和数据结构用到很少,一般比较大型项目或者复杂度比较高项目和游戏里面可能才会用到这些,但是我们还是要了解,说不定面试考到了呢?(答对了会加分的哦!^_^)

    3.链表什么时候会用到呢?比如说象棋里面有悔棋,我们就可以用双向链表来实现,这样就可以悔到上一步也可以下一步了,还有很多应用场景。而单链表的话像LinkedList就是用单链表实现的(但是LinkedList被List代替,不推荐用LinkedList,推荐用List.自己查一下为什么?)

  

  (本人学识有限,文章如有误,愿见谅。希望能指出来,以免误人子弟了。^_^)

C# 数据结构 - 单链表 双链表 环形链表的更多相关文章

  1. 【算法训练营day4】LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表II

    [算法训练营day4]LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表 ...

  2. 数据结构与算法——链表 Linked List(单链表、双向链表、单向环形链表-Josephu 问题)

    链表是有序的列表,但是在内存中存储图下图所示 链表是以 节点 的方式来存储,是 链式存储 每个节点包含 data 域.next 域,指向下一个节点 链表的各个节点 不一定是连续存储,如上图所示 链表还 ...

  3. 图解Java数据结构之环形链表

    本篇文章介绍数据结构中的环形链表. 介绍 环形链表,类似于单链表,也是一种链式存储结构,环形链表由单链表演化过来.单链表的最后一个结点的链域指向NULL,而环形链表的建立,不要专门的头结点,让最后一个 ...

  4. 代码随想录第四天| 24. 两两交换链表中的节点 、19.删除链表的倒数第N个节点 、160.链表相交、142.环形链表II

    今天链表致死量 第一题 public static class ListNode { int val; ListNode next; ListNode() {} ListNode(int val) { ...

  5. 【LeetCode题解】141_环形链表

    目录 141_环形链表 描述 解法一:哈希表 思路 Java 实现 Python 实现 解法二:双指针(龟兔算法) 思路 Java 实现 Python 实现 141_环形链表 描述 给定一个链表,判断 ...

  6. java数据结构——单链表、双端链表、双向链表(Linked List)

    1.继续学习单链表,终于摆脱数组的魔爪了,单链表分为数据域(前突)和引用域(指针域)(后继),还有一个头结点(就好比一辆火车,我们只关心火车头,不关心其它车厢,只需知晓车头顺藤摸瓜即可),头结点没有前 ...

  7. php实现单,双向链表,环形链表解决约瑟夫问题

    传智播客PHP学院 韩顺平 PHP程序员玩转算法第一季  http://php.itcast.cn 聊天篇: 数学对我们编程来说,重不重要? 看你站在什么样的层次来说. 如果你应用程序开发,对数学要求 ...

  8. python实现数据结构单链表

    #python实现数据结构单链表 # -*- coding: utf-8 -*- class Node(object): """节点""" ...

  9. C语言数据结构-单链表的实现-初始化、销毁、长度、查找、前驱、后继、插入、删除、显示操作

    1.数据结构-单链表的实现-C语言 typedef struct LNode { int data; struct LNode* next; } LNode,*LinkList; //这两者等价.Li ...

随机推荐

  1. spring-eureka 源码解读----为什么一个服务最多两分钟被其他服务感知

    Eureka的wiki上有一句话,大意是一个服务启动后最长可能需要2分钟时间才能被其它服务感知到,但是文档并没有解释为什么会有这2分钟.其实这是由三处缓存 + 一处延迟造成的. 首先,Eureka对H ...

  2. [Xcode 实际操作]六、媒体与动画-(1)使用图形上下文按一定比例缩放图片

    目录:[Swift]Xcode实际操作 本文将演示如何通过图形上下文,来实现图片缩放的功能. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKi ...

  3. css正方形盒子 自适应

      <!DOCTYPE html>   <html lang="en">   <head>   <meta charset="U ...

  4. nodejs 从helloworld到高质量的后台服务server的一点思考

    ---恢复内容开始--- 新公司用的nodejs作为app和网站的后台服务server,所以最近对nodejs一直在学习,加上之前简单的学习了一点,看了两天后台接口源码,所以就直接上手干活了,下面是我 ...

  5. Huber鲁棒损失函数

    在统计学习角度,Huber损失函数是一种使用鲁棒性回归的损失函数,它相比均方误差来说,它对异常值不敏感.常常被用于分类问题上. 下面先给出Huber函数的定义: 这个函数对于小的a值误差函数是二次的, ...

  6. PAT甲级——1107 Social Clusters (并查集)

    本文同步发布在CSDN:https://blog.csdn.net/weixin_44385565/article/details/90409731 1107 Social Clusters (30  ...

  7. 【ZROI 537】贪心题 题解

    [ZROI 537]贪心题 题解 Link Solution 最大的一边直接放到一起贪心即可 着重讲小的一边 已知对于二分图匹配,其答案即为最大流 令时间集合为 \(T = {1,2,3,\dots, ...

  8. Luogu P1155 双栈排序 图论?模拟吧。。

    今天想做做图论,于是点开了这道题....(是二分图染色然而我没看出来) 四种操作及条件: 1. s1.push() 需满足 待push的元素小于栈顶 && { 若在原序列中,待push ...

  9. RabbitMQ使用教程(二)RabbitMQ用户管理,角色管理及权限设置

    上一篇博客 RabbitMQ使用教程(一)RabbitMQ环境安装配置及Hello World示例 中,我们成功的安装好了RabbitMQ环境,并通过一个Java客户端示例了解了用生产者来发布消息,用 ...

  10. abp(net core)+easyui+efcore仓储系统——ABP总体介绍(一)

    在前面我已经介绍了ASP.NET MVC.ASP.NET Razor.WEBAPI等技术.我准备通过一个实践项目来整体应用一下之前介绍的技术.本系列是介绍基于ABP+EasyUI的Web开发框架的形成 ...