C# 数据结构 - 单链表 双链表 环形链表
链表特点(单链表 双链表)
优点:插入和删除非常快。因为单链表只需要修改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# 数据结构 - 单链表 双链表 环形链表的更多相关文章
- 【算法训练营day4】LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表II
[算法训练营day4]LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表 ...
- 数据结构与算法——链表 Linked List(单链表、双向链表、单向环形链表-Josephu 问题)
链表是有序的列表,但是在内存中存储图下图所示 链表是以 节点 的方式来存储,是 链式存储 每个节点包含 data 域.next 域,指向下一个节点 链表的各个节点 不一定是连续存储,如上图所示 链表还 ...
- 图解Java数据结构之环形链表
本篇文章介绍数据结构中的环形链表. 介绍 环形链表,类似于单链表,也是一种链式存储结构,环形链表由单链表演化过来.单链表的最后一个结点的链域指向NULL,而环形链表的建立,不要专门的头结点,让最后一个 ...
- 代码随想录第四天| 24. 两两交换链表中的节点 、19.删除链表的倒数第N个节点 、160.链表相交、142.环形链表II
今天链表致死量 第一题 public static class ListNode { int val; ListNode next; ListNode() {} ListNode(int val) { ...
- 【LeetCode题解】141_环形链表
目录 141_环形链表 描述 解法一:哈希表 思路 Java 实现 Python 实现 解法二:双指针(龟兔算法) 思路 Java 实现 Python 实现 141_环形链表 描述 给定一个链表,判断 ...
- java数据结构——单链表、双端链表、双向链表(Linked List)
1.继续学习单链表,终于摆脱数组的魔爪了,单链表分为数据域(前突)和引用域(指针域)(后继),还有一个头结点(就好比一辆火车,我们只关心火车头,不关心其它车厢,只需知晓车头顺藤摸瓜即可),头结点没有前 ...
- php实现单,双向链表,环形链表解决约瑟夫问题
传智播客PHP学院 韩顺平 PHP程序员玩转算法第一季 http://php.itcast.cn 聊天篇: 数学对我们编程来说,重不重要? 看你站在什么样的层次来说. 如果你应用程序开发,对数学要求 ...
- python实现数据结构单链表
#python实现数据结构单链表 # -*- coding: utf-8 -*- class Node(object): """节点""" ...
- C语言数据结构-单链表的实现-初始化、销毁、长度、查找、前驱、后继、插入、删除、显示操作
1.数据结构-单链表的实现-C语言 typedef struct LNode { int data; struct LNode* next; } LNode,*LinkList; //这两者等价.Li ...
随机推荐
- js 常用排序
1. 冒泡排序 原理:从第一个元素开始,把当前元素和下一个索引元素进行比较.如果当前元素大,那么就交换位置,重复操作直到比较到最后一个元素 function bubbleSort(arr) { if ...
- poj 2769 感觉♂良好 (单调栈)
poj 2769 感觉♂良好 (单调栈) 比尔正在研发一种关于人类情感的新数学理论.他最近致力于研究一个日子的好坏,如何影响人们对某个时期的回忆. 比尔为人的一天赋予了一个正整数值. 比尔称这个值为当 ...
- 洛谷P2905 [USACO08OPEN]农场危机Crisis on the Farm
P2905 [USACO08OPEN]农场危机Crisis on the Farm 题目描述 约翰和他的奶牛组建了一只乐队“后街奶牛”,现在他们正在牧场里排练.奶牛们分成一堆 一堆,共1000)堆.每 ...
- 洛谷 P1875 佳佳的魔法药水
P1875 佳佳的魔法药水 题目描述 发完了 k 张照片,佳佳却得到了一个坏消息:他的 MM 得病了!佳佳和大家一样焦急 万分!治好 MM 的病只有一种办法,那就是传说中的 0 号药水 --怎么样才能 ...
- 洛谷P4003 无限之环(费用流)
传送门 神仙题啊……不看题解我可能一年都不一定做得出来……FlashHu大佬太强啦 到底是得有怎样的脑回路才能一眼看去就是费用流啊…… 建好图之后套个板子就好了,那么我们着重来讨论一下怎么建图 首先, ...
- 如何备份Chrome浏览器收藏夹
前言:最近,由于工作需要,要卸载当前Chrome版本,并安装最新版Chrome.卸载前,意识到之前收藏在收藏夹里的很多知识链接还未备份,于是有了今天的话题:如何备份Chrome浏览器的收藏夹? 主题: ...
- 【T-BABY 夜谈大数据】基于内容的推荐算法
这个系列主要也是自己最近在研究大数据方向,所以边研究.开发也边整理相关的资料.网上的资料经常是碎片式的,如果要完整的看完可能需要同时看好几篇文章,所以我希望有兴趣的人能够更轻松和快速地学习相关的知识. ...
- Linux上传下载工具FileZilla(GNU软件) 文件传输和配置文件修改
- 全功能Python测试框架:pytest
python通用测试框架大多数人用的是unittest+HTMLTestRunner,这段时间看到了pytest文档,发现这个框架和丰富的plugins很好用,所以来学习下pytest. imag ...
- 牛客练习赛41E(球的体积并)
球冠公式是\(\frac{\pi h^2(3R-h)}{3}\),这样再余弦公式用\(R_a\)和\(R_b\)导一导两个球冠的\(h\)就做完了.算是补了个camp时没做出来的小坑了. #inclu ...